Merge "MediaRouter: clear session info when disconnected"
diff --git a/Android.bp b/Android.bp
index 12bc906..df852bd 100644
--- a/Android.bp
+++ b/Android.bp
@@ -263,8 +263,6 @@
":libcamera_client_aidl",
":libcamera_client_framework_aidl",
":libupdate_engine_aidl",
- // TODO: this needs to be removed when statsd-framework.jar is separated out
- ":statsd_java_aidl",
":storaged_aidl",
":vold_aidl",
@@ -403,7 +401,6 @@
"unsupportedappusage",
"framework-media-stubs-systemapi",
"framework-mediaprovider-stubs-systemapi",
- "framework-tethering",
"framework-telephony-stubs",
],
@@ -446,13 +443,6 @@
}
filegroup {
- name: "graphicsstats_proto",
- srcs: [
- "libs/hwui/protos/graphicsstats.proto",
- ],
-}
-
-filegroup {
name: "libvibrator_aidl",
srcs: [
"core/java/android/os/IExternalVibrationController.aidl",
@@ -468,10 +458,11 @@
libs: [
"framework-appsearch-stubs",
"framework-sdkextensions-stubs-systemapi",
- "framework-statsd", // TODO(b/146167933): Use framework-statsd-stubs
+ "framework-statsd-stubs-module_libs_api",
"framework-permission-stubs-systemapi",
"framework-wifi-stubs",
"ike-stubs",
+ "framework-tethering-stubs",
],
installable: true,
javac_shard_size: 150,
@@ -496,6 +487,7 @@
"//frameworks/base/apex/blobstore/framework",
"//frameworks/base/apex/jobscheduler/framework",
"//frameworks/base/apex/statsd/service",
+ "//frameworks/base/packages/Tethering/tests/unit",
],
}
@@ -519,12 +511,10 @@
"framework-mediaprovider-stubs-systemapi",
"framework-permission-stubs-systemapi",
"framework-sdkextensions-stubs-systemapi",
- // TODO(b/146167933): Use framework-statsd-stubs instead.
- "framework-statsd",
+ "framework-statsd-stubs-module_libs_api",
"framework-wifi-stubs",
"ike-stubs",
- // TODO(b/147200698): should be the stub of framework-tethering
- "framework-tethering",
+ "framework-tethering-stubs",
// TODO (b/147688669) should be framework-telephony-stubs
"framework-telephony",
// TODO(jiyong): add stubs for APEXes here
@@ -625,6 +615,18 @@
out: ["com/android/internal/util/FrameworkStatsLog.java"],
}
+java_library {
+ name: "uieventloggerlib",
+ srcs: [
+ "core/java/com/android/internal/logging/UiEvent.java",
+ "core/java/com/android/internal/logging/UiEventLogger.java",
+ "core/java/com/android/internal/logging/UiEventLoggerImpl.java",
+ "core/java/com/android/internal/logging/InstanceId.java",
+ "core/java/com/android/internal/logging/InstanceIdSequence.java",
+ ":statslog-framework-java-gen",
+ ],
+}
+
gensrcs {
name: "framework-javastream-protos",
depfile: true,
diff --git a/apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java b/apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java
deleted file mode 100644
index 236f548..0000000
--- a/apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package android.os;
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.perftests.utils.BenchmarkState;
-import android.perftests.utils.PerfStatusReporter;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@LargeTest
-public class PackageManagerPerfTest {
- private static final String PERMISSION_NAME_EXISTS =
- "com.android.perftests.core.TestPermission";
- private static final String PERMISSION_NAME_DOESNT_EXIST =
- "com.android.perftests.core.TestBadPermission";
- private static final ComponentName TEST_ACTIVITY =
- new ComponentName("com.android.perftests.core",
- "android.perftests.utils.PerfTestActivity");
-
- @Rule
- public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
-
- @Test
- public void testCheckPermissionExists() {
- final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager();
- final String packageName = TEST_ACTIVITY.getPackageName();
-
- while (state.keepRunning()) {
- int ret = pm.checkPermission(PERMISSION_NAME_EXISTS, packageName);
- }
- }
-
- @Test
- public void testCheckPermissionDoesntExist() {
- final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager();
- final String packageName = TEST_ACTIVITY.getPackageName();
-
- while (state.keepRunning()) {
- int ret = pm.checkPermission(PERMISSION_NAME_DOESNT_EXIST, packageName);
- }
- }
-
- @Test
- public void testQueryIntentActivities() {
- final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager();
- final Intent intent = new Intent("com.android.perftests.core.PERFTEST");
-
- while (state.keepRunning()) {
- pm.queryIntentActivities(intent, 0);
- }
- }
-
- @Test
- public void testGetPackageInfo() throws Exception {
- final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager();
- final String packageName = TEST_ACTIVITY.getPackageName();
-
- while (state.keepRunning()) {
- pm.getPackageInfo(packageName, 0);
- }
- }
-
- @Test
- public void testGetApplicationInfo() throws Exception {
- final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager();
- final String packageName = TEST_ACTIVITY.getPackageName();
-
- while (state.keepRunning()) {
- pm.getApplicationInfo(packageName, 0);
- }
- }
-
- @Test
- public void testGetActivityInfo() throws Exception {
- final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager();
-
- while (state.keepRunning()) {
- pm.getActivityInfo(TEST_ACTIVITY, 0);
- }
- }
-}
diff --git a/apct-tests/perftests/core/src/android/view/CutoutSpecificationBenchmark.java b/apct-tests/perftests/core/src/android/view/CutoutSpecificationBenchmark.java
new file mode 100644
index 0000000..14282bf
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/view/CutoutSpecificationBenchmark.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.content.Context;
+import android.graphics.Matrix;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Region;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.PathParser;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class CutoutSpecificationBenchmark {
+ private static final String TAG = "CutoutSpecificationBenchmark";
+
+ private static final String BOTTOM_MARKER = "@bottom";
+ private static final String DP_MARKER = "@dp";
+ private static final String RIGHT_MARKER = "@right";
+ private static final String LEFT_MARKER = "@left";
+
+ private static final String DOUBLE_CUTOUT_SPEC = "M 0,0\n"
+ + "L -72, 0\n"
+ + "L -69.9940446283, 20.0595537175\n"
+ + "C -69.1582133885, 28.4178661152 -65.2, 32.0 -56.8, 32.0\n"
+ + "L 56.8, 32.0\n"
+ + "C 65.2, 32.0 69.1582133885, 28.4178661152 69.9940446283, 20.0595537175\n"
+ + "L 72, 0\n"
+ + "Z\n"
+ + "@bottom\n"
+ + "M 0,0\n"
+ + "L -72, 0\n"
+ + "L -69.9940446283, -20.0595537175\n"
+ + "C -69.1582133885, -28.4178661152 -65.2, -32.0 -56.8, -32.0\n"
+ + "L 56.8, -32.0\n"
+ + "C 65.2, -32.0 69.1582133885, -28.4178661152 69.9940446283, -20.0595537175\n"
+ + "L 72, 0\n"
+ + "Z\n"
+ + "@dp";
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private Context mContext;
+ private DisplayMetrics mDisplayMetrics;
+
+ /**
+ * Setup the necessary member field used by test methods.
+ */
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+ mDisplayMetrics = new DisplayMetrics();
+ mContext.getDisplay().getRealMetrics(mDisplayMetrics);
+ }
+
+
+ private static void toRectAndAddToRegion(Path p, Region inoutRegion, Rect inoutRect) {
+ final RectF rectF = new RectF();
+ p.computeBounds(rectF, false /* unused */);
+ rectF.round(inoutRect);
+ inoutRegion.op(inoutRect, Region.Op.UNION);
+ }
+
+ private static void oldMethodParsingSpec(String spec, int displayWidth, int displayHeight,
+ float density) {
+ Path p = null;
+ Rect boundTop = null;
+ Rect boundBottom = null;
+ Rect safeInset = new Rect();
+ String bottomSpec = null;
+ if (!TextUtils.isEmpty(spec)) {
+ spec = spec.trim();
+ final float offsetX;
+ if (spec.endsWith(RIGHT_MARKER)) {
+ offsetX = displayWidth;
+ spec = spec.substring(0, spec.length() - RIGHT_MARKER.length()).trim();
+ } else if (spec.endsWith(LEFT_MARKER)) {
+ offsetX = 0;
+ spec = spec.substring(0, spec.length() - LEFT_MARKER.length()).trim();
+ } else {
+ offsetX = displayWidth / 2f;
+ }
+ final boolean inDp = spec.endsWith(DP_MARKER);
+ if (inDp) {
+ spec = spec.substring(0, spec.length() - DP_MARKER.length());
+ }
+
+ if (spec.contains(BOTTOM_MARKER)) {
+ String[] splits = spec.split(BOTTOM_MARKER, 2);
+ spec = splits[0].trim();
+ bottomSpec = splits[1].trim();
+ }
+
+ final Matrix m = new Matrix();
+ final Region r = Region.obtain();
+ if (!spec.isEmpty()) {
+ try {
+ p = PathParser.createPathFromPathData(spec);
+ } catch (Throwable e) {
+ Log.wtf(TAG, "Could not inflate cutout: ", e);
+ }
+
+ if (p != null) {
+ if (inDp) {
+ m.postScale(density, density);
+ }
+ m.postTranslate(offsetX, 0);
+ p.transform(m);
+
+ boundTop = new Rect();
+ toRectAndAddToRegion(p, r, boundTop);
+ safeInset.top = boundTop.bottom;
+ }
+ }
+
+ if (bottomSpec != null) {
+ int bottomInset = 0;
+ Path bottomPath = null;
+ try {
+ bottomPath = PathParser.createPathFromPathData(bottomSpec);
+ } catch (Throwable e) {
+ Log.wtf(TAG, "Could not inflate bottom cutout: ", e);
+ }
+
+ if (bottomPath != null) {
+ // Keep top transform
+ m.postTranslate(0, displayHeight);
+ bottomPath.transform(m);
+ p.addPath(bottomPath);
+ boundBottom = new Rect();
+ toRectAndAddToRegion(bottomPath, r, boundBottom);
+ bottomInset = displayHeight - boundBottom.top;
+ }
+ safeInset.bottom = bottomInset;
+ }
+ }
+ }
+
+ @Test
+ public void parseByOldMethodForDoubleCutout() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ oldMethodParsingSpec(DOUBLE_CUTOUT_SPEC, mDisplayMetrics.widthPixels,
+ mDisplayMetrics.heightPixels, mDisplayMetrics.density);
+ }
+ }
+
+ @Test
+ public void parseByNewMethodForDoubleCutout() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ new CutoutSpecification.Parser(mDisplayMetrics.density,
+ mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels)
+ .parse(DOUBLE_CUTOUT_SPEC);
+ }
+ }
+
+ @Test
+ public void parseLongEdgeCutout() {
+ final String spec = "M 0,0\n"
+ + "H 48\n"
+ + "V 48\n"
+ + "H -48\n"
+ + "Z\n"
+ + "@left\n"
+ + "@center_vertical\n"
+ + "M 0,0\n"
+ + "H 48\n"
+ + "V 48\n"
+ + "H -48\n"
+ + "Z\n"
+ + "@left\n"
+ + "@center_vertical\n"
+ + "M 0,0\n"
+ + "H -48\n"
+ + "V 48\n"
+ + "H 48\n"
+ + "Z\n"
+ + "@right\n"
+ + "@dp";
+
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ new CutoutSpecification.Parser(mDisplayMetrics.density,
+ mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels).parse(spec);
+ }
+ }
+
+ @Test
+ public void parseShortEdgeCutout() {
+ final String spec = "M 0,0\n"
+ + "H 48\n"
+ + "V 48\n"
+ + "H -48\n"
+ + "Z\n"
+ + "@bottom\n"
+ + "M 0,0\n"
+ + "H 48\n"
+ + "V -48\n"
+ + "H -48\n"
+ + "Z\n"
+ + "@dp";
+
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ new CutoutSpecification.Parser(mDisplayMetrics.density,
+ mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels).parse(spec);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java
index b6e39e1..8633c96 100644
--- a/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java
@@ -125,7 +125,9 @@
final WindowManager.LayoutParams mParams;
final int mWidth;
final int mHeight;
+ final Point mOutSurfaceSize = new Point();
final SurfaceControl mOutSurfaceControl;
+ final SurfaceControl mOutBlastSurfaceControl = new SurfaceControl();
final IntSupplier mViewVisibility;
@@ -150,7 +152,8 @@
mViewVisibility.getAsInt(), mFlags, mFrameNumber, mOutFrame,
mOutContentInsets, mOutVisibleInsets, mOutStableInsets,
mOutBackDropFrame, mOutDisplayCutout, mOutMergedConfiguration,
- mOutSurfaceControl, mOutInsetsState, new Point(), new SurfaceControl());
+ mOutSurfaceControl, mOutInsetsState, mOutSurfaceSize,
+ mOutBlastSurfaceControl);
}
}
}
diff --git a/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java b/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
index 62e9ba8..9e17e94 100644
--- a/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
+++ b/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
@@ -20,15 +20,19 @@
import android.app.Activity;
import android.app.UiAutomation;
+import android.content.Context;
import android.content.Intent;
+import android.os.BatteryManager;
import android.os.ParcelFileDescriptor;
import android.perftests.utils.PerfTestActivity;
+import android.provider.Settings;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.lifecycle.ActivityLifecycleCallback;
import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
import androidx.test.runner.lifecycle.Stage;
+import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
@@ -52,18 +56,36 @@
*/
static final File BASE_OUT_PATH = new File("/data/local/CorePerfTests");
+ private static int sOriginalStayOnWhilePluggedIn;
+
@BeforeClass
public static void setUpOnce() {
+ final Context context = getInstrumentation().getContext();
+ sOriginalStayOnWhilePluggedIn = Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
+ // Keep the device awake during testing.
+ setStayOnWhilePluggedIn(BatteryManager.BATTERY_PLUGGED_USB);
+
if (!BASE_OUT_PATH.exists()) {
executeShellCommand("mkdir -p " + BASE_OUT_PATH);
}
// In order to be closer to the real use case.
executeShellCommand("input keyevent KEYCODE_WAKEUP");
executeShellCommand("wm dismiss-keyguard");
- getInstrumentation().getContext().startActivity(new Intent(Intent.ACTION_MAIN)
+ context.startActivity(new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
+ @AfterClass
+ public static void tearDownOnce() {
+ setStayOnWhilePluggedIn(sOriginalStayOnWhilePluggedIn);
+ }
+
+ private static void setStayOnWhilePluggedIn(int value) {
+ executeShellCommand(String.format("settings put global %s %d",
+ Settings.Global.STAY_ON_WHILE_PLUGGED_IN, value));
+ }
+
/**
* Executes shell command with reading the output. It may also used to block until the current
* command is completed.
@@ -97,7 +119,7 @@
*/
static class PerfTestActivityRule extends ActivityTestRule<PerfTestActivity> {
private final Intent mStartIntent =
- new Intent().putExtra(PerfTestActivity.INTENT_EXTRA_KEEP_SCREEN_ON, true);
+ new Intent(getInstrumentation().getTargetContext(), PerfTestActivity.class);
private final LifecycleListener mLifecycleListener = new LifecycleListener();
PerfTestActivityRule() {
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
index 661f32f..c458d11 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
@@ -670,7 +670,7 @@
private void startApp(int userId, String packageName) throws RemoteException {
final Context context = InstrumentationRegistry.getContext();
final WaitResult result = ActivityTaskManager.getService().startActivityAndWait(null,
- context.getPackageName(),
+ context.getPackageName(), context.getFeatureId(),
context.getPackageManager().getLaunchIntentForPackage(packageName), null, null,
null, 0, 0, null, null, userId);
attestTrue("User " + userId + " failed to start " + packageName,
diff --git a/apct-tests/perftests/packagemanager/Android.bp b/apct-tests/perftests/packagemanager/Android.bp
new file mode 100644
index 0000000..17033e0
--- /dev/null
+++ b/apct-tests/perftests/packagemanager/Android.bp
@@ -0,0 +1,21 @@
+android_test {
+ name: "PackageManagerPerfTests",
+
+ srcs: ["src/**/*.java"],
+
+ static_libs: [
+ "platform-compat-test-rules",
+ "androidx.appcompat_appcompat",
+ "androidx.test.rules",
+ "androidx.test.ext.junit",
+ "androidx.annotation_annotation",
+ "apct-perftests-utils",
+ ],
+
+ libs: ["android.test.base"],
+
+ platform_apis: true,
+
+ test_suites: ["device-tests"],
+
+}
diff --git a/apct-tests/perftests/packagemanager/AndroidManifest.xml b/apct-tests/perftests/packagemanager/AndroidManifest.xml
new file mode 100644
index 0000000..520f4b5
--- /dev/null
+++ b/apct-tests/perftests/packagemanager/AndroidManifest.xml
@@ -0,0 +1,89 @@
+<?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.packagemanager">
+
+ <permission android:name="com.android.perftests.packagemanager.TestPermission" />
+ <uses-permission android:name="com.android.perftests.packagemanager.TestPermission" />
+
+ <queries>
+ <package android:name="com.android.perftests.appenumeration0" />
+ <package android:name="com.android.perftests.appenumeration1" />
+ <package android:name="com.android.perftests.appenumeration2" />
+ <package android:name="com.android.perftests.appenumeration3" />
+ <package android:name="com.android.perftests.appenumeration4" />
+ <package android:name="com.android.perftests.appenumeration5" />
+ <package android:name="com.android.perftests.appenumeration6" />
+ <package android:name="com.android.perftests.appenumeration7" />
+ <package android:name="com.android.perftests.appenumeration8" />
+ <package android:name="com.android.perftests.appenumeration9" />
+ <package android:name="com.android.perftests.appenumeration10" />
+ <package android:name="com.android.perftests.appenumeration11" />
+ <package android:name="com.android.perftests.appenumeration12" />
+ <package android:name="com.android.perftests.appenumeration13" />
+ <package android:name="com.android.perftests.appenumeration14" />
+ <package android:name="com.android.perftests.appenumeration15" />
+ <package android:name="com.android.perftests.appenumeration16" />
+ <package android:name="com.android.perftests.appenumeration17" />
+ <package android:name="com.android.perftests.appenumeration18" />
+ <package android:name="com.android.perftests.appenumeration19" />
+ <package android:name="com.android.perftests.appenumeration20" />
+ <package android:name="com.android.perftests.appenumeration21" />
+ <package android:name="com.android.perftests.appenumeration22" />
+ <package android:name="com.android.perftests.appenumeration23" />
+ <package android:name="com.android.perftests.appenumeration24" />
+ <package android:name="com.android.perftests.appenumeration25" />
+ <package android:name="com.android.perftests.appenumeration26" />
+ <package android:name="com.android.perftests.appenumeration27" />
+ <package android:name="com.android.perftests.appenumeration28" />
+ <package android:name="com.android.perftests.appenumeration29" />
+ <package android:name="com.android.perftests.appenumeration30" />
+ <package android:name="com.android.perftests.appenumeration31" />
+ <package android:name="com.android.perftests.appenumeration32" />
+ <package android:name="com.android.perftests.appenumeration33" />
+ <package android:name="com.android.perftests.appenumeration34" />
+ <package android:name="com.android.perftests.appenumeration35" />
+ <package android:name="com.android.perftests.appenumeration36" />
+ <package android:name="com.android.perftests.appenumeration37" />
+ <package android:name="com.android.perftests.appenumeration38" />
+ <package android:name="com.android.perftests.appenumeration39" />
+ <package android:name="com.android.perftests.appenumeration40" />
+ <package android:name="com.android.perftests.appenumeration41" />
+ <package android:name="com.android.perftests.appenumeration42" />
+ <package android:name="com.android.perftests.appenumeration43" />
+ <package android:name="com.android.perftests.appenumeration44" />
+ <package android:name="com.android.perftests.appenumeration45" />
+ <package android:name="com.android.perftests.appenumeration46" />
+ <package android:name="com.android.perftests.appenumeration47" />
+ <package android:name="com.android.perftests.appenumeration48" />
+ <package android:name="com.android.perftests.appenumeration49" />
+ </queries>
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.perftests.utils.PerfTestActivity">
+ <intent-filter>
+ <action android:name="com.android.perftests.packagemanager.PERFTEST" />
+ </intent-filter>
+ </activity>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.perftests.packagemanager"/>
+
+</manifest>
diff --git a/apct-tests/perftests/packagemanager/AndroidTest.xml b/apct-tests/perftests/packagemanager/AndroidTest.xml
new file mode 100644
index 0000000..c112d87
--- /dev/null
+++ b/apct-tests/perftests/packagemanager/AndroidTest.xml
@@ -0,0 +1,88 @@
+<?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 PackageManagerPerfTests 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="PackageManagerPerfTests.apk" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="force-queryable" value="false" />
+ <option name="test-file-name" value="QueriesAll0.apk" />
+ <option name="test-file-name" value="QueriesAll1.apk" />
+ <option name="test-file-name" value="QueriesAll2.apk" />
+ <option name="test-file-name" value="QueriesAll3.apk" />
+ <option name="test-file-name" value="QueriesAll4.apk" />
+ <option name="test-file-name" value="QueriesAll5.apk" />
+ <option name="test-file-name" value="QueriesAll6.apk" />
+ <option name="test-file-name" value="QueriesAll7.apk" />
+ <option name="test-file-name" value="QueriesAll8.apk" />
+ <option name="test-file-name" value="QueriesAll9.apk" />
+ <option name="test-file-name" value="QueriesAll10.apk" />
+ <option name="test-file-name" value="QueriesAll11.apk" />
+ <option name="test-file-name" value="QueriesAll12.apk" />
+ <option name="test-file-name" value="QueriesAll13.apk" />
+ <option name="test-file-name" value="QueriesAll14.apk" />
+ <option name="test-file-name" value="QueriesAll15.apk" />
+ <option name="test-file-name" value="QueriesAll16.apk" />
+ <option name="test-file-name" value="QueriesAll17.apk" />
+ <option name="test-file-name" value="QueriesAll18.apk" />
+ <option name="test-file-name" value="QueriesAll19.apk" />
+ <option name="test-file-name" value="QueriesAll20.apk" />
+ <option name="test-file-name" value="QueriesAll21.apk" />
+ <option name="test-file-name" value="QueriesAll22.apk" />
+ <option name="test-file-name" value="QueriesAll23.apk" />
+ <option name="test-file-name" value="QueriesAll24.apk" />
+ <option name="test-file-name" value="QueriesAll25.apk" />
+ <option name="test-file-name" value="QueriesAll26.apk" />
+ <option name="test-file-name" value="QueriesAll27.apk" />
+ <option name="test-file-name" value="QueriesAll28.apk" />
+ <option name="test-file-name" value="QueriesAll29.apk" />
+ <option name="test-file-name" value="QueriesAll30.apk" />
+ <option name="test-file-name" value="QueriesAll31.apk" />
+ <option name="test-file-name" value="QueriesAll32.apk" />
+ <option name="test-file-name" value="QueriesAll33.apk" />
+ <option name="test-file-name" value="QueriesAll34.apk" />
+ <option name="test-file-name" value="QueriesAll35.apk" />
+ <option name="test-file-name" value="QueriesAll36.apk" />
+ <option name="test-file-name" value="QueriesAll37.apk" />
+ <option name="test-file-name" value="QueriesAll38.apk" />
+ <option name="test-file-name" value="QueriesAll39.apk" />
+ <option name="test-file-name" value="QueriesAll40.apk" />
+ <option name="test-file-name" value="QueriesAll41.apk" />
+ <option name="test-file-name" value="QueriesAll42.apk" />
+ <option name="test-file-name" value="QueriesAll43.apk" />
+ <option name="test-file-name" value="QueriesAll44.apk" />
+ <option name="test-file-name" value="QueriesAll45.apk" />
+ <option name="test-file-name" value="QueriesAll46.apk" />
+ <option name="test-file-name" value="QueriesAll47.apk" />
+ <option name="test-file-name" value="QueriesAll48.apk" />
+ <option name="test-file-name" value="QueriesAll49.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.perftests.packagemanager" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/data/local/PackageManagerPerfTests" />
+ <option name="collect-on-run-ended-only" value="true" />
+ </metrics_collector>
+</configuration>
diff --git a/apct-tests/perftests/packagemanager/apps/query-all/Android.bp b/apct-tests/perftests/packagemanager/apps/query-all/Android.bp
new file mode 100644
index 0000000..3cb1589
--- /dev/null
+++ b/apct-tests/perftests/packagemanager/apps/query-all/Android.bp
@@ -0,0 +1,314 @@
+// 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_helper_app {
+ name: "QueriesAll0",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration0",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll1",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration1",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll2",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration2",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll3",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration3",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll4",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration4",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll5",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration5",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll6",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration6",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll7",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration7",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll8",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration8",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll9",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration9",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll10",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration10",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll11",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration11",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll12",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration12",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll13",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration13",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll14",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration14",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll15",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration15",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll16",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration16",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll17",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration17",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll18",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration18",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll19",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration19",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll20",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration20",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll21",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration21",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll22",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration22",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll23",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration23",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll24",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration24",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll25",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration25",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll26",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration26",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll27",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration27",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll28",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration28",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll29",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration29",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll30",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration30",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll31",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration31",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll32",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration32",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll33",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration33",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll34",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration34",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll35",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration35",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll36",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration36",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll37",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration37",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll38",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration38",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll39",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration39",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll40",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration40",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll41",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration41",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll42",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration42",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll43",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration43",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll44",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration44",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll45",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration45",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll46",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration46",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll47",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration47",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll48",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration48",
+ ]
+}
+android_test_helper_app {
+ name: "QueriesAll49",
+ aaptflags: [
+ "--rename-manifest-package com.android.perftests.appenumeration49",
+ ]
+}
diff --git a/apct-tests/perftests/packagemanager/apps/query-all/AndroidManifest.xml b/apct-tests/perftests/packagemanager/apps/query-all/AndroidManifest.xml
new file mode 100644
index 0000000..e2cfa04
--- /dev/null
+++ b/apct-tests/perftests/packagemanager/apps/query-all/AndroidManifest.xml
@@ -0,0 +1,81 @@
+<?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.appenumeration">
+
+ <application android:hasCode="false" >
+ <activity android:name="android.perftests.utils.PerfTestActivity">
+ <intent-filter>
+ <action android:name="com.android.perftests.packagemanager.PERFTEST" />
+ </intent-filter>
+ </activity>
+ </application>
+
+ <queries>
+ <package android:name="com.android.perftests.appenumeration0" />
+ <package android:name="com.android.perftests.appenumeration1" />
+ <package android:name="com.android.perftests.appenumeration2" />
+ <package android:name="com.android.perftests.appenumeration3" />
+ <package android:name="com.android.perftests.appenumeration4" />
+ <package android:name="com.android.perftests.appenumeration5" />
+ <package android:name="com.android.perftests.appenumeration6" />
+ <package android:name="com.android.perftests.appenumeration7" />
+ <package android:name="com.android.perftests.appenumeration8" />
+ <package android:name="com.android.perftests.appenumeration9" />
+ <package android:name="com.android.perftests.appenumeration10" />
+ <package android:name="com.android.perftests.appenumeration11" />
+ <package android:name="com.android.perftests.appenumeration12" />
+ <package android:name="com.android.perftests.appenumeration13" />
+ <package android:name="com.android.perftests.appenumeration14" />
+ <package android:name="com.android.perftests.appenumeration15" />
+ <package android:name="com.android.perftests.appenumeration16" />
+ <package android:name="com.android.perftests.appenumeration17" />
+ <package android:name="com.android.perftests.appenumeration18" />
+ <package android:name="com.android.perftests.appenumeration19" />
+ <package android:name="com.android.perftests.appenumeration20" />
+ <package android:name="com.android.perftests.appenumeration21" />
+ <package android:name="com.android.perftests.appenumeration22" />
+ <package android:name="com.android.perftests.appenumeration23" />
+ <package android:name="com.android.perftests.appenumeration24" />
+ <package android:name="com.android.perftests.appenumeration25" />
+ <package android:name="com.android.perftests.appenumeration26" />
+ <package android:name="com.android.perftests.appenumeration27" />
+ <package android:name="com.android.perftests.appenumeration28" />
+ <package android:name="com.android.perftests.appenumeration29" />
+ <package android:name="com.android.perftests.appenumeration30" />
+ <package android:name="com.android.perftests.appenumeration31" />
+ <package android:name="com.android.perftests.appenumeration32" />
+ <package android:name="com.android.perftests.appenumeration33" />
+ <package android:name="com.android.perftests.appenumeration34" />
+ <package android:name="com.android.perftests.appenumeration35" />
+ <package android:name="com.android.perftests.appenumeration36" />
+ <package android:name="com.android.perftests.appenumeration37" />
+ <package android:name="com.android.perftests.appenumeration38" />
+ <package android:name="com.android.perftests.appenumeration39" />
+ <package android:name="com.android.perftests.appenumeration40" />
+ <package android:name="com.android.perftests.appenumeration41" />
+ <package android:name="com.android.perftests.appenumeration42" />
+ <package android:name="com.android.perftests.appenumeration43" />
+ <package android:name="com.android.perftests.appenumeration44" />
+ <package android:name="com.android.perftests.appenumeration45" />
+ <package android:name="com.android.perftests.appenumeration46" />
+ <package android:name="com.android.perftests.appenumeration47" />
+ <package android:name="com.android.perftests.appenumeration48" />
+ <package android:name="com.android.perftests.appenumeration49" />
+ </queries>
+
+</manifest>
\ No newline at end of file
diff --git a/apct-tests/perftests/packagemanager/src/android/os/PackageManagerPerfTest.java b/apct-tests/perftests/packagemanager/src/android/os/PackageManagerPerfTest.java
new file mode 100644
index 0000000..d7428cf
--- /dev/null
+++ b/apct-tests/perftests/packagemanager/src/android/os/PackageManagerPerfTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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.os;
+
+import static libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
+import static libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
+import android.compat.testing.PlatformCompatChangeRule;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class PackageManagerPerfTest {
+ private static final String PERMISSION_NAME_EXISTS =
+ "com.android.perftests.packagemanager.TestPermission";
+ private static final String PERMISSION_NAME_DOESNT_EXIST =
+ "com.android.perftests.packagemanager.TestBadPermission";
+ private static final String OTHER_PACKAGE_NAME = "com.android.perftests.appenumeration0";
+ private static final ComponentName TEST_ACTIVITY =
+ new ComponentName(OTHER_PACKAGE_NAME,
+ "android.perftests.utils.PerfTestActivity");
+
+ @Rule
+ public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Rule
+ public final PlatformCompatChangeRule mPlatformCompatChangeRule =
+ new PlatformCompatChangeRule();
+
+ public PackageManagerPerfTest() throws PackageManager.NameNotFoundException {
+ final Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ }
+
+ @Test
+ @DisableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY)
+ public void testCheckPermissionExists() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final PackageManager pm =
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager();
+ final String packageName = TEST_ACTIVITY.getPackageName();
+
+ while (state.keepRunning()) {
+ int ret = pm.checkPermission(PERMISSION_NAME_EXISTS, packageName);
+ }
+ }
+
+ @Test
+ @EnableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY)
+ public void testCheckPermissionExistsWithFiltering() {
+ testCheckPermissionExists();
+ }
+
+ @Test
+ @DisableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY)
+ public void testCheckPermissionDoesntExist() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final PackageManager pm =
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager();
+ final String packageName = TEST_ACTIVITY.getPackageName();
+
+ while (state.keepRunning()) {
+ int ret = pm.checkPermission(PERMISSION_NAME_DOESNT_EXIST, packageName);
+ }
+ }
+
+ @Test
+ @EnableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY)
+ public void testCheckPermissionDoesntExistWithFiltering() {
+ testCheckPermissionDoesntExist();
+ }
+
+ @Test
+ @DisableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY)
+ public void testQueryIntentActivities() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final PackageManager pm =
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager();
+ final Intent intent = new Intent("com.android.perftests.core.PERFTEST");
+
+ while (state.keepRunning()) {
+ pm.queryIntentActivities(intent, 0);
+ }
+ }
+
+ @Test
+ @EnableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY)
+ public void testQueryIntentActivitiesWithFiltering() {
+ testQueryIntentActivities();
+ }
+
+ @Test
+ @DisableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY)
+ public void testGetPackageInfo() throws Exception {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final PackageManager pm =
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager();
+
+ while (state.keepRunning()) {
+ pm.getPackageInfo(OTHER_PACKAGE_NAME, 0);
+ }
+ }
+
+ @Test
+ @EnableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY)
+ public void testGetPackageInfoWithFiltering() throws Exception {
+ testGetPackageInfo();
+ }
+
+ @Test
+ @DisableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY)
+ public void testGetApplicationInfo() throws Exception {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final PackageManager pm =
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager();
+
+ while (state.keepRunning()) {
+ pm.getApplicationInfo(OTHER_PACKAGE_NAME, 0);
+ }
+ }
+
+ @Test
+ @EnableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY)
+ public void testGetApplicationInfoWithFiltering() throws Exception {
+ testGetApplicationInfo();
+ }
+
+ @Test
+ @DisableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY)
+ public void testGetActivityInfo() throws Exception {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final PackageManager pm =
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager();
+
+ while (state.keepRunning()) {
+ pm.getActivityInfo(TEST_ACTIVITY, 0);
+ }
+ }
+
+ @Test
+ @EnableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY)
+ public void testGetActivityInfoWithFiltering() throws Exception {
+ testGetActivityInfo();
+ }
+
+ @Test
+ @DisableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY)
+ public void testGetInstalledPackages() throws Exception {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final PackageManager pm =
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager();
+
+ while (state.keepRunning()) {
+ pm.getInstalledPackages(0);
+ }
+ }
+
+ @Test
+ @EnableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY)
+ public void testGetInstalledPackagesWithFiltering() throws Exception {
+ testGetInstalledPackages();
+ }
+}
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 69f4748..939164e 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -494,9 +494,10 @@
private static final String DEPRECATED_KEY_BG_LOW_JOB_COUNT = "bg_low_job_count";
private static final String DEPRECATED_KEY_BG_CRITICAL_JOB_COUNT = "bg_critical_job_count";
- private static final String KEY_MAX_STANDARD_RESCHEDULE_COUNT
+ private static final String DEPRECATED_KEY_MAX_STANDARD_RESCHEDULE_COUNT
= "max_standard_reschedule_count";
- private static final String KEY_MAX_WORK_RESCHEDULE_COUNT = "max_work_reschedule_count";
+ private static final String DEPRECATED_KEY_MAX_WORK_RESCHEDULE_COUNT =
+ "max_work_reschedule_count";
private static final String KEY_MIN_LINEAR_BACKOFF_TIME = "min_linear_backoff_time";
private static final String KEY_MIN_EXP_BACKOFF_TIME = "min_exp_backoff_time";
private static final String DEPRECATED_KEY_STANDBY_HEARTBEAT_TIME =
@@ -525,8 +526,6 @@
private static final long DEFAULT_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS = 31 * MINUTE_IN_MILLIS;
private static final float DEFAULT_HEAVY_USE_FACTOR = .9f;
private static final float DEFAULT_MODERATE_USE_FACTOR = .5f;
- private static final int DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT = Integer.MAX_VALUE;
- private static final int DEFAULT_MAX_WORK_RESCHEDULE_COUNT = Integer.MAX_VALUE;
private static final long DEFAULT_MIN_LINEAR_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS;
private static final long DEFAULT_MIN_EXP_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS;
private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f;
@@ -640,16 +639,6 @@
"screen_off_job_concurrency_increase_delay_ms", 30_000);
/**
- * The maximum number of times we allow a job to have itself rescheduled before
- * giving up on it, for standard jobs.
- */
- int MAX_STANDARD_RESCHEDULE_COUNT = DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT;
- /**
- * The maximum number of times we allow a job to have itself rescheduled before
- * giving up on it, for jobs that are executing work.
- */
- int MAX_WORK_RESCHEDULE_COUNT = DEFAULT_MAX_WORK_RESCHEDULE_COUNT;
- /**
* The minimum backoff time to allow for linear backoff.
*/
long MIN_LINEAR_BACKOFF_TIME = DEFAULT_MIN_LINEAR_BACKOFF_TIME;
@@ -735,10 +724,6 @@
SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS.parse(mParser);
- MAX_STANDARD_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_STANDARD_RESCHEDULE_COUNT,
- DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT);
- MAX_WORK_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_WORK_RESCHEDULE_COUNT,
- DEFAULT_MAX_WORK_RESCHEDULE_COUNT);
MIN_LINEAR_BACKOFF_TIME = mParser.getDurationMillis(KEY_MIN_LINEAR_BACKOFF_TIME,
DEFAULT_MIN_LINEAR_BACKOFF_TIME);
MIN_EXP_BACKOFF_TIME = mParser.getDurationMillis(KEY_MIN_EXP_BACKOFF_TIME,
@@ -790,8 +775,6 @@
SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS.dump(pw, "");
- pw.printPair(KEY_MAX_STANDARD_RESCHEDULE_COUNT, MAX_STANDARD_RESCHEDULE_COUNT).println();
- pw.printPair(KEY_MAX_WORK_RESCHEDULE_COUNT, MAX_WORK_RESCHEDULE_COUNT).println();
pw.printPair(KEY_MIN_LINEAR_BACKOFF_TIME, MIN_LINEAR_BACKOFF_TIME).println();
pw.printPair(KEY_MIN_EXP_BACKOFF_TIME, MIN_EXP_BACKOFF_TIME).println();
pw.printPair(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println();
@@ -827,8 +810,6 @@
SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS.dumpProto(proto,
ConstantsProto.SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS);
- proto.write(ConstantsProto.MAX_STANDARD_RESCHEDULE_COUNT, MAX_STANDARD_RESCHEDULE_COUNT);
- proto.write(ConstantsProto.MAX_WORK_RESCHEDULE_COUNT, MAX_WORK_RESCHEDULE_COUNT);
proto.write(ConstantsProto.MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME);
proto.write(ConstantsProto.MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME);
proto.write(ConstantsProto.CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC);
@@ -1390,18 +1371,8 @@
// Effective standby bucket can change after this in some situations so use
// the real bucket so that the job is tracked by the controllers.
if (js.getStandbyBucket() == RESTRICTED_INDEX) {
- js.addDynamicConstraint(JobStatus.CONSTRAINT_BATTERY_NOT_LOW);
- js.addDynamicConstraint(JobStatus.CONSTRAINT_CHARGING);
- js.addDynamicConstraint(JobStatus.CONSTRAINT_CONNECTIVITY);
- js.addDynamicConstraint(JobStatus.CONSTRAINT_IDLE);
-
mRestrictiveControllers.get(j).startTrackingRestrictedJobLocked(js);
} else {
- js.removeDynamicConstraint(JobStatus.CONSTRAINT_BATTERY_NOT_LOW);
- js.removeDynamicConstraint(JobStatus.CONSTRAINT_CHARGING);
- js.removeDynamicConstraint(JobStatus.CONSTRAINT_CONNECTIVITY);
- js.removeDynamicConstraint(JobStatus.CONSTRAINT_IDLE);
-
mRestrictiveControllers.get(j).stopTrackingRestrictedJobLocked(js);
}
}
@@ -1738,19 +1709,6 @@
final int backoffAttempts = failureToReschedule.getNumFailures() + 1;
long delayMillis;
- if (failureToReschedule.hasWorkLocked()) {
- if (backoffAttempts > mConstants.MAX_WORK_RESCHEDULE_COUNT) {
- Slog.w(TAG, "Not rescheduling " + failureToReschedule + ": attempt #"
- + backoffAttempts + " > work limit "
- + mConstants.MAX_STANDARD_RESCHEDULE_COUNT);
- return null;
- }
- } else if (backoffAttempts > mConstants.MAX_STANDARD_RESCHEDULE_COUNT) {
- Slog.w(TAG, "Not rescheduling " + failureToReschedule + ": attempt #"
- + backoffAttempts + " > std limit " + mConstants.MAX_STANDARD_RESCHEDULE_COUNT);
- return null;
- }
-
switch (job.getBackoffPolicy()) {
case JobInfo.BACKOFF_POLICY_LINEAR: {
long backoff = initialBackoffMillis;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index f706260..1e89158 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -17,6 +17,8 @@
package com.android.server.job.controllers;
import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX;
+import static com.android.server.job.JobSchedulerService.NEVER_INDEX;
+import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import android.app.AppGlobals;
@@ -63,26 +65,36 @@
* @hide
*/
public final class JobStatus {
- static final String TAG = "JobSchedulerService";
+ private static final String TAG = "JobScheduler.JobStatus";
static final boolean DEBUG = JobSchedulerService.DEBUG;
public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
public static final long NO_EARLIEST_RUNTIME = 0L;
- public static final int CONSTRAINT_CHARGING = JobInfo.CONSTRAINT_FLAG_CHARGING; // 1 < 0
- public static final int CONSTRAINT_IDLE = JobInfo.CONSTRAINT_FLAG_DEVICE_IDLE; // 1 << 2
- public static final int CONSTRAINT_BATTERY_NOT_LOW =
- JobInfo.CONSTRAINT_FLAG_BATTERY_NOT_LOW; // 1 << 1
+ static final int CONSTRAINT_CHARGING = JobInfo.CONSTRAINT_FLAG_CHARGING; // 1 < 0
+ static final int CONSTRAINT_IDLE = JobInfo.CONSTRAINT_FLAG_DEVICE_IDLE; // 1 << 2
+ static final int CONSTRAINT_BATTERY_NOT_LOW = JobInfo.CONSTRAINT_FLAG_BATTERY_NOT_LOW; // 1 << 1
static final int CONSTRAINT_STORAGE_NOT_LOW = JobInfo.CONSTRAINT_FLAG_STORAGE_NOT_LOW; // 1 << 3
static final int CONSTRAINT_TIMING_DELAY = 1<<31;
static final int CONSTRAINT_DEADLINE = 1<<30;
- public static final int CONSTRAINT_CONNECTIVITY = 1 << 28;
+ static final int CONSTRAINT_CONNECTIVITY = 1 << 28;
static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26;
static final int CONSTRAINT_DEVICE_NOT_DOZING = 1 << 25; // Implicit constraint
static final int CONSTRAINT_WITHIN_QUOTA = 1 << 24; // Implicit constraint
static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1 << 22; // Implicit constraint
/**
+ * The additional set of dynamic constraints that must be met if the job's effective bucket is
+ * {@link JobSchedulerService#RESTRICTED_INDEX}. Connectivity can be ignored if the job doesn't
+ * need network.
+ */
+ private static final int DYNAMIC_RESTRICTED_CONSTRAINTS =
+ CONSTRAINT_BATTERY_NOT_LOW
+ | CONSTRAINT_CHARGING
+ | CONSTRAINT_CONNECTIVITY
+ | CONSTRAINT_IDLE;
+
+ /**
* The constraints that we want to log to statsd.
*
* Constraints that can be inferred from other atoms have been excluded to avoid logging too
@@ -419,7 +431,11 @@
this.requiredConstraints = requiredConstraints;
mRequiredConstraintsOfInterest = requiredConstraints & CONSTRAINTS_OF_INTEREST;
mReadyNotDozing = (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
- mReadyDynamicSatisfied = true;
+ if (standbyBucket == RESTRICTED_INDEX) {
+ addDynamicConstraints(DYNAMIC_RESTRICTED_CONSTRAINTS);
+ } else {
+ mReadyDynamicSatisfied = true;
+ }
mLastSuccessfulRunTime = lastSuccessfulRunTime;
mLastFailedRunTime = lastFailedRunTime;
@@ -727,6 +743,14 @@
}
public void setStandbyBucket(int newBucket) {
+ if (newBucket == RESTRICTED_INDEX) {
+ // Adding to the bucket.
+ addDynamicConstraints(DYNAMIC_RESTRICTED_CONSTRAINTS);
+ } else if (standbyBucket == RESTRICTED_INDEX) {
+ // Removing from the RESTRICTED bucket.
+ removeDynamicConstraints(DYNAMIC_RESTRICTED_CONSTRAINTS);
+ }
+
standbyBucket = newBucket;
}
@@ -1054,6 +1078,11 @@
if (old == state) {
return false;
}
+ if (DEBUG) {
+ Slog.v(TAG,
+ "Constraint " + constraint + " is " + (!state ? "NOT " : "") + "satisfied for "
+ + toShortString());
+ }
satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0);
mSatisfiedConstraintsOfInterest = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
mReadyDynamicSatisfied =
@@ -1086,38 +1115,40 @@
}
/**
- * Indicates that this job cannot run without the specified constraint. This is evaluated
+ * Indicates that this job cannot run without the specified constraints. This is evaluated
* separately from the job's explicitly requested constraints and MUST be satisfied before
* the job can run if the app doesn't have quota.
- *
*/
- public void addDynamicConstraint(int constraint) {
- if (constraint == CONSTRAINT_WITHIN_QUOTA) {
+ private void addDynamicConstraints(int constraints) {
+ if ((constraints & CONSTRAINT_WITHIN_QUOTA) != 0) {
+ // Quota should never be used as a dynamic constraint.
Slog.wtf(TAG, "Tried to set quota as a dynamic constraint");
- return;
+ constraints &= ~CONSTRAINT_WITHIN_QUOTA;
}
// Connectivity and content trigger are special since they're only valid to add if the
// job has requested network or specific content URIs. Adding these constraints to jobs
// that don't need them doesn't make sense.
- if ((constraint == CONSTRAINT_CONNECTIVITY && !hasConnectivityConstraint())
- || (constraint == CONSTRAINT_CONTENT_TRIGGER && !hasContentTriggerConstraint())) {
- return;
+ if (!hasConnectivityConstraint()) {
+ constraints &= ~CONSTRAINT_CONNECTIVITY;
+ }
+ if (!hasContentTriggerConstraint()) {
+ constraints &= ~CONSTRAINT_CONTENT_TRIGGER;
}
- mDynamicConstraints |= constraint;
+ mDynamicConstraints |= constraints;
mReadyDynamicSatisfied =
mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints);
}
/**
- * Removes a dynamic constraint from a job, meaning that the requirement is not required for
+ * Removes dynamic constraints from a job, meaning that the requirements are not required for
* the job to run (if the job itself hasn't requested the constraint. This is separate from
* the job's explicitly requested constraints and does not remove those requested constraints.
*
*/
- public void removeDynamicConstraint(int constraint) {
- mDynamicConstraints &= ~constraint;
+ private void removeDynamicConstraints(int constraints) {
+ mDynamicConstraints &= ~constraints;
mReadyDynamicSatisfied =
mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints);
}
@@ -1193,7 +1224,11 @@
private boolean isReady(int satisfiedConstraints) {
// Quota and dynamic constraints trump all other constraints.
- if (!mReadyWithinQuota && !mReadyDynamicSatisfied) {
+ // NEVER jobs are not supposed to run at all. Since we're using quota to allow parole
+ // sessions (exempt from dynamic restrictions), we need the additional check to ensure
+ // that NEVER jobs don't run.
+ // TODO: cleanup quota and standby bucket management so we don't need the additional checks
+ if ((!mReadyWithinQuota && !mReadyDynamicSatisfied) || standbyBucket == NEVER_INDEX) {
return false;
}
// Deadline constraint trumps other constraints besides quota and dynamic (except for
diff --git a/apex/permission/testing/Android.bp b/apex/permission/testing/Android.bp
index f8978dc..63bf0a0 100644
--- a/apex/permission/testing/Android.bp
+++ b/apex/permission/testing/Android.bp
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-apex {
+apex_test {
name: "test_com.android.permission",
visibility: [
"//system/apex/tests",
diff --git a/apex/sdkextensions/derive_sdk/derive_sdk.cpp b/apex/sdkextensions/derive_sdk/derive_sdk.cpp
index 6fb7ef4..900193a 100644
--- a/apex/sdkextensions/derive_sdk/derive_sdk.cpp
+++ b/apex/sdkextensions/derive_sdk/derive_sdk.cpp
@@ -69,7 +69,7 @@
auto itr = std::min_element(versions.begin(), versions.end());
std::string prop_value = itr == versions.end() ? "0" : std::to_string(*itr);
- if (!android::base::SetProperty("ro.build.version.extensions.r", prop_value)) {
+ if (!android::base::SetProperty("build.version.extensions.r", prop_value)) {
LOG(ERROR) << "failed to set sdk_info prop";
return EXIT_FAILURE;
}
diff --git a/apex/sdkextensions/framework/java/android/os/ext/SdkExtensions.java b/apex/sdkextensions/framework/java/android/os/ext/SdkExtensions.java
index a8a7eff..103b53e 100644
--- a/apex/sdkextensions/framework/java/android/os/ext/SdkExtensions.java
+++ b/apex/sdkextensions/framework/java/android/os/ext/SdkExtensions.java
@@ -38,7 +38,7 @@
private static final int R_EXTENSION_INT;
static {
- R_EXTENSION_INT = SystemProperties.getInt("ro.build.version.extensions.r", 0);
+ R_EXTENSION_INT = SystemProperties.getInt("build.version.extensions.r", 0);
}
/**
diff --git a/apex/sdkextensions/framework/java/android/os/ext/test/Test.java b/apex/sdkextensions/framework/java/android/os/ext/test/Test.java
new file mode 100644
index 0000000..1715f49
--- /dev/null
+++ b/apex/sdkextensions/framework/java/android/os/ext/test/Test.java
@@ -0,0 +1,53 @@
+/*
+ * 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.os.ext.test;
+
+import android.annotation.SystemApi;
+
+/**
+ * This class exists temporarily to verify SDK updates are working properly.
+ * @deprecated Do not use.
+ */
+@Deprecated
+public class Test {
+
+ public Test() { }
+
+ /** @hide */
+ public void testA() {}
+
+ /** @hide */
+ public void testB() {}
+
+ /** @hide */
+ public void testC() {}
+
+ /** @hide */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public void testD() {}
+
+ public void testE() {}
+
+ /** @hide */
+ @SystemApi
+ public void testF() {}
+
+ /** @hide */
+ @SystemApi
+ public void testG() {}
+
+}
diff --git a/apex/statsd/aidl/Android.bp b/apex/statsd/aidl/Android.bp
index 6d639fd..db5f439 100644
--- a/apex/statsd/aidl/Android.bp
+++ b/apex/statsd/aidl/Android.bp
@@ -13,35 +13,31 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-
-// TODO(b/145815909): move StatsDimensionsValue.aidl here
filegroup {
- name: "statsd_aidl",
+ name: "statsd_java_aidl",
+ srcs: ["**/*.aidl"],
+}
+
+aidl_interface {
+ name: "statsd-aidl",
srcs: [
"android/os/IPendingIntentRef.aidl",
"android/os/IPullAtomCallback.aidl",
"android/os/IPullAtomResultReceiver.aidl",
"android/os/IStatsCompanionService.aidl",
"android/os/IStatsd.aidl",
+ "android/os/StatsDimensionsValueParcel.aidl",
"android/util/StatsEventParcel.aidl",
],
-}
-
-filegroup {
- name: "statsd_java_aidl",
- srcs: ["**/*.aidl"],
-}
-
-// This library is currently unused
-aidl_interface {
- name: "stats-event-parcel-aidl",
- srcs: ["android/util/StatsEventParcel.aidl"],
backend: {
java: {
- sdk_version: "28",
+ enabled: false, // the platform uses statsd_java_aidl
},
cpp: {
- enabled: false,
+ enabled: true,
+ },
+ ndk: {
+ enabled: true,
}
}
}
diff --git a/apex/statsd/aidl/android/os/IPendingIntentRef.aidl b/apex/statsd/aidl/android/os/IPendingIntentRef.aidl
index 6b9e467..000a699 100644
--- a/apex/statsd/aidl/android/os/IPendingIntentRef.aidl
+++ b/apex/statsd/aidl/android/os/IPendingIntentRef.aidl
@@ -16,7 +16,7 @@
package android.os;
-import android.os.StatsDimensionsValue;
+import android.os.StatsDimensionsValueParcel;
/**
* Binder interface to hold a PendingIntent for StatsCompanionService.
@@ -42,5 +42,5 @@
*/
oneway void sendSubscriberBroadcast(long configUid, long configId, long subscriptionId,
long subscriptionRuleId, in String[] cookies,
- in StatsDimensionsValue dimensionsValue);
-}
\ No newline at end of file
+ in StatsDimensionsValueParcel dimensionsValueParcel);
+}
diff --git a/apex/statsd/aidl/android/os/IStatsd.aidl b/apex/statsd/aidl/android/os/IStatsd.aidl
index 253b2c1..10b1e5b 100644
--- a/apex/statsd/aidl/android/os/IStatsd.aidl
+++ b/apex/statsd/aidl/android/os/IStatsd.aidl
@@ -222,12 +222,6 @@
const int FLAG_REQUIRE_LOW_LATENCY_MONITOR = 0x04;
/**
- * Logs an event for watchdog rollbacks.
- */
- oneway void sendWatchdogRollbackOccurredAtom(in int rollbackType, in String packageName,
- in long packageVersionCode, in int rollbackReason, in String failingPackageName);
-
- /**
* Returns the most recently registered experiment IDs.
*/
long[] getRegisteredExperimentIds();
diff --git a/apex/statsd/aidl/android/os/StatsDimensionsValueParcel.aidl b/apex/statsd/aidl/android/os/StatsDimensionsValueParcel.aidl
new file mode 100644
index 0000000..a8685e3
--- /dev/null
+++ b/apex/statsd/aidl/android/os/StatsDimensionsValueParcel.aidl
@@ -0,0 +1,21 @@
+package android.os;
+
+/**
+ * @hide
+ */
+parcelable StatsDimensionsValueParcel {
+ /**
+ * Field equals:
+ * - atomTag for top level StatsDimensionsValueParcel
+ * - position in dimension for all other levels
+ */
+ int field;
+ int valueType;
+
+ String stringValue;
+ int intValue;
+ long longValue;
+ boolean boolValue;
+ float floatValue;
+ StatsDimensionsValueParcel[] tupleValue;
+}
diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp
index d85ae69..80def47 100644
--- a/apex/statsd/framework/Android.bp
+++ b/apex/statsd/framework/Android.bp
@@ -12,12 +12,28 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+genrule {
+ name: "statslog-statsd-java-gen",
+ tools: ["stats-log-api-gen"],
+ cmd: "$(location stats-log-api-gen) --java $(out) --module statsd" +
+ " --javaPackage com.android.internal.util --javaClass StatsdStatsLog",
+ out: ["com/android/internal/util/StatsdStatsLog.java"],
+}
+
+java_library_static {
+ name: "statslog-statsd",
+ srcs: [
+ ":statslog-statsd-java-gen",
+ ],
+}
+
filegroup {
name: "framework-statsd-sources",
srcs: [
- "java/**/*.java",
+ "java/**/*.java",
+ ":statsd_java_aidl",
+ ":statslog-statsd-java-gen",
],
- path: "java",
}
java_library {
@@ -42,8 +58,7 @@
hostdex: true, // for hiddenapi check
visibility: [
"//frameworks/base/apex/statsd:__subpackages__",
- //TODO(b/146167933) remove this when framework is built with framework-statsd-stubs
- "//frameworks/base",
+ //TODO(b/146167933) remove this
"//frameworks/opt/net/wifi/service",
],
apex_available: [
@@ -103,7 +118,6 @@
sdk_version: "core_platform",
}
-// TODO(b/146167933): Use these stubs in frameworks/base/Android.bp
java_library {
name: "framework-statsd-stubs-systemapi",
srcs: [ ":framework-statsd-stubs-srcs-systemapi" ],
diff --git a/apex/statsd/framework/java/android/app/StatsManager.java b/apex/statsd/framework/java/android/app/StatsManager.java
index 411482b..526d17f 100644
--- a/apex/statsd/framework/java/android/app/StatsManager.java
+++ b/apex/statsd/framework/java/android/app/StatsManager.java
@@ -32,7 +32,7 @@
import android.os.RemoteException;
import android.os.StatsFrameworkInitializer;
import android.util.AndroidException;
-import android.util.Slog;
+import android.util.Log;
import android.util.StatsEvent;
import android.util.StatsEventParcel;
@@ -155,7 +155,7 @@
// can throw IllegalArgumentException
service.addConfiguration(configKey, config, mContext.getOpPackageName());
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to connect to statsmanager when adding configuration");
+ Log.e(TAG, "Failed to connect to statsmanager when adding configuration");
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
@@ -191,7 +191,7 @@
IStatsManagerService service = getIStatsManagerServiceLocked();
service.removeConfiguration(configKey, mContext.getOpPackageName());
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to connect to statsmanager when removing configuration");
+ Log.e(TAG, "Failed to connect to statsmanager when removing configuration");
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
@@ -258,7 +258,7 @@
mContext.getOpPackageName());
}
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to connect to statsmanager when adding broadcast subscriber",
+ Log.e(TAG, "Failed to connect to statsmanager when adding broadcast subscriber",
e);
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
@@ -311,7 +311,7 @@
}
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to connect to statsmanager when registering data listener.");
+ Log.e(TAG, "Failed to connect to statsmanager when registering data listener.");
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
@@ -348,7 +348,7 @@
}
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to connect to statsmanager "
+ Log.e(TAG, "Failed to connect to statsmanager "
+ "when registering active configs listener.");
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
@@ -387,7 +387,7 @@
IStatsManagerService service = getIStatsManagerServiceLocked();
return service.getData(configKey, mContext.getOpPackageName());
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to connect to statsmanager when getting data");
+ Log.e(TAG, "Failed to connect to statsmanager when getting data");
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
@@ -424,7 +424,7 @@
IStatsManagerService service = getIStatsManagerServiceLocked();
return service.getMetadata(mContext.getOpPackageName());
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to connect to statsmanager when getting metadata");
+ Log.e(TAG, "Failed to connect to statsmanager when getting metadata");
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
@@ -464,7 +464,7 @@
return service.getRegisteredExperimentIds();
} catch (RemoteException e) {
if (DEBUG) {
- Slog.d(TAG,
+ Log.d(TAG,
"Failed to connect to StatsManagerService when getting "
+ "registered experiment IDs");
}
@@ -555,7 +555,7 @@
try {
resultReceiver.pullFinished(atomTag, success, parcels);
} catch (RemoteException e) {
- Slog.w(TAG, "StatsPullResultReceiver failed for tag " + mAtomId);
+ Log.w(TAG, "StatsPullResultReceiver failed for tag " + mAtomId);
}
});
} finally {
diff --git a/apex/statsd/framework/java/android/os/StatsDimensionsValue.java b/apex/statsd/framework/java/android/os/StatsDimensionsValue.java
index 886130f..35273da 100644
--- a/apex/statsd/framework/java/android/os/StatsDimensionsValue.java
+++ b/apex/statsd/framework/java/android/os/StatsDimensionsValue.java
@@ -16,7 +16,7 @@
package android.os;
import android.annotation.SystemApi;
-import android.util.Slog;
+import android.util.Log;
import java.util.ArrayList;
import java.util.List;
@@ -96,6 +96,47 @@
}
/**
+ * Creates a {@code StatsDimensionsValue} from a StatsDimensionsValueParcel
+ * TODO(b/149103391): Make StatsDimensionsValue a wrapper on top of
+ * StatsDimensionsValueParcel.
+ *
+ * @hide
+ */
+ public StatsDimensionsValue(StatsDimensionsValueParcel parcel) {
+ mField = parcel.field;
+ mValueType = parcel.valueType;
+ switch (mValueType) {
+ case STRING_VALUE_TYPE:
+ mValue = parcel.stringValue;
+ break;
+ case INT_VALUE_TYPE:
+ mValue = parcel.intValue;
+ break;
+ case LONG_VALUE_TYPE:
+ mValue = parcel.longValue;
+ break;
+ case BOOLEAN_VALUE_TYPE:
+ mValue = parcel.boolValue;
+ break;
+ case FLOAT_VALUE_TYPE:
+ mValue = parcel.floatValue;
+ break;
+ case TUPLE_VALUE_TYPE:
+ StatsDimensionsValue[] values = new StatsDimensionsValue[parcel.tupleValue.length];
+ for (int i = 0; i < parcel.tupleValue.length; i++) {
+ values[i] = new StatsDimensionsValue(parcel.tupleValue[i]);
+ }
+ mValue = values;
+ break;
+ default:
+ Log.w(TAG, "StatsDimensionsValueParcel contains bad valueType: " + mValueType);
+ mValue = null;
+ break;
+ }
+ }
+
+
+ /**
* Return the field, i.e. the tag of a statsd atom.
*
* @return the field
@@ -114,7 +155,7 @@
try {
if (mValueType == STRING_VALUE_TYPE) return (String) mValue;
} catch (ClassCastException e) {
- Slog.w(TAG, "Failed to successfully get value", e);
+ Log.w(TAG, "Failed to successfully get value", e);
}
return null;
}
@@ -128,7 +169,7 @@
try {
if (mValueType == INT_VALUE_TYPE) return (Integer) mValue;
} catch (ClassCastException e) {
- Slog.w(TAG, "Failed to successfully get value", e);
+ Log.w(TAG, "Failed to successfully get value", e);
}
return 0;
}
@@ -142,7 +183,7 @@
try {
if (mValueType == LONG_VALUE_TYPE) return (Long) mValue;
} catch (ClassCastException e) {
- Slog.w(TAG, "Failed to successfully get value", e);
+ Log.w(TAG, "Failed to successfully get value", e);
}
return 0;
}
@@ -157,7 +198,7 @@
try {
if (mValueType == BOOLEAN_VALUE_TYPE) return (Boolean) mValue;
} catch (ClassCastException e) {
- Slog.w(TAG, "Failed to successfully get value", e);
+ Log.w(TAG, "Failed to successfully get value", e);
}
return false;
}
@@ -171,7 +212,7 @@
try {
if (mValueType == FLOAT_VALUE_TYPE) return (Float) mValue;
} catch (ClassCastException e) {
- Slog.w(TAG, "Failed to successfully get value", e);
+ Log.w(TAG, "Failed to successfully get value", e);
}
return 0;
}
@@ -197,7 +238,7 @@
}
return copy;
} catch (ClassCastException e) {
- Slog.w(TAG, "Failed to successfully get value", e);
+ Log.w(TAG, "Failed to successfully get value", e);
return null;
}
}
@@ -256,7 +297,7 @@
}
return sb.toString();
} catch (ClassCastException e) {
- Slog.w(TAG, "Failed to successfully get value", e);
+ Log.w(TAG, "Failed to successfully get value", e);
}
return "";
}
@@ -316,11 +357,11 @@
return true;
}
default:
- Slog.w(TAG, "readValue of an impossible type " + valueType);
+ Log.w(TAG, "readValue of an impossible type " + valueType);
return false;
}
} catch (ClassCastException e) {
- Slog.w(TAG, "writeValue cast failed", e);
+ Log.w(TAG, "writeValue cast failed", e);
return false;
}
}
@@ -347,7 +388,7 @@
return values;
}
default:
- Slog.w(TAG, "readValue of an impossible type " + valueType);
+ Log.w(TAG, "readValue of an impossible type " + valueType);
return null;
}
}
diff --git a/apex/statsd/framework/java/android/util/StatsLog.java b/apex/statsd/framework/java/android/util/StatsLog.java
index 7910737..511bc01 100644
--- a/apex/statsd/framework/java/android/util/StatsLog.java
+++ b/apex/statsd/framework/java/android/util/StatsLog.java
@@ -26,10 +26,10 @@
import android.content.Context;
import android.os.IStatsd;
import android.os.RemoteException;
-import android.os.ServiceManager;
+import android.os.StatsFrameworkInitializer;
import android.util.proto.ProtoOutputStream;
-import com.android.internal.util.FrameworkStatsLog;
+import com.android.internal.util.StatsdStatsLog;
/**
* StatsLog provides an API for developers to send events to statsd. The events can be used to
@@ -59,17 +59,17 @@
IStatsd service = getIStatsdLocked();
if (service == null) {
if (DEBUG) {
- Slog.d(TAG, "Failed to find statsd when logging start");
+ Log.d(TAG, "Failed to find statsd when logging start");
}
return false;
}
service.sendAppBreadcrumbAtom(label,
- FrameworkStatsLog.APP_BREADCRUMB_REPORTED__STATE__START);
+ StatsdStatsLog.APP_BREADCRUMB_REPORTED__STATE__START);
return true;
} catch (RemoteException e) {
sService = null;
if (DEBUG) {
- Slog.d(TAG, "Failed to connect to statsd when logging start");
+ Log.d(TAG, "Failed to connect to statsd when logging start");
}
return false;
}
@@ -88,17 +88,17 @@
IStatsd service = getIStatsdLocked();
if (service == null) {
if (DEBUG) {
- Slog.d(TAG, "Failed to find statsd when logging stop");
+ Log.d(TAG, "Failed to find statsd when logging stop");
}
return false;
}
service.sendAppBreadcrumbAtom(
- label, FrameworkStatsLog.APP_BREADCRUMB_REPORTED__STATE__STOP);
+ label, StatsdStatsLog.APP_BREADCRUMB_REPORTED__STATE__STOP);
return true;
} catch (RemoteException e) {
sService = null;
if (DEBUG) {
- Slog.d(TAG, "Failed to connect to statsd when logging stop");
+ Log.d(TAG, "Failed to connect to statsd when logging stop");
}
return false;
}
@@ -117,17 +117,17 @@
IStatsd service = getIStatsdLocked();
if (service == null) {
if (DEBUG) {
- Slog.d(TAG, "Failed to find statsd when logging event");
+ Log.d(TAG, "Failed to find statsd when logging event");
}
return false;
}
service.sendAppBreadcrumbAtom(
- label, FrameworkStatsLog.APP_BREADCRUMB_REPORTED__STATE__UNSPECIFIED);
+ label, StatsdStatsLog.APP_BREADCRUMB_REPORTED__STATE__UNSPECIFIED);
return true;
} catch (RemoteException e) {
sService = null;
if (DEBUG) {
- Slog.d(TAG, "Failed to connect to statsd when logging event");
+ Log.d(TAG, "Failed to connect to statsd when logging event");
}
return false;
}
@@ -162,7 +162,7 @@
| EXPERIMENT_IDS_FIELD_ID,
id);
}
- FrameworkStatsLog.write(FrameworkStatsLog.BINARY_PUSH_STATE_CHANGED,
+ StatsdStatsLog.write(StatsdStatsLog.BINARY_PUSH_STATE_CHANGED,
trainName,
trainVersionCode,
(options & IStatsd.FLAG_REQUIRE_STAGING) > 0,
@@ -171,57 +171,19 @@
state,
proto.getBytes(),
0,
- 0);
+ 0,
+ false);
return true;
}
- /**
- * Logs an event for watchdog rollbacks.
- *
- * @param rollbackType state of the rollback.
- * @param packageName package name being rolled back.
- * @param packageVersionCode version of the package being rolled back.
- * @param rollbackReason reason the package is being rolled back.
- * @param failingPackageName the package name causing the failure.
- *
- * @return True if the log request was sent to statsd.
- *
- * @hide
- */
- @RequiresPermission(allOf = {DUMP, PACKAGE_USAGE_STATS})
- public static boolean logWatchdogRollbackOccurred(int rollbackType, String packageName,
- long packageVersionCode, int rollbackReason, String failingPackageName) {
- synchronized (sLogLock) {
- try {
- IStatsd service = getIStatsdLocked();
- if (service == null) {
- if (DEBUG) {
- Slog.d(TAG, "Failed to find statsd when logging event");
- }
- return false;
- }
-
- service.sendWatchdogRollbackOccurredAtom(rollbackType, packageName,
- packageVersionCode, rollbackReason, failingPackageName);
- return true;
- } catch (RemoteException e) {
- sService = null;
- if (DEBUG) {
- Slog.d(TAG,
- "Failed to connect to StatsCompanionService when logging "
- + "WatchdogRollbackOccurred");
- }
- return false;
- }
- }
- }
-
-
private static IStatsd getIStatsdLocked() throws RemoteException {
if (sService != null) {
return sService;
}
- sService = IStatsd.Stub.asInterface(ServiceManager.getService("stats"));
+ sService = IStatsd.Stub.asInterface(StatsFrameworkInitializer
+ .getStatsServiceManager()
+ .getStatsdServiceRegisterer()
+ .get());
return sService;
}
diff --git a/apex/statsd/service/Android.bp b/apex/statsd/service/Android.bp
index 9103848..0f8a151 100644
--- a/apex/statsd/service/Android.bp
+++ b/apex/statsd/service/Android.bp
@@ -1,17 +1,30 @@
// Statsd Service jar, which will eventually be put in the statsd mainline apex.
// service-statsd needs to be added to PRODUCT_UPDATABLE_SYSTEM_SERVER_JARS.
// This jar will contain StatsCompanionService
+
+filegroup {
+ name: "service-statsd-sources",
+ srcs: [
+ "java/**/*.java",
+ ],
+}
+
java_library {
name: "service-statsd",
installable: true,
srcs: [
- "java/**/*.java",
+ ":service-statsd-sources",
],
- // TODO: link against the proper stubs (b/146084685).
+ // TODO(b/146209659): Use system_current instead once framework-statsd compiles against
+ // system_current.
+ sdk_version: "core_platform",
libs: [
- "framework-minus-apex",
- "services.core",
+ "framework-annotations-lib",
+ "framework-statsd",
+ // TODO(b/146758669): Remove this line after nullability annotations are system APIs.
+ "android_system_stubs_current",
+ "services-stubs",
],
apex_available: [
"com.android.os.statsd",
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java
index 4495dc9..c1ba73f 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java
@@ -24,7 +24,8 @@
import android.os.IPendingIntentRef;
import android.os.Process;
import android.os.StatsDimensionsValue;
-import android.util.Slog;
+import android.os.StatsDimensionsValueParcel;
+import android.util.Log;
import com.android.server.SystemService;
@@ -40,6 +41,9 @@
private static final int AID_STATSD = 1066;
+ private static final String STATS_COMPANION_SERVICE = "statscompanion";
+ private static final String STATS_MANAGER_SERVICE = "statsmanager";
+
static void enforceStatsdCallingUid() {
if (Binder.getCallingPid() == Process.myPid()) {
return;
@@ -68,14 +72,12 @@
mStatsManagerService.setStatsCompanionService(mStatsCompanionService);
try {
- publishBinderService(Context.STATS_COMPANION_SERVICE,
- mStatsCompanionService);
- if (DEBUG) Slog.d(TAG, "Published " + Context.STATS_COMPANION_SERVICE);
- publishBinderService(Context.STATS_MANAGER_SERVICE,
- mStatsManagerService);
- if (DEBUG) Slog.d(TAG, "Published " + Context.STATS_MANAGER_SERVICE);
+ publishBinderService(STATS_COMPANION_SERVICE, mStatsCompanionService);
+ if (DEBUG) Log.d(TAG, "Published " + STATS_COMPANION_SERVICE);
+ publishBinderService(STATS_MANAGER_SERVICE, mStatsManagerService);
+ if (DEBUG) Log.d(TAG, "Published " + STATS_MANAGER_SERVICE);
} catch (Exception e) {
- Slog.e(TAG, "Failed to publishBinderService", e);
+ Log.e(TAG, "Failed to publishBinderService", e);
}
}
@@ -124,7 +126,7 @@
try {
mPendingIntent.send(mContext, CODE_DATA_BROADCAST, intent, null, null);
} catch (PendingIntent.CanceledException e) {
- Slog.w(TAG, "Unable to send PendingIntent");
+ Log.w(TAG, "Unable to send PendingIntent");
}
}
@@ -136,17 +138,19 @@
try {
mPendingIntent.send(mContext, CODE_ACTIVE_CONFIGS_BROADCAST, intent, null, null);
if (DEBUG) {
- Slog.d(TAG, "Sent broadcast with config ids " + Arrays.toString(configIds));
+ Log.d(TAG, "Sent broadcast with config ids " + Arrays.toString(configIds));
}
} catch (PendingIntent.CanceledException e) {
- Slog.w(TAG, "Unable to send active configs changed broadcast using PendingIntent");
+ Log.w(TAG, "Unable to send active configs changed broadcast using PendingIntent");
}
}
@Override
public void sendSubscriberBroadcast(long configUid, long configId, long subscriptionId,
- long subscriptionRuleId, String[] cookies, StatsDimensionsValue dimensionsValue) {
+ long subscriptionRuleId, String[] cookies,
+ StatsDimensionsValueParcel dimensionsValueParcel) {
enforceStatsdCallingUid();
+ StatsDimensionsValue dimensionsValue = new StatsDimensionsValue(dimensionsValueParcel);
Intent intent =
new Intent()
.putExtra(StatsManager.EXTRA_STATS_CONFIG_UID, configUid)
@@ -162,7 +166,7 @@
StatsManager.EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES, cookieList);
if (DEBUG) {
- Slog.d(TAG,
+ Log.d(TAG,
String.format(
"Statsd sendSubscriberBroadcast with params {%d %d %d %d %s %s}",
configUid, configId, subscriptionId, subscriptionRuleId,
@@ -172,7 +176,7 @@
try {
mPendingIntent.send(mContext, CODE_SUBSCRIBER_BROADCAST, intent, null, null);
} catch (PendingIntent.CanceledException e) {
- Slog.w(TAG,
+ Log.w(TAG,
"Unable to send using PendingIntent from uid " + configUid
+ "; presumably it had been cancelled.");
}
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 a735cb8..cb167c3 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -40,14 +40,10 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
-import android.util.Slog;
+import android.util.Log;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.os.LooperStats;
-import com.android.internal.util.DumpUtils;
-import com.android.server.BinderCallsStatsService;
-import com.android.server.LocalServices;
import libcore.io.IoUtils;
@@ -89,6 +85,12 @@
public static final int DEATH_THRESHOLD = 10;
+ // TODO(b/149090705): Implement an alternative to sending broadcast with @hide flag
+ // FLAG_RECEIVER_INCLUDE_BACKGROUND. Instead of using the flag, find the
+ // list of registered broadcast receivers and send them directed broadcasts
+ // to wake them up. See b/147374337.
+ private static final int FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000;
+
static final class CompanionHandler extends Handler {
CompanionHandler(Looper looper) {
super(looper);
@@ -126,7 +128,7 @@
public void onReceive(Context context, Intent intent) {
synchronized (sStatsdLock) {
if (sStatsd == null) {
- Slog.w(TAG, "Could not access statsd for UserUpdateReceiver");
+ Log.w(TAG, "Could not access statsd for UserUpdateReceiver");
return;
}
try {
@@ -134,14 +136,14 @@
// Needed since the new user basically has a version of every app.
informAllUidsLocked(context);
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to inform statsd latest update of all apps", e);
+ Log.e(TAG, "Failed to inform statsd latest update of all apps", e);
forgetEverythingLocked();
}
}
}
};
mShutdownEventReceiver = new ShutdownEventReceiver();
- if (DEBUG) Slog.d(TAG, "Registered receiver for ACTION_PACKAGE_REPLACED and ADDED.");
+ if (DEBUG) Log.d(TAG, "Registered receiver for ACTION_PACKAGE_REPLACED and ADDED.");
HandlerThread handlerThread = new HandlerThread(TAG);
handlerThread.start();
mHandler = new CompanionHandler(handlerThread.getLooper());
@@ -171,21 +173,21 @@
PackageManager pm = context.getPackageManager();
final List<UserHandle> users = um.getUserHandles(true);
if (DEBUG) {
- Slog.d(TAG, "Iterating over " + users.size() + " userHandles.");
+ Log.d(TAG, "Iterating over " + users.size() + " userHandles.");
}
ParcelFileDescriptor[] fds;
try {
fds = ParcelFileDescriptor.createPipe();
} catch (IOException e) {
- Slog.e(TAG, "Failed to create a pipe to send uid map data.", e);
+ Log.e(TAG, "Failed to create a pipe to send uid map data.", e);
return;
}
sStatsd.informAllUidData(fds[0]);
try {
fds[0].close();
} catch (IOException e) {
- Slog.e(TAG, "Failed to close the read side of the pipe.", e);
+ Log.e(TAG, "Failed to close the read side of the pipe.", e);
}
final ParcelFileDescriptor writeFd = fds[1];
HandlerThread backgroundThread = new HandlerThread(
@@ -239,7 +241,7 @@
}
output.flush();
if (DEBUG) {
- Slog.d(TAG, "Sent data for " + numRecords + " apps");
+ Log.d(TAG, "Sent data for " + numRecords + " apps");
}
} finally {
IoUtils.closeQuietly(fout);
@@ -261,10 +263,10 @@
&& intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
return; // Keep only replacing or normal add and remove.
}
- if (DEBUG) Slog.d(TAG, "StatsCompanionService noticed an app was updated.");
+ if (DEBUG) Log.d(TAG, "StatsCompanionService noticed an app was updated.");
synchronized (sStatsdLock) {
if (sStatsd == null) {
- Slog.w(TAG, "Could not access statsd to inform it of an app update");
+ Log.w(TAG, "Could not access statsd to inform it of an app update");
return;
}
try {
@@ -299,7 +301,7 @@
installer == null ? "" : installer);
}
} catch (Exception e) {
- Slog.w(TAG, "Failed to inform statsd of an app update", e);
+ Log.w(TAG, "Failed to inform statsd of an app update", e);
}
}
}
@@ -308,18 +310,18 @@
public final static class AnomalyAlarmListener implements OnAlarmListener {
@Override
public void onAlarm() {
- Slog.i(TAG, "StatsCompanionService believes an anomaly has occurred at time "
+ Log.i(TAG, "StatsCompanionService believes an anomaly has occurred at time "
+ System.currentTimeMillis() + "ms.");
synchronized (sStatsdLock) {
if (sStatsd == null) {
- Slog.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
+ Log.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
return;
}
try {
// Two-way call to statsd to retain AlarmManager wakelock
sStatsd.informAnomalyAlarmFired();
} catch (RemoteException e) {
- Slog.w(TAG, "Failed to inform statsd of anomaly alarm firing", e);
+ Log.w(TAG, "Failed to inform statsd of anomaly alarm firing", e);
}
}
// AlarmManager releases its own wakelock here.
@@ -330,18 +332,18 @@
@Override
public void onAlarm() {
if (DEBUG) {
- Slog.d(TAG, "Time to poll something.");
+ Log.d(TAG, "Time to poll something.");
}
synchronized (sStatsdLock) {
if (sStatsd == null) {
- Slog.w(TAG, "Could not access statsd to inform it of pulling alarm firing.");
+ Log.w(TAG, "Could not access statsd to inform it of pulling alarm firing.");
return;
}
try {
// Two-way call to statsd to retain AlarmManager wakelock
sStatsd.informPollAlarmFired();
} catch (RemoteException e) {
- Slog.w(TAG, "Failed to inform statsd of pulling alarm firing.", e);
+ Log.w(TAG, "Failed to inform statsd of pulling alarm firing.", e);
}
}
}
@@ -351,18 +353,18 @@
@Override
public void onAlarm() {
if (DEBUG) {
- Slog.d(TAG, "Time to trigger periodic alarm.");
+ Log.d(TAG, "Time to trigger periodic alarm.");
}
synchronized (sStatsdLock) {
if (sStatsd == null) {
- Slog.w(TAG, "Could not access statsd to inform it of periodic alarm firing.");
+ Log.w(TAG, "Could not access statsd to inform it of periodic alarm firing.");
return;
}
try {
// Two-way call to statsd to retain AlarmManager wakelock
sStatsd.informAlarmForSubscriberTriggeringFired();
} catch (RemoteException e) {
- Slog.w(TAG, "Failed to inform statsd of periodic alarm firing.", e);
+ Log.w(TAG, "Failed to inform statsd of periodic alarm firing.", e);
}
}
// AlarmManager releases its own wakelock here.
@@ -381,16 +383,16 @@
return;
}
- Slog.i(TAG, "StatsCompanionService noticed a shutdown.");
+ Log.i(TAG, "StatsCompanionService noticed a shutdown.");
synchronized (sStatsdLock) {
if (sStatsd == null) {
- Slog.w(TAG, "Could not access statsd to inform it of a shutdown event.");
+ Log.w(TAG, "Could not access statsd to inform it of a shutdown event.");
return;
}
try {
sStatsd.informDeviceShutdown();
} catch (Exception e) {
- Slog.w(TAG, "Failed to inform statsd of a shutdown event.", e);
+ Log.w(TAG, "Failed to inform statsd of a shutdown event.", e);
}
}
}
@@ -399,7 +401,7 @@
@Override // Binder call
public void setAnomalyAlarm(long timestampMs) {
StatsCompanion.enforceStatsdCallingUid();
- if (DEBUG) Slog.d(TAG, "Setting anomaly alarm for " + timestampMs);
+ if (DEBUG) Log.d(TAG, "Setting anomaly alarm for " + timestampMs);
final long callingToken = Binder.clearCallingIdentity();
try {
// using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
@@ -415,7 +417,7 @@
@Override // Binder call
public void cancelAnomalyAlarm() {
StatsCompanion.enforceStatsdCallingUid();
- if (DEBUG) Slog.d(TAG, "Cancelling anomaly alarm");
+ if (DEBUG) Log.d(TAG, "Cancelling anomaly alarm");
final long callingToken = Binder.clearCallingIdentity();
try {
mAlarmManager.cancel(mAnomalyAlarmListener);
@@ -428,7 +430,7 @@
public void setAlarmForSubscriberTriggering(long timestampMs) {
StatsCompanion.enforceStatsdCallingUid();
if (DEBUG) {
- Slog.d(TAG,
+ Log.d(TAG,
"Setting periodic alarm in about " + (timestampMs
- SystemClock.elapsedRealtime()));
}
@@ -447,7 +449,7 @@
public void cancelAlarmForSubscriberTriggering() {
StatsCompanion.enforceStatsdCallingUid();
if (DEBUG) {
- Slog.d(TAG, "Cancelling periodic alarm");
+ Log.d(TAG, "Cancelling periodic alarm");
}
final long callingToken = Binder.clearCallingIdentity();
try {
@@ -461,7 +463,7 @@
public void setPullingAlarm(long nextPullTimeMs) {
StatsCompanion.enforceStatsdCallingUid();
if (DEBUG) {
- Slog.d(TAG, "Setting pulling alarm in about "
+ Log.d(TAG, "Setting pulling alarm in about "
+ (nextPullTimeMs - SystemClock.elapsedRealtime()));
}
final long callingToken = Binder.clearCallingIdentity();
@@ -479,7 +481,7 @@
public void cancelPullingAlarm() {
StatsCompanion.enforceStatsdCallingUid();
if (DEBUG) {
- Slog.d(TAG, "Cancelling pulling alarm");
+ Log.d(TAG, "Cancelling pulling alarm");
}
final long callingToken = Binder.clearCallingIdentity();
try {
@@ -493,11 +495,11 @@
public void statsdReady() {
StatsCompanion.enforceStatsdCallingUid();
if (DEBUG) {
- Slog.d(TAG, "learned that statsdReady");
+ Log.d(TAG, "learned that statsdReady");
}
sayHiToStatsd(); // tell statsd that we're ready too and link to it
mContext.sendBroadcastAsUser(new Intent(StatsManager.ACTION_STATSD_STARTED)
- .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND),
+ .addFlags(FLAG_RECEIVER_INCLUDE_BACKGROUND),
UserHandle.SYSTEM, android.Manifest.permission.DUMP);
}
@@ -509,7 +511,7 @@
try {
informAllUidsLocked(mContext);
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to trigger uid snapshot.", e);
+ Log.e(TAG, "Failed to trigger uid snapshot.", e);
} finally {
restoreCallingIdentity(token);
}
@@ -540,7 +542,7 @@
* Now that the android system is ready, StatsCompanion is ready too, so inform statsd.
*/
void systemReady() {
- if (DEBUG) Slog.d(TAG, "Learned that systemReady");
+ if (DEBUG) Log.d(TAG, "Learned that systemReady");
sayHiToStatsd();
}
@@ -555,27 +557,27 @@
private void sayHiToStatsd() {
synchronized (sStatsdLock) {
if (sStatsd != null) {
- Slog.e(TAG, "Trying to fetch statsd, but it was already fetched",
+ Log.e(TAG, "Trying to fetch statsd, but it was already fetched",
new IllegalStateException(
"sStatsd is not null when being fetched"));
return;
}
sStatsd = fetchStatsdService();
if (sStatsd == null) {
- Slog.i(TAG,
+ Log.i(TAG,
"Could not yet find statsd to tell it that StatsCompanion is "
+ "alive.");
return;
}
mStatsManagerService.statsdReady(sStatsd);
- if (DEBUG) Slog.d(TAG, "Saying hi to statsd");
+ if (DEBUG) Log.d(TAG, "Saying hi to statsd");
try {
sStatsd.statsCompanionReady();
// If the statsCompanionReady two-way binder call returns, link to statsd.
try {
sStatsd.asBinder().linkToDeath(new StatsdDeathRecipient(), 0);
} catch (RemoteException e) {
- Slog.e(TAG, "linkToDeath(StatsdDeathRecipient) failed", e);
+ Log.e(TAG, "linkToDeath(StatsdDeathRecipient) failed", e);
forgetEverythingLocked();
}
// Setup broadcast receiver for updates.
@@ -605,9 +607,9 @@
} finally {
restoreCallingIdentity(token);
}
- Slog.i(TAG, "Told statsd that StatsCompanionService is alive.");
+ Log.i(TAG, "Told statsd that StatsCompanionService is alive.");
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
+ Log.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
forgetEverythingLocked();
}
}
@@ -616,7 +618,7 @@
private class StatsdDeathRecipient implements IBinder.DeathRecipient {
@Override
public void binderDied() {
- Slog.i(TAG, "Statsd is dead - erase all my knowledge, except pullers");
+ Log.i(TAG, "Statsd is dead - erase all my knowledge, except pullers");
synchronized (sStatsdLock) {
long now = SystemClock.elapsedRealtime();
for (Long timeMillis : mDeathTimeMillis) {
@@ -656,22 +658,15 @@
cancelAnomalyAlarm();
cancelPullingAlarm();
- BinderCallsStatsService.Internal binderStats =
- LocalServices.getService(BinderCallsStatsService.Internal.class);
- if (binderStats != null) {
- binderStats.reset();
- }
-
- LooperStats looperStats = LocalServices.getService(LooperStats.class);
- if (looperStats != null) {
- looperStats.reset();
- }
mStatsManagerService.statsdNotReady();
}
@Override
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
- if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return;
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ return;
+ }
synchronized (sStatsdLock) {
writer.println(
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 c1dc584..4e4bc40 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
@@ -30,7 +30,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.util.ArrayMap;
-import android.util.Slog;
+import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -192,7 +192,7 @@
statsd.registerPullAtomCallback(
callingUid, atomTag, coolDownNs, timeoutNs, additiveFields, pullerCallback);
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to access statsd to register puller for atom " + atomTag);
+ Log.e(TAG, "Failed to access statsd to register puller for atom " + atomTag);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -219,7 +219,7 @@
try {
statsd.unregisterPullAtomCallback(callingUid, atomTag);
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to access statsd to unregister puller for atom " + atomTag);
+ Log.e(TAG, "Failed to access statsd to unregister puller for atom " + atomTag);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -243,7 +243,7 @@
statsd.setDataFetchOperation(configId, pir, callingUid);
}
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to setDataFetchOperation with statsd");
+ Log.e(TAG, "Failed to setDataFetchOperation with statsd");
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -264,7 +264,7 @@
statsd.removeDataFetchOperation(configId, callingUid);
}
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to removeDataFetchOperation with statsd");
+ Log.e(TAG, "Failed to removeDataFetchOperation with statsd");
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -287,7 +287,7 @@
return statsd.setActiveConfigsChangedOperation(pir, callingUid);
}
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to setActiveConfigsChangedOperation with statsd");
+ Log.e(TAG, "Failed to setActiveConfigsChangedOperation with statsd");
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -308,7 +308,7 @@
statsd.removeActiveConfigsChangedOperation(callingUid);
}
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to removeActiveConfigsChangedOperation with statsd");
+ Log.e(TAG, "Failed to removeActiveConfigsChangedOperation with statsd");
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -336,7 +336,7 @@
configId, subscriberId, pir, callingUid);
}
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to setBroadcastSubscriber with statsd");
+ Log.e(TAG, "Failed to setBroadcastSubscriber with statsd");
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -362,7 +362,7 @@
statsd.unsetBroadcastSubscriber(configId, subscriberId, callingUid);
}
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to unsetBroadcastSubscriber with statsd");
+ Log.e(TAG, "Failed to unsetBroadcastSubscriber with statsd");
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -378,7 +378,7 @@
return statsd.getRegisteredExperimentIds();
}
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to getRegisteredExperimentIds with statsd");
+ Log.e(TAG, "Failed to getRegisteredExperimentIds with statsd");
throw new IllegalStateException(e.getMessage(), e);
} finally {
Binder.restoreCallingIdentity(token);
@@ -396,7 +396,7 @@
return statsd.getMetadata();
}
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to getMetadata with statsd");
+ Log.e(TAG, "Failed to getMetadata with statsd");
throw new IllegalStateException(e.getMessage(), e);
} finally {
Binder.restoreCallingIdentity(token);
@@ -415,7 +415,7 @@
return statsd.getData(key, callingUid);
}
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to getData with statsd");
+ Log.e(TAG, "Failed to getData with statsd");
throw new IllegalStateException(e.getMessage(), e);
} finally {
Binder.restoreCallingIdentity(token);
@@ -436,7 +436,7 @@
return;
}
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to addConfiguration with statsd");
+ Log.e(TAG, "Failed to addConfiguration with statsd");
throw new IllegalStateException(e.getMessage(), e);
} finally {
Binder.restoreCallingIdentity(token);
@@ -457,7 +457,7 @@
return;
}
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to removeConfiguration with statsd");
+ Log.e(TAG, "Failed to removeConfiguration with statsd");
throw new IllegalStateException(e.getMessage(), e);
} finally {
Binder.restoreCallingIdentity(token);
@@ -522,7 +522,7 @@
try {
mLock.wait(STATSD_TIMEOUT_MILLIS);
} catch (InterruptedException e) {
- Slog.e(TAG, "wait for statsd interrupted");
+ Log.e(TAG, "wait for statsd interrupted");
}
}
return mStatsd;
@@ -578,7 +578,7 @@
registerAllActiveConfigsChangedOperations(statsd);
registerAllBroadcastSubscribers(statsd);
} catch (RemoteException e) {
- Slog.e(TAG, "StatsManager failed to (re-)register data with statsd");
+ Log.e(TAG, "StatsManager failed to (re-)register data with statsd");
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/apex/statsd/testing/Android.bp b/apex/statsd/testing/Android.bp
index 22e7301..a9cd0cc 100644
--- a/apex/statsd/testing/Android.bp
+++ b/apex/statsd/testing/Android.bp
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-apex {
+apex_test {
name: "test_com.android.os.statsd",
visibility: [
"//system/apex/tests",
diff --git a/api/current.txt b/api/current.txt
index dcf23b0..826d409 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4015,7 +4015,7 @@
method public android.util.Size getAppTaskThumbnailSize();
method public java.util.List<android.app.ActivityManager.AppTask> getAppTasks();
method public android.content.pm.ConfigurationInfo getDeviceConfigurationInfo();
- method @Nullable public java.util.List<android.app.ApplicationExitInfo> getHistoricalProcessExitReasons(@Nullable String, @IntRange(from=0) int, @IntRange(from=0) int);
+ method @NonNull public java.util.List<android.app.ApplicationExitInfo> getHistoricalProcessExitReasons(@Nullable String, @IntRange(from=0) int, @IntRange(from=0) int);
method public int getLargeMemoryClass();
method public int getLauncherLargeIconDensity();
method public int getLauncherLargeIconSize();
@@ -4555,12 +4555,13 @@
method public int getPackageUid();
method public int getPid();
method @NonNull public String getProcessName();
- method public int getPss();
+ method public long getPss();
method public int getRealUid();
method public int getReason();
- method public int getRss();
+ method public long getRss();
method public int getStatus();
method public long getTimestamp();
+ method @NonNull public android.os.UserHandle getUserHandle();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.ApplicationExitInfo> CREATOR;
field public static final int REASON_ANR = 6; // 0x6
@@ -29702,7 +29703,7 @@
method public long getReportTimestamp();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.ConnectivityReport> CREATOR;
- field public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK = "networkProbesAttemped";
+ field public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK = "networkProbesAttempted";
field public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK = "networkProbesSucceeded";
field public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult";
field public static final int NETWORK_PROBE_DNS = 4; // 0x4
@@ -30779,7 +30780,6 @@
method public void close();
method public void continueCall(int) throws android.net.sip.SipException;
method public void endCall() throws android.net.sip.SipException;
- method @Nullable public android.net.rtp.AudioGroup getAudioGroup();
method public android.net.sip.SipProfile getLocalProfile();
method public android.net.sip.SipProfile getPeerProfile();
method public int getState();
@@ -30790,7 +30790,6 @@
method public void makeCall(android.net.sip.SipProfile, android.net.sip.SipSession, int) throws android.net.sip.SipException;
method public void sendDtmf(int);
method public void sendDtmf(int, android.os.Message);
- method public void setAudioGroup(@NonNull android.net.rtp.AudioGroup);
method public void setListener(android.net.sip.SipAudioCall.Listener);
method public void setListener(android.net.sip.SipAudioCall.Listener, boolean);
method public void setSpeakerMode(boolean);
@@ -30839,7 +30838,6 @@
method public void close(String) throws android.net.sip.SipException;
method public android.net.sip.SipSession createSipSession(android.net.sip.SipProfile, android.net.sip.SipSession.Listener) throws android.net.sip.SipException;
method public static String getCallId(android.content.Intent);
- method @NonNull public java.util.List<android.net.sip.SipProfile> getListOfProfiles() throws android.net.sip.SipException;
method public static String getOfferSessionDescription(android.content.Intent);
method public android.net.sip.SipSession getSessionFor(android.content.Intent) throws android.net.sip.SipException;
method public static boolean isApiSupported(android.content.Context);
@@ -30857,11 +30855,6 @@
method public void setRegistrationListener(String, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException;
method public android.net.sip.SipAudioCall takeAudioCall(android.content.Intent, android.net.sip.SipAudioCall.Listener) throws android.net.sip.SipException;
method public void unregister(android.net.sip.SipProfile, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException;
- field public static final String ACTION_SIP_CALL_OPTION_CHANGED = "android.net.sip.action.SIP_CALL_OPTION_CHANGED";
- field public static final String ACTION_SIP_INCOMING_CALL = "android.net.sip.action.SIP_INCOMING_CALL";
- field public static final String ACTION_SIP_REMOVE_PROFILE = "android.net.sip.action.SIP_REMOVE_PROFILE";
- field public static final String ACTION_SIP_SERVICE_UP = "android.net.sip.action.SIP_SERVICE_UP";
- field public static final String ACTION_START_SIP = "android.net.sip.action.START_SIP";
field public static final String EXTRA_CALL_ID = "android:sipCallID";
field public static final String EXTRA_OFFER_SD = "android:sipOfferSD";
field public static final int INCOMING_CALL_RESULT_CODE = 101; // 0x65
@@ -30871,7 +30864,6 @@
method public int describeContents();
method public String getAuthUserName();
method public boolean getAutoRegistration();
- method public int getCallingUid();
method public String getDisplayName();
method public String getPassword();
method public int getPort();
@@ -31295,6 +31287,7 @@
method public boolean isP2pSupported();
method public boolean isPreferredNetworkOffloadSupported();
method @Deprecated public boolean isScanAlwaysAvailable();
+ method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isScanThrottleEnabled();
method public boolean isStaApConcurrencySupported();
method public boolean isTdlsSupported();
method public boolean isWapiSupported();
@@ -37045,6 +37038,15 @@
}
+package android.os.ext.test {
+
+ @Deprecated public class Test {
+ ctor @Deprecated public Test();
+ method @Deprecated public void testE();
+ }
+
+}
+
package android.os.health {
public class HealthStats {
@@ -40415,6 +40417,7 @@
field public static final String EXTRA_BATTERY_SAVER_MODE_ENABLED = "android.settings.extra.battery_saver_mode_enabled";
field public static final String EXTRA_BIOMETRIC_MINIMUM_STRENGTH_REQUIRED = "android.provider.extra.BIOMETRIC_MINIMUM_STRENGTH_REQUIRED";
field public static final String EXTRA_CHANNEL_ID = "android.provider.extra.CHANNEL_ID";
+ field public static final String EXTRA_CONVERSATION_ID = "android.provider.extra.CONVERSATION_ID";
field public static final String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
field public static final String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
field public static final String EXTRA_EASY_CONNECT_ATTEMPTED_SSID = "android.provider.extra.EASY_CONNECT_ATTEMPTED_SSID";
@@ -43994,7 +43997,7 @@
field public static final String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
field public static final String ACTION_QS_TILE_PREFERENCES = "android.service.quicksettings.action.QS_TILE_PREFERENCES";
field public static final String META_DATA_ACTIVE_TILE = "android.service.quicksettings.ACTIVE_TILE";
- field public static final String META_DATA_BOOLEAN_TILE = "android.service.quicksettings.BOOLEAN_TILE";
+ field public static final String META_DATA_TOGGLEABLE_TILE = "android.service.quicksettings.TOGGLEABLE_TILE";
}
}
@@ -47311,7 +47314,7 @@
method public void onSignalStrengthsChanged(android.telephony.SignalStrength);
method public void onUserMobileDataStateChanged(boolean);
field public static final int LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE = 4194304; // 0x400000
- field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int LISTEN_BARRING_INFO = -2147483648; // 0x80000000
+ field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_BARRING_INFO = -2147483648; // 0x80000000
field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_CALL_DISCONNECT_CAUSES = 33554432; // 0x2000000
field public static final int LISTEN_CALL_FORWARDING_INDICATOR = 8; // 0x8
field public static final int LISTEN_CALL_STATE = 32; // 0x20
@@ -47324,7 +47327,7 @@
field public static final int LISTEN_MESSAGE_WAITING_INDICATOR = 4; // 0x4
field public static final int LISTEN_NONE = 0; // 0x0
field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000
- field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int LISTEN_REGISTRATION_FAILURE = 1073741824; // 0x40000000
+ field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_REGISTRATION_FAILURE = 1073741824; // 0x40000000
field public static final int LISTEN_SERVICE_STATE = 1; // 0x1
field @Deprecated public static final int LISTEN_SIGNAL_STRENGTH = 2; // 0x2
field public static final int LISTEN_SIGNAL_STRENGTHS = 256; // 0x100
@@ -60834,7 +60837,6 @@
method public void setTypeface(@Nullable android.graphics.Typeface, int);
method public void setTypeface(@Nullable android.graphics.Typeface);
method public void setWidth(int);
- field public static final int ACCESSIBILITY_ACTION_IME_ENTER = 16908372; // 0x1020054
field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0
field public static final int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1; // 0x1
}
@@ -60889,7 +60891,7 @@
method public int getGravity();
method public float getHorizontalMargin();
method public float getVerticalMargin();
- method @Deprecated public android.view.View getView();
+ method @Deprecated @Nullable public android.view.View getView();
method public int getXOffset();
method public int getYOffset();
method public static android.widget.Toast makeText(android.content.Context, CharSequence, int);
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 90531b1..59aa145 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -1,4 +1,133 @@
// Signature format: 2.0
+package android.net {
+
+ public final class TetheredClient implements android.os.Parcelable {
+ ctor public TetheredClient(@NonNull android.net.MacAddress, @NonNull java.util.Collection<android.net.TetheredClient.AddressInfo>, int);
+ method public int describeContents();
+ method @NonNull public java.util.List<android.net.TetheredClient.AddressInfo> getAddresses();
+ method @NonNull public android.net.MacAddress getMacAddress();
+ method public int getTetheringType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient> CREATOR;
+ }
+
+ public static final class TetheredClient.AddressInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.net.LinkAddress getAddress();
+ method @Nullable public String getHostname();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient.AddressInfo> CREATOR;
+ }
+
+ public class TetheringConstants {
+ ctor public TetheringConstants();
+ field public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
+ field public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
+ field public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
+ field public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
+ field public static final String EXTRA_SET_ALARM = "extraSetAlarm";
+ }
+
+ public class TetheringManager {
+ ctor public TetheringManager(@NonNull android.content.Context, @NonNull java.util.function.Supplier<android.os.IBinder>);
+ method public int getLastTetherError(@NonNull String);
+ method @NonNull public String[] getTetherableBluetoothRegexs();
+ method @NonNull public String[] getTetherableIfaces();
+ method @NonNull public String[] getTetherableUsbRegexs();
+ method @NonNull public String[] getTetherableWifiRegexs();
+ method @NonNull public String[] getTetheredIfaces();
+ method @NonNull public String[] getTetheringErroredIfaces();
+ method public boolean isTetheringSupported();
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback);
+ method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener);
+ method public void requestLatestTetheringEntitlementResult(int, @NonNull android.os.ResultReceiver, boolean);
+ method @Deprecated public int setUsbTethering(boolean);
+ method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
+ method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
+ method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering();
+ method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int);
+ method @Deprecated public int tether(@NonNull String);
+ method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback);
+ method @Deprecated public int untether(@NonNull String);
+ field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED";
+ field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
+ field public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
+ field public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
+ field public static final String EXTRA_ERRORED_TETHER = "erroredArray";
+ field public static final int TETHERING_BLUETOOTH = 2; // 0x2
+ field public static final int TETHERING_ETHERNET = 5; // 0x5
+ field public static final int TETHERING_INVALID = -1; // 0xffffffff
+ field public static final int TETHERING_NCM = 4; // 0x4
+ field public static final int TETHERING_USB = 1; // 0x1
+ field public static final int TETHERING_WIFI = 0; // 0x0
+ field public static final int TETHERING_WIFI_P2P = 3; // 0x3
+ field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc
+ field public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9; // 0x9
+ field public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8; // 0x8
+ field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd
+ field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa
+ field public static final int TETHER_ERROR_MASTER_ERROR = 5; // 0x5
+ field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf
+ field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe
+ field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
+ field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
+ field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2
+ field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6
+ field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4
+ field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
+ field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
+ field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
+ }
+
+ public static interface TetheringManager.OnTetheringEntitlementResultListener {
+ method public void onTetheringEntitlementResult(int);
+ }
+
+ public abstract static class TetheringManager.StartTetheringCallback {
+ ctor public TetheringManager.StartTetheringCallback();
+ method public void onTetheringFailed(int);
+ method public void onTetheringStarted();
+ }
+
+ public abstract static class TetheringManager.TetheringEventCallback {
+ ctor public TetheringManager.TetheringEventCallback();
+ method public void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
+ method public void onError(@NonNull String, int);
+ method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
+ method public void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+ method public void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+ method public void onTetheringSupported(boolean);
+ method public void onUpstreamChanged(@Nullable android.net.Network);
+ }
+
+ @Deprecated public static class TetheringManager.TetheringInterfaceRegexps {
+ ctor @Deprecated public TetheringManager.TetheringInterfaceRegexps(@NonNull String[], @NonNull String[], @NonNull String[]);
+ method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableBluetoothRegexs();
+ method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableUsbRegexs();
+ method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
+ }
+
+ public static class TetheringManager.TetheringRequest {
+ }
+
+ public static class TetheringManager.TetheringRequest.Builder {
+ ctor public TetheringManager.TetheringRequest.Builder(int);
+ method @NonNull public android.net.TetheringManager.TetheringRequest build();
+ method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
+ method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setSilentProvisioning(boolean);
+ method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder useStaticIpv4Addresses(@NonNull android.net.LinkAddress);
+ }
+
+}
+
+package android.os.ext.test {
+
+ @Deprecated public class Test {
+ method @Deprecated public void testD();
+ }
+
+}
+
package android.util {
public final class Log {
diff --git a/api/system-current.txt b/api/system-current.txt
index b927edd..24936d5 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -585,10 +585,6 @@
field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.PackageOps> CREATOR;
}
- public final class ApplicationExitInfo implements android.os.Parcelable {
- method @NonNull public android.os.UserHandle getUserHandle();
- }
-
public class BroadcastOptions {
method public static android.app.BroadcastOptions makeBasic();
method @RequiresPermission("android.permission.START_ACTIVITIES_FROM_BACKGROUND") public void setBackgroundActivityStartsAllowed(boolean);
@@ -3866,6 +3862,20 @@
method @NonNull public android.location.GnssReflectingPlane.Builder setLongitudeDegrees(@FloatRange(from=-180.0F, to=180.0f) double);
}
+ public final class GnssRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public boolean isFullTracking();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssRequest> CREATOR;
+ }
+
+ public static final class GnssRequest.Builder {
+ ctor public GnssRequest.Builder();
+ ctor public GnssRequest.Builder(@NonNull android.location.GnssRequest);
+ method @NonNull public android.location.GnssRequest build();
+ method @NonNull public android.location.GnssRequest.Builder setFullTracking(boolean);
+ }
+
public final class GnssSingleSatCorrection implements android.os.Parcelable {
method public int describeContents();
method @FloatRange(from=0.0f, fromInclusive=false) public float getCarrierFrequencyHz();
@@ -4139,6 +4149,7 @@
method public boolean isProviderEnabledForUser(@NonNull String, @NonNull android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@NonNull String);
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
+ method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.LOCATION_HARDWARE}) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
@@ -4216,15 +4227,15 @@
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioAttributes.Builder setSystemUsage(int);
}
- public final class AudioDeviceAddress implements android.os.Parcelable {
- ctor public AudioDeviceAddress(@NonNull android.media.AudioDeviceInfo);
- ctor public AudioDeviceAddress(int, int, @NonNull String);
+ public final class AudioDevice implements android.os.Parcelable {
+ ctor public AudioDevice(@NonNull android.media.AudioDeviceInfo);
+ ctor public AudioDevice(int, int, @NonNull String);
method public int describeContents();
method @NonNull public String getAddress();
method public int getRole();
method public int getType();
method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioDeviceAddress> CREATOR;
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioDevice> CREATOR;
field public static final int ROLE_INPUT = 1; // 0x1
field public static final int ROLE_OUTPUT = 2; // 0x2
}
@@ -4261,11 +4272,11 @@
method @IntRange(from=0) public int getAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioProductStrategy> getAudioProductStrategies();
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioVolumeGroup> getAudioVolumeGroups();
- method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAddress> getDevicesForAttributes(@NonNull android.media.AudioAttributes);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDevice> getDevicesForAttributes(@NonNull android.media.AudioAttributes);
method @IntRange(from=0) public int getMaxAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
- method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioDeviceAddress getPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
+ method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioDevice getPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int[] getSupportedSystemUsages();
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
method public boolean isAudioServerRunning();
@@ -4279,7 +4290,7 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo, @IntRange(from=0) int);
method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAddress);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDevice);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setSupportedSystemUsages(@NonNull int[]);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setVolumeIndexForAttributes(@NonNull android.media.AudioAttributes, int, int);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
@@ -4375,7 +4386,7 @@
package android.media.audiofx {
public class AudioEffect {
- ctor @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public AudioEffect(@NonNull java.util.UUID, @NonNull android.media.AudioDeviceAddress);
+ ctor @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public AudioEffect(@NonNull java.util.UUID, @NonNull android.media.AudioDevice);
}
}
@@ -5746,7 +5757,6 @@
method public int getFreqOffset();
method public int getHierarchy();
method @NonNull public boolean[] getLayerErrors();
- method public int getLberCn();
method public int getLnbVoltage();
method public int getMer();
method public int getModulation();
@@ -5758,37 +5768,32 @@
method public int getSnr();
method public int getSpectralInversion();
method public int getSymbolRate();
- method public int getVberCn();
- method public int getXerCn();
method public boolean isDemodLocked();
method public boolean isEwbs();
method public boolean isLnaOn();
method public boolean isRfLock();
field public static final int FRONTEND_STATUS_TYPE_AGC = 14; // 0xe
- field public static final int FRONTEND_STATUS_TYPE_ATSC3_PLP_INFO = 24; // 0x18
+ field public static final int FRONTEND_STATUS_TYPE_ATSC3_PLP_INFO = 21; // 0x15
field public static final int FRONTEND_STATUS_TYPE_BER = 2; // 0x2
field public static final int FRONTEND_STATUS_TYPE_DEMOD_LOCK = 0; // 0x0
field public static final int FRONTEND_STATUS_TYPE_EWBS = 13; // 0xd
field public static final int FRONTEND_STATUS_TYPE_FEC = 8; // 0x8
- field public static final int FRONTEND_STATUS_TYPE_FREQ_OFFSET = 21; // 0x15
- field public static final int FRONTEND_STATUS_TYPE_HIERARCHY = 22; // 0x16
+ field public static final int FRONTEND_STATUS_TYPE_FREQ_OFFSET = 18; // 0x12
+ field public static final int FRONTEND_STATUS_TYPE_HIERARCHY = 19; // 0x13
field public static final int FRONTEND_STATUS_TYPE_LAYER_ERROR = 16; // 0x10
- field public static final int FRONTEND_STATUS_TYPE_LBER_CN = 18; // 0x12
field public static final int FRONTEND_STATUS_TYPE_LNA = 15; // 0xf
field public static final int FRONTEND_STATUS_TYPE_LNB_VOLTAGE = 11; // 0xb
- field public static final int FRONTEND_STATUS_TYPE_MER = 20; // 0x14
+ field public static final int FRONTEND_STATUS_TYPE_MER = 17; // 0x11
field public static final int FRONTEND_STATUS_TYPE_MODULATION = 9; // 0x9
field public static final int FRONTEND_STATUS_TYPE_PER = 3; // 0x3
field public static final int FRONTEND_STATUS_TYPE_PLP_ID = 12; // 0xc
field public static final int FRONTEND_STATUS_TYPE_PRE_BER = 4; // 0x4
- field public static final int FRONTEND_STATUS_TYPE_RF_LOCK = 23; // 0x17
+ field public static final int FRONTEND_STATUS_TYPE_RF_LOCK = 20; // 0x14
field public static final int FRONTEND_STATUS_TYPE_SIGNAL_QUALITY = 5; // 0x5
field public static final int FRONTEND_STATUS_TYPE_SIGNAL_STRENGTH = 6; // 0x6
field public static final int FRONTEND_STATUS_TYPE_SNR = 1; // 0x1
field public static final int FRONTEND_STATUS_TYPE_SPECTRAL = 10; // 0xa
field public static final int FRONTEND_STATUS_TYPE_SYMBOL_RATE = 7; // 0x7
- field public static final int FRONTEND_STATUS_TYPE_VBER_CN = 17; // 0x11
- field public static final int FRONTEND_STATUS_TYPE_XER_CN = 19; // 0x13
}
public static class FrontendStatus.Atsc3PlpInfo {
@@ -7210,6 +7215,28 @@
}
+package android.net.sip {
+
+ public class SipAudioCall {
+ method @Nullable public android.net.rtp.AudioGroup getAudioGroup();
+ method public void setAudioGroup(@NonNull android.net.rtp.AudioGroup);
+ }
+
+ public class SipManager {
+ method @NonNull public java.util.List<android.net.sip.SipProfile> getProfiles() throws android.net.sip.SipException;
+ field public static final String ACTION_SIP_CALL_OPTION_CHANGED = "android.net.sip.action.SIP_CALL_OPTION_CHANGED";
+ field public static final String ACTION_SIP_INCOMING_CALL = "android.net.sip.action.SIP_INCOMING_CALL";
+ field public static final String ACTION_SIP_REMOVE_PROFILE = "android.net.sip.action.SIP_REMOVE_PROFILE";
+ field public static final String ACTION_SIP_SERVICE_UP = "android.net.sip.action.SIP_SERVICE_UP";
+ field public static final String ACTION_START_SIP = "android.net.sip.action.START_SIP";
+ }
+
+ public class SipProfile implements java.lang.Cloneable android.os.Parcelable java.io.Serializable {
+ method public int getCallingUid();
+ }
+
+}
+
package android.net.util {
public final class SocketUtils {
@@ -7693,6 +7720,7 @@
method @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(int);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setMacRandomizationSettingPasspointEnabled(@NonNull String, boolean);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setMeteredOverridePasspoint(@NonNull String, int);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setScanThrottleEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public boolean setSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setVerboseLoggingEnabled(boolean);
method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
@@ -7837,23 +7865,23 @@
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING) public android.net.wifi.WifiNetworkSuggestion.Builder setCarrierId(int);
}
- public final class WifiOemConfigStoreMigrationHook {
- method @Nullable public static android.net.wifi.WifiOemConfigStoreMigrationHook.MigrationData load();
+ public final class WifiOemMigrationHook {
+ method @Nullable public static android.net.wifi.WifiOemMigrationHook.ConfigStoreMigrationData loadFromConfigStore();
}
- public static final class WifiOemConfigStoreMigrationHook.MigrationData implements android.os.Parcelable {
+ public static final class WifiOemMigrationHook.ConfigStoreMigrationData implements android.os.Parcelable {
method public int describeContents();
method @Nullable public java.util.List<android.net.wifi.WifiConfiguration> getUserSavedNetworkConfigurations();
method @Nullable public android.net.wifi.SoftApConfiguration getUserSoftApConfiguration();
method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiOemConfigStoreMigrationHook.MigrationData> CREATOR;
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiOemMigrationHook.ConfigStoreMigrationData> CREATOR;
}
- public static final class WifiOemConfigStoreMigrationHook.MigrationData.Builder {
- ctor public WifiOemConfigStoreMigrationHook.MigrationData.Builder();
- method @NonNull public android.net.wifi.WifiOemConfigStoreMigrationHook.MigrationData build();
- method @NonNull public android.net.wifi.WifiOemConfigStoreMigrationHook.MigrationData.Builder setUserSavedNetworkConfigurations(@NonNull java.util.List<android.net.wifi.WifiConfiguration>);
- method @NonNull public android.net.wifi.WifiOemConfigStoreMigrationHook.MigrationData.Builder setUserSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration);
+ public static final class WifiOemMigrationHook.ConfigStoreMigrationData.Builder {
+ ctor public WifiOemMigrationHook.ConfigStoreMigrationData.Builder();
+ method @NonNull public android.net.wifi.WifiOemMigrationHook.ConfigStoreMigrationData build();
+ method @NonNull public android.net.wifi.WifiOemMigrationHook.ConfigStoreMigrationData.Builder setUserSavedNetworkConfigurations(@NonNull java.util.List<android.net.wifi.WifiConfiguration>);
+ method @NonNull public android.net.wifi.WifiOemMigrationHook.ConfigStoreMigrationData.Builder setUserSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration);
}
public class WifiScanner {
@@ -9145,6 +9173,15 @@
}
+package android.os.ext.test {
+
+ @Deprecated public class Test {
+ method @Deprecated public void testF();
+ method @Deprecated public void testG();
+ }
+
+}
+
package android.os.image {
public class DynamicSystemClient {
@@ -14130,6 +14167,10 @@
method public boolean isContentCaptureFeatureEnabled();
}
+ public abstract class ContentCaptureSession implements java.lang.AutoCloseable {
+ field public static final int NO_SESSION_ID = 0; // 0x0
+ }
+
public final class ViewNode extends android.app.assist.AssistStructure.ViewNode {
method @Nullable public android.view.autofill.AutofillId getParentAutofillId();
}
diff --git a/api/test-current.txt b/api/test-current.txt
index e1f8382..e352cb6 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -923,6 +923,7 @@
field public static final int FLAG_PERMISSION_USER_SET = 1; // 0x1
field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
field public static final int MATCH_KNOWN_PACKAGES = 4202496; // 0x402000
+ field public static final int MODULE_APEX_NAME = 1; // 0x1
field public static final String SYSTEM_SHARED_LIBRARY_SERVICES = "android.ext.services";
field public static final String SYSTEM_SHARED_LIBRARY_SHARED = "android.ext.shared";
}
@@ -2539,6 +2540,7 @@
}
public class UserManager {
+ method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.CREATE_USERS"}) public boolean hasBaseUserRestriction(@NonNull String, @NonNull android.os.UserHandle);
method public static boolean isSplitSystemUser();
field public static final String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED";
}
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 7e069a6..956fd29 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -44,12 +44,8 @@
cc_defaults {
name: "statsd_defaults",
- aidl: {
- include_dirs: ["frameworks/base/core/java"],
- },
srcs: [
- ":statsd_aidl",
"src/active_config_list.proto",
"src/anomaly/AlarmMonitor.cpp",
"src/anomaly/AlarmTracker.cpp",
@@ -124,14 +120,14 @@
"libstatslog",
"libstatsmetadata",
"libsysutils",
+ "libutils",
],
shared_libs: [
"libbinder",
"libincident",
"liblog",
- "libservices",
"libstatssocket",
- "libutils",
+ "statsd-aidl-cpp",
],
}
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index 5b75b97..6b9d0e4 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -26,6 +26,86 @@
using std::string;
using std::vector;
+// These constants must be kept in sync with those in StatsDimensionsValue.java
+const static int STATS_DIMENSIONS_VALUE_STRING_TYPE = 2;
+const static int STATS_DIMENSIONS_VALUE_INT_TYPE = 3;
+const static int STATS_DIMENSIONS_VALUE_LONG_TYPE = 4;
+// const static int STATS_DIMENSIONS_VALUE_BOOL_TYPE = 5; (commented out because
+// unused -- statsd does not correctly support bool types)
+const static int STATS_DIMENSIONS_VALUE_FLOAT_TYPE = 6;
+const static int STATS_DIMENSIONS_VALUE_TUPLE_TYPE = 7;
+
+/**
+ * Recursive helper function that populates a parent StatsDimensionsValueParcel
+ * with children StatsDimensionsValueParcels.
+ *
+ * \param dims vector of FieldValues stored by HashableDimensionKey
+ * \param index positions in dims vector to start reading children from
+ * \param depth level of parent parcel in the full StatsDimensionsValueParcel
+ * tree
+ */
+static void populateStatsDimensionsValueParcelChildren(StatsDimensionsValueParcel &parentParcel,
+ const vector<FieldValue>& dims, size_t& index,
+ int depth, int prefix) {
+ while (index < dims.size()) {
+ const FieldValue& dim = dims[index];
+ int fieldDepth = dim.mField.getDepth();
+ int fieldPrefix = dim.mField.getPrefix(depth);
+ StatsDimensionsValueParcel childParcel;
+ childParcel.field = dim.mField.getPosAtDepth(depth);
+ if (depth > 2) {
+ ALOGE("Depth > 2 not supported by StatsDimensionsValueParcel.");
+ return;
+ }
+ if (depth == fieldDepth && prefix == fieldPrefix) {
+ switch (dim.mValue.getType()) {
+ case INT:
+ childParcel.valueType = STATS_DIMENSIONS_VALUE_INT_TYPE;
+ childParcel.intValue = dim.mValue.int_value;
+ break;
+ case LONG:
+ childParcel.valueType = STATS_DIMENSIONS_VALUE_LONG_TYPE;
+ childParcel.longValue = dim.mValue.long_value;
+ break;
+ case FLOAT:
+ childParcel.valueType = STATS_DIMENSIONS_VALUE_FLOAT_TYPE;
+ childParcel.floatValue = dim.mValue.float_value;
+ break;
+ case STRING:
+ childParcel.valueType = STATS_DIMENSIONS_VALUE_STRING_TYPE;
+ childParcel.stringValue = String16(dim.mValue.str_value.c_str());
+ break;
+ default:
+ ALOGE("Encountered FieldValue with unsupported value type.");
+ break;
+ }
+ index++;
+ parentParcel.tupleValue.push_back(childParcel);
+ } else if (fieldDepth > depth && fieldPrefix == prefix) {
+ childParcel.valueType = STATS_DIMENSIONS_VALUE_TUPLE_TYPE;
+ populateStatsDimensionsValueParcelChildren(childParcel, dims, index, depth + 1,
+ dim.mField.getPrefix(depth + 1));
+ parentParcel.tupleValue.push_back(childParcel);
+ } else {
+ return;
+ }
+ }
+}
+
+StatsDimensionsValueParcel HashableDimensionKey::toStatsDimensionsValueParcel() const {
+ StatsDimensionsValueParcel parcel;
+ if (mValues.size() == 0) {
+ return parcel;
+ }
+
+ parcel.field = mValues[0].mField.getTag();
+ parcel.valueType = STATS_DIMENSIONS_VALUE_TUPLE_TYPE;
+
+ size_t index = 0;
+ populateStatsDimensionsValueParcelChildren(parcel, mValues, index, /*depth=*/0, /*prefix=*/0);
+ return parcel;
+}
+
android::hash_t hashDimension(const HashableDimensionKey& value) {
android::hash_t hash = 0;
for (const auto& fieldValue : value.getValues()) {
diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h
index 654e135..4adcf96 100644
--- a/cmds/statsd/src/HashableDimensionKey.h
+++ b/cmds/statsd/src/HashableDimensionKey.h
@@ -16,10 +16,11 @@
#pragma once
+#include <android/os/StatsDimensionsValueParcel.h>
#include <utils/JenkinsHash.h>
#include <vector>
-#include "FieldValue.h"
#include "android-base/stringprintf.h"
+#include "FieldValue.h"
#include "logd/LogEvent.h"
namespace android {
@@ -69,6 +70,8 @@
return nullptr;
}
+ StatsDimensionsValueParcel toStatsDimensionsValueParcel() const;
+
std::string toString() const;
bool operator!=(const HashableDimensionKey& that) const;
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index bde15a5..6e7f081 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -196,17 +196,27 @@
!checkPermissionForIds(kPermissionUsage, pid, uid)) {
return;
}
- status_t err = NO_ERROR, err2 = NO_ERROR, err3 = NO_ERROR, err4 = NO_ERROR;
- string trainName = string(event->GetString(1 /*train name field id*/, &err));
- int64_t trainVersionCode = event->GetLong(2 /*train version field id*/, &err2);
- int32_t state = int32_t(event->GetLong(6 /*state field id*/, &err3));
+ // The Get* functions don't modify the status on success, they only write in
+ // failure statuses, so we can use one status variable for all calls then
+ // check if it is no longer NO_ERROR.
+ status_t err = NO_ERROR;
+ InstallTrainInfo trainInfo;
+ trainInfo.trainName = string(event->GetString(1 /*train name field id*/, &err));
+ trainInfo.trainVersionCode = event->GetLong(2 /*train version field id*/, &err);
+ trainInfo.requiresStaging = event->GetBool(3 /*requires staging field id*/, &err);
+ trainInfo.rollbackEnabled = event->GetBool(4 /*rollback enabled field id*/, &err);
+ trainInfo.requiresLowLatencyMonitor =
+ event->GetBool(5 /*requires low latency monitor field id*/, &err);
+ trainInfo.status = int32_t(event->GetLong(6 /*state field id*/, &err));
#ifdef NEW_ENCODING_SCHEME
std::vector<uint8_t> trainExperimentIdBytes =
- event->GetStorage(7 /*experiment ids field id*/, &err4);
+ event->GetStorage(7 /*experiment ids field id*/, &err);
#else
- string trainExperimentIdString = event->GetString(7 /*experiment ids field id*/, &err4);
+ string trainExperimentIdString = event->GetString(7 /*experiment ids field id*/, &err);
#endif
- if (err != NO_ERROR || err2 != NO_ERROR || err3 != NO_ERROR || err4 != NO_ERROR) {
+ bool is_rollback = event->GetBool(10 /*is rollback field id*/, &err);
+
+ if (err != NO_ERROR) {
ALOGE("Failed to parse fields in binary push state changed log event");
return;
}
@@ -220,83 +230,154 @@
ALOGE("Failed to parse experimentids in binary push state changed.");
return;
}
- vector<int64_t> experimentIdVector = {trainExperimentIds.experiment_id().begin(),
- trainExperimentIds.experiment_id().end()};
+ trainInfo.experimentIds = {trainExperimentIds.experiment_id().begin(),
+ trainExperimentIds.experiment_id().end()};
+
// Update the train info on disk and get any data the logevent is missing.
- getAndUpdateTrainInfoOnDisk(
- state, &trainVersionCode, &trainName, &experimentIdVector);
+ getAndUpdateTrainInfoOnDisk(is_rollback, &trainInfo);
std::vector<uint8_t> trainExperimentIdProto;
- writeExperimentIdsToProto(experimentIdVector, &trainExperimentIdProto);
+ writeExperimentIdsToProto(trainInfo.experimentIds, &trainExperimentIdProto);
int32_t userId = multiuser_get_user_id(uid);
- event->updateValue(1 /*train name field id*/, trainName, STRING);
- event->updateValue(2 /*train version field id*/, trainVersionCode, LONG);
+ event->updateValue(2 /*train version field id*/, trainInfo.trainVersionCode, LONG);
#ifdef NEW_ENCODING_SCHEME
event->updateValue(7 /*experiment ids field id*/, trainExperimentIdProto, STORAGE);
#else
event->updateValue(7 /*experiment ids field id*/, trainExperimentIdProto, STRING);
#endif
event->updateValue(8 /*user id field id*/, userId, INT);
+
+ if (is_rollback) {
+ int bit = trainInfo.requiresStaging ? 1 : 0;
+ event->updateValue(3 /*requires staging field id*/, bit, INT);
+ bit = trainInfo.rollbackEnabled ? 1 : 0;
+ event->updateValue(4 /*rollback enabled field id*/, bit, INT);
+ bit = trainInfo.requiresLowLatencyMonitor ? 1 : 0;
+ event->updateValue(5 /*requires low latency monitor field id*/, bit, INT);
+ }
}
-void StatsLogProcessor::getAndUpdateTrainInfoOnDisk(int32_t state,
- int64_t* trainVersionCode,
- string* trainName,
- std::vector<int64_t>* experimentIds) {
+void StatsLogProcessor::getAndUpdateTrainInfoOnDisk(bool is_rollback,
+ InstallTrainInfo* trainInfo) {
+ // If the train name is empty, we don't know which train to attribute the
+ // event to, so return early.
+ if (trainInfo->trainName.empty()) {
+ return;
+ }
bool readTrainInfoSuccess = false;
InstallTrainInfo trainInfoOnDisk;
- readTrainInfoSuccess = StorageManager::readTrainInfo(trainInfoOnDisk);
+ readTrainInfoSuccess = StorageManager::readTrainInfo(trainInfo->trainName, trainInfoOnDisk);
bool resetExperimentIds = false;
if (readTrainInfoSuccess) {
// Keep the old train version if we received an empty version.
- if (*trainVersionCode == -1) {
- *trainVersionCode = trainInfoOnDisk.trainVersionCode;
- } else if (*trainVersionCode != trainInfoOnDisk.trainVersionCode) {
- // Reset experiment ids if we receive a new non-empty train version.
- resetExperimentIds = true;
- }
-
- // Keep the old train name if we received an empty train name.
- if (trainName->size() == 0) {
- *trainName = trainInfoOnDisk.trainName;
- } else if (*trainName != trainInfoOnDisk.trainName) {
- // Reset experiment ids if we received a new valid train name.
+ if (trainInfo->trainVersionCode == -1) {
+ trainInfo->trainVersionCode = trainInfoOnDisk.trainVersionCode;
+ } else if (trainInfo->trainVersionCode != trainInfoOnDisk.trainVersionCode) {
+ // Reset experiment ids if we receive a new non-empty train version.
resetExperimentIds = true;
}
// Reset if we received a different experiment id.
- if (!experimentIds->empty() &&
- (trainInfoOnDisk.experimentIds.empty() ||
- experimentIds->at(0) != trainInfoOnDisk.experimentIds[0])) {
+ if (!trainInfo->experimentIds.empty() &&
+ (trainInfoOnDisk.experimentIds.empty() ||
+ trainInfo->experimentIds.at(0) != trainInfoOnDisk.experimentIds[0])) {
resetExperimentIds = true;
}
}
// Find the right experiment IDs
- if (!resetExperimentIds && readTrainInfoSuccess) {
- *experimentIds = trainInfoOnDisk.experimentIds;
+ if ((!resetExperimentIds || is_rollback) && readTrainInfoSuccess) {
+ trainInfo->experimentIds = trainInfoOnDisk.experimentIds;
}
- if (!experimentIds->empty()) {
- int64_t firstId = experimentIds->at(0);
- switch (state) {
+ if (!trainInfo->experimentIds.empty()) {
+ int64_t firstId = trainInfo->experimentIds.at(0);
+ switch (trainInfo->status) {
case android::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALL_SUCCESS:
- experimentIds->push_back(firstId + 1);
+ trainInfo->experimentIds.push_back(firstId + 1);
break;
case android::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_INITIATED:
- experimentIds->push_back(firstId + 2);
+ trainInfo->experimentIds.push_back(firstId + 2);
break;
case android::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_SUCCESS:
- experimentIds->push_back(firstId + 3);
+ trainInfo->experimentIds.push_back(firstId + 3);
break;
}
}
- StorageManager::writeTrainInfo(*trainVersionCode, *trainName, state, *experimentIds);
+ if (is_rollback) {
+ trainInfo->requiresStaging = trainInfoOnDisk.requiresStaging;
+ trainInfo->rollbackEnabled = trainInfoOnDisk.rollbackEnabled;
+ trainInfo->requiresLowLatencyMonitor = trainInfoOnDisk.requiresLowLatencyMonitor;
+ }
+
+ StorageManager::writeTrainInfo(*trainInfo);
}
+void StatsLogProcessor::onWatchdogRollbackOccurredLocked(LogEvent* event) {
+ pid_t pid = event->GetPid();
+ uid_t uid = event->GetUid();
+ if (!checkPermissionForIds(kPermissionDump, pid, uid) ||
+ !checkPermissionForIds(kPermissionUsage, pid, uid)) {
+ return;
+ }
+ // The Get* functions don't modify the status on success, they only write in
+ // failure statuses, so we can use one status variable for all calls then
+ // check if it is no longer NO_ERROR.
+ status_t err = NO_ERROR;
+ int32_t rollbackType = int32_t(event->GetInt(1 /*rollback type field id*/, &err));
+ string packageName = string(event->GetString(2 /*package name field id*/, &err));
+
+ if (err != NO_ERROR) {
+ ALOGE("Failed to parse fields in watchdog rollback occurred log event");
+ return;
+ }
+
+ vector<int64_t> experimentIds =
+ processWatchdogRollbackOccurred(rollbackType, packageName);
+ vector<uint8_t> experimentIdProto;
+ writeExperimentIdsToProto(experimentIds, &experimentIdProto);
+
+#ifdef NEW_ENCODING_SCHEME
+ event->updateValue(6 /*experiment ids field id*/, experimentIdProto, STORAGE);
+#else
+ event->updateValue(6 /*experiment ids field id*/, experimentIdProto, STRING);
+#endif
+}
+
+vector<int64_t> StatsLogProcessor::processWatchdogRollbackOccurred(const int32_t rollbackTypeIn,
+ const string& packageNameIn) {
+ // If the package name is empty, we can't attribute it to any train, so
+ // return early.
+ if (packageNameIn.empty()) {
+ return vector<int64_t>();
+ }
+ bool readTrainInfoSuccess = false;
+ InstallTrainInfo trainInfoOnDisk;
+ readTrainInfoSuccess = StorageManager::readTrainInfo(packageNameIn, trainInfoOnDisk);
+
+ if (!readTrainInfoSuccess) {
+ return vector<int64_t>();
+ }
+
+ if (trainInfoOnDisk.experimentIds.empty()) {
+ return vector<int64_t>();
+ }
+ switch (rollbackTypeIn) {
+ case android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE:
+ trainInfoOnDisk.experimentIds.push_back(trainInfoOnDisk.experimentIds[0] + 4);
+ StorageManager::writeTrainInfo(trainInfoOnDisk);
+ break;
+ case android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS:
+ trainInfoOnDisk.experimentIds.push_back(trainInfoOnDisk.experimentIds[0] + 5);
+ StorageManager::writeTrainInfo(trainInfoOnDisk);
+ break;
+ }
+
+ return trainInfoOnDisk.experimentIds;
+}
void StatsLogProcessor::resetConfigs() {
std::lock_guard<std::mutex> lock(mMetricsMutex);
@@ -321,7 +402,13 @@
// Hard-coded logic to update train info on disk and fill in any information
// this log event may be missing.
if (event->GetTagId() == android::util::BINARY_PUSH_STATE_CHANGED) {
- onBinaryPushStateChangedEventLocked(event);
+ onBinaryPushStateChangedEventLocked(event);
+ }
+
+ // Hard-coded logic to update experiment ids on disk for certain rollback
+ // types and fill the rollback atom with experiment ids
+ if (event->GetTagId() == android::util::WATCHDOG_ROLLBACK_OCCURRED) {
+ onWatchdogRollbackOccurredLocked(event);
}
#ifdef VERY_VERBOSE_PRINTING
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index c49f2e0..42e5676 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -18,6 +18,7 @@
#include <gtest/gtest_prod.h>
#include "config/ConfigListener.h"
+#include "logd/LogEvent.h"
#include "metrics/MetricsManager.h"
#include "packages/UidMap.h"
#include "external/StatsPullerManager.h"
@@ -199,10 +200,18 @@
// Handler over the binary push state changed event.
void onBinaryPushStateChangedEventLocked(LogEvent* event);
+ // Handler over the watchdog rollback occurred event.
+ void onWatchdogRollbackOccurredLocked(LogEvent* event);
+
// Updates train info on disk based on binary push state changed info and
// write disk info into parameters.
- void getAndUpdateTrainInfoOnDisk(int32_t state, int64_t* trainVersionCode,
- string* trainName, std::vector<int64_t>* experimentIds);
+ void getAndUpdateTrainInfoOnDisk(bool is_rollback, InstallTrainInfo* trainInfoIn);
+
+ // Gets experiment ids on disk for associated train and updates them
+ // depending on rollback type. Then writes them back to disk and returns
+ // them.
+ std::vector<int64_t> processWatchdogRollbackOccurred(const int32_t rollbackTypeIn,
+ const string& packageName);
// Reset all configs.
void resetConfigsLocked(const int64_t timestampNs);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index a06e59c..168833f 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1293,81 +1293,24 @@
return Status::ok();
}
-Status StatsService::sendWatchdogRollbackOccurredAtom(const int32_t rollbackTypeIn,
- const android::String16& packageNameIn,
- const int64_t packageVersionCodeIn,
- const int32_t rollbackReasonIn,
- const android::String16&
- failingPackageNameIn) {
- // Note: We skip the usage stats op check here since we do not have a package name.
- // This is ok since we are overloading the usage_stats permission.
- // This method only sends data, it does not receive it.
- pid_t pid = IPCThreadState::self()->getCallingPid();
- uid_t uid = IPCThreadState::self()->getCallingUid();
- // Root, system, and shell always have access
- if (uid != AID_ROOT && uid != AID_SYSTEM && uid != AID_SHELL) {
- // Caller must be granted these permissions
- if (!checkPermission(kPermissionDump)) {
- return exception(binder::Status::EX_SECURITY,
- StringPrintf("UID %d / PID %d lacks permission %s", uid, pid,
- kPermissionDump));
- }
- if (!checkPermission(kPermissionUsage)) {
- return exception(binder::Status::EX_SECURITY,
- StringPrintf("UID %d / PID %d lacks permission %s", uid, pid,
- kPermissionUsage));
- }
- }
-
- android::util::stats_write(android::util::WATCHDOG_ROLLBACK_OCCURRED,
- rollbackTypeIn, String8(packageNameIn).string(), packageVersionCodeIn,
- rollbackReasonIn, String8(failingPackageNameIn).string());
-
- // Fast return to save disk read.
- if (rollbackTypeIn != android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS
- && rollbackTypeIn !=
- android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE) {
- return Status::ok();
- }
-
- bool readTrainInfoSuccess = false;
- InstallTrainInfo trainInfoOnDisk;
- readTrainInfoSuccess = StorageManager::readTrainInfo(trainInfoOnDisk);
-
- if (!readTrainInfoSuccess) {
- return Status::ok();
- }
- std::vector<int64_t> experimentIds = trainInfoOnDisk.experimentIds;
- if (experimentIds.empty()) {
- return Status::ok();
- }
- switch (rollbackTypeIn) {
- case android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE:
- experimentIds.push_back(experimentIds[0] + 4);
- break;
- case android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS:
- experimentIds.push_back(experimentIds[0] + 5);
- break;
- }
- StorageManager::writeTrainInfo(trainInfoOnDisk.trainVersionCode, trainInfoOnDisk.trainName,
- trainInfoOnDisk.status, experimentIds);
- return Status::ok();
-}
-
Status StatsService::getRegisteredExperimentIds(std::vector<int64_t>* experimentIdsOut) {
ENFORCE_UID(AID_SYSTEM);
// TODO: add verifier permission
+ experimentIdsOut->clear();
// Read the latest train info
- InstallTrainInfo trainInfo;
- if (!StorageManager::readTrainInfo(trainInfo)) {
+ vector<InstallTrainInfo> trainInfoList = StorageManager::readAllTrainInfo();
+ if (trainInfoList.empty()) {
// No train info means no experiment IDs, return an empty list
- experimentIdsOut->clear();
return Status::ok();
}
// Copy the experiment IDs to the out vector
- experimentIdsOut->assign(trainInfo.experimentIds.begin(), trainInfo.experimentIds.end());
+ for (InstallTrainInfo& trainInfo : trainInfoList) {
+ experimentIdsOut->insert(experimentIdsOut->end(),
+ trainInfo.experimentIds.begin(),
+ trainInfo.experimentIds.end());
+ }
return Status::ok();
}
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 82a5a53..0527d43 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -187,16 +187,6 @@
virtual Status unregisterNativePullAtomCallback(int32_t atomTag) override;
/**
- * Binder call to log WatchdogRollbackOccurred atom.
- */
- virtual Status sendWatchdogRollbackOccurredAtom(
- const int32_t rollbackTypeIn,
- const android::String16& packageNameIn,
- const int64_t packageVersionCodeIn,
- const int32_t rollbackReasonIn,
- const android::String16& failingPackageNameIn) override;
-
- /**
* Binder call to get registered experiment IDs.
*/
virtual Status getRegisteredExperimentIds(std::vector<int64_t>* expIdsOut);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 71afc32..0bee44f 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -127,7 +127,7 @@
WallClockTimeShifted wall_clock_time_shifted = 45 [(module) = "framework"];
AnomalyDetected anomaly_detected = 46;
AppBreadcrumbReported app_breadcrumb_reported =
- 47 [(allow_from_any_uid) = true, (module) = "framework"];
+ 47 [(allow_from_any_uid) = true, (module) = "statsd"];
AppStartOccurred app_start_occurred = 48 [(module) = "framework"];
AppStartCanceled app_start_canceled = 49 [(module) = "framework"];
AppStartFullyDrawn app_start_fully_drawn = 50 [(module) = "framework"];
@@ -188,7 +188,7 @@
ServiceStateChanged service_state_changed = 99 [(module) = "framework"];
ServiceLaunchReported service_launch_reported = 100 [(module) = "framework"];
FlagFlipUpdateOccurred flag_flip_update_occurred = 101 [(module) = "framework"];
- BinaryPushStateChanged binary_push_state_changed = 102 [(module) = "framework"];
+ BinaryPushStateChanged binary_push_state_changed = 102 [(module) = "statsd"];
DevicePolicyEvent device_policy_event = 103 [(module) = "framework"];
DocsUIFileOperationCanceledReported docs_ui_file_op_canceled = 104 [(module) = "docsui"];
DocsUIFileOperationCopyMoveModeReported docs_ui_file_op_copy_move_mode_reported =
@@ -1874,6 +1874,8 @@
// Set by RollbackPackageHealthObserver to be the package that is failing when a rollback
// is initiated. Empty if the package is unknown.
optional string failing_package_name = 5;
+
+ optional TrainExperimentIds experiment_ids = 6 [(log_mode) = MODE_BYTES];
}
/**
@@ -3770,6 +3772,8 @@
// user id
optional int32 user_id = 8;
optional int32 reason = 9;
+ // Whether or not this is a rollback event
+ optional bool is_rollback = 10;
}
/* Test atom, is not logged anywhere */
diff --git a/cmds/statsd/src/external/TrainInfoPuller.cpp b/cmds/statsd/src/external/TrainInfoPuller.cpp
index 9d09242..a7d8d4e 100644
--- a/cmds/statsd/src/external/TrainInfoPuller.cpp
+++ b/cmds/statsd/src/external/TrainInfoPuller.cpp
@@ -37,14 +37,16 @@
}
bool TrainInfoPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
- InstallTrainInfo trainInfo;
- bool ret = StorageManager::readTrainInfo(trainInfo);
- if (!ret) {
- ALOGW("Failed to read train info.");
- return false;
+ vector<InstallTrainInfo> trainInfoList =
+ StorageManager::readAllTrainInfo();
+ if (trainInfoList.empty()) {
+ ALOGW("Train info was empty.");
+ return true;
}
- auto event = make_shared<LogEvent>(getWallClockNs(), getElapsedRealtimeNs(), trainInfo);
- data->push_back(event);
+ for (InstallTrainInfo& trainInfo : trainInfoList) {
+ auto event = make_shared<LogEvent>(getWallClockNs(), getElapsedRealtimeNs(), trainInfo);
+ data->push_back(event);
+ }
return true;
}
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 5509c09..a67bef4 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -56,6 +56,9 @@
std::string trainName;
int32_t status;
std::vector<int64_t> experimentIds;
+ bool requiresStaging;
+ bool rollbackEnabled;
+ bool requiresLowLatencyMonitor;
};
/**
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 507297c..1bac19e 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -44,7 +44,7 @@
#define TRAIN_INFO_PATH "/data/misc/train-info/train-info.bin"
// Magic word at the start of the train info file, change this if changing the file format
-const uint32_t TRAIN_INFO_FILE_MAGIC = 0xff7447ff;
+const uint32_t TRAIN_INFO_FILE_MAGIC = 0xfb7447bf;
// for ConfigMetricsReportList
const int FIELD_ID_REPORTS = 2;
@@ -75,6 +75,29 @@
(long long)id);
}
+static const char* findTrainInfoFileNameLocked(const string& trainName) {
+ unique_ptr<DIR, decltype(&closedir)> dir(opendir(TRAIN_INFO_DIR), closedir);
+ if (dir == NULL) {
+ VLOG("Path %s does not exist", TRAIN_INFO_DIR);
+ return nullptr;
+ }
+ dirent* de;
+ while ((de = readdir(dir.get()))) {
+ char* fileName = de->d_name;
+ if (fileName[0] == '.') continue;
+
+ size_t fileNameLength = strlen(fileName);
+ if (fileNameLength >= trainName.length()) {
+ if (0 == strncmp(fileName + fileNameLength - trainName.length(), trainName.c_str(),
+ trainName.length())) {
+ return fileName;
+ }
+ }
+ }
+
+ return nullptr;
+}
+
// Returns array of int64_t which contains timestamp in seconds, uid,
// configID and whether the file is a local history file.
static void parseFileName(char* name, FileName* output) {
@@ -123,20 +146,25 @@
close(fd);
}
-bool StorageManager::writeTrainInfo(int64_t trainVersionCode, const std::string& trainName,
- int32_t status, const std::vector<int64_t>& experimentIds) {
+bool StorageManager::writeTrainInfo(const InstallTrainInfo& trainInfo) {
std::lock_guard<std::mutex> lock(sTrainInfoMutex);
- deleteAllFiles(TRAIN_INFO_DIR);
+ if (trainInfo.trainName.empty()) {
+ return false;
+ }
+ deleteSuffixedFiles(TRAIN_INFO_DIR, trainInfo.trainName.c_str());
- int fd = open(TRAIN_INFO_PATH, O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
+ std::string fileName =
+ StringPrintf("%s/%ld_%s", TRAIN_INFO_DIR, (long) getWallClockSec(),
+ trainInfo.trainName.c_str());
+
+ int fd = open(fileName.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
if (fd == -1) {
- VLOG("Attempt to access %s but failed", TRAIN_INFO_PATH);
+ VLOG("Attempt to access %s but failed", fileName.c_str());
return false;
}
size_t result;
-
// Write the magic word
result = write(fd, &TRAIN_INFO_FILE_MAGIC, sizeof(TRAIN_INFO_FILE_MAGIC));
if (result != sizeof(TRAIN_INFO_FILE_MAGIC)) {
@@ -146,8 +174,8 @@
}
// Write the train version
- const size_t trainVersionCodeByteCount = sizeof(trainVersionCode);
- result = write(fd, &trainVersionCode, trainVersionCodeByteCount);
+ const size_t trainVersionCodeByteCount = sizeof(trainInfo.trainVersionCode);
+ result = write(fd, &trainInfo.trainVersionCode, trainVersionCodeByteCount);
if (result != trainVersionCodeByteCount) {
VLOG("Failed to wrtie train version code");
close(fd);
@@ -155,7 +183,7 @@
}
// Write # of bytes in trainName to file
- const size_t trainNameSize = trainName.size();
+ const size_t trainNameSize = trainInfo.trainName.size();
const size_t trainNameSizeByteCount = sizeof(trainNameSize);
result = write(fd, (uint8_t*)&trainNameSize, trainNameSizeByteCount);
if (result != trainNameSizeByteCount) {
@@ -165,7 +193,7 @@
}
// Write trainName to file
- result = write(fd, trainName.c_str(), trainNameSize);
+ result = write(fd, trainInfo.trainName.c_str(), trainNameSize);
if (result != trainNameSize) {
VLOG("Failed to write train name");
close(fd);
@@ -173,8 +201,8 @@
}
// Write status to file
- const size_t statusByteCount = sizeof(status);
- result = write(fd, (uint8_t*)&status, statusByteCount);
+ const size_t statusByteCount = sizeof(trainInfo.status);
+ result = write(fd, (uint8_t*)&trainInfo.status, statusByteCount);
if (result != statusByteCount) {
VLOG("Failed to write status");
close(fd);
@@ -182,7 +210,7 @@
}
// Write experiment id count to file.
- const size_t experimentIdsCount = experimentIds.size();
+ const size_t experimentIdsCount = trainInfo.experimentIds.size();
const size_t experimentIdsCountByteCount = sizeof(experimentIdsCount);
result = write(fd, (uint8_t*) &experimentIdsCount, experimentIdsCountByteCount);
if (result != experimentIdsCountByteCount) {
@@ -193,7 +221,7 @@
// Write experimentIds to file
for (size_t i = 0; i < experimentIdsCount; i++) {
- const int64_t experimentId = experimentIds[i];
+ const int64_t experimentId = trainInfo.experimentIds[i];
const size_t experimentIdByteCount = sizeof(experimentId);
result = write(fd, &experimentId, experimentIdByteCount);
if (result == experimentIdByteCount) {
@@ -205,23 +233,47 @@
}
}
- result = fchown(fd, AID_STATSD, AID_STATSD);
- if (result) {
- VLOG("Failed to chown train info file to statsd");
- close(fd);
- return false;
+ // Write bools to file
+ const size_t boolByteCount = sizeof(trainInfo.requiresStaging);
+ result = write(fd, (uint8_t*)&trainInfo.requiresStaging, boolByteCount);
+ if (result != boolByteCount) {
+ VLOG("Failed to write requires staging");
+ close(fd);
+ return false;
+ }
+
+ result = write(fd, (uint8_t*)&trainInfo.rollbackEnabled, boolByteCount);
+ if (result != boolByteCount) {
+ VLOG("Failed to write rollback enabled");
+ close(fd);
+ return false;
+ }
+
+ result = write(fd, (uint8_t*)&trainInfo.requiresLowLatencyMonitor, boolByteCount);
+ if (result != boolByteCount) {
+ VLOG("Failed to write requires log latency monitor");
+ close(fd);
+ return false;
}
close(fd);
return true;
}
-bool StorageManager::readTrainInfo(InstallTrainInfo& trainInfo) {
+bool StorageManager::readTrainInfo(const std::string& trainName, InstallTrainInfo& trainInfo) {
std::lock_guard<std::mutex> lock(sTrainInfoMutex);
+ return readTrainInfoLocked(trainName, trainInfo);
+}
- int fd = open(TRAIN_INFO_PATH, O_RDONLY | O_CLOEXEC);
+bool StorageManager::readTrainInfoLocked(const std::string& trainName, InstallTrainInfo& trainInfo) {
+ trimToFit(TRAIN_INFO_DIR, /*parseTimestampOnly=*/ true);
+ const char* fileName = findTrainInfoFileNameLocked(trainName);
+ if (fileName == nullptr) {
+ return false;
+ }
+ int fd = open(StringPrintf("%s/%s", TRAIN_INFO_DIR, fileName).c_str(), O_RDONLY | O_CLOEXEC);
if (fd == -1) {
- VLOG("Failed to open train-info.bin");
+ VLOG("Failed to open %s", fileName);
return false;
}
@@ -297,6 +349,29 @@
trainInfo.experimentIds.push_back(experimentId);
}
+ // Read bools
+ const size_t boolByteCount = sizeof(trainInfo.requiresStaging);
+ result = read(fd, &trainInfo.requiresStaging, boolByteCount);
+ if (result != boolByteCount) {
+ VLOG("Failed to read requires requires staging from train info file");
+ close(fd);
+ return false;
+ }
+
+ result = read(fd, &trainInfo.rollbackEnabled, boolByteCount);
+ if (result != boolByteCount) {
+ VLOG("Failed to read requires rollback enabled from train info file");
+ close(fd);
+ return false;
+ }
+
+ result = read(fd, &trainInfo.requiresLowLatencyMonitor, boolByteCount);
+ if (result != boolByteCount) {
+ VLOG("Failed to read requires requires low latency monitor from train info file");
+ close(fd);
+ return false;
+ }
+
// Expect to be at EOF.
char c;
result = read(fd, &c, 1);
@@ -311,6 +386,32 @@
return true;
}
+vector<InstallTrainInfo> StorageManager::readAllTrainInfo() {
+ std::lock_guard<std::mutex> lock(sTrainInfoMutex);
+ vector<InstallTrainInfo> trainInfoList;
+ unique_ptr<DIR, decltype(&closedir)> dir(opendir(TRAIN_INFO_DIR), closedir);
+ if (dir == NULL) {
+ VLOG("Directory does not exist: %s", TRAIN_INFO_DIR);
+ return trainInfoList;
+ }
+
+ dirent* de;
+ while ((de = readdir(dir.get()))) {
+ char* name = de->d_name;
+ if (name[0] == '.') {
+ continue;
+ }
+
+ InstallTrainInfo trainInfo;
+ bool readSuccess = StorageManager::readTrainInfoLocked(name, trainInfo);
+ if (!readSuccess) {
+ continue;
+ }
+ trainInfoList.push_back(trainInfo);
+ }
+ return trainInfoList;
+}
+
void StorageManager::deleteFile(const char* file) {
if (remove(file) != 0) {
VLOG("Attempt to delete %s but is not found", file);
@@ -574,7 +675,7 @@
});
}
-void StorageManager::trimToFit(const char* path) {
+void StorageManager::trimToFit(const char* path, bool parseTimestampOnly) {
unique_ptr<DIR, decltype(&closedir)> dir(opendir(path), closedir);
if (dir == NULL) {
VLOG("Path %s does not exist", path);
@@ -589,7 +690,12 @@
if (name[0] == '.') continue;
FileName output;
- parseFileName(name, &output);
+ if (parseTimestampOnly) {
+ output.mTimestampSec = StrToInt64(strtok(name, "_"));
+ output.mIsHistory = false;
+ } else {
+ parseFileName(name, &output);
+ }
if (output.mTimestampSec == -1) continue;
string file_name = output.getFullFileName(path);
diff --git a/cmds/statsd/src/storage/StorageManager.h b/cmds/statsd/src/storage/StorageManager.h
index 69b41c2..d59046d 100644
--- a/cmds/statsd/src/storage/StorageManager.h
+++ b/cmds/statsd/src/storage/StorageManager.h
@@ -52,13 +52,22 @@
/**
* Writes train info.
*/
- static bool writeTrainInfo(int64_t trainVersionCode, const std::string& trainName,
- int32_t status, const std::vector<int64_t>& experimentIds);
+ static bool writeTrainInfo(const InstallTrainInfo& trainInfo);
/**
* Reads train info.
*/
- static bool readTrainInfo(InstallTrainInfo& trainInfo);
+ static bool readTrainInfo(const std::string& trainName, InstallTrainInfo& trainInfo);
+
+ /**
+ * Reads train info assuming lock is obtained.
+ */
+ static bool readTrainInfoLocked(const std::string& trainName, InstallTrainInfo& trainInfo);
+
+ /**
+ * Reads all train info and returns a vector of train info.
+ */
+ static vector<InstallTrainInfo> readAllTrainInfo();
/**
* Reads the file content to the buffer.
@@ -124,7 +133,7 @@
* Trims files in the provided directory to limit the total size, number of
* files, accumulation of outdated files.
*/
- static void trimToFit(const char* dir);
+ static void trimToFit(const char* dir, bool parseTimestampOnly = false);
/**
* Returns true if there already exists identical configuration on device.
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.cpp b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
index 160b57e..8fd6b46 100644
--- a/cmds/statsd/src/subscriber/SubscriberReporter.cpp
+++ b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
@@ -121,7 +121,7 @@
subscription.id(),
subscription.rule_id(),
cookies,
- getStatsDimensionsValue(dimKey.getDimensionKeyInWhat()));
+ dimKey.getDimensionKeyInWhat().toStatsDimensionsValueParcel());
}
sp<IPendingIntentRef> SubscriberReporter::getBroadcastSubscriber(const ConfigKey& configKey,
@@ -138,61 +138,6 @@
return pirMapIt->second;
}
-void getStatsDimensionsValueHelper(const vector<FieldValue>& dims, size_t* index, int depth,
- int prefix, vector<StatsDimensionsValue>* output) {
- size_t count = dims.size();
- while (*index < count) {
- const auto& dim = dims[*index];
- const int valueDepth = dim.mField.getDepth();
- const int valuePrefix = dim.mField.getPrefix(depth);
- if (valueDepth > 2) {
- ALOGE("Depth > 2 not supported");
- return;
- }
- if (depth == valueDepth && valuePrefix == prefix) {
- switch (dim.mValue.getType()) {
- case INT:
- output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth),
- dim.mValue.int_value));
- break;
- case LONG:
- output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth),
- dim.mValue.long_value));
- break;
- case FLOAT:
- output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth),
- dim.mValue.float_value));
- break;
- case STRING:
- output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth),
- String16(dim.mValue.str_value.c_str())));
- break;
- default:
- break;
- }
- (*index)++;
- } else if (valueDepth > depth && valuePrefix == prefix) {
- vector<StatsDimensionsValue> childOutput;
- getStatsDimensionsValueHelper(dims, index, depth + 1, dim.mField.getPrefix(depth + 1),
- &childOutput);
- output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth), childOutput));
- } else {
- return;
- }
- }
-}
-
-StatsDimensionsValue SubscriberReporter::getStatsDimensionsValue(const HashableDimensionKey& dim) {
- if (dim.getValues().size() == 0) {
- return StatsDimensionsValue();
- }
-
- vector<StatsDimensionsValue> fields;
- size_t index = 0;
- getStatsDimensionsValueHelper(dim.getValues(), &index, 0, 0, &fields);
- return StatsDimensionsValue(dim.getValues()[0].mField.getTag(), fields);
-}
-
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.h b/cmds/statsd/src/subscriber/SubscriberReporter.h
index 087a1b8..42599f5 100644
--- a/cmds/statsd/src/subscriber/SubscriberReporter.h
+++ b/cmds/statsd/src/subscriber/SubscriberReporter.h
@@ -22,7 +22,6 @@
#include "config/ConfigKey.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // subscription
-#include "android/os/StatsDimensionsValue.h"
#include "HashableDimensionKey.h"
#include <mutex>
@@ -70,8 +69,6 @@
sp<IPendingIntentRef> getBroadcastSubscriber(const ConfigKey& configKey, int64_t subscriberId);
- static StatsDimensionsValue getStatsDimensionsValue(const HashableDimensionKey& dim);
-
private:
SubscriberReporter() {};
diff --git a/cmds/statsd/tests/FieldValue_test.cpp b/cmds/statsd/tests/FieldValue_test.cpp
index f4a59ed..9e69d97 100644
--- a/cmds/statsd/tests/FieldValue_test.cpp
+++ b/cmds/statsd/tests/FieldValue_test.cpp
@@ -290,33 +290,34 @@
}
}
-TEST(AtomMatcherTest, TestSubscriberDimensionWrite) {
- HashableDimensionKey dim;
-
- int pos1[] = {1, 1, 1};
- int pos2[] = {1, 1, 2};
- int pos3[] = {1, 1, 3};
- int pos4[] = {2, 0, 0};
-
- Field field1(10, pos1, 2);
- Field field2(10, pos2, 2);
- Field field3(10, pos3, 2);
- Field field4(10, pos4, 0);
-
- Value value1((int32_t)10025);
- Value value2("tag");
- Value value3((int32_t)987654);
- Value value4((int32_t)99999);
-
- dim.addValue(FieldValue(field1, value1));
- dim.addValue(FieldValue(field2, value2));
- dim.addValue(FieldValue(field3, value3));
- dim.addValue(FieldValue(field4, value4));
-
- SubscriberReporter::getStatsDimensionsValue(dim);
- // TODO(b/110562792): can't test anything here because StatsDimensionsValue class doesn't
- // have any read api.
-}
+//TODO(b/149050405) Update this test for StatsDimensionValueParcel
+//TEST(AtomMatcherTest, TestSubscriberDimensionWrite) {
+// HashableDimensionKey dim;
+//
+// int pos1[] = {1, 1, 1};
+// int pos2[] = {1, 1, 2};
+// int pos3[] = {1, 1, 3};
+// int pos4[] = {2, 0, 0};
+//
+// Field field1(10, pos1, 2);
+// Field field2(10, pos2, 2);
+// Field field3(10, pos3, 2);
+// Field field4(10, pos4, 0);
+//
+// Value value1((int32_t)10025);
+// Value value2("tag");
+// Value value3((int32_t)987654);
+// Value value4((int32_t)99999);
+//
+// dim.addValue(FieldValue(field1, value1));
+// dim.addValue(FieldValue(field2, value2));
+// dim.addValue(FieldValue(field3, value3));
+// dim.addValue(FieldValue(field4, value4));
+//
+// SubscriberReporter::getStatsDimensionsValue(dim);
+// // TODO(b/110562792): can't test anything here because StatsDimensionsValue class doesn't
+// // have any read api.
+//}
TEST(AtomMatcherTest, TestWriteDimensionToProto) {
HashableDimensionKey dim;
diff --git a/cmds/statsd/tests/storage/StorageManager_test.cpp b/cmds/statsd/tests/storage/StorageManager_test.cpp
index b91e5a0..27a86e42 100644
--- a/cmds/statsd/tests/storage/StorageManager_test.cpp
+++ b/cmds/statsd/tests/storage/StorageManager_test.cpp
@@ -40,40 +40,12 @@
bool result;
- result = StorageManager::writeTrainInfo(trainInfo.trainVersionCode, trainInfo.trainName,
- trainInfo.status, trainInfo.experimentIds);
+ result = StorageManager::writeTrainInfo(trainInfo);
EXPECT_TRUE(result);
InstallTrainInfo trainInfoResult;
- result = StorageManager::readTrainInfo(trainInfoResult);
- EXPECT_TRUE(result);
-
- EXPECT_EQ(trainInfo.trainVersionCode, trainInfoResult.trainVersionCode);
- EXPECT_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());
- EXPECT_EQ(trainInfo.experimentIds, trainInfoResult.experimentIds);
-}
-
-TEST(StorageManagerTest, TrainInfoReadWriteEmptyTrainNameTest) {
- InstallTrainInfo trainInfo;
- trainInfo.trainVersionCode = 12345;
- trainInfo.trainName = "";
- trainInfo.status = 1;
- const char* expIds = "test_ids";
- trainInfo.experimentIds.assign(expIds, expIds + strlen(expIds));
-
- bool result;
-
- result = StorageManager::writeTrainInfo(trainInfo.trainVersionCode, trainInfo.trainName,
- trainInfo.status, trainInfo.experimentIds);
-
- EXPECT_TRUE(result);
-
- InstallTrainInfo trainInfoResult;
- result = StorageManager::readTrainInfo(trainInfoResult);
+ result = StorageManager::readTrainInfo(trainInfo.trainName, trainInfoResult);
EXPECT_TRUE(result);
EXPECT_EQ(trainInfo.trainVersionCode, trainInfoResult.trainVersionCode);
@@ -94,13 +66,12 @@
bool result;
- result = StorageManager::writeTrainInfo(trainInfo.trainVersionCode, trainInfo.trainName,
- trainInfo.status, trainInfo.experimentIds);
+ result = StorageManager::writeTrainInfo(trainInfo);
EXPECT_TRUE(result);
InstallTrainInfo trainInfoResult;
- result = StorageManager::readTrainInfo(trainInfoResult);
+ result = StorageManager::readTrainInfo(trainInfo.trainName, trainInfoResult);
EXPECT_TRUE(result);
EXPECT_EQ(trainInfo.trainVersionCode, trainInfoResult.trainVersionCode);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 642f51b..2319dd2 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -5810,9 +5810,9 @@
intent.prepareToLeaveProcess(this);
result = ActivityTaskManager.getService()
.startActivity(mMainThread.getApplicationThread(), getBasePackageName(),
- intent, intent.resolveTypeIfNeeded(getContentResolver()), mToken,
- mEmbeddedID, requestCode, ActivityManager.START_FLAG_ONLY_IF_NEEDED,
- null, options);
+ getFeatureId(), intent,
+ intent.resolveTypeIfNeeded(getContentResolver()), mToken, mEmbeddedID,
+ requestCode, ActivityManager.START_FLAG_ONLY_IF_NEEDED, null, options);
} catch (RemoteException e) {
// Empty
}
@@ -6606,8 +6606,8 @@
try {
data.prepareToLeaveProcess(this);
IIntentSender target =
- ActivityManager.getService().getIntentSender(
- ActivityManager.INTENT_SENDER_ACTIVITY_RESULT, packageName,
+ ActivityManager.getService().getIntentSenderWithFeature(
+ ActivityManager.INTENT_SENDER_ACTIVITY_RESULT, packageName, getFeatureId(),
mParent == null ? mToken : mParent.mToken,
mEmbeddedID, requestCode, new Intent[] { data }, null, flags, null,
getUserId());
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index db9aa18..2838ad8 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -94,6 +94,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.Locale;
@@ -3555,13 +3556,13 @@
* @return a list of {@link ApplicationExitInfo} records matching the criteria, sorted in
* the order from most recent to least recent.
*/
- @Nullable
+ @NonNull
public List<ApplicationExitInfo> getHistoricalProcessExitReasons(@Nullable String packageName,
@IntRange(from = 0) int pid, @IntRange(from = 0) int maxNum) {
try {
ParceledListSlice<ApplicationExitInfo> r = getService().getHistoricalProcessExitReasons(
packageName, pid, maxNum, mContext.getUserId());
- return r == null ? null : r.getList();
+ return r == null ? Collections.emptyList() : r.getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4315,8 +4316,8 @@
*/
public static void broadcastStickyIntent(Intent intent, int appOp, int userId) {
try {
- getService().broadcastIntent(
- null, intent, null, null, Activity.RESULT_OK, null, null,
+ getService().broadcastIntentWithFeature(
+ null, null, intent, null, null, Activity.RESULT_OK, null, null,
null /*permission*/, appOp, null, false, true, userId);
} catch (RemoteException ex) {
}
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index c60f7bd..ec11043 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -269,13 +269,16 @@
public abstract void tempWhitelistForPendingIntent(int callerPid, int callerUid, int targetUid,
long duration, String tag);
- public abstract int broadcastIntentInPackage(String packageName, int uid, int realCallingUid,
- int realCallingPid, Intent intent, String resolvedType, IIntentReceiver resultTo,
- int resultCode, String resultData, Bundle resultExtras, String requiredPermission,
- Bundle bOptions, boolean serialized, boolean sticky, @UserIdInt int userId,
- boolean allowBackgroundActivityStarts);
+
+ public abstract int broadcastIntentInPackage(String packageName, @Nullable String featureId,
+ int uid, int realCallingUid, int realCallingPid, Intent intent, String resolvedType,
+ IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras,
+ String requiredPermission, Bundle bOptions, boolean serialized, boolean sticky,
+ @UserIdInt int userId, boolean allowBackgroundActivityStarts);
+
public abstract ComponentName startServiceInPackage(int uid, Intent service,
- String resolvedType, boolean fgRequired, String callingPackage, @UserIdInt int userId,
+ String resolvedType, boolean fgRequired, String callingPackage,
+ @Nullable String callingFeatureId, @UserIdInt int userId,
boolean allowBackgroundActivityStarts) throws TransactionTooLargeException;
public abstract void disconnectActivityFromServices(Object connectionHolder);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 6ef99a3..fc37af9 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -3916,7 +3916,10 @@
}
/**
- * The features that have been used when checking the op
+ * The features that have been used when checking the op keyed by id of the feature.
+ *
+ * @see Context#createFeatureContext(String)
+ * @see #noteOp(String, int, String, String, String)
*/
@DataClass.Generated.Member
public @NonNull Map<String,OpFeatureEntry> getFeatures() {
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index 4bf5f07..c55453e 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -19,7 +19,6 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.app.ActivityManager.RunningAppProcessInfo.Importance;
import android.icu.text.SimpleDateFormat;
import android.os.Parcel;
@@ -245,12 +244,12 @@
/**
* @see {@link #getPss}
*/
- private int mPss;
+ private long mPss;
/**
* @see {@link #getRss}
*/
- private int mRss;
+ private long mRss;
/**
* @see {@link #getTimestamp}
@@ -385,7 +384,7 @@
* it's NOT the exact memory information prior to its death; and it'll be zero
* if the process died before system had a chance to take the sample. </p>
*/
- public int getPss() {
+ public long getPss() {
return mPss;
}
@@ -396,12 +395,13 @@
* it's NOT the exact memory information prior to its death; and it'll be zero
* if the process died before system had a chance to take the sample. </p>
*/
- public int getRss() {
+ public long getRss() {
return mRss;
}
/**
- * The timestamp of the process's death, in milliseconds since the epoch.
+ * The timestamp of the process's death, in milliseconds since the epoch,
+ * as returned by {@link System#currentTimeMillis System.currentTimeMillis()}.
*/
public long getTimestamp() {
return mTimestamp;
@@ -409,6 +409,9 @@
/**
* The human readable description of the process's death, given by the system; could be null.
+ *
+ * <p class="note">Note: only intended to be human-readable and the system provides no
+ * guarantees that the format is stable across devices or Android releases.</p>
*/
public @Nullable String getDescription() {
return mDescription;
@@ -416,10 +419,7 @@
/**
* Return the user id of the record on a multi-user system.
- *
- * @hide
*/
- @SystemApi
public @NonNull UserHandle getUserHandle() {
return UserHandle.of(UserHandle.getUserId(mRealUid));
}
@@ -546,7 +546,7 @@
*
* @hide
*/
- public void setPss(final int pss) {
+ public void setPss(final long pss) {
mPss = pss;
}
@@ -555,7 +555,7 @@
*
* @hide
*/
- public void setRss(final int rss) {
+ public void setRss(final long rss) {
mRss = rss;
}
@@ -630,8 +630,8 @@
dest.writeInt(mSubReason);
dest.writeInt(mStatus);
dest.writeInt(mImportance);
- dest.writeInt(mPss);
- dest.writeInt(mRss);
+ dest.writeLong(mPss);
+ dest.writeLong(mRss);
dest.writeLong(mTimestamp);
dest.writeString(mDescription);
}
@@ -669,8 +669,8 @@
mSubReason = in.readInt();
mStatus = in.readInt();
mImportance = in.readInt();
- mPss = in.readInt();
- mRss = in.readInt();
+ mPss = in.readLong();
+ mRss = in.readLong();
mTimestamp = in.readLong();
mDescription = in.readString();
}
@@ -848,10 +848,10 @@
mImportance = proto.readInt(ApplicationExitInfoProto.IMPORTANCE);
break;
case (int) ApplicationExitInfoProto.PSS:
- mPss = proto.readInt(ApplicationExitInfoProto.PSS);
+ mPss = proto.readLong(ApplicationExitInfoProto.PSS);
break;
case (int) ApplicationExitInfoProto.RSS:
- mRss = proto.readInt(ApplicationExitInfoProto.RSS);
+ mRss = proto.readLong(ApplicationExitInfoProto.RSS);
break;
case (int) ApplicationExitInfoProto.TIMESTAMP:
mTimestamp = proto.readLong(ApplicationExitInfoProto.TIMESTAMP);
@@ -891,8 +891,8 @@
result = 31 * result + mSubReason;
result = 31 * result + mImportance;
result = 31 * result + mStatus;
- result = 31 * result + mPss;
- result = 31 * result + mRss;
+ result = 31 * result + (int) mPss;
+ result = 31 * result + (int) mRss;
result = 31 * result + Long.hashCode(mTimestamp);
result = 31 * result + Objects.hashCode(mProcessName);
result = 31 * result + Objects.hashCode(mDescription);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 57cd894..6b5bfda 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1020,7 +1020,7 @@
public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) {
try {
ActivityTaskManager.getService().startActivityAsUser(
- mMainThread.getApplicationThread(), getBasePackageName(), intent,
+ mMainThread.getApplicationThread(), getBasePackageName(), getFeatureId(), intent,
intent.resolveTypeIfNeeded(getContentResolver()),
null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, options,
user.getIdentifier());
@@ -1102,8 +1102,8 @@
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
- ActivityManager.getService().broadcastIntent(
- mMainThread.getApplicationThread(), intent, resolvedType, null,
+ ActivityManager.getService().broadcastIntentWithFeature(
+ mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
getUserId());
} catch (RemoteException e) {
@@ -1119,8 +1119,8 @@
: new String[] {receiverPermission};
try {
intent.prepareToLeaveProcess(this);
- ActivityManager.getService().broadcastIntent(
- mMainThread.getApplicationThread(), intent, resolvedType, null,
+ ActivityManager.getService().broadcastIntentWithFeature(
+ mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
null, false, false, getUserId());
} catch (RemoteException e) {
@@ -1134,8 +1134,8 @@
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
- ActivityManager.getService().broadcastIntent(
- mMainThread.getApplicationThread(), intent, resolvedType, null,
+ ActivityManager.getService().broadcastIntentWithFeature(
+ mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
null, false, false, getUserId());
} catch (RemoteException e) {
@@ -1149,8 +1149,8 @@
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
- ActivityManager.getService().broadcastIntent(
- mMainThread.getApplicationThread(), intent, resolvedType, null,
+ ActivityManager.getService().broadcastIntentWithFeature(
+ mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
null, false, false, user.getIdentifier());
} catch (RemoteException e) {
@@ -1166,8 +1166,8 @@
: new String[] {receiverPermission};
try {
intent.prepareToLeaveProcess(this);
- ActivityManager.getService().broadcastIntent(
- mMainThread.getApplicationThread(), intent, resolvedType, null,
+ ActivityManager.getService().broadcastIntentWithFeature(
+ mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
options, false, false, getUserId());
} catch (RemoteException e) {
@@ -1183,8 +1183,8 @@
: new String[] {receiverPermission};
try {
intent.prepareToLeaveProcess(this);
- ActivityManager.getService().broadcastIntent(
- mMainThread.getApplicationThread(), intent, resolvedType, null,
+ ActivityManager.getService().broadcastIntentWithFeature(
+ mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
getUserId());
} catch (RemoteException e) {
@@ -1200,8 +1200,8 @@
: new String[] {receiverPermission};
try {
intent.prepareToLeaveProcess(this);
- ActivityManager.getService().broadcastIntent(
- mMainThread.getApplicationThread(), intent, resolvedType, null,
+ ActivityManager.getService().broadcastIntentWithFeature(
+ mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
null, true, false, getUserId());
} catch (RemoteException e) {
@@ -1263,8 +1263,8 @@
: new String[] {receiverPermission};
try {
intent.prepareToLeaveProcess(this);
- ActivityManager.getService().broadcastIntent(
- mMainThread.getApplicationThread(), intent, resolvedType, rd,
+ ActivityManager.getService().broadcastIntentWithFeature(
+ mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, receiverPermissions, appOp,
options, true, false, getUserId());
} catch (RemoteException e) {
@@ -1277,9 +1277,10 @@
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
- ActivityManager.getService().broadcastIntent(mMainThread.getApplicationThread(),
- intent, resolvedType, null, Activity.RESULT_OK, null, null, null,
- AppOpsManager.OP_NONE, null, false, false, user.getIdentifier());
+ ActivityManager.getService().broadcastIntentWithFeature(
+ mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
+ Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
+ user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1299,8 +1300,8 @@
: new String[] {receiverPermission};
try {
intent.prepareToLeaveProcess(this);
- ActivityManager.getService().broadcastIntent(
- mMainThread.getApplicationThread(), intent, resolvedType, null,
+ ActivityManager.getService().broadcastIntentWithFeature(
+ mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
options, false, false, user.getIdentifier());
} catch (RemoteException e) {
@@ -1316,8 +1317,8 @@
: new String[] {receiverPermission};
try {
intent.prepareToLeaveProcess(this);
- ActivityManager.getService().broadcastIntent(
- mMainThread.getApplicationThread(), intent, resolvedType, null,
+ ActivityManager.getService().broadcastIntentWithFeature(
+ mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
user.getIdentifier());
} catch (RemoteException e) {
@@ -1367,8 +1368,8 @@
: new String[] {receiverPermission};
try {
intent.prepareToLeaveProcess(this);
- ActivityManager.getService().broadcastIntent(
- mMainThread.getApplicationThread(), intent, resolvedType, rd,
+ ActivityManager.getService().broadcastIntentWithFeature(
+ mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, receiverPermissions,
appOp, options, true, false, user.getIdentifier());
} catch (RemoteException e) {
@@ -1408,8 +1409,8 @@
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
- ActivityManager.getService().broadcastIntent(
- mMainThread.getApplicationThread(), intent, resolvedType, null,
+ ActivityManager.getService().broadcastIntentWithFeature(
+ mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true,
getUserId());
} catch (RemoteException e) {
@@ -1444,8 +1445,8 @@
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
- ActivityManager.getService().broadcastIntent(
- mMainThread.getApplicationThread(), intent, resolvedType, rd,
+ ActivityManager.getService().broadcastIntentWithFeature(
+ mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, null,
AppOpsManager.OP_NONE, null, true, true, getUserId());
} catch (RemoteException e) {
@@ -1476,8 +1477,8 @@
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
- ActivityManager.getService().broadcastIntent(
- mMainThread.getApplicationThread(), intent, resolvedType, null,
+ ActivityManager.getService().broadcastIntentWithFeature(
+ mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true,
user.getIdentifier());
} catch (RemoteException e) {
@@ -1491,8 +1492,8 @@
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
- ActivityManager.getService().broadcastIntent(
- mMainThread.getApplicationThread(), intent, resolvedType, null,
+ ActivityManager.getService().broadcastIntentWithFeature(
+ mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options, false, true,
user.getIdentifier());
} catch (RemoteException e) {
@@ -1526,8 +1527,8 @@
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
- ActivityManager.getService().broadcastIntent(
- mMainThread.getApplicationThread(), intent, resolvedType, rd,
+ ActivityManager.getService().broadcastIntentWithFeature(
+ mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, null,
AppOpsManager.OP_NONE, null, true, true, user.getIdentifier());
} catch (RemoteException e) {
@@ -1612,9 +1613,9 @@
}
}
try {
- final Intent intent = ActivityManager.getService().registerReceiver(
- mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
- broadcastPermission, userId, flags);
+ final Intent intent = ActivityManager.getService().registerReceiverWithFeature(
+ mMainThread.getApplicationThread(), mBasePackageName, getFeatureId(), rd,
+ filter, broadcastPermission, userId, flags);
if (intent != null) {
intent.setExtrasClassLoader(getClassLoader());
intent.prepareToEnterProcess();
@@ -1687,9 +1688,9 @@
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManager.getService().startService(
- mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
- getContentResolver()), requireForeground,
- getOpPackageName(), user.getIdentifier());
+ mMainThread.getApplicationThread(), service,
+ service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
+ getOpPackageName(), getFeatureId(), user.getIdentifier());
if (cn != null) {
if (cn.getPackageName().equals("!")) {
throw new SecurityException(
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index cb6a476..83fa9d7 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -104,25 +104,38 @@
// Special low-level communication with activity manager.
void handleApplicationCrash(in IBinder app,
in ApplicationErrorReport.ParcelableCrashInfo crashInfo);
- @UnsupportedAppUsage
+ /** @deprecated Use {@link #startActivityWithFeature} instead */
+ @UnsupportedAppUsage(maxTargetSdk=29, publicAlternatives="Use {@link android.content.Context#startActivity(android.content.Intent)} instead")
int startActivity(in IApplicationThread caller, in String callingPackage, in Intent intent,
in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode,
int flags, in ProfilerInfo profilerInfo, in Bundle options);
+ int startActivityWithFeature(in IApplicationThread caller, in String callingPackage,
+ in String callingFeatureId, in Intent intent, in String resolvedType,
+ in IBinder resultTo, in String resultWho, int requestCode, int flags,
+ in ProfilerInfo profilerInfo, in Bundle options);
@UnsupportedAppUsage
void unhandledBack();
@UnsupportedAppUsage
boolean finishActivity(in IBinder token, int code, in Intent data, int finishTask);
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk=29, publicAlternatives="Use {@link android.content.Context#registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter)} instead")
Intent registerReceiver(in IApplicationThread caller, in String callerPackage,
in IIntentReceiver receiver, in IntentFilter filter,
in String requiredPermission, int userId, int flags);
+ Intent registerReceiverWithFeature(in IApplicationThread caller, in String callerPackage,
+ in String callingFeatureId, in IIntentReceiver receiver, in IntentFilter filter,
+ in String requiredPermission, int userId, int flags);
@UnsupportedAppUsage
void unregisterReceiver(in IIntentReceiver receiver);
- @UnsupportedAppUsage
+ /** @deprecated Use {@link #broadcastIntentWithFeature} instead */
+ @UnsupportedAppUsage(maxTargetSdk=29, publicAlternatives="Use {@link android.content.Context#sendBroadcast(android.content.Intent)} instead")
int broadcastIntent(in IApplicationThread caller, in Intent intent,
in String resolvedType, in IIntentReceiver resultTo, int resultCode,
in String resultData, in Bundle map, in String[] requiredPermissions,
int appOp, in Bundle options, boolean serialized, boolean sticky, int userId);
+ int broadcastIntentWithFeature(in IApplicationThread caller, in String callingFeatureId,
+ in Intent intent, in String resolvedType, in IIntentReceiver resultTo, int resultCode,
+ in String resultData, in Bundle map, in String[] requiredPermissions,
+ int appOp, in Bundle options, boolean serialized, boolean sticky, int userId);
void unbroadcastIntent(in IApplicationThread caller, in Intent intent, int userId);
@UnsupportedAppUsage
oneway void finishReceiver(in IBinder who, int resultCode, in String resultData, in Bundle map,
@@ -145,7 +158,8 @@
boolean refContentProvider(in IBinder connection, int stableDelta, int unstableDelta);
PendingIntent getRunningServiceControlPanel(in ComponentName service);
ComponentName startService(in IApplicationThread caller, in Intent service,
- in String resolvedType, boolean requireForeground, in String callingPackage, int userId);
+ in String resolvedType, boolean requireForeground, in String callingPackage,
+ in String callingFeatureId, int userId);
@UnsupportedAppUsage
int stopService(in IApplicationThread caller, in Intent service,
in String resolvedType, int userId);
@@ -226,10 +240,14 @@
ParceledListSlice getRecentTasks(int maxNum, int flags, int userId);
@UnsupportedAppUsage
oneway void serviceDoneExecuting(in IBinder token, int type, int startId, int res);
- @UnsupportedAppUsage
+ /** @deprecated Use {@link #getIntentSenderWithFeature} instead */
+ @UnsupportedAppUsage(maxTargetSdk=29, publicAlternatives="Use {@link PendingIntent#getIntentSender()} instead")
IIntentSender getIntentSender(int type, in String packageName, in IBinder token,
in String resultWho, int requestCode, in Intent[] intents, in String[] resolvedTypes,
int flags, in Bundle options, int userId);
+ IIntentSender getIntentSenderWithFeature(int type, in String packageName, in String featureId,
+ in IBinder token, in String resultWho, int requestCode, in Intent[] intents,
+ in String[] resolvedTypes, int flags, in Bundle options, int userId);
void cancelIntentSender(in IIntentSender sender);
String getPackageForIntentSender(in IIntentSender sender);
void registerIntentSenderCancelListener(in IIntentSender sender, in IResultReceiver receiver);
@@ -355,11 +373,16 @@
boolean isIntentSenderAnActivity(in IIntentSender sender);
boolean isIntentSenderAForegroundService(in IIntentSender sender);
boolean isIntentSenderABroadcast(in IIntentSender sender);
- @UnsupportedAppUsage
+ /** @deprecated Use {@link startActivityAsUserWithFeature} instead */
+ @UnsupportedAppUsage(maxTargetSdk=29, publicAlternatives="Use {@code android.content.Context#createContextAsUser(android.os.UserHandle, int)} and {@link android.content.Context#startActivity(android.content.Intent)} instead")
int startActivityAsUser(in IApplicationThread caller, in String callingPackage,
in Intent intent, in String resolvedType, in IBinder resultTo, in String resultWho,
int requestCode, int flags, in ProfilerInfo profilerInfo,
in Bundle options, int userId);
+ int startActivityAsUserWithFeature(in IApplicationThread caller, in String callingPackage,
+ in String callingFeatureId, in Intent intent, in String resolvedType,
+ in IBinder resultTo, in String resultWho, int requestCode, int flags,
+ in ProfilerInfo profilerInfo, in Bundle options, int userId);
@UnsupportedAppUsage
int stopUser(int userid, boolean force, in IStopUserCallback callback);
/**
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index be2f144..180507c 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -85,16 +85,17 @@
* {@hide}
*/
interface IActivityTaskManager {
- int startActivity(in IApplicationThread caller, in String callingPackage, in Intent intent,
- in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode,
+ int startActivity(in IApplicationThread caller, in String callingPackage,
+ in String callingFeatureId, in Intent intent, in String resolvedType,
+ in IBinder resultTo, in String resultWho, int requestCode,
int flags, in ProfilerInfo profilerInfo, in Bundle options);
int startActivities(in IApplicationThread caller, in String callingPackage,
- in Intent[] intents, in String[] resolvedTypes, in IBinder resultTo,
- in Bundle options, int userId);
+ in String callingFeatureId, in Intent[] intents, in String[] resolvedTypes,
+ in IBinder resultTo, in Bundle options, int userId);
int startActivityAsUser(in IApplicationThread caller, in String callingPackage,
- in Intent intent, in String resolvedType, in IBinder resultTo, in String resultWho,
- int requestCode, int flags, in ProfilerInfo profilerInfo,
- in Bundle options, int userId);
+ in String callingFeatureId, in Intent intent, in String resolvedType,
+ in IBinder resultTo, in String resultWho, int requestCode, int flags,
+ in ProfilerInfo profilerInfo, in Bundle options, int userId);
boolean startNextMatchingActivity(in IBinder callingActivity,
in Intent intent, in Bundle options);
int startActivityIntentSender(in IApplicationThread caller,
@@ -102,19 +103,19 @@
in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode,
int flagsMask, int flagsValues, in Bundle options);
WaitResult startActivityAndWait(in IApplicationThread caller, in String callingPackage,
- in Intent intent, in String resolvedType, in IBinder resultTo, in String resultWho,
- int requestCode, int flags, in ProfilerInfo profilerInfo, in Bundle options,
- int userId);
+ in String callingFeatureId, in Intent intent, in String resolvedType,
+ in IBinder resultTo, in String resultWho, int requestCode, int flags,
+ in ProfilerInfo profilerInfo, in Bundle options, int userId);
int startActivityWithConfig(in IApplicationThread caller, in String callingPackage,
- in Intent intent, in String resolvedType, in IBinder resultTo, in String resultWho,
- int requestCode, int startFlags, in Configuration newConfig,
- in Bundle options, int userId);
- int startVoiceActivity(in String callingPackage, int callingPid, int callingUid,
- in Intent intent, in String resolvedType, in IVoiceInteractionSession session,
- in IVoiceInteractor interactor, int flags, in ProfilerInfo profilerInfo,
- in Bundle options, int userId);
- int startAssistantActivity(in String callingPackage, int callingPid, int callingUid,
- in Intent intent, in String resolvedType, in Bundle options, int userId);
+ in String callingFeatureId, in Intent intent, in String resolvedType,
+ in IBinder resultTo, in String resultWho, int requestCode, int startFlags,
+ in Configuration newConfig, in Bundle options, int userId);
+ int startVoiceActivity(in String callingPackage, in String callingFeatureId, int callingPid,
+ int callingUid, in Intent intent, in String resolvedType,
+ in IVoiceInteractionSession session, in IVoiceInteractor interactor, int flags,
+ in ProfilerInfo profilerInfo, in Bundle options, int userId);
+ int startAssistantActivity(in String callingPackage, in String callingFeatureId, int callingPid,
+ int callingUid, in Intent intent, in String resolvedType, in Bundle options, int userId);
void startRecentsActivity(in Intent intent, in IAssistDataReceiver assistDataReceiver,
in IRecentsAnimationRunner recentsAnimationRunner);
int startActivityFromRecents(int taskId, in Bundle options);
diff --git a/core/java/android/app/IAppTask.aidl b/core/java/android/app/IAppTask.aidl
index 3ce7190..f41d705 100644
--- a/core/java/android/app/IAppTask.aidl
+++ b/core/java/android/app/IAppTask.aidl
@@ -27,7 +27,7 @@
@UnsupportedAppUsage
ActivityManager.RecentTaskInfo getTaskInfo();
void moveToFront(in IApplicationThread appThread, in String callingPackage);
- int startActivity(IBinder whoThread, String callingPackage,
+ int startActivity(IBinder whoThread, String callingPackage, String callingFeatureId,
in Intent intent, String resolvedType, in Bundle options);
void setExcludeFromRecents(boolean exclude);
}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 16c0910..1d4a1ac 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -88,6 +88,7 @@
void createNotificationChannelGroups(String pkg, in ParceledListSlice channelGroupList);
void createNotificationChannels(String pkg, in ParceledListSlice channelsList);
void createNotificationChannelsForPackage(String pkg, int uid, in ParceledListSlice channelsList);
+ ParceledListSlice getConversationsForPackage(String pkg, int uid);
ParceledListSlice getNotificationChannelGroupsForPackage(String pkg, int uid, boolean includeDeleted);
NotificationChannelGroup getNotificationChannelGroupForPackage(String groupId, String pkg, int uid);
NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(String pkg, int uid, String groupId, boolean includeDeleted);
@@ -96,7 +97,7 @@
NotificationChannel getNotificationChannel(String callingPkg, int userId, String pkg, String channelId);
NotificationChannel getConversationNotificationChannel(String callingPkg, int userId, String pkg, String channelId, boolean returnParentIfNoConversationChannel, String conversationId);
void createConversationNotificationChannelForPackage(String pkg, int uid, String triggeringKey, in NotificationChannel parentChannel, String conversationId);
- NotificationChannel getNotificationChannelForPackage(String pkg, int uid, String channelId, boolean includeDeleted);
+ NotificationChannel getNotificationChannelForPackage(String pkg, int uid, String channelId, String conversationId, boolean includeDeleted);
void deleteNotificationChannel(String pkg, String channelId);
void deleteConversationNotificationChannels(String pkg, int uid, String conversationId);
ParceledListSlice getNotificationChannels(String callingPkg, String targetPkg, int userId);
@@ -113,6 +114,7 @@
int getAppsBypassingDndCount(int uid);
ParceledListSlice getNotificationChannelsBypassingDnd(String pkg, int userId);
boolean isPackagePaused(String pkg);
+ void deleteNotificationHistoryItem(String pkg, int uid, long postedTime);
void silenceNotificationSound();
diff --git a/core/java/android/app/ITaskOrganizerController.aidl b/core/java/android/app/ITaskOrganizerController.aidl
index bfc42ef..5d5956e 100644
--- a/core/java/android/app/ITaskOrganizerController.aidl
+++ b/core/java/android/app/ITaskOrganizerController.aidl
@@ -51,6 +51,9 @@
/** Deletes a persistent root task in WM */
boolean deleteRootTask(IWindowContainer task);
+ /** Gets direct child tasks (ordered from top-to-bottom) */
+ List<ActivityManager.RunningTaskInfo> getChildTasks(in IWindowContainer parent);
+
/** Get the root task which contains the current ime target */
IWindowContainer getImeTarget(int display);
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 62c905d..18932c6 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1721,7 +1721,7 @@
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
int result = ActivityTaskManager.getService()
- .startActivity(whoThread, who.getBasePackageName(), intent,
+ .startActivity(whoThread, who.getBasePackageName(), who.getFeatureId(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
@@ -1794,8 +1794,8 @@
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(who.getContentResolver());
}
int result = ActivityTaskManager.getService()
- .startActivities(whoThread, who.getBasePackageName(), intents, resolvedTypes,
- token, options, userId);
+ .startActivities(whoThread, who.getBasePackageName(), who.getFeatureId(), intents,
+ resolvedTypes, token, options, userId);
checkStartActivityResult(result, intents[0]);
return result;
} catch (RemoteException e) {
@@ -1861,7 +1861,7 @@
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
int result = ActivityTaskManager.getService()
- .startActivity(whoThread, who.getBasePackageName(), intent,
+ .startActivity(whoThread, who.getBasePackageName(), who.getFeatureId(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target, requestCode, 0, null, options);
checkStartActivityResult(result, intent);
@@ -1928,8 +1928,8 @@
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
int result = ActivityTaskManager.getService()
- .startActivityAsUser(whoThread, who.getBasePackageName(), intent,
- intent.resolveTypeIfNeeded(who.getContentResolver()),
+ .startActivityAsUser(whoThread, who.getBasePackageName(), who.getFeatureId(),
+ intent, intent.resolveTypeIfNeeded(who.getContentResolver()),
token, resultWho,
requestCode, 0, null, options, user.getIdentifier());
checkStartActivityResult(result, intent);
@@ -2022,7 +2022,8 @@
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
int result = appTask.startActivity(whoThread.asBinder(), who.getBasePackageName(),
- intent, intent.resolveTypeIfNeeded(who.getContentResolver()), options);
+ who.getFeatureId(), intent,
+ intent.resolveTypeIfNeeded(who.getContentResolver()), options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
diff --git a/core/java/android/app/NotificationHistory.java b/core/java/android/app/NotificationHistory.java
index 909a476..f26e628 100644
--- a/core/java/android/app/NotificationHistory.java
+++ b/core/java/android/app/NotificationHistory.java
@@ -346,6 +346,26 @@
}
/**
+ * Removes an individual historical notification and regenerates the string pool
+ */
+ public boolean removeNotificationFromWrite(String packageName, long postedTime) {
+ boolean removed = false;
+ for (int i = mNotificationsToWrite.size() - 1; i >= 0; i--) {
+ HistoricalNotification hn = mNotificationsToWrite.get(i);
+ if (packageName.equals(hn.getPackage())
+ && postedTime == hn.getPostedTimeMs()) {
+ removed = true;
+ mNotificationsToWrite.remove(i);
+ }
+ }
+ if (removed) {
+ poolStringsFromNotifications();
+ }
+
+ return removed;
+ }
+
+ /**
* Gets pooled strings in order to write them to disk
*/
public @NonNull String[] getPooledStringsToWrite() {
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index b8348c7..f68c929 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -354,8 +354,8 @@
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(context);
IIntentSender target =
- ActivityManager.getService().getIntentSender(
- ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
+ ActivityManager.getService().getIntentSenderWithFeature(
+ ActivityManager.INTENT_SENDER_ACTIVITY, packageName, context.getFeatureId(),
null, null, requestCode, new Intent[] { intent },
resolvedType != null ? new String[] { resolvedType } : null,
flags, options, context.getUserId());
@@ -380,8 +380,8 @@
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(context);
IIntentSender target =
- ActivityManager.getService().getIntentSender(
- ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
+ ActivityManager.getService().getIntentSenderWithFeature(
+ ActivityManager.INTENT_SENDER_ACTIVITY, packageName, context.getFeatureId(),
null, null, requestCode, new Intent[] { intent },
resolvedType != null ? new String[] { resolvedType } : null,
flags, options, user.getIdentifier());
@@ -497,8 +497,8 @@
}
try {
IIntentSender target =
- ActivityManager.getService().getIntentSender(
- ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
+ ActivityManager.getService().getIntentSenderWithFeature(
+ ActivityManager.INTENT_SENDER_ACTIVITY, packageName, context.getFeatureId(),
null, null, requestCode, intents, resolvedTypes, flags, options,
context.getUserId());
return target != null ? new PendingIntent(target) : null;
@@ -523,8 +523,8 @@
}
try {
IIntentSender target =
- ActivityManager.getService().getIntentSender(
- ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
+ ActivityManager.getService().getIntentSenderWithFeature(
+ ActivityManager.INTENT_SENDER_ACTIVITY, packageName, context.getFeatureId(),
null, null, requestCode, intents, resolvedTypes,
flags, options, user.getIdentifier());
return target != null ? new PendingIntent(target) : null;
@@ -575,8 +575,8 @@
try {
intent.prepareToLeaveProcess(context);
IIntentSender target =
- ActivityManager.getService().getIntentSender(
- ActivityManager.INTENT_SENDER_BROADCAST, packageName,
+ ActivityManager.getService().getIntentSenderWithFeature(
+ ActivityManager.INTENT_SENDER_BROADCAST, packageName, context.getFeatureId(),
null, null, requestCode, new Intent[] { intent },
resolvedType != null ? new String[] { resolvedType } : null,
flags, null, userHandle.getIdentifier());
@@ -654,8 +654,8 @@
try {
intent.prepareToLeaveProcess(context);
IIntentSender target =
- ActivityManager.getService().getIntentSender(
- serviceKind, packageName,
+ ActivityManager.getService().getIntentSenderWithFeature(
+ serviceKind, packageName, context.getFeatureId(),
null, null, requestCode, new Intent[] { intent },
resolvedType != null ? new String[] { resolvedType } : null,
flags, null, context.getUserId());
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 6f1effd..5f74d2e 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -598,7 +598,8 @@
* is not able to access the wallpaper.
*/
public Drawable getDrawable() {
- Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, mCmProxy);
+ final ColorManagementProxy cmProxy = getColorManagementProxy();
+ Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, cmProxy);
if (bm != null) {
Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
dr.setDither(false);
@@ -829,7 +830,8 @@
* null pointer if these is none.
*/
public Drawable peekDrawable() {
- Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false, FLAG_SYSTEM, mCmProxy);
+ final ColorManagementProxy cmProxy = getColorManagementProxy();
+ Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false, FLAG_SYSTEM, cmProxy);
if (bm != null) {
Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
dr.setDither(false);
@@ -853,7 +855,8 @@
*/
@RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
public Drawable getFastDrawable() {
- Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, mCmProxy);
+ final ColorManagementProxy cmProxy = getColorManagementProxy();
+ Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, cmProxy);
if (bm != null) {
return new FastBitmapDrawable(bm);
}
@@ -869,7 +872,8 @@
*/
@RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
public Drawable peekFastDrawable() {
- Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false, FLAG_SYSTEM, mCmProxy);
+ final ColorManagementProxy cmProxy = getColorManagementProxy();
+ Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false, FLAG_SYSTEM, cmProxy);
if (bm != null) {
return new FastBitmapDrawable(bm);
}
@@ -892,10 +896,11 @@
if (!shouldEnableWideColorGamut()) {
return false;
}
- Bitmap bitmap = sGlobals.peekWallpaperBitmap(mContext, false, which, mCmProxy);
+ final ColorManagementProxy cmProxy = getColorManagementProxy();
+ Bitmap bitmap = sGlobals.peekWallpaperBitmap(mContext, false, which, cmProxy);
return bitmap != null && bitmap.getColorSpace() != null
&& bitmap.getColorSpace() != ColorSpace.get(ColorSpace.Named.SRGB)
- && mCmProxy.isSupportedColorSpace(bitmap.getColorSpace());
+ && cmProxy.isSupportedColorSpace(bitmap.getColorSpace());
}
/**
@@ -928,8 +933,8 @@
* @hide
*/
public Bitmap getBitmapAsUser(int userId, boolean hardware) {
- return sGlobals.peekWallpaperBitmap(
- mContext, true, FLAG_SYSTEM, userId, hardware, mCmProxy);
+ final ColorManagementProxy cmProxy = getColorManagementProxy();
+ return sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, userId, hardware, cmProxy);
}
/**
@@ -2074,12 +2079,23 @@
}
/**
- * A private class to help Globals#getCurrentWallpaperLocked handle color management.
+ * Get the instance of {@link ColorManagementProxy}.
+ *
+ * @return instance of {@link ColorManagementProxy}.
+ * @hide
*/
- private static class ColorManagementProxy {
+ public ColorManagementProxy getColorManagementProxy() {
+ return mCmProxy;
+ }
+
+ /**
+ * A hidden class to help {@link Globals#getCurrentWallpaperLocked} handle color management.
+ * @hide
+ */
+ public static class ColorManagementProxy {
private final Set<ColorSpace> mSupportedColorSpaces = new HashSet<>();
- ColorManagementProxy(Context context) {
+ public ColorManagementProxy(@NonNull Context context) {
// Get a list of supported wide gamut color spaces.
Display display = context.getDisplay();
if (display != null) {
@@ -2087,9 +2103,14 @@
}
}
+ @NonNull
+ public Set<ColorSpace> getSupportedColorSpaces() {
+ return mSupportedColorSpaces;
+ }
+
boolean isSupportedColorSpace(ColorSpace colorSpace) {
return colorSpace != null && (colorSpace == ColorSpace.get(ColorSpace.Named.SRGB)
- || mSupportedColorSpaces.contains(colorSpace));
+ || getSupportedColorSpaces().contains(colorSpace));
}
void doColorManagement(ImageDecoder decoder, ImageDecoder.ImageInfo info) {
diff --git a/core/java/android/app/WindowContext.java b/core/java/android/app/WindowContext.java
index 36ae450..d279983 100644
--- a/core/java/android/app/WindowContext.java
+++ b/core/java/android/app/WindowContext.java
@@ -60,12 +60,12 @@
if (token != null && !isWindowToken(token)) {
throw new IllegalArgumentException("Token must be registered to server.");
}
+ mToken = token != null ? token : new Binder();
- final ContextImpl contextImpl = createBaseWindowContext(base, token);
+ final ContextImpl contextImpl = createBaseWindowContext(base, mToken);
attachBaseContext(contextImpl);
contextImpl.setOuterContext(this);
- mToken = token != null ? token : new Binder();
mDisplayId = getDisplayId();
mWindowManager = new WindowManagerImpl(this);
mWindowManager.setDefaultToken(mToken);
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index f32a4ab..0e0161f 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -700,6 +700,27 @@
/** @hide */
public static final String REMOTE_CALLBACK_RESULT = "result";
+ /**
+ * How long we wait for an attached process to publish its content providers
+ * before we decide it must be hung.
+ * @hide
+ */
+ public static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS = 10 * 1000;
+
+ /**
+ * How long we wait for an provider to be published. Should be longer than
+ * {@link #CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS}.
+ * @hide
+ */
+ public static final int CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS =
+ CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS + 10 * 1000;
+
+ // Should be >= {@link #CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS}, because that's how
+ // long ActivityManagerService is giving a content provider to get published if a new process
+ // needs to be started for that.
+ private static final int GET_TYPE_TIMEOUT_MILLIS =
+ CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS + 5 * 1000;
+
public ContentResolver(@Nullable Context context) {
this(context, null);
}
@@ -849,8 +870,6 @@
}
}
- private static final int GET_TYPE_TIMEOUT_MILLIS = 3000;
-
private static class GetTypeResultListener implements RemoteCallback.OnResultListener {
@GuardedBy("this")
public boolean done;
diff --git a/core/java/android/content/integrity/AppInstallMetadata.java b/core/java/android/content/integrity/AppInstallMetadata.java
index 351edc9..cd5117b 100644
--- a/core/java/android/content/integrity/AppInstallMetadata.java
+++ b/core/java/android/content/integrity/AppInstallMetadata.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
+import java.util.List;
import java.util.Objects;
/**
@@ -33,18 +34,18 @@
public final class AppInstallMetadata {
private final String mPackageName;
// Raw string encoding for the SHA-256 hash of the certificate of the app.
- private final String mAppCertificate;
+ private final List<String> mAppCertificates;
private final String mInstallerName;
// Raw string encoding for the SHA-256 hash of the certificate of the installer.
- private final String mInstallerCertificate;
+ private final List<String> mInstallerCertificates;
private final long mVersionCode;
private final boolean mIsPreInstalled;
private AppInstallMetadata(Builder builder) {
this.mPackageName = builder.mPackageName;
- this.mAppCertificate = builder.mAppCertificate;
+ this.mAppCertificates = builder.mAppCertificates;
this.mInstallerName = builder.mInstallerName;
- this.mInstallerCertificate = builder.mInstallerCertificate;
+ this.mInstallerCertificates = builder.mInstallerCertificates;
this.mVersionCode = builder.mVersionCode;
this.mIsPreInstalled = builder.mIsPreInstalled;
}
@@ -55,8 +56,8 @@
}
@NonNull
- public String getAppCertificate() {
- return mAppCertificate;
+ public List<String> getAppCertificates() {
+ return mAppCertificates;
}
@NonNull
@@ -65,8 +66,8 @@
}
@NonNull
- public String getInstallerCertificate() {
- return mInstallerCertificate;
+ public List<String> getInstallerCertificates() {
+ return mInstallerCertificates;
}
/** @see AppInstallMetadata.Builder#setVersionCode(long) */
@@ -82,12 +83,12 @@
@Override
public String toString() {
return String.format(
- "AppInstallMetadata { PackageName = %s, AppCert = %s, InstallerName = %s,"
- + " InstallerCert = %s, VersionCode = %d, PreInstalled = %b }",
+ "AppInstallMetadata { PackageName = %s, AppCerts = %s, InstallerName = %s,"
+ + " InstallerCerts = %s, VersionCode = %d, PreInstalled = %b }",
mPackageName,
- mAppCertificate,
+ mAppCertificates,
mInstallerName == null ? "null" : mInstallerName,
- mInstallerCertificate == null ? "null" : mInstallerCertificate,
+ mInstallerCertificates == null ? "null" : mInstallerCertificates,
mVersionCode,
mIsPreInstalled);
}
@@ -95,9 +96,9 @@
/** Builder class for constructing {@link AppInstallMetadata} objects. */
public static final class Builder {
private String mPackageName;
- private String mAppCertificate;
+ private List<String> mAppCertificates;
private String mInstallerName;
- private String mInstallerCertificate;
+ private List<String> mInstallerCertificates;
private long mVersionCode;
private boolean mIsPreInstalled;
@@ -118,11 +119,11 @@
* <p>It is represented as the raw string encoding for the SHA-256 hash of the certificate
* of the app.
*
- * @see AppInstallMetadata#getAppCertificate()
+ * @see AppInstallMetadata#getAppCertificates()
*/
@NonNull
- public Builder setAppCertificate(@NonNull String appCertificate) {
- this.mAppCertificate = Objects.requireNonNull(appCertificate);
+ public Builder setAppCertificates(@NonNull List<String> appCertificates) {
+ this.mAppCertificates = Objects.requireNonNull(appCertificates);
return this;
}
@@ -143,11 +144,11 @@
* <p>It is represented as the raw string encoding for the SHA-256 hash of the certificate
* of the installer.
*
- * @see AppInstallMetadata#getInstallerCertificate()
+ * @see AppInstallMetadata#getInstallerCertificates()
*/
@NonNull
- public Builder setInstallerCertificate(@NonNull String installerCertificate) {
- this.mInstallerCertificate = Objects.requireNonNull(installerCertificate);
+ public Builder setInstallerCertificates(@NonNull List<String> installerCertificates) {
+ this.mInstallerCertificates = Objects.requireNonNull(installerCertificates);
return this;
}
@@ -181,7 +182,7 @@
@NonNull
public AppInstallMetadata build() {
Objects.requireNonNull(mPackageName);
- Objects.requireNonNull(mAppCertificate);
+ Objects.requireNonNull(mAppCertificates);
return new AppInstallMetadata(this);
}
}
diff --git a/core/java/android/content/integrity/AtomicFormula.java b/core/java/android/content/integrity/AtomicFormula.java
index d25f413..42459779 100644
--- a/core/java/android/content/integrity/AtomicFormula.java
+++ b/core/java/android/content/integrity/AtomicFormula.java
@@ -30,6 +30,8 @@
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
/**
@@ -387,7 +389,7 @@
if (mValue == null || mIsHashedValue == null) {
return false;
}
- return getStringMetadataValue(appInstallMetadata, getKey()).equals(mValue);
+ return getMetadataValue(appInstallMetadata, getKey()).contains(mValue);
}
@Override
@@ -448,17 +450,17 @@
return mIsHashedValue;
}
- private static String getStringMetadataValue(
+ private static List<String> getMetadataValue(
AppInstallMetadata appInstallMetadata, int key) {
switch (key) {
case AtomicFormula.PACKAGE_NAME:
- return appInstallMetadata.getPackageName();
+ return Collections.singletonList(appInstallMetadata.getPackageName());
case AtomicFormula.APP_CERTIFICATE:
- return appInstallMetadata.getAppCertificate();
+ return appInstallMetadata.getAppCertificates();
case AtomicFormula.INSTALLER_CERTIFICATE:
- return appInstallMetadata.getInstallerCertificate();
+ return appInstallMetadata.getInstallerCertificates();
case AtomicFormula.INSTALLER_NAME:
- return appInstallMetadata.getInstallerName();
+ return Collections.singletonList(appInstallMetadata.getInstallerName());
default:
throw new IllegalStateException(
"Unexpected key in StringAtomicFormula: " + key);
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index edc20d9..2ba2840 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -87,6 +87,7 @@
mService.startActivityAsUser(
mContext.getIApplicationThread(),
mContext.getPackageName(),
+ mContext.getFeatureId(),
component,
targetUser.getIdentifier(),
true);
@@ -114,6 +115,7 @@
mService.startActivityAsUserByIntent(
mContext.getIApplicationThread(),
mContext.getPackageName(),
+ mContext.getFeatureId(),
intent,
targetUser.getIdentifier());
} catch (RemoteException ex) {
@@ -139,7 +141,8 @@
public void startActivity(@NonNull ComponentName component, @NonNull UserHandle targetUser) {
try {
mService.startActivityAsUser(mContext.getIApplicationThread(),
- mContext.getPackageName(), component, targetUser.getIdentifier(), false);
+ mContext.getPackageName(), mContext.getFeatureId(), component,
+ targetUser.getIdentifier(), false);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
diff --git a/core/java/android/content/pm/ICrossProfileApps.aidl b/core/java/android/content/pm/ICrossProfileApps.aidl
index a69b988..98bf2dd 100644
--- a/core/java/android/content/pm/ICrossProfileApps.aidl
+++ b/core/java/android/content/pm/ICrossProfileApps.aidl
@@ -28,13 +28,14 @@
*/
interface ICrossProfileApps {
void startActivityAsUser(in IApplicationThread caller, in String callingPackage,
- in ComponentName component, int userId, boolean launchMainActivity);
+ in String callingFeatureId, in ComponentName component, int userId,
+ boolean launchMainActivity);
void startActivityAsUserByIntent(in IApplicationThread caller, in String callingPackage,
- in Intent intent, int userId);
+ in String callingFeatureId, in Intent intent, int userId);
List<UserHandle> getTargetUserProfiles(in String callingPackage);
boolean canInteractAcrossProfiles(in String callingPackage);
boolean canRequestInteractAcrossProfiles(in String callingPackage);
void setInteractAcrossProfilesAppOp(in String packageName, int newMode);
boolean canConfigureInteractAcrossProfiles(in String packageName);
void resetInteractAcrossProfilesAppOps(in List<String> packageNames);
-}
\ No newline at end of file
+}
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index 0492359..b5f4f80 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -49,13 +49,13 @@
ActivityInfo resolveActivity(
String callingPackage, in ComponentName component, in UserHandle user);
void startSessionDetailsActivityAsUser(in IApplicationThread caller, String callingPackage,
- in PackageInstaller.SessionInfo sessionInfo, in Rect sourceBounds, in Bundle opts,
- in UserHandle user);
+ String callingFeatureId, in PackageInstaller.SessionInfo sessionInfo,
+ in Rect sourceBounds, in Bundle opts, in UserHandle user);
void startActivityAsUser(in IApplicationThread caller, String callingPackage,
- in ComponentName component, in Rect sourceBounds,
+ String callingFeatureId, in ComponentName component, in Rect sourceBounds,
in Bundle opts, in UserHandle user);
- void showAppDetailsAsUser(in IApplicationThread caller,
- String callingPackage, in ComponentName component, in Rect sourceBounds,
+ void showAppDetailsAsUser(in IApplicationThread caller, String callingPackage,
+ String callingFeatureId, in ComponentName component, in Rect sourceBounds,
in Bundle opts, in UserHandle user);
boolean isPackageEnabled(String callingPackage, String packageName, in UserHandle user);
Bundle getSuspendedPackageLauncherExtras(String packageName, in UserHandle user);
@@ -72,7 +72,7 @@
int flags, in UserHandle user);
void pinShortcuts(String callingPackage, String packageName, in List<String> shortcutIds,
in UserHandle user);
- boolean startShortcut(String callingPackage, String packageName, String id,
+ boolean startShortcut(String callingPackage, String packageName, String featureId, String id,
in Rect sourceBounds, in Bundle startActivityOptions, int userId);
int getShortcutIconResId(String callingPackage, String packageName, String id,
@@ -98,4 +98,9 @@
in ComponentName componentName, int flags, in IShortcutChangeCallback callback,
int callbackId);
void unregisterShortcutChangeCallback(String callingPackage, int callbackId);
+
+ void cacheShortcuts(String callingPackage, String packageName, in List<String> shortcutIds,
+ in UserHandle user);
+ void uncacheShortcuts(String callingPackage, String packageName, in List<String> shortcutIds,
+ in UserHandle user);
}
diff --git a/core/java/android/content/pm/InstantAppRequest.java b/core/java/android/content/pm/InstantAppRequest.java
index f692db1..84f5021 100644
--- a/core/java/android/content/pm/InstantAppRequest.java
+++ b/core/java/android/content/pm/InstantAppRequest.java
@@ -35,6 +35,8 @@
public final String resolvedType;
/** The name of the package requesting the instant application */
public final String callingPackage;
+ /** The feature in the package requesting the instant application */
+ public final String callingFeatureId;
/** Whether or not the requesting package was an instant app */
public final boolean isRequesterInstantApp;
/** ID of the user requesting the instant application */
@@ -57,13 +59,15 @@
public final String token;
public InstantAppRequest(AuxiliaryResolveInfo responseObj, Intent origIntent,
- String resolvedType, String callingPackage, boolean isRequesterInstantApp,
- int userId, Bundle verificationBundle, boolean resolveForStart,
- @Nullable int[] hostDigestPrefixSecure, @NonNull String token) {
+ String resolvedType, String callingPackage, @Nullable String callingFeatureId,
+ boolean isRequesterInstantApp, int userId, Bundle verificationBundle,
+ boolean resolveForStart, @Nullable int[] hostDigestPrefixSecure,
+ @NonNull String token) {
this.responseObj = responseObj;
this.origIntent = origIntent;
this.resolvedType = resolvedType;
this.callingPackage = callingPackage;
+ this.callingFeatureId = callingFeatureId;
this.isRequesterInstantApp = isRequesterInstantApp;
this.userId = userId;
this.verificationBundle = verificationBundle;
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 73c9e4d..271d5e4 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -20,6 +20,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
@@ -714,7 +715,7 @@
}
try {
mService.startActivityAsUser(mContext.getIApplicationThread(),
- mContext.getPackageName(),
+ mContext.getPackageName(), mContext.getFeatureId(),
component, sourceBounds, opts, user);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
@@ -732,8 +733,8 @@
@Nullable Rect sourceBounds, @Nullable Bundle opts) {
try {
mService.startSessionDetailsActivityAsUser(mContext.getIApplicationThread(),
- mContext.getPackageName(), sessionInfo, sourceBounds, opts,
- sessionInfo.getUser());
+ mContext.getPackageName(), mContext.getFeatureId(), sessionInfo, sourceBounds,
+ opts, sessionInfo.getUser());
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -753,7 +754,7 @@
logErrorForInvalidProfileAccess(user);
try {
mService.showAppDetailsAsUser(mContext.getIApplicationThread(),
- mContext.getPackageName(),
+ mContext.getPackageName(), mContext.getFeatureId(),
component, sourceBounds, opts, user);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
@@ -1089,6 +1090,61 @@
}
/**
+ * Mark shortcuts as cached for a package.
+ *
+ * <p>Only dynamic long lived shortcuts can be cached. None dynamic or non long lived shortcuts
+ * in the list will be ignored.
+ *
+ * <p>Unlike pinned shortcuts, where different callers can have different sets of pinned
+ * shortcuts, cached state is per shortcut only, and even if multiple callers cache the same
+ * shortcut, it can be uncached by any valid caller.
+ *
+ * @param packageName The target package name.
+ * @param shortcutIds The IDs of the shortcut to be cached.
+ * @param user The UserHandle of the profile.
+ * @throws IllegalStateException when the user is locked, or when the {@code user} user
+ * is locked or not running.
+ *
+ * @see ShortcutManager
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_SHORTCUTS)
+ public void cacheShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds,
+ @NonNull UserHandle user) {
+ logErrorForInvalidProfileAccess(user);
+ try {
+ mService.cacheShortcuts(mContext.getPackageName(), packageName, shortcutIds, user);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Remove cached flag from shortcuts for a package.
+ *
+ * @param packageName The target package name.
+ * @param shortcutIds The IDs of the shortcut to be uncached.
+ * @param user The UserHandle of the profile.
+ * @throws IllegalStateException when the user is locked, or when the {@code user} user
+ * is locked or not running.
+ *
+ * @see ShortcutManager
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_SHORTCUTS)
+ public void uncacheShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds,
+ @NonNull UserHandle user) {
+ logErrorForInvalidProfileAccess(user);
+ try {
+ mService.uncacheShortcuts(mContext.getPackageName(), packageName, shortcutIds, user);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* @hide kept for testing.
*/
@Deprecated
@@ -1290,9 +1346,9 @@
@Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
int userId) {
try {
- final boolean success =
- mService.startShortcut(mContext.getPackageName(), packageName, shortcutId,
- sourceBounds, startActivityOptions, userId);
+ final boolean success = mService.startShortcut(mContext.getPackageName(), packageName,
+ null /* default featureId */, shortcutId, sourceBounds, startActivityOptions,
+ userId);
if (!success) {
throw new ActivityNotFoundException("Shortcut could not be started");
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 9f7f482..e8668f1 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -597,6 +597,7 @@
* @hide
*/
@SystemApi
+ @TestApi
public static final int MODULE_APEX_NAME = 0x00000001;
/** @hide */
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index a11a1dd..a69905e 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -85,4 +85,11 @@
public abstract boolean isForegroundDefaultLauncher(@NonNull String callingPackage,
int callingUid);
+
+ public abstract void cacheShortcuts(int launcherUserId,
+ @NonNull String callingPackage, @NonNull String packageName,
+ @NonNull List<String> shortcutIds, int userId);
+ public abstract void uncacheShortcuts(int launcherUserId,
+ @NonNull String callingPackage, @NonNull String packageName,
+ @NonNull List<String> shortcutIds, int userId);
}
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
index 73b8a48..7ebeb21 100644
--- a/core/java/android/content/rollback/RollbackManager.java
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -216,6 +216,10 @@
* across device reboot, by simulating what happens on reboot without
* actually rebooting the device.
*
+ * Note rollbacks in the process of enabling will be lost after calling
+ * this method since they are not persisted yet. Don't call this method
+ * in the middle of the install process.
+ *
* @throws SecurityException if the caller does not have appropriate permissions.
*
* @hide
diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
index 9bd3992..c1df5b6 100644
--- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
+++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
@@ -221,10 +221,8 @@
/**
* Set a model specific {@link ModelParams} with the given value. This
* parameter will keep its value for the duration the model is loaded regardless of starting
- * and
- * stopping recognition. Once the model is unloaded, the value will be lost.
- * {@link SoundTriggerModule#queryParameter(int, int)} should be checked first before calling
- * this method.
+ * and stopping recognition. Once the model is unloaded, the value will be lost.
+ * {@link #queryParameter} should be checked first before calling this method.
*
* @param soundModelHandle handle of model to apply parameter
* @param modelParam {@link ModelParams}
@@ -251,22 +249,14 @@
* for the duration the model is loaded regardless of starting and stopping recognition.
* Once the model is unloaded, the value will be lost. If the value is not set, a default
* value is returned. See {@link ModelParams} for parameter default values.
- * {@link SoundTriggerModule#queryParameter(int, int)} should be checked first before
+ * {@link #queryParameter} should be checked first before
* calling this method. Otherwise, an exception can be thrown.
*
* @param soundModelHandle handle of model to get parameter
* @param modelParam {@link ModelParams}
* @return value of parameter
- * @throws UnsupportedOperationException if hal or model do not support this API.
- * {@link SoundTriggerModule#queryParameter(int, int)}
- * should
- * be checked first.
- * @throws IllegalArgumentException if invalid model handle or parameter is passed.
- * {@link SoundTriggerModule#queryParameter(int, int)}
- * should be checked first.
*/
- public synchronized int getParameter(int soundModelHandle, @ModelParams int modelParam)
- throws UnsupportedOperationException, IllegalArgumentException {
+ public synchronized int getParameter(int soundModelHandle, @ModelParams int modelParam) {
try {
return mService.getModelParameter(soundModelHandle,
ConversionUtil.api2aidlModelParameter(modelParam));
@@ -276,9 +266,8 @@
}
/**
- * Determine if parameter control is supported for the given model handle.
- * This method should be checked prior to calling {@link SoundTriggerModule#setParameter} or
- * {@link SoundTriggerModule#getParameter}.
+ * Query the parameter support and range for a given {@link ModelParams}.
+ * This method should be check prior to calling {@link #setParameter} or {@link #getParameter}.
*
* @param soundModelHandle handle of model to get parameter
* @param modelParam {@link ModelParams}
diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java
index b128ea7..3c39d15 100644
--- a/core/java/android/net/ConnectivityDiagnosticsManager.java
+++ b/core/java/android/net/ConnectivityDiagnosticsManager.java
@@ -202,7 +202,7 @@
*/
@NetworkProbe
public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK =
- "networkProbesAttemped";
+ "networkProbesAttempted";
/** @hide */
@StringDef(prefix = {"KEY_"}, value = {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index f644f14..a305948 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2423,14 +2423,14 @@
/**
* Get the set of tethered dhcp ranges.
*
- * @return an array of 0 or more {@code String} of tethered dhcp ranges.
- * @deprecated This API just return the default value which is not used in DhcpServer.
+ * @deprecated This method is not supported.
+ * TODO: remove this function when all of clients are removed.
* {@hide}
*/
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
@Deprecated
public String[] getTetheredDhcpRanges() {
- return getTetheringManager().getTetheredDhcpRanges();
+ throw new UnsupportedOperationException("getTetheredDhcpRanges is not supported");
}
/**
diff --git a/core/java/android/os/SharedMemory.java b/core/java/android/os/SharedMemory.java
index 26d9c7d..7512352 100644
--- a/core/java/android/os/SharedMemory.java
+++ b/core/java/android/os/SharedMemory.java
@@ -27,6 +27,7 @@
import java.io.Closeable;
import java.io.FileDescriptor;
+import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.DirectByteBuffer;
import java.nio.NioUtils;
@@ -272,6 +273,20 @@
dest.writeFileDescriptor(mFileDescriptor);
}
+ /**
+ * Returns a dup'd ParcelFileDescriptor from the SharedMemory FileDescriptor.
+ * This obeys standard POSIX semantics, where the
+ * new file descriptor shared state such as file position with the
+ * original file descriptor.
+ * TODO: propose this method as a public or system API for next release to achieve parity with
+ * NDK ASharedMemory_dupFromJava.
+ *
+ * @hide
+ */
+ public ParcelFileDescriptor getFdDup() throws IOException {
+ return ParcelFileDescriptor.dup(mFileDescriptor);
+ }
+
public static final @android.annotation.NonNull Parcelable.Creator<SharedMemory> CREATOR =
new Parcelable.Creator<SharedMemory>() {
@Override
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 25584f1..3508b70 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -101,6 +101,8 @@
public static final long TRACE_TAG_NNAPI = 1L << 25;
/** @hide */
public static final long TRACE_TAG_RRO = 1L << 26;
+ /** @hide */
+ public static final long TRACE_TAG_APEX_MANAGER = 1L << 18;
private static final long TRACE_TAG_NOT_READY = 1L << 63;
private static final int MAX_SECTION_NAME_LEN = 127;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 6ed1d2c..b202053 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -2325,10 +2325,12 @@
* @param restrictionKey the string key representing the restriction
* @param userHandle the UserHandle of the user for whom to retrieve the restrictions.
*/
+ @TestApi
@UnsupportedAppUsage
- @RequiresPermission(Manifest.permission.MANAGE_USERS)
- public boolean hasBaseUserRestriction(@UserRestrictionKey String restrictionKey,
- UserHandle userHandle) {
+ @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
+ Manifest.permission.CREATE_USERS})
+ public boolean hasBaseUserRestriction(@UserRestrictionKey @NonNull String restrictionKey,
+ @NonNull UserHandle userHandle) {
try {
return mService.hasBaseUserRestriction(restrictionKey, userHandle.getIdentifier());
} catch (RemoteException re) {
diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl
index 21434a2..9d98b3b 100644
--- a/core/java/android/os/incremental/IIncrementalService.aidl
+++ b/core/java/android/os/incremental/IIncrementalService.aidl
@@ -103,4 +103,9 @@
* Deletes a storage given its ID. Deletes its bind mounts and unmount it. Stop its data loader.
*/
void deleteStorage(int storageId);
+
+ /**
+ * Setting up native library directories and extract native libs onto a storage.
+ */
+ boolean configureNativeBinaries(int storageId, in @utf8InCpp String apkFullPath, in @utf8InCpp String libDirRelativePath, in @utf8InCpp String abi);
}
diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
index 0024ac7..ba38268 100644
--- a/core/java/android/os/incremental/IncrementalManager.java
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -229,16 +229,41 @@
if (linkedApkStorage == null) {
throw new IOException("Failed to create linked storage at dir: " + afterCodePathParent);
}
- linkedApkStorage.makeDirectory(afterCodePathName);
- File[] files = beforeCodeFile.listFiles();
- for (int i = 0; i < files.length; i++) {
- if (files[i].isFile()) {
- String fileName = files[i].getName();
- apkStorage.makeLink(
- fileName, linkedApkStorage, afterCodePathName + "/" + fileName);
+ linkFiles(apkStorage, beforeCodeFile, "", linkedApkStorage, afterCodePathName);
+ apkStorage.unBind(beforeCodePath);
+ }
+
+ /**
+ * Recursively set up directories and link all the files from source storage to target storage.
+ *
+ * @param sourceStorage The storage that has all the files and directories underneath.
+ * @param sourceAbsolutePath The absolute path of the directory that holds all files and dirs.
+ * @param sourceRelativePath The relative path on the source directory, e.g., "" or "lib".
+ * @param targetStorage The target storage that will have the same files and directories.
+ * @param targetRelativePath The relative path to the directory on the target storage that
+ * should have all the files and dirs underneath,
+ * e.g., "packageName-random".
+ * @throws IOException When makeDirectory or makeLink fails on the Incremental File System.
+ */
+ private void linkFiles(IncrementalStorage sourceStorage, File sourceAbsolutePath,
+ String sourceRelativePath, IncrementalStorage targetStorage,
+ String targetRelativePath) throws IOException {
+ targetStorage.makeDirectory(targetRelativePath);
+ final File[] entryList = sourceAbsolutePath.listFiles();
+ for (int i = 0; i < entryList.length; i++) {
+ final File entry = entryList[i];
+ final String entryName = entryList[i].getName();
+ final String sourceEntryRelativePath =
+ sourceRelativePath.isEmpty() ? entryName : sourceRelativePath + "/" + entryName;
+ final String targetEntryRelativePath = targetRelativePath + "/" + entryName;
+ if (entry.isFile()) {
+ sourceStorage.makeLink(
+ sourceEntryRelativePath, targetStorage, targetEntryRelativePath);
+ } else if (entry.isDirectory()) {
+ linkFiles(sourceStorage, entry, sourceEntryRelativePath, targetStorage,
+ targetEntryRelativePath);
}
}
- apkStorage.unBind(beforeCodePath);
}
/**
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index c4b843b..5df44ff 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -416,4 +416,24 @@
return false;
}
}
+
+ /**
+ * Configure all the lib files inside Incremental Service, e.g., create lib dirs, create new lib
+ * files, extract original lib file data from zip and then write data to the lib files on the
+ * Incremental File System.
+ *
+ * @param apkFullPath Source APK to extract native libs from.
+ * @param libDirRelativePath Target dir to put lib files, e.g., "lib" or "lib/arm".
+ * @param abi Target ABI of the native lib files. Only extract native libs of this ABI.
+ * @return Success of not.
+ */
+ public boolean configureNativeBinaries(String apkFullPath, String libDirRelativePath,
+ String abi) {
+ try {
+ return mService.configureNativeBinaries(mId, apkFullPath, libDirRelativePath, abi);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return false;
+ }
+ }
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 30e4eee08..b9207e5 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1830,6 +1830,17 @@
public static final String EXTRA_CHANNEL_ID = "android.provider.extra.CHANNEL_ID";
/**
+ * Activity Extra: The {@link NotificationChannel#getConversationId()} of the notification
+ * conversation settings to display.
+ * <p>
+ * This is an optional extra field to the {@link #ACTION_CHANNEL_NOTIFICATION_SETTINGS}. If
+ * included the system will first look up notification settings by channel and conversation id,
+ * and will fall back to channel id if a specialized channel for this conversation doesn't
+ * exist, similar to {@link NotificationManager#getNotificationChannel(String, String)}.
+ */
+ public static final String EXTRA_CONVERSATION_ID = "android.provider.extra.CONVERSATION_ID";
+
+ /**
* Activity Action: Show notification redaction settings.
*
* @hide
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index 707426a..0edd013 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -345,9 +345,11 @@
}
/**
- * Notifies the service of {@link SnapshotData snapshot data} associated with a session.
+ * Notifies the service of {@link SnapshotData snapshot data} associated with an activity.
*
- * @param sessionId the session's Id
+ * @param sessionId the session's Id. This may also be
+ * {@link ContentCaptureSession#NO_SESSION_ID} if no content capture session
+ * exists for the activity being snapshotted
* @param snapshotData the data
*/
public void onActivitySnapshot(@NonNull ContentCaptureSessionId sessionId,
diff --git a/core/java/android/os/StatsDimensionsValue.aidl b/core/java/android/service/notification/ConversationChannelWrapper.aidl
similarity index 76%
copy from core/java/android/os/StatsDimensionsValue.aidl
copy to core/java/android/service/notification/ConversationChannelWrapper.aidl
index 81a14a4..f324158 100644
--- a/core/java/android/os/StatsDimensionsValue.aidl
+++ b/core/java/android/service/notification/ConversationChannelWrapper.aidl
@@ -1,5 +1,5 @@
-/**
- * Copyright (c) 2018, The Android Open Source Project
+/*
+ * Copyright (c) 2020, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-package android.os;
+package android.service.notification;
-/** @hide */
-parcelable StatsDimensionsValue cpp_header "android/os/StatsDimensionsValue.h";
\ No newline at end of file
+parcelable ConversationChannelWrapper;
\ No newline at end of file
diff --git a/core/java/android/service/notification/ConversationChannelWrapper.java b/core/java/android/service/notification/ConversationChannelWrapper.java
new file mode 100644
index 0000000..9847695
--- /dev/null
+++ b/core/java/android/service/notification/ConversationChannelWrapper.java
@@ -0,0 +1,122 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.notification;
+
+import android.app.NotificationChannel;
+import android.content.pm.ShortcutInfo;
+import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * @hide
+ */
+public final class ConversationChannelWrapper implements Parcelable {
+
+ private NotificationChannel mNotificationChannel;
+ private CharSequence mGroupLabel;
+ private CharSequence mParentChannelLabel;
+ private ShortcutInfo mShortcutInfo;
+
+ public ConversationChannelWrapper() {}
+
+ protected ConversationChannelWrapper(Parcel in) {
+ mNotificationChannel = in.readParcelable(NotificationChannel.class.getClassLoader());
+ mGroupLabel = in.readCharSequence();
+ mParentChannelLabel = in.readCharSequence();
+ mShortcutInfo = in.readParcelable(ShortcutInfo.class.getClassLoader());
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mNotificationChannel, flags);
+ dest.writeCharSequence(mGroupLabel);
+ dest.writeCharSequence(mParentChannelLabel);
+ dest.writeParcelable(mShortcutInfo, flags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<ConversationChannelWrapper> CREATOR =
+ new Creator<ConversationChannelWrapper>() {
+ @Override
+ public ConversationChannelWrapper createFromParcel(Parcel in) {
+ return new ConversationChannelWrapper(in);
+ }
+
+ @Override
+ public ConversationChannelWrapper[] newArray(int size) {
+ return new ConversationChannelWrapper[size];
+ }
+ };
+
+
+ public NotificationChannel getNotificationChannel() {
+ return mNotificationChannel;
+ }
+
+ public void setNotificationChannel(
+ NotificationChannel notificationChannel) {
+ mNotificationChannel = notificationChannel;
+ }
+
+ public CharSequence getGroupLabel() {
+ return mGroupLabel;
+ }
+
+ public void setGroupLabel(CharSequence groupLabel) {
+ mGroupLabel = groupLabel;
+ }
+
+ public CharSequence getParentChannelLabel() {
+ return mParentChannelLabel;
+ }
+
+ public void setParentChannelLabel(CharSequence parentChannelLabel) {
+ mParentChannelLabel = parentChannelLabel;
+ }
+
+ public ShortcutInfo getShortcutInfo() {
+ return mShortcutInfo;
+ }
+
+ public void setShortcutInfo(ShortcutInfo shortcutInfo) {
+ mShortcutInfo = shortcutInfo;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ConversationChannelWrapper that = (ConversationChannelWrapper) o;
+ return Objects.equals(getNotificationChannel(), that.getNotificationChannel()) &&
+ Objects.equals(getGroupLabel(), that.getGroupLabel()) &&
+ Objects.equals(getParentChannelLabel(), that.getParentChannelLabel()) &&
+ Objects.equals(getShortcutInfo(), that.getShortcutInfo());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getNotificationChannel(), getGroupLabel(), getParentChannelLabel(),
+ getShortcutInfo());
+ }
+}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index e053ed5..0ff2e03 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -214,6 +214,32 @@
public static final int REASON_TIMEOUT = 19;
/**
+ * @hide
+ */
+ @IntDef(prefix = "REASON_", value = {
+ REASON_CLICK,
+ REASON_CANCEL,
+ REASON_CANCEL_ALL,
+ REASON_ERROR,
+ REASON_PACKAGE_CHANGED,
+ REASON_USER_STOPPED,
+ REASON_PACKAGE_BANNED,
+ REASON_APP_CANCEL,
+ REASON_APP_CANCEL_ALL,
+ REASON_LISTENER_CANCEL,
+ REASON_LISTENER_CANCEL_ALL,
+ REASON_GROUP_SUMMARY_CANCELED,
+ REASON_GROUP_OPTIMIZATION,
+ REASON_PACKAGE_SUSPENDED,
+ REASON_PROFILE_TURNED_OFF,
+ REASON_UNAUTOBUNDLED,
+ REASON_CHANNEL_BANNED,
+ REASON_SNOOZED,
+ REASON_TIMEOUT
+ })
+ public @interface NotificationCancelReason{};
+
+ /**
* The full trim of the StatusBarNotification including all its features.
*
* @hide
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index d0675ed..b4b5819 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -126,22 +126,22 @@
= "android.service.quicksettings.ACTIVE_TILE";
/**
- * Meta-data for a tile to support {@code BooleanState}.
+ * Meta-data for a tile to mark is toggleable.
* <p>
- * BooleanState is for tiles that should support switch tile behavior in accessibility. This is
+ * Toggleable tiles support switch tile behavior in accessibility. This is
* the behavior of most of the framework tiles.
*
- * To make a TileService support BooleanState, set this meta-data to true on the TileService's
- * manifest declaration.
+ * To indicate that a TileService is toggleable, set this meta-data to true on the
+ * TileService's manifest declaration.
* <pre class="prettyprint">
* {@literal
- * <meta-data android:name="android.service.quicksettings.BOOLEAN_TILE"
+ * <meta-data android:name="android.service.quicksettings.TOGGLEABLE_TILE"
* android:value="true" />
* }
* </pre>
*/
- public static final String META_DATA_BOOLEAN_TILE =
- "android.service.quicksettings.BOOLEAN_TILE";
+ public static final String META_DATA_TOGGLEABLE_TILE =
+ "android.service.quicksettings.TOGGLEABLE_TILE";
/**
* Used to notify SysUI that Listening has be requested.
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 36f2c62..8e6f77b 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -1314,7 +1314,7 @@
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(mContext);
int res = mSystemService.startVoiceActivity(mToken, intent,
- intent.resolveType(mContext.getContentResolver()));
+ intent.resolveType(mContext.getContentResolver()), mContext.getFeatureId());
Instrumentation.checkStartActivityResult(res, intent);
} catch (RemoteException e) {
}
@@ -1342,7 +1342,7 @@
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(mContext);
int res = mSystemService.startAssistantActivity(mToken, intent,
- intent.resolveType(mContext.getContentResolver()));
+ intent.resolveType(mContext.getContentResolver()), mContext.getFeatureId());
Instrumentation.checkStartActivityResult(res, intent);
} catch (RemoteException e) {
}
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index 531ade0..e65bd9f 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -412,23 +412,23 @@
* domain. This indication does not necessarily indicate a change of service state, which should
* be tracked via {@link #LISTEN_SERVICE_STATE}.
*
- * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
- * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or
+ * the calling app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
*
* @see #onRegistrationFailed()
*/
- @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
public static final int LISTEN_REGISTRATION_FAILURE = 0x40000000;
/**
* Listen for Barring Information for the current registered / camped cell.
*
- * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
- * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or
+ * the calling app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
*
* @see #onBarringInfoChanged()
*/
- @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
public static final int LISTEN_BARRING_INFO = 0x80000000;
/*
diff --git a/core/java/android/view/CutoutSpecification.java b/core/java/android/view/CutoutSpecification.java
new file mode 100644
index 0000000..d21a952
--- /dev/null
+++ b/core/java/android/view/CutoutSpecification.java
@@ -0,0 +1,486 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static android.view.Gravity.BOTTOM;
+import static android.view.Gravity.LEFT;
+import static android.view.Gravity.RIGHT;
+import static android.view.Gravity.TOP;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Insets;
+import android.graphics.Matrix;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Region;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.PathParser;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * In order to accept the cutout specification for all of edges in devices, the specification
+ * parsing method is extracted from
+ * {@link android.view.DisplayCutout#fromResourcesRectApproximation(Resources, int, int)} to be
+ * the specified class for parsing the specification.
+ * BNF definition:
+ * <ul>
+ * <li>Cutouts Specification = ([Cutout Delimiter],Cutout Specification) {...}, [Dp] ; </li>
+ * <li>Cutout Specification = [Vertical Position], (SVG Path Element), [Horizontal Position]
+ * [Bind Cutout] ;</li>
+ * <li>Vertical Position = "@bottom" | "@center_vertical" ;</li>
+ * <li>Horizontal Position = "@left" | "@right" ;</li>
+ * <li>Bind Cutout = "@bind_left_cutout" | "@bind_right_cutout" ;</li>
+ * <li>Cutout Delimiter = "@cutout" ;</li>
+ * <li>Dp = "@dp"</li>
+ * </ul>
+ *
+ * <ul>
+ * <li>Vertical position is top by default if there is neither "@bottom" nor "@center_vertical"
+ * </li>
+ * <li>Horizontal position is center horizontal by default if there is neither "@left" nor
+ * "@right".</li>
+ * <li>@bottom make the cutout piece bind to bottom edge.</li>
+ * <li>both of @bind_left_cutout and @bind_right_cutout are use to claim the cutout belong to
+ * left or right edge cutout.</li>
+ * </ul>
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = PACKAGE)
+public class CutoutSpecification {
+ private static final String TAG = "CutoutSpecification";
+ private static final boolean DEBUG = false;
+
+ private static final int MINIMAL_ACCEPTABLE_PATH_LENGTH = "H1V1Z".length();
+
+ private static final char MARKER_START_CHAR = '@';
+ private static final String DP_MARKER = MARKER_START_CHAR + "dp";
+
+ private static final String BOTTOM_MARKER = MARKER_START_CHAR + "bottom";
+ private static final String RIGHT_MARKER = MARKER_START_CHAR + "right";
+ private static final String LEFT_MARKER = MARKER_START_CHAR + "left";
+ private static final String CUTOUT_MARKER = MARKER_START_CHAR + "cutout";
+ private static final String CENTER_VERTICAL_MARKER = MARKER_START_CHAR + "center_vertical";
+
+ /* By default, it's top bound cutout. That's why TOP_BOUND_CUTOUT_MARKER is not defined */
+ private static final String BIND_RIGHT_CUTOUT_MARKER = MARKER_START_CHAR + "bind_right_cutout";
+ private static final String BIND_LEFT_CUTOUT_MARKER = MARKER_START_CHAR + "bind_left_cutout";
+
+ private final Path mPath;
+ private final Rect mLeftBound;
+ private final Rect mTopBound;
+ private final Rect mRightBound;
+ private final Rect mBottomBound;
+ private final Insets mInsets;
+
+ private CutoutSpecification(@NonNull Parser parser) {
+ mPath = parser.mPath;
+ mLeftBound = parser.mLeftBound;
+ mTopBound = parser.mTopBound;
+ mRightBound = parser.mRightBound;
+ mBottomBound = parser.mBottomBound;
+ mInsets = parser.mInsets;
+
+ if (DEBUG) {
+ Log.d(TAG, String.format(Locale.ENGLISH,
+ "left cutout = %s, top cutout = %s, right cutout = %s, bottom cutout = %s",
+ mLeftBound != null ? mLeftBound.toString() : "",
+ mTopBound != null ? mTopBound.toString() : "",
+ mRightBound != null ? mRightBound.toString() : "",
+ mBottomBound != null ? mBottomBound.toString() : ""));
+ }
+ }
+
+ @VisibleForTesting(visibility = PACKAGE)
+ @Nullable
+ public Path getPath() {
+ return mPath;
+ }
+
+ @VisibleForTesting(visibility = PACKAGE)
+ @Nullable
+ public Rect getLeftBound() {
+ return mLeftBound;
+ }
+
+ @VisibleForTesting(visibility = PACKAGE)
+ @Nullable
+ public Rect getTopBound() {
+ return mTopBound;
+ }
+
+ @VisibleForTesting(visibility = PACKAGE)
+ @Nullable
+ public Rect getRightBound() {
+ return mRightBound;
+ }
+
+ @VisibleForTesting(visibility = PACKAGE)
+ @Nullable
+ public Rect getBottomBound() {
+ return mBottomBound;
+ }
+
+ /**
+ * To count the safe inset according to the cutout bounds and waterfall inset.
+ *
+ * @return the safe inset.
+ */
+ @VisibleForTesting(visibility = PACKAGE)
+ @NonNull
+ public Rect getSafeInset() {
+ return mInsets.toRect();
+ }
+
+ private static int decideWhichEdge(boolean isTopEdgeShortEdge,
+ boolean isShortEdge, boolean isStart) {
+ return (isTopEdgeShortEdge)
+ ? ((isShortEdge) ? (isStart ? TOP : BOTTOM) : (isStart ? LEFT : RIGHT))
+ : ((isShortEdge) ? (isStart ? LEFT : RIGHT) : (isStart ? TOP : BOTTOM));
+ }
+
+ /**
+ * The CutoutSpecification Parser.
+ */
+ @VisibleForTesting(visibility = PACKAGE)
+ public static class Parser {
+ private final boolean mIsShortEdgeOnTop;
+ private final float mDensity;
+ private final int mDisplayWidth;
+ private final int mDisplayHeight;
+ private final Matrix mMatrix;
+ private Insets mInsets;
+ private int mSafeInsetLeft;
+ private int mSafeInsetTop;
+ private int mSafeInsetRight;
+ private int mSafeInsetBottom;
+
+ private final Rect mTmpRect = new Rect();
+ private final RectF mTmpRectF = new RectF();
+
+ private boolean mInDp;
+
+ private Path mPath;
+ private Rect mLeftBound;
+ private Rect mTopBound;
+ private Rect mRightBound;
+ private Rect mBottomBound;
+
+ private boolean mPositionFromLeft = false;
+ private boolean mPositionFromRight = false;
+ private boolean mPositionFromBottom = false;
+ private boolean mPositionFromCenterVertical = false;
+
+ private boolean mBindLeftCutout = false;
+ private boolean mBindRightCutout = false;
+ private boolean mBindBottomCutout = false;
+
+ private boolean mIsTouchShortEdgeStart;
+ private boolean mIsTouchShortEdgeEnd;
+ private boolean mIsCloserToStartSide;
+
+ /**
+ * The constructor of the CutoutSpecification parser to parse the specification of cutout.
+ * @param density the display density.
+ * @param displayWidth the display width.
+ * @param displayHeight the display height.
+ */
+ @VisibleForTesting(visibility = PACKAGE)
+ public Parser(float density, int displayWidth, int displayHeight) {
+ mDensity = density;
+ mDisplayWidth = displayWidth;
+ mDisplayHeight = displayHeight;
+ mMatrix = new Matrix();
+ mIsShortEdgeOnTop = mDisplayWidth < mDisplayHeight;
+ }
+
+ private void computeBoundsRectAndAddToRegion(Path p, Region inoutRegion, Rect inoutRect) {
+ mTmpRectF.setEmpty();
+ p.computeBounds(mTmpRectF, false /* unused */);
+ mTmpRectF.round(inoutRect);
+ inoutRegion.op(inoutRect, Region.Op.UNION);
+ }
+
+ private void resetStatus(StringBuilder sb) {
+ sb.setLength(0);
+ mPositionFromBottom = false;
+ mPositionFromLeft = false;
+ mPositionFromRight = false;
+ mPositionFromCenterVertical = false;
+
+ mBindLeftCutout = false;
+ mBindRightCutout = false;
+ mBindBottomCutout = false;
+ }
+
+ private void translateMatrix() {
+ final float offsetX;
+ if (mPositionFromRight) {
+ offsetX = mDisplayWidth;
+ } else if (mPositionFromLeft) {
+ offsetX = 0;
+ } else {
+ offsetX = mDisplayWidth / 2f;
+ }
+
+ final float offsetY;
+ if (mPositionFromBottom) {
+ offsetY = mDisplayHeight;
+ } else if (mPositionFromCenterVertical) {
+ offsetY = mDisplayHeight / 2f;
+ } else {
+ offsetY = 0;
+ }
+
+ mMatrix.reset();
+ if (mInDp) {
+ mMatrix.postScale(mDensity, mDensity);
+ }
+ mMatrix.postTranslate(offsetX, offsetY);
+ }
+
+ private int computeSafeInsets(int gravity, Rect rect) {
+ if (gravity == LEFT && rect.right > 0 && rect.right < mDisplayWidth) {
+ return rect.right;
+ } else if (gravity == TOP && rect.bottom > 0 && rect.bottom < mDisplayHeight) {
+ return rect.bottom;
+ } else if (gravity == RIGHT && rect.left > 0 && rect.left < mDisplayWidth) {
+ return mDisplayWidth - rect.left;
+ } else if (gravity == BOTTOM && rect.top > 0 && rect.top < mDisplayHeight) {
+ return mDisplayHeight - rect.top;
+ }
+ return 0;
+ }
+
+ private void setSafeInset(int gravity, int inset) {
+ if (gravity == LEFT) {
+ mSafeInsetLeft = inset;
+ } else if (gravity == TOP) {
+ mSafeInsetTop = inset;
+ } else if (gravity == RIGHT) {
+ mSafeInsetRight = inset;
+ } else if (gravity == BOTTOM) {
+ mSafeInsetBottom = inset;
+ }
+ }
+
+ private int getSafeInset(int gravity) {
+ if (gravity == LEFT) {
+ return mSafeInsetLeft;
+ } else if (gravity == TOP) {
+ return mSafeInsetTop;
+ } else if (gravity == RIGHT) {
+ return mSafeInsetRight;
+ } else if (gravity == BOTTOM) {
+ return mSafeInsetBottom;
+ }
+ return 0;
+ }
+
+ @NonNull
+ private Rect onSetEdgeCutout(boolean isStart, boolean isShortEdge, @NonNull Rect rect) {
+ final int gravity;
+ if (isShortEdge) {
+ gravity = decideWhichEdge(mIsShortEdgeOnTop, true, isStart);
+ } else {
+ if (mIsTouchShortEdgeStart && mIsTouchShortEdgeEnd) {
+ gravity = decideWhichEdge(mIsShortEdgeOnTop, false, isStart);
+ } else if (mIsTouchShortEdgeStart || mIsTouchShortEdgeEnd) {
+ gravity = decideWhichEdge(mIsShortEdgeOnTop, true,
+ mIsCloserToStartSide);
+ } else {
+ gravity = decideWhichEdge(mIsShortEdgeOnTop, isShortEdge, isStart);
+ }
+ }
+
+ int oldSafeInset = getSafeInset(gravity);
+ int newSafeInset = computeSafeInsets(gravity, rect);
+ if (oldSafeInset < newSafeInset) {
+ setSafeInset(gravity, newSafeInset);
+ }
+
+ return new Rect(rect);
+ }
+
+ private void setEdgeCutout(@NonNull Path newPath) {
+ if (mBindRightCutout && mRightBound == null) {
+ mRightBound = onSetEdgeCutout(false, !mIsShortEdgeOnTop, mTmpRect);
+ } else if (mBindLeftCutout && mLeftBound == null) {
+ mLeftBound = onSetEdgeCutout(true, !mIsShortEdgeOnTop, mTmpRect);
+ } else if (mBindBottomCutout && mBottomBound == null) {
+ mBottomBound = onSetEdgeCutout(false, mIsShortEdgeOnTop, mTmpRect);
+ } else if (!(mBindBottomCutout || mBindLeftCutout || mBindRightCutout)
+ && mTopBound == null) {
+ mTopBound = onSetEdgeCutout(true, mIsShortEdgeOnTop, mTmpRect);
+ } else {
+ return;
+ }
+
+ if (mPath != null) {
+ mPath.addPath(newPath);
+ } else {
+ mPath = newPath;
+ }
+ }
+
+ private void parseSvgPathSpec(Region region, String spec) {
+ if (TextUtils.length(spec) < MINIMAL_ACCEPTABLE_PATH_LENGTH) {
+ Log.e(TAG, "According to SVG definition, it shouldn't happen");
+ return;
+ }
+ spec.trim();
+ translateMatrix();
+
+ final Path newPath = PathParser.createPathFromPathData(spec);
+ newPath.transform(mMatrix);
+ computeBoundsRectAndAddToRegion(newPath, region, mTmpRect);
+
+ if (DEBUG) {
+ Log.d(TAG, String.format(Locale.ENGLISH,
+ "hasLeft = %b, hasRight = %b, hasBottom = %b, hasCenterVertical = %b",
+ mPositionFromLeft, mPositionFromRight, mPositionFromBottom,
+ mPositionFromCenterVertical));
+ Log.d(TAG, "region = " + region);
+ Log.d(TAG, "spec = \"" + spec + "\" rect = " + mTmpRect + " newPath = " + newPath);
+ }
+
+ if (mTmpRect.isEmpty()) {
+ return;
+ }
+
+ if (mIsShortEdgeOnTop) {
+ mIsTouchShortEdgeStart = mTmpRect.top <= 0;
+ mIsTouchShortEdgeEnd = mTmpRect.bottom >= mDisplayHeight;
+ mIsCloserToStartSide = mTmpRect.centerY() < mDisplayHeight / 2;
+ } else {
+ mIsTouchShortEdgeStart = mTmpRect.left <= 0;
+ mIsTouchShortEdgeEnd = mTmpRect.right >= mDisplayWidth;
+ mIsCloserToStartSide = mTmpRect.centerX() < mDisplayWidth / 2;
+ }
+
+ setEdgeCutout(newPath);
+ }
+
+ private void parseSpecWithoutDp(@NonNull String specWithoutDp) {
+ Region region = Region.obtain();
+ StringBuilder sb = null;
+ int currentIndex = 0;
+ int lastIndex = 0;
+ while ((currentIndex = specWithoutDp.indexOf(MARKER_START_CHAR, lastIndex)) != -1) {
+ if (sb == null) {
+ sb = new StringBuilder(specWithoutDp.length());
+ }
+ sb.append(specWithoutDp, lastIndex, currentIndex);
+
+ if (specWithoutDp.startsWith(LEFT_MARKER, currentIndex)) {
+ if (!mPositionFromRight) {
+ mPositionFromLeft = true;
+ }
+ currentIndex += LEFT_MARKER.length();
+ } else if (specWithoutDp.startsWith(RIGHT_MARKER, currentIndex)) {
+ if (!mPositionFromLeft) {
+ mPositionFromRight = true;
+ }
+ currentIndex += RIGHT_MARKER.length();
+ } else if (specWithoutDp.startsWith(BOTTOM_MARKER, currentIndex)) {
+ if (!mPositionFromCenterVertical) {
+ parseSvgPathSpec(region, sb.toString());
+ }
+ currentIndex += BOTTOM_MARKER.length();
+
+ /* prepare to parse the rest path */
+ resetStatus(sb);
+ mBindBottomCutout = true;
+ mPositionFromBottom = true;
+ } else if (specWithoutDp.startsWith(CENTER_VERTICAL_MARKER, currentIndex)) {
+ if (!mPositionFromBottom) {
+ parseSvgPathSpec(region, sb.toString());
+ }
+ currentIndex += CENTER_VERTICAL_MARKER.length();
+
+ /* prepare to parse the rest path */
+ resetStatus(sb);
+ mPositionFromCenterVertical = true;
+ } else if (specWithoutDp.startsWith(CUTOUT_MARKER, currentIndex)) {
+ parseSvgPathSpec(region, sb.toString());
+ currentIndex += CUTOUT_MARKER.length();
+
+ /* prepare to parse the rest path */
+ resetStatus(sb);
+ } else if (specWithoutDp.startsWith(BIND_LEFT_CUTOUT_MARKER, currentIndex)) {
+ if (!mBindBottomCutout && !mBindRightCutout) {
+ mBindLeftCutout = true;
+ }
+ currentIndex += BIND_LEFT_CUTOUT_MARKER.length();
+ } else if (specWithoutDp.startsWith(BIND_RIGHT_CUTOUT_MARKER, currentIndex)) {
+ if (!mBindBottomCutout && !mBindLeftCutout) {
+ mBindRightCutout = true;
+ }
+ currentIndex += BIND_RIGHT_CUTOUT_MARKER.length();
+ } else {
+ currentIndex += 1;
+ }
+
+ lastIndex = currentIndex;
+ }
+
+ if (sb == null) {
+ parseSvgPathSpec(region, specWithoutDp);
+ } else {
+ sb.append(specWithoutDp, lastIndex, specWithoutDp.length());
+ parseSvgPathSpec(region, sb.toString());
+ }
+
+ region.recycle();
+ }
+
+ /**
+ * To parse specification string as the CutoutSpecification.
+ *
+ * @param originalSpec the specification string
+ * @return the CutoutSpecification instance
+ */
+ @VisibleForTesting(visibility = PACKAGE)
+ public CutoutSpecification parse(@NonNull String originalSpec) {
+ Objects.requireNonNull(originalSpec);
+
+ int dpIndex = originalSpec.lastIndexOf(DP_MARKER);
+ mInDp = (dpIndex != -1);
+ final String spec;
+ if (dpIndex != -1) {
+ spec = originalSpec.substring(0, dpIndex)
+ + originalSpec.substring(dpIndex + DP_MARKER.length());
+ } else {
+ spec = originalSpec;
+ }
+
+ parseSpecWithoutDp(spec);
+
+ mInsets = Insets.of(mSafeInsetLeft, mSafeInsetTop, mSafeInsetRight, mSafeInsetBottom);
+ return new CutoutSpecification(this);
+ }
+ }
+}
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index d433591..31fc161 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -31,18 +31,12 @@
import android.annotation.Nullable;
import android.content.res.Resources;
import android.graphics.Insets;
-import android.graphics.Matrix;
import android.graphics.Path;
import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Region;
-import android.graphics.Region.Op;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
-import android.util.Log;
import android.util.Pair;
-import android.util.PathParser;
import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
@@ -63,10 +57,6 @@
public final class DisplayCutout {
private static final String TAG = "DisplayCutout";
- private static final String BOTTOM_MARKER = "@bottom";
- private static final String DP_MARKER = "@dp";
- private static final String RIGHT_MARKER = "@right";
- private static final String LEFT_MARKER = "@left";
/**
* Category for overlays that allow emulating a display cutout on devices that don't have
@@ -703,77 +693,16 @@
}
}
- Path p = null;
- Rect boundTop = null;
- Rect boundBottom = null;
- Rect safeInset = new Rect();
- String bottomSpec = null;
- if (!TextUtils.isEmpty(spec)) {
- spec = spec.trim();
- final float offsetX;
- if (spec.endsWith(RIGHT_MARKER)) {
- offsetX = displayWidth;
- spec = spec.substring(0, spec.length() - RIGHT_MARKER.length()).trim();
- } else if (spec.endsWith(LEFT_MARKER)) {
- offsetX = 0;
- spec = spec.substring(0, spec.length() - LEFT_MARKER.length()).trim();
- } else {
- offsetX = displayWidth / 2f;
- }
- final boolean inDp = spec.endsWith(DP_MARKER);
- if (inDp) {
- spec = spec.substring(0, spec.length() - DP_MARKER.length());
- }
+ spec = spec.trim();
- if (spec.contains(BOTTOM_MARKER)) {
- String[] splits = spec.split(BOTTOM_MARKER, 2);
- spec = splits[0].trim();
- bottomSpec = splits[1].trim();
- }
+ CutoutSpecification cutoutSpec = new CutoutSpecification.Parser(density,
+ displayWidth, displayHeight).parse(spec);
+ Rect safeInset = cutoutSpec.getSafeInset();
+ final Rect boundLeft = cutoutSpec.getLeftBound();
+ final Rect boundTop = cutoutSpec.getTopBound();
+ final Rect boundRight = cutoutSpec.getRightBound();
+ final Rect boundBottom = cutoutSpec.getBottomBound();
- final Matrix m = new Matrix();
- final Region r = Region.obtain();
- if (!spec.isEmpty()) {
- try {
- p = PathParser.createPathFromPathData(spec);
- } catch (Throwable e) {
- Log.wtf(TAG, "Could not inflate cutout: ", e);
- }
-
- if (p != null) {
- if (inDp) {
- m.postScale(density, density);
- }
- m.postTranslate(offsetX, 0);
- p.transform(m);
-
- boundTop = new Rect();
- toRectAndAddToRegion(p, r, boundTop);
- safeInset.top = boundTop.bottom;
- }
- }
-
- if (bottomSpec != null) {
- int bottomInset = 0;
- Path bottomPath = null;
- try {
- bottomPath = PathParser.createPathFromPathData(bottomSpec);
- } catch (Throwable e) {
- Log.wtf(TAG, "Could not inflate bottom cutout: ", e);
- }
-
- if (bottomPath != null) {
- // Keep top transform
- m.postTranslate(0, displayHeight);
- bottomPath.transform(m);
- p.addPath(bottomPath);
- boundBottom = new Rect();
- toRectAndAddToRegion(bottomPath, r, boundBottom);
- bottomInset = displayHeight - boundBottom.top;
- }
- safeInset.bottom = bottomInset;
- }
- }
if (!waterfallInsets.equals(Insets.NONE)) {
safeInset.set(
@@ -784,9 +713,9 @@
}
final DisplayCutout cutout = new DisplayCutout(
- safeInset, waterfallInsets, null /* boundLeft */, boundTop,
- null /* boundRight */, boundBottom, false /* copyArguments */);
- final Pair<Path, DisplayCutout> result = new Pair<>(p, cutout);
+ safeInset, waterfallInsets, boundLeft, boundTop,
+ boundRight, boundBottom, false /* copyArguments */);
+ final Pair<Path, DisplayCutout> result = new Pair<>(cutoutSpec.getPath(), cutout);
synchronized (CACHE_LOCK) {
sCachedSpec = spec;
sCachedDisplayWidth = displayWidth;
@@ -798,14 +727,6 @@
return result;
}
- private static void toRectAndAddToRegion(Path p, Region inoutRegion, Rect inoutRect) {
- final RectF rectF = new RectF();
- p.computeBounds(rectF, false /* unused */);
- rectF.round(inoutRect);
- inoutRegion.op(inoutRect, Op.UNION);
- }
-
-
private static Insets loadWaterfallInset(Resources res) {
return Insets.of(
res.getDimensionPixelSize(R.dimen.waterfall_display_left_edge_size),
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a407bd8..a6f8fad 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -12729,12 +12729,14 @@
return findViewInsideOutShouldExist(root, mNextFocusForwardId);
case FOCUS_BACKWARD: {
if (mID == View.NO_ID) return null;
- return root.findViewByPredicateInsideOut(this, new Predicate<View>() {
- @Override
- public boolean test(View t) {
- return t.findViewById(t.mNextFocusForwardId) == View.this;
- }
- });
+ final View rootView = root;
+ final View startView = this;
+ // Since we have forward links but no backward links, we need to find the view that
+ // forward links to this view. We can't just find the view with the specified ID
+ // because view IDs need not be unique throughout the tree.
+ return root.findViewByPredicateInsideOut(startView,
+ t -> findViewInsideOutShouldExist(rootView, t, t.mNextFocusForwardId)
+ == startView);
}
}
return null;
@@ -12764,11 +12766,15 @@
}
private View findViewInsideOutShouldExist(View root, int id) {
+ return findViewInsideOutShouldExist(root, this, id);
+ }
+
+ private View findViewInsideOutShouldExist(View root, View start, int id) {
if (mMatchIdPredicate == null) {
mMatchIdPredicate = new MatchIdPredicate();
}
mMatchIdPredicate.mId = id;
- View result = root.findViewByPredicateInsideOut(this, mMatchIdPredicate);
+ View result = root.findViewByPredicateInsideOut(start, mMatchIdPredicate);
if (result == null) {
Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id);
}
diff --git a/core/java/android/view/WindowContainerTransaction.java b/core/java/android/view/WindowContainerTransaction.java
index 33f21f2..cf34b0b 100644
--- a/core/java/android/view/WindowContainerTransaction.java
+++ b/core/java/android/view/WindowContainerTransaction.java
@@ -16,6 +16,8 @@
package android.view;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -25,6 +27,8 @@
import android.os.Parcelable;
import android.util.ArrayMap;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
/**
@@ -36,10 +40,14 @@
public class WindowContainerTransaction implements Parcelable {
private final ArrayMap<IBinder, Change> mChanges = new ArrayMap<>();
+ // Flat list because re-order operations are order-dependent
+ private final ArrayList<HierarchyOp> mHierarchyOps = new ArrayList<>();
+
public WindowContainerTransaction() {}
protected WindowContainerTransaction(Parcel in) {
in.readMap(mChanges, null /* loader */);
+ in.readList(mHierarchyOps, null /* loader */);
}
private Change getOrCreateChange(IBinder token) {
@@ -97,10 +105,39 @@
return this;
}
+ /**
+ * Reparents a container into another one. The effect of a {@code null} parent can vary. For
+ * example, reparenting a stack to {@code null} will reparent it to its display.
+ *
+ * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
+ * the bottom.
+ */
+ public WindowContainerTransaction reparent(@NonNull IWindowContainer child,
+ @Nullable IWindowContainer parent, boolean onTop) {
+ mHierarchyOps.add(new HierarchyOp(child.asBinder(),
+ parent == null ? null : parent.asBinder(), onTop));
+ return this;
+ }
+
+ /**
+ * Reorders a container within its parent.
+ *
+ * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
+ * the bottom.
+ */
+ public WindowContainerTransaction reorder(@NonNull IWindowContainer child, boolean onTop) {
+ mHierarchyOps.add(new HierarchyOp(child.asBinder(), onTop));
+ return this;
+ }
+
public Map<IBinder, Change> getChanges() {
return mChanges;
}
+ public List<HierarchyOp> getHierarchyOps() {
+ return mHierarchyOps;
+ }
+
@Override
public String toString() {
return "WindowContainerTransaction { changes = " + mChanges + " }";
@@ -109,6 +146,7 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeMap(mChanges);
+ dest.writeList(mHierarchyOps);
}
@Override
@@ -249,4 +287,88 @@
}
};
}
+
+ /**
+ * Holds information about a reparent/reorder operation in the hierarchy. This is separate from
+ * Changes because they must be executed in the same order that they are added.
+ */
+ public static class HierarchyOp implements Parcelable {
+ private final IBinder mContainer;
+
+ // If this is same as mContainer, then only change position, don't reparent.
+ private final IBinder mReparent;
+
+ // Moves/reparents to top of parent when {@code true}, otherwise moves/reparents to bottom.
+ private final boolean mToTop;
+
+ public HierarchyOp(@NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) {
+ mContainer = container;
+ mReparent = reparent;
+ mToTop = toTop;
+ }
+
+ public HierarchyOp(@NonNull IBinder container, boolean toTop) {
+ mContainer = container;
+ mReparent = container;
+ mToTop = toTop;
+ }
+
+ protected HierarchyOp(Parcel in) {
+ mContainer = in.readStrongBinder();
+ mReparent = in.readStrongBinder();
+ mToTop = in.readBoolean();
+ }
+
+ public boolean isReparent() {
+ return mContainer != mReparent;
+ }
+
+ @Nullable
+ public IBinder getNewParent() {
+ return mReparent;
+ }
+
+ @NonNull
+ public IBinder getContainer() {
+ return mContainer;
+ }
+
+ public boolean getToTop() {
+ return mToTop;
+ }
+
+ @Override
+ public String toString() {
+ if (isReparent()) {
+ return "{reparent: " + mContainer + " to " + (mToTop ? "top of " : "bottom of ")
+ + mReparent + "}";
+ } else {
+ return "{reorder: " + mContainer + " to " + (mToTop ? "top" : "bottom") + "}";
+ }
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStrongBinder(mContainer);
+ dest.writeStrongBinder(mReparent);
+ dest.writeBoolean(mToTop);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<HierarchyOp> CREATOR = new Creator<HierarchyOp>() {
+ @Override
+ public HierarchyOp createFromParcel(Parcel in) {
+ return new HierarchyOp(in);
+ }
+
+ @Override
+ public HierarchyOp[] newArray(int size) {
+ return new HierarchyOp[size];
+ }
+ };
+ }
}
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 4365d1f..56683dd 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -277,7 +277,7 @@
.setStableInsets(Insets.of(stableInsets))
.setDisplayCutout(displayCutout.get()).build();
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return null;
}
}
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 05cf3ed..bf2de14 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -4854,8 +4854,11 @@
new AccessibilityAction(R.id.accessibilityActionPressAndHold);
/**
- * Action to send ime action. A node should expose this action only for views that are
- * currently with input focus and editable.
+ * Action to send an ime action which is from
+ * {@link android.view.inputmethod.EditorInfo#actionId}. This action would be
+ * {@link android.view.inputmethod.EditorInfo#IME_ACTION_UNSPECIFIED} if no specific
+ * actionId defined. A node should expose this action only for views that are currently
+ * with input focus and editable.
*/
@NonNull public static final AccessibilityAction ACTION_IME_ENTER =
new AccessibilityAction(R.id.accessibilityActionImeEnter);
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 232d96b..2134dab 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -22,6 +22,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.util.DebugUtils;
import android.util.Log;
import android.view.View;
@@ -50,7 +51,11 @@
private static final Random sIdGenerator = new Random();
- /** @hide */
+ /**
+ * ID used to indicate that a session does not exist
+ * @hide
+ */
+ @SystemApi
public static final int NO_SESSION_ID = 0;
/**
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index c80a1ae..7f90d57 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -33,11 +33,11 @@
import android.view.View;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
+import java.util.Objects;
/**
* An EditorInfo describes several attributes of a text editing object
@@ -558,7 +558,7 @@
* editor wants to trim out the first 10 chars, subTextStart should be 10.
*/
public void setInitialSurroundingSubText(@NonNull CharSequence subText, int subTextStart) {
- Preconditions.checkNotNull(subText);
+ Objects.requireNonNull(subText);
// Swap selection start and end if necessary.
final int subTextSelStart = initialSelStart > initialSelEnd
@@ -585,25 +585,35 @@
return;
}
- // The input text is too long. Let's try to trim it reasonably. Fundamental rules are:
- // 1. Text before the cursor is the most important information to IMEs.
- // 2. Text after the cursor is the second important information to IMEs.
- // 3. Selected text is the least important information but it shall NEVER be truncated.
- // When it is too long, just drop it.
- //
- // Source: <TextBeforeCursor><Selection><TextAfterCursor>
- // Possible results:
- // 1. <(maybeTrimmedAtHead)TextBeforeCursor><Selection><TextAfterCursor(maybeTrimmedAtTail)>
- // 2. <(maybeTrimmedAtHead)TextBeforeCursor><TextAfterCursor(maybeTrimmedAtTail)>
- //
- final int sourceSelLength = subTextSelEnd - subTextSelStart;
+ trimLongSurroundingText(subText, subTextSelStart, subTextSelEnd);
+ }
+
+ /**
+ * Trims the initial surrounding text when it is over sized. Fundamental trimming rules are:
+ * - The text before the cursor is the most important information to IMEs.
+ * - The text after the cursor is the second important information to IMEs.
+ * - The selected text is the least important information but it shall NEVER be truncated. When
+ * it is too long, just drop it.
+ *<p><pre>
+ * For example, the subText can be viewed as
+ * TextBeforeCursor + Selection + TextAfterCursor
+ * The result could be
+ * 1. (maybeTrimmedAtHead)TextBeforeCursor + Selection + TextAfterCursor(maybeTrimmedAtTail)
+ * 2. (maybeTrimmedAtHead)TextBeforeCursor + TextAfterCursor(maybeTrimmedAtTail)</pre>
+ *
+ * @param subText The long text that needs to be trimmed.
+ * @param selStart The text offset of the start of the selection.
+ * @param selEnd The text offset of the end of the selection
+ */
+ private void trimLongSurroundingText(CharSequence subText, int selStart, int selEnd) {
+ final int sourceSelLength = selEnd - selStart;
// When the selected text is too long, drop it.
final int newSelLength = (sourceSelLength > MAX_INITIAL_SELECTION_LENGTH)
? 0 : sourceSelLength;
// Distribute rest of length quota to TextBeforeCursor and TextAfterCursor in 4:1 ratio.
- final int subTextBeforeCursorLength = subTextSelStart;
- final int subTextAfterCursorLength = subTextLength - subTextSelEnd;
+ final int subTextBeforeCursorLength = selStart;
+ final int subTextAfterCursorLength = subText.length() - selEnd;
final int maxLengthMinusSelection = MEMORY_EFFICIENT_TEXT_LENGTH - newSelLength;
final int possibleMaxBeforeCursorLength =
Math.min(subTextBeforeCursorLength, (int) (0.8 * maxLengthMinusSelection));
@@ -617,24 +627,23 @@
// We don't want to cut surrogate pairs in the middle. Exam that at the new head and tail.
if (isCutOnSurrogate(subText,
- subTextSelStart - newBeforeCursorLength, TrimPolicy.HEAD)) {
+ selStart - newBeforeCursorLength, TrimPolicy.HEAD)) {
newBeforeCursorHead = newBeforeCursorHead + 1;
newBeforeCursorLength = newBeforeCursorLength - 1;
}
if (isCutOnSurrogate(subText,
- subTextSelEnd + newAfterCursorLength - 1, TrimPolicy.TAIL)) {
+ selEnd + newAfterCursorLength - 1, TrimPolicy.TAIL)) {
newAfterCursorLength = newAfterCursorLength - 1;
}
// Now we know where to trim, compose the initialSurroundingText.
final int newTextLength = newBeforeCursorLength + newSelLength + newAfterCursorLength;
- CharSequence newInitialSurroundingText;
+ final CharSequence newInitialSurroundingText;
if (newSelLength != sourceSelLength) {
final CharSequence beforeCursor = subText.subSequence(newBeforeCursorHead,
newBeforeCursorHead + newBeforeCursorLength);
-
- final CharSequence afterCursor = subText.subSequence(subTextSelEnd,
- subTextSelEnd + newAfterCursorLength);
+ final CharSequence afterCursor = subText.subSequence(selEnd,
+ selEnd + newAfterCursorLength);
newInitialSurroundingText = TextUtils.concat(beforeCursor, afterCursor);
} else {
@@ -651,15 +660,16 @@
}
/**
- * Get <var>n</var> characters of text before the current cursor position. May be {@code null}
- * when the protocol is not supported.
+ * Get <var>length</var> characters of text before the current cursor position. May be
+ * {@code null} when the protocol is not supported.
*
* @param length The expected length of the text.
* @param flags Supplies additional options controlling how the text is returned. May be
* either 0 or {@link InputConnection#GET_TEXT_WITH_STYLES}.
* @return the text before the cursor position; the length of the returned text might be less
- * than <var>n</var>. When there is no text before the cursor, an empty string will be returned.
- * It could also be {@code null} when the editor or system could not support this protocol.
+ * than <var>length</var>. When there is no text before the cursor, an empty string will be
+ * returned. It could also be {@code null} when the editor or system could not support this
+ * protocol.
*/
@Nullable
public CharSequence getInitialTextBeforeCursor(int length, int flags) {
@@ -667,8 +677,8 @@
}
/**
- * Gets the selected text, if any. May be {@code null} when no text is selected or the selected
- * text is way too long.
+ * Gets the selected text, if any. May be {@code null} when the protocol is not supported or the
+ * selected text is way too long.
*
* @param flags Supplies additional options controlling how the text is returned. May be
* either 0 or {@link InputConnection#GET_TEXT_WITH_STYLES}.
@@ -693,15 +703,16 @@
}
/**
- * Get <var>n</var> characters of text after the current cursor position. May be {@code null}
- * when the protocol is not supported.
+ * Get <var>length</var> characters of text after the current cursor position. May be
+ * {@code null} when the protocol is not supported.
*
* @param length The expected length of the text.
* @param flags Supplies additional options controlling how the text is returned. May be
* either 0 or {@link InputConnection#GET_TEXT_WITH_STYLES}.
* @return the text after the cursor position; the length of the returned text might be less
- * than <var>n</var>. When there is no text after the cursor, an empty string will be returned.
- * It could also be {@code null} when the editor or system could not support this protocol.
+ * than <var>length</var>. When there is no text after the cursor, an empty string will be
+ * returned. It could also be {@code null} when the editor or system could not support this
+ * protocol.
*/
@Nullable
public CharSequence getInitialTextAfterCursor(int length, int flags) {
@@ -863,7 +874,6 @@
return 0;
}
- // TODO(b/148035211): Unit tests for this class
static final class InitialSurroundingText implements Parcelable {
@Nullable final CharSequence mSurroundingText;
final int mSelectionHead;
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index f0c16aa..dbab81b1 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -664,8 +664,6 @@
*/
@Override
public void setCurrentRootView(ViewRootImpl rootView) {
- // If the mCurRootView is losing window focus, release the strong reference to it
- // so as not to prevent it from being garbage-collected.
if (mWindowFocusGainFuture != null) {
mWindowFocusGainFuture.cancel(false /* mayInterruptIfRunning */);
mWindowFocusGainFuture = null;
diff --git a/core/java/android/webkit/WebResourceRequest.java b/core/java/android/webkit/WebResourceRequest.java
index 964b6f8..0b307e6 100644
--- a/core/java/android/webkit/WebResourceRequest.java
+++ b/core/java/android/webkit/WebResourceRequest.java
@@ -32,10 +32,10 @@
Uri getUrl();
/**
- * Gets whether the request was made for the main frame.
+ * Gets whether the request was made in order to fetch the main frame's document.
*
- * @return whether the request was made for the main frame. Will be {@code false} for iframes,
- * for example.
+ * @return whether the request was made for the main frame document. Will be
+ * {@code false} for subresources or iframes, for example.
*/
boolean isForMainFrame();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index cbfa05c..469ab2e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -422,9 +422,6 @@
*/
static final int PROCESS_TEXT_REQUEST_CODE = 100;
- // Accessibility action to send IME custom action for CTS testing.
- public static final int ACCESSIBILITY_ACTION_IME_ENTER = R.id.accessibilityActionImeEnter;
-
/**
* Return code of {@link #doKeyDown}.
*/
@@ -11758,7 +11755,7 @@
}
AccessibilityNodeInfo.AccessibilityAction action =
new AccessibilityNodeInfo.AccessibilityAction(
- ACCESSIBILITY_ACTION_IME_ENTER, imeActionLabel);
+ R.id.accessibilityActionImeEnter, imeActionLabel);
info.addAction(action);
}
}
@@ -12072,7 +12069,7 @@
}
}
} return true;
- case ACCESSIBILITY_ACTION_IME_ENTER: {
+ case R.id.accessibilityActionImeEnter: {
if (isFocused() && isTextEditable()) {
final int imeActionId = (arguments != null) ? arguments.getInt(
AccessibilityNodeInfo.ACTION_ARGUMENT_IME_ACTION_ID_INT,
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index a2c70b9..8c52d1f 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -263,9 +263,14 @@
/**
* Return the view.
*
- * <p><strong>Warning:</strong> Starting from Android {@link Build.VERSION_CODES#R}, for apps
- * targeting API level {@link Build.VERSION_CODES#R} or higher that haven't called {@link
- * #setView(View)} with a non-{@code null} view, this method will return {@code null}.
+ * <p>Toasts constructed with {@link #Toast(Context)} that haven't called {@link #setView(View)}
+ * with a non-{@code null} view will return {@code null} here.
+ *
+ * <p>Starting from Android {@link Build.VERSION_CODES#R}, in apps targeting API level {@link
+ * Build.VERSION_CODES#R} or higher, toasts constructed with {@link #makeText(Context,
+ * CharSequence, int)} or its variants will also return {@code null} here unless they had called
+ * {@link #setView(View)} with a non-{@code null} view. If you want to be notified when the
+ * toast is shown or hidden, use {@link #addCallback(Callback)}.
*
* @see #setView
* @deprecated Custom toast views are deprecated. Apps can create a standard text toast with the
@@ -276,7 +281,7 @@
* will not have custom toast views displayed.
*/
@Deprecated
- public View getView() {
+ @Nullable public View getView() {
return mNextView;
}
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index f3b6d29..417e23f 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -38,8 +38,10 @@
IVoiceInteractor interactor);
boolean showSessionFromSession(IBinder token, in Bundle sessionArgs, int flags);
boolean hideSessionFromSession(IBinder token);
- int startVoiceActivity(IBinder token, in Intent intent, String resolvedType);
- int startAssistantActivity(IBinder token, in Intent intent, String resolvedType);
+ int startVoiceActivity(IBinder token, in Intent intent, String resolvedType,
+ String callingFeatureId);
+ int startAssistantActivity(IBinder token, in Intent intent, String resolvedType,
+ String callingFeatureId);
void setKeepAwake(IBinder token, boolean keepAwake);
void closeSystemDialogs(IBinder token);
void finish(IBinder token);
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index bbb7513..a934de3 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1487,7 +1487,6 @@
for (int i = 0; i < tabWidget.getChildCount(); i++) {
TextView title = tabWidget.getChildAt(i).findViewById(android.R.id.title);
title.setTextColor(getColor(R.color.resolver_tabs_inactive_color));
- title.setAllCaps(false);
}
}
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 22fe31e..0ccc45e 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -25,6 +25,7 @@
import static android.system.OsConstants.S_IXGRP;
import static android.system.OsConstants.S_IXOTH;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
@@ -32,7 +33,12 @@
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.parsing.AndroidPackage;
import android.os.Build;
+import android.os.IBinder;
import android.os.SELinux;
+import android.os.ServiceManager;
+import android.os.incremental.IIncrementalService;
+import android.os.incremental.IncrementalManager;
+import android.os.incremental.IncrementalStorage;
import android.system.ErrnoException;
import android.system.Os;
import android.util.Slog;
@@ -44,6 +50,7 @@
import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
+import java.nio.file.Path;
import java.util.List;
/**
@@ -73,6 +80,7 @@
private final CloseGuard mGuard = CloseGuard.get();
private volatile boolean mClosed;
+ final String[] apkPaths;
final long[] apkHandles;
final boolean multiArch;
final boolean extractNativeLibs;
@@ -103,9 +111,11 @@
private static Handle create(List<String> codePaths, boolean multiArch,
boolean extractNativeLibs, boolean debuggable) throws IOException {
final int size = codePaths.size();
+ final String[] apkPaths = new String[size];
final long[] apkHandles = new long[size];
for (int i = 0; i < size; i++) {
final String path = codePaths.get(i);
+ apkPaths[i] = path;
apkHandles[i] = nativeOpenApk(path);
if (apkHandles[i] == 0) {
// Unwind everything we've opened so far
@@ -116,7 +126,7 @@
}
}
- return new Handle(apkHandles, multiArch, extractNativeLibs, debuggable);
+ return new Handle(apkPaths, apkHandles, multiArch, extractNativeLibs, debuggable);
}
public static Handle createFd(PackageLite lite, FileDescriptor fd) throws IOException {
@@ -127,11 +137,13 @@
throw new IOException("Unable to open APK " + path + " from fd " + fd);
}
- return new Handle(apkHandles, lite.multiArch, lite.extractNativeLibs, lite.debuggable);
+ return new Handle(new String[]{path}, apkHandles, lite.multiArch,
+ lite.extractNativeLibs, lite.debuggable);
}
- Handle(long[] apkHandles, boolean multiArch, boolean extractNativeLibs,
- boolean debuggable) {
+ Handle(String[] apkPaths, long[] apkHandles, boolean multiArch,
+ boolean extractNativeLibs, boolean debuggable) {
+ this.apkPaths = apkPaths;
this.apkHandles = apkHandles;
this.multiArch = multiArch;
this.extractNativeLibs = extractNativeLibs;
@@ -313,40 +325,58 @@
}
public static int copyNativeBinariesForSupportedAbi(Handle handle, File libraryRoot,
- String[] abiList, boolean useIsaSubdir) throws IOException {
- createNativeLibrarySubdir(libraryRoot);
-
+ String[] abiList, boolean useIsaSubdir, boolean isIncremental) throws IOException {
/*
* If this is an internal application or our nativeLibraryPath points to
* the app-lib directory, unpack the libraries if necessary.
*/
int abi = findSupportedAbi(handle, abiList);
- if (abi >= 0) {
- /*
- * If we have a matching instruction set, construct a subdir under the native
- * library root that corresponds to this instruction set.
- */
- final String instructionSet = VMRuntime.getInstructionSet(abiList[abi]);
- final File subDir;
- if (useIsaSubdir) {
- final File isaSubdir = new File(libraryRoot, instructionSet);
- createNativeLibrarySubdir(isaSubdir);
- subDir = isaSubdir;
- } else {
- subDir = libraryRoot;
- }
+ if (abi < 0) {
+ return abi;
+ }
- int copyRet = copyNativeBinaries(handle, subDir, abiList[abi]);
- if (copyRet != PackageManager.INSTALL_SUCCEEDED) {
- return copyRet;
+ /*
+ * If we have a matching instruction set, construct a subdir under the native
+ * library root that corresponds to this instruction set.
+ */
+ final String supportedAbi = abiList[abi];
+ final String instructionSet = VMRuntime.getInstructionSet(supportedAbi);
+ final File subDir;
+ if (useIsaSubdir) {
+ subDir = new File(libraryRoot, instructionSet);
+ } else {
+ subDir = libraryRoot;
+ }
+
+ if (isIncremental) {
+ int res =
+ incrementalConfigureNativeBinariesForSupportedAbi(handle, subDir, supportedAbi);
+ if (res != PackageManager.INSTALL_SUCCEEDED) {
+ // TODO(b/133435829): the caller of this function expects that we return the index
+ // to the supported ABI. However, any non-negative integer can be a valid index.
+ // We should fix this function and make sure it doesn't accidentally return an error
+ // code that can also be a valid index.
+ return res;
}
+ return abi;
+ }
+
+ // For non-incremental, use regular extraction and copy
+ createNativeLibrarySubdir(libraryRoot);
+ if (subDir != libraryRoot) {
+ createNativeLibrarySubdir(subDir);
+ }
+
+ int copyRet = copyNativeBinaries(handle, subDir, supportedAbi);
+ if (copyRet != PackageManager.INSTALL_SUCCEEDED) {
+ return copyRet;
}
return abi;
}
public static int copyNativeBinariesWithOverride(Handle handle, File libraryRoot,
- String abiOverride) {
+ String abiOverride, boolean isIncremental) {
try {
if (handle.multiArch) {
// Warn if we've set an abiOverride for multi-lib packages..
@@ -359,7 +389,8 @@
int copyRet = PackageManager.NO_NATIVE_LIBRARIES;
if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
copyRet = copyNativeBinariesForSupportedAbi(handle, libraryRoot,
- Build.SUPPORTED_32_BIT_ABIS, true /* use isa specific subdirs */);
+ Build.SUPPORTED_32_BIT_ABIS, true /* use isa specific subdirs */,
+ isIncremental);
if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES &&
copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
Slog.w(TAG, "Failure copying 32 bit native libraries; copyRet=" +copyRet);
@@ -369,7 +400,8 @@
if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
copyRet = copyNativeBinariesForSupportedAbi(handle, libraryRoot,
- Build.SUPPORTED_64_BIT_ABIS, true /* use isa specific subdirs */);
+ Build.SUPPORTED_64_BIT_ABIS, true /* use isa specific subdirs */,
+ isIncremental);
if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES &&
copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
Slog.w(TAG, "Failure copying 64 bit native libraries; copyRet=" +copyRet);
@@ -392,7 +424,7 @@
}
int copyRet = copyNativeBinariesForSupportedAbi(handle, libraryRoot, abiList,
- true /* use isa specific subdirs */);
+ true /* use isa specific subdirs */, isIncremental);
if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
Slog.w(TAG, "Failure copying native libraries [errorCode=" + copyRet + "]");
return copyRet;
@@ -449,29 +481,61 @@
* Service will create native library directories and set up native library binary files in the
* same structure as they are in non-incremental installations.
*
- * @param pkg The package to be installed, including all the APK files.
- * @param handle The pointer to an zip archive.
- * @param libraryRoot The root directory of the native library files, e.g., lib/
- * @param abiList The list of ABIs that are supported by the current device.
- * @param useIsaSubdir Whether or not to set up a sub dir for the ISA.
- * @return ABI code if installation succeeds or error code if installation fails.
+ * @param handle The Handle object that contains all apk paths.
+ * @param libSubDir The target directory to put the native library files, e.g., lib/ or lib/arm
+ * @param abi The abi that is supported by the current device.
+ * @return Integer code if installation succeeds or fails.
*/
- public static int configureNativeBinariesForSupportedAbi(AndroidPackage pkg, Handle handle,
- File libraryRoot, String[] abiList, boolean useIsaSubdir) {
- int abi = findSupportedAbi(handle, abiList);
- if (abi < 0) {
- Slog.e(TAG, "Failed to find find matching ABI.");
- return abi;
+ private static int incrementalConfigureNativeBinariesForSupportedAbi(Handle handle,
+ File libSubDir, String abi) {
+ final String[] apkPaths = handle.apkPaths;
+ if (apkPaths == null || apkPaths.length == 0) {
+ Slog.e(TAG, "No apks to extract native libraries from.");
+ return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
}
- // Currently only support installations that have pre-configured native library files
- // TODO(b/136132412): implement this after incfs supports file mapping
- if (!libraryRoot.exists()) {
- Slog.e(TAG, "Incremental installation currently does not configure native libs");
- return INSTALL_FAILED_NO_MATCHING_ABIS;
+ final IBinder incrementalService = ServiceManager.getService(Context.INCREMENTAL_SERVICE);
+ if (incrementalService == null) {
+ //TODO(b/133435829): add incremental specific error codes
+ return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ }
+ final IncrementalManager incrementalManager = new IncrementalManager(
+ IIncrementalService.Stub.asInterface(incrementalService));
+ final File apkParent = new File(apkPaths[0]).getParentFile();
+ IncrementalStorage incrementalStorage =
+ incrementalManager.openStorage(apkParent.getAbsolutePath());
+ if (incrementalStorage == null) {
+ Slog.e(TAG, "Failed to find incremental storage");
+ return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
}
- return abi;
+ String libRelativeDir = getRelativePath(apkParent, libSubDir);
+ if (libRelativeDir == null) {
+ return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ }
+
+ for (int i = 0; i < apkPaths.length; i++) {
+ if (!incrementalStorage.configureNativeBinaries(apkPaths[i], libRelativeDir, abi)) {
+ return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ }
+ }
+ return PackageManager.INSTALL_SUCCEEDED;
+ }
+
+ private static String getRelativePath(File base, File target) {
+ try {
+ final Path basePath = base.toPath();
+ final Path targetPath = target.toPath();
+ final Path relativePath = basePath.relativize(targetPath);
+ if (relativePath.toString().isEmpty()) {
+ return "";
+ }
+ return relativePath.toString();
+ } catch (IllegalArgumentException ex) {
+ Slog.e(TAG, "Failed to find relative path between: " + base.getAbsolutePath()
+ + " and: " + target.getAbsolutePath());
+ return null;
+ }
}
// We don't care about the other return values for now.
diff --git a/core/java/com/android/internal/logging/UiEventLogger.java b/core/java/com/android/internal/logging/UiEventLogger.java
index 48d2bc2..67ffd4d 100644
--- a/core/java/com/android/internal/logging/UiEventLogger.java
+++ b/core/java/com/android/internal/logging/UiEventLogger.java
@@ -56,8 +56,8 @@
* @param event an enum implementing UiEventEnum interface.
* @param uid the uid of the relevant app, if known (0 otherwise).
* @param packageName the package name of the relevant app, if known (null otherwise).
- * @param instance An identifier obtained from an InstanceIdSequence.
+ * @param instance An identifier obtained from an InstanceIdSequence. If null, reduces to log().
*/
void logWithInstanceId(@NonNull UiEventEnum event, int uid, @Nullable String packageName,
- @NonNull InstanceId instance);
+ @Nullable InstanceId instance);
}
diff --git a/core/java/com/android/internal/logging/UiEventLoggerImpl.java b/core/java/com/android/internal/logging/UiEventLoggerImpl.java
index 785b2ed..4d171ec 100644
--- a/core/java/com/android/internal/logging/UiEventLoggerImpl.java
+++ b/core/java/com/android/internal/logging/UiEventLoggerImpl.java
@@ -41,9 +41,11 @@
public void logWithInstanceId(UiEventEnum event, int uid, String packageName,
InstanceId instance) {
final int eventID = event.getId();
- if (eventID > 0) {
+ if ((eventID > 0) && (instance != null)) {
FrameworkStatsLog.write(FrameworkStatsLog.UI_EVENT_REPORTED, eventID, uid, packageName,
instance.getId());
+ } else {
+ log(event, uid, packageName);
}
}
}
diff --git a/core/java/com/android/internal/policy/TaskResizingAlgorithm.java b/core/java/com/android/internal/policy/TaskResizingAlgorithm.java
new file mode 100644
index 0000000..1fce098
--- /dev/null
+++ b/core/java/com/android/internal/policy/TaskResizingAlgorithm.java
@@ -0,0 +1,179 @@
+/*
+ * 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.policy;
+
+import android.annotation.IntDef;
+import android.graphics.Point;
+import android.graphics.Rect;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Given a move coordinate (x, y), the original taks bounds and relevant details, calculate the new
+ * bounds.
+ *
+ * @hide
+ */
+public class TaskResizingAlgorithm {
+
+ @IntDef(flag = true,
+ value = {
+ CTRL_NONE,
+ CTRL_LEFT,
+ CTRL_RIGHT,
+ CTRL_TOP,
+ CTRL_BOTTOM
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CtrlType {}
+
+ public static final int CTRL_NONE = 0x0;
+ public static final int CTRL_LEFT = 0x1;
+ public static final int CTRL_RIGHT = 0x2;
+ public static final int CTRL_TOP = 0x4;
+ public static final int CTRL_BOTTOM = 0x8;
+
+ // The minimal aspect ratio which needs to be met to count as landscape (or 1/.. for portrait).
+ // Note: We do not use the 1.33 from the CDD here since the user is allowed to use what ever
+ // aspect he desires.
+ @VisibleForTesting
+ public static final float MIN_ASPECT = 1.2f;
+
+ /**
+ * Given a (x, y) point and its original starting down point and its original bounds, calculate
+ * and return a new resized bound.
+ * @param x the new moved X point.
+ * @param y the new moved Y point.
+ * @param startDragX the original starting X point.
+ * @param startDragY the original starting Y point.
+ * @param originalBounds the original bound before resize.
+ * @param ctrlType The type of resize operation.
+ * @param minVisibleWidth The minimal width required for the new size.
+ * @param minVisibleHeight The minimal height required for the new size.
+ * @param maxVisibleSize The maximum size allowed.
+ * @param preserveOrientation
+ * @param startOrientationWasLandscape
+ * @return
+ */
+ public static Rect resizeDrag(float x, float y, float startDragX, float startDragY,
+ Rect originalBounds, int ctrlType, int minVisibleWidth, int minVisibleHeight,
+ Point maxVisibleSize, boolean preserveOrientation,
+ boolean startOrientationWasLandscape) {
+ // This is a resizing operation.
+ // We need to keep various constraints:
+ // 1. mMinVisible[Width/Height] <= [width/height] <= mMaxVisibleSize.[x/y]
+ // 2. The orientation is kept - if required.
+ final int deltaX = Math.round(x - startDragX);
+ final int deltaY = Math.round(y - startDragY);
+ int left = originalBounds.left;
+ int top = originalBounds.top;
+ int right = originalBounds.right;
+ int bottom = originalBounds.bottom;
+
+ // Calculate the resulting width and height of the drag operation.
+ int width = right - left;
+ int height = bottom - top;
+ if ((ctrlType & CTRL_LEFT) != 0) {
+ width = Math.max(minVisibleWidth, width - deltaX);
+ } else if ((ctrlType & CTRL_RIGHT) != 0) {
+ width = Math.max(minVisibleWidth, width + deltaX);
+ }
+ if ((ctrlType & CTRL_TOP) != 0) {
+ height = Math.max(minVisibleHeight, height - deltaY);
+ } else if ((ctrlType & CTRL_BOTTOM) != 0) {
+ height = Math.max(minVisibleHeight, height + deltaY);
+ }
+
+ // If we have to preserve the orientation - check that we are doing so.
+ final float aspect = (float) width / (float) height;
+ if (preserveOrientation && ((startOrientationWasLandscape && aspect < MIN_ASPECT)
+ || (!startOrientationWasLandscape && aspect > (1.0 / MIN_ASPECT)))) {
+ // Calculate 2 rectangles fulfilling all requirements for either X or Y being the major
+ // drag axis. What ever is producing the bigger rectangle will be chosen.
+ int width1;
+ int width2;
+ int height1;
+ int height2;
+ if (startOrientationWasLandscape) {
+ // Assuming that the width is our target we calculate the height.
+ width1 = Math.max(minVisibleWidth, Math.min(maxVisibleSize.x, width));
+ height1 = Math.min(height, Math.round((float) width1 / MIN_ASPECT));
+ if (height1 < minVisibleHeight) {
+ // If the resulting height is too small we adjust to the minimal size.
+ height1 = minVisibleHeight;
+ width1 = Math.max(minVisibleWidth,
+ Math.min(maxVisibleSize.x, Math.round((float) height1 * MIN_ASPECT)));
+ }
+ // Assuming that the height is our target we calculate the width.
+ height2 = Math.max(minVisibleHeight, Math.min(maxVisibleSize.y, height));
+ width2 = Math.max(width, Math.round((float) height2 * MIN_ASPECT));
+ if (width2 < minVisibleWidth) {
+ // If the resulting width is too small we adjust to the minimal size.
+ width2 = minVisibleWidth;
+ height2 = Math.max(minVisibleHeight,
+ Math.min(maxVisibleSize.y, Math.round((float) width2 / MIN_ASPECT)));
+ }
+ } else {
+ // Assuming that the width is our target we calculate the height.
+ width1 = Math.max(minVisibleWidth, Math.min(maxVisibleSize.x, width));
+ height1 = Math.max(height, Math.round((float) width1 * MIN_ASPECT));
+ if (height1 < minVisibleHeight) {
+ // If the resulting height is too small we adjust to the minimal size.
+ height1 = minVisibleHeight;
+ width1 = Math.max(minVisibleWidth,
+ Math.min(maxVisibleSize.x, Math.round((float) height1 / MIN_ASPECT)));
+ }
+ // Assuming that the height is our target we calculate the width.
+ height2 = Math.max(minVisibleHeight, Math.min(maxVisibleSize.y, height));
+ width2 = Math.min(width, Math.round((float) height2 / MIN_ASPECT));
+ if (width2 < minVisibleWidth) {
+ // If the resulting width is too small we adjust to the minimal size.
+ width2 = minVisibleWidth;
+ height2 = Math.max(minVisibleHeight,
+ Math.min(maxVisibleSize.y, Math.round((float) width2 * MIN_ASPECT)));
+ }
+ }
+
+ // Use the bigger of the two rectangles if the major change was positive, otherwise
+ // do the opposite.
+ final boolean grows = width > (right - left) || height > (bottom - top);
+ if (grows == (width1 * height1 > width2 * height2)) {
+ width = width1;
+ height = height1;
+ } else {
+ width = width2;
+ height = height2;
+ }
+ }
+
+ // Generate the final bounds by keeping the opposite drag edge constant.
+ if ((ctrlType & CTRL_LEFT) != 0) {
+ left = right - width;
+ } else { // Note: The right might have changed - if we pulled at the right or not.
+ right = left + width;
+ }
+ if ((ctrlType & CTRL_TOP) != 0) {
+ top = bottom - height;
+ } else { // Note: The height might have changed - if we pulled at the bottom or not.
+ bottom = top + height;
+ }
+ return new Rect(left, top, right, bottom);
+ }
+}
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 26d2f19..2fcc1de 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -903,7 +903,6 @@
} break;
case "component-override": {
readComponentOverrides(parser, permFile);
- XmlUtils.skipCurrentTag(parser);
} break;
case "backup-transport-whitelisted-service": {
if (allowFeatures) {
@@ -1403,8 +1402,7 @@
final int depth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, depth)) {
- String name = parser.getName();
- if ("component".equals(name)) {
+ if ("component".equals(parser.getName())) {
String clsname = parser.getAttributeValue(null, "class");
String enabled = parser.getAttributeValue(null, "enabled");
if (clsname == null) {
@@ -1432,8 +1430,6 @@
}
componentEnabledStates.put(clsname, !"false".equals(enabled));
- } else {
- XmlUtils.skipCurrentTag(parser);
}
}
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 35eb0fc..76e7e19 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -153,7 +153,7 @@
"android_util_MemoryIntArray.cpp",
"android_util_Process.cpp",
"android_util_jar_StrictJarFile.cpp",
- "android_media_AudioDeviceAddress.cpp",
+ "android_media_AudioDevice.cpp",
"android_media_AudioEffectDescriptor.cpp",
"android_media_AudioRecord.cpp",
"android_media_AudioSystem.cpp",
@@ -182,6 +182,7 @@
"android_hardware_UsbRequest.cpp",
"android_hardware_location_ActivityRecognitionHardware.cpp",
"android_util_FileObserver.cpp",
+ "android/graphics/GraphicsStatsService.cpp",
"android/graphics/SurfaceTexture.cpp",
"android/opengl/poly_clip.cpp", // TODO: .arm
"android/opengl/util.cpp",
@@ -273,6 +274,7 @@
"libstats_jni",
"libstatslog",
"server_configurable_flags",
+ "libstatspull",
],
export_shared_lib_headers: [
// AndroidRuntime.h depends on nativehelper/jni.h
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 657336e..b47b7e3 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -86,7 +86,7 @@
extern int register_android_hardware_UsbRequest(JNIEnv *env);
extern int register_android_hardware_location_ActivityRecognitionHardware(JNIEnv* env);
-extern int register_android_media_AudioDeviceAddress(JNIEnv *env);
+extern int register_android_media_AudioDevice(JNIEnv* env);
extern int register_android_media_AudioEffectDescriptor(JNIEnv *env);
extern int register_android_media_AudioRecord(JNIEnv *env);
extern int register_android_media_AudioSystem(JNIEnv *env);
@@ -209,9 +209,11 @@
static const char* PROFILE_BOOT_CLASS_PATH = "profilebootclasspath";
// Feature flag name for running the JIT in Zygote experiment, b/119800099.
-static const char* ENABLE_APEX_IMAGE = "enable_apex_image";
-// Flag to pass to the runtime when using the apex image.
-static const char* kApexImageOption = "-Ximage:/system/framework/apex.art";
+// TODO: Rename the server-level flag or remove.
+static const char* ENABLE_JITZYGOTE_IMAGE = "enable_apex_image";
+// Flag to pass to the runtime when using the JIT Zygote image.
+static const char* kJitZygoteImageOption =
+ "-Ximage:boot.art:/nonx/boot-framework.art!/system/etc/boot-image.prof";
// Feature flag name for disabling lock profiling.
static const char* DISABLE_LOCK_PROFILING = "disable_lock_profiling";
@@ -631,6 +633,8 @@
char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
char foregroundHeapGrowthMultiplierOptsBuf[
sizeof("-XX:ForegroundHeapGrowthMultiplier=")-1 + PROPERTY_VALUE_MAX];
+ char finalizerTimeoutMsOptsBuf[sizeof("-XX:FinalizerTimeoutMs=")-1 + PROPERTY_VALUE_MAX];
+ char threadSuspendTimeoutOptsBuf[sizeof("-XX:ThreadSuspendTimeout=")-1 + PROPERTY_VALUE_MAX];
char cachePruneBuf[sizeof("-Xzygote-max-boot-retry=")-1 + PROPERTY_VALUE_MAX];
char dex2oatXmsImageFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
char dex2oatXmxImageFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
@@ -687,16 +691,16 @@
addOption("-Xjitsaveprofilinginfo");
}
- std::string use_apex_image_flag =
- server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
- ENABLE_APEX_IMAGE,
- /*default_value=*/ "");
+ std::string use_jitzygote_image_flag =
+ server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
+ ENABLE_JITZYGOTE_IMAGE,
+ /*default_value=*/"");
// Use the APEX boot image for boot class path profiling to get JIT samples on BCP methods.
// Also use the APEX boot image if it's explicitly enabled via configuration flag.
- const bool use_apex_image = profile_boot_class_path || (use_apex_image_flag == "true");
+ const bool use_apex_image = profile_boot_class_path || (use_jitzygote_image_flag == "true");
if (use_apex_image) {
- addOption(kApexImageOption);
- ALOGI("Using Apex boot image: '%s'\n", kApexImageOption);
+ ALOGI("Using JIT Zygote image: '%s'\n", kJitZygoteImageOption);
+ addOption(kJitZygoteImageOption);
} else if (parseRuntimeOption("dalvik.vm.boot-image", bootImageBuf, "-Ximage:")) {
ALOGI("Using dalvik.vm.boot-image: '%s'\n", bootImageBuf);
} else {
@@ -784,7 +788,15 @@
parseRuntimeOption("dalvik.vm.foreground-heap-growth-multiplier",
foregroundHeapGrowthMultiplierOptsBuf,
"-XX:ForegroundHeapGrowthMultiplier=");
-
+ /*
+ * Finalizer and thread suspend timeouts.
+ */
+ parseRuntimeOption("dalvik.vm.finalizer-timeout-ms",
+ finalizerTimeoutMsOptsBuf,
+ "-XX:FinalizerTimeoutMs=");
+ parseRuntimeOption("dalvik.vm.thread-suspend-timeout-ms",
+ threadSuspendTimeoutOptsBuf,
+ "-XX:ThreadSuspendTimeout=");
/*
* JIT related options.
*/
@@ -1424,140 +1436,140 @@
}
static const RegJNIRec gRegJNI[] = {
- REG_JNI(register_com_android_internal_os_RuntimeInit),
- REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
- REG_JNI(register_android_os_SystemClock),
- REG_JNI(register_android_util_EventLog),
- REG_JNI(register_android_util_Log),
- REG_JNI(register_android_util_MemoryIntArray),
- REG_JNI(register_android_util_StatsLog),
- REG_JNI(register_android_util_StatsLogInternal),
- REG_JNI(register_android_app_admin_SecurityLog),
- REG_JNI(register_android_content_AssetManager),
- REG_JNI(register_android_content_StringBlock),
- REG_JNI(register_android_content_XmlBlock),
- REG_JNI(register_android_content_res_ApkAssets),
- REG_JNI(register_android_text_AndroidCharacter),
- REG_JNI(register_android_text_Hyphenator),
- REG_JNI(register_android_view_InputDevice),
- REG_JNI(register_android_view_KeyCharacterMap),
- REG_JNI(register_android_os_Process),
- REG_JNI(register_android_os_SystemProperties),
- REG_JNI(register_android_os_Binder),
- REG_JNI(register_android_os_Parcel),
- REG_JNI(register_android_os_HidlMemory),
- REG_JNI(register_android_os_HidlSupport),
- REG_JNI(register_android_os_HwBinder),
- REG_JNI(register_android_os_HwBlob),
- REG_JNI(register_android_os_HwParcel),
- REG_JNI(register_android_os_HwRemoteBinder),
- REG_JNI(register_android_os_NativeHandle),
- REG_JNI(register_android_os_storage_StorageManager),
- REG_JNI(register_android_os_VintfObject),
- REG_JNI(register_android_os_VintfRuntimeInfo),
- REG_JNI(register_android_service_DataLoaderService),
- REG_JNI(register_android_view_DisplayEventReceiver),
- REG_JNI(register_android_view_RenderNodeAnimator),
- REG_JNI(register_android_view_InputApplicationHandle),
- REG_JNI(register_android_view_InputWindowHandle),
- REG_JNI(register_android_view_Surface),
- REG_JNI(register_android_view_SurfaceControl),
- REG_JNI(register_android_view_SurfaceSession),
- REG_JNI(register_android_view_CompositionSamplingListener),
- REG_JNI(register_android_view_TextureView),
- REG_JNI(register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper),
- REG_JNI(register_com_google_android_gles_jni_EGLImpl),
- REG_JNI(register_com_google_android_gles_jni_GLImpl),
- REG_JNI(register_android_opengl_jni_EGL14),
- REG_JNI(register_android_opengl_jni_EGL15),
- REG_JNI(register_android_opengl_jni_EGLExt),
- REG_JNI(register_android_opengl_jni_GLES10),
- REG_JNI(register_android_opengl_jni_GLES10Ext),
- REG_JNI(register_android_opengl_jni_GLES11),
- REG_JNI(register_android_opengl_jni_GLES11Ext),
- REG_JNI(register_android_opengl_jni_GLES20),
- REG_JNI(register_android_opengl_jni_GLES30),
- REG_JNI(register_android_opengl_jni_GLES31),
- REG_JNI(register_android_opengl_jni_GLES31Ext),
- REG_JNI(register_android_opengl_jni_GLES32),
- REG_JNI(register_android_graphics_classes),
- REG_JNI(register_android_graphics_BLASTBufferQueue),
- REG_JNI(register_android_graphics_GraphicBuffer),
- REG_JNI(register_android_database_CursorWindow),
- REG_JNI(register_android_database_SQLiteConnection),
- REG_JNI(register_android_database_SQLiteGlobal),
- REG_JNI(register_android_database_SQLiteDebug),
- REG_JNI(register_android_os_Debug),
- REG_JNI(register_android_os_FileObserver),
- REG_JNI(register_android_os_GraphicsEnvironment),
- REG_JNI(register_android_os_MessageQueue),
- REG_JNI(register_android_os_SELinux),
- REG_JNI(register_android_os_Trace),
- REG_JNI(register_android_os_UEventObserver),
- REG_JNI(register_android_net_LocalSocketImpl),
- REG_JNI(register_android_net_NetworkUtils),
- REG_JNI(register_android_os_MemoryFile),
- REG_JNI(register_android_os_SharedMemory),
- REG_JNI(register_android_os_incremental_IncrementalManager),
- REG_JNI(register_com_android_internal_os_ClassLoaderFactory),
- REG_JNI(register_com_android_internal_os_Zygote),
- REG_JNI(register_com_android_internal_os_ZygoteInit),
- REG_JNI(register_com_android_internal_util_VirtualRefBasePtr),
- REG_JNI(register_android_hardware_Camera),
- REG_JNI(register_android_hardware_camera2_CameraMetadata),
- 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_HardwareBuffer),
- REG_JNI(register_android_hardware_SensorManager),
- REG_JNI(register_android_hardware_SerialPort),
- REG_JNI(register_android_hardware_UsbDevice),
- REG_JNI(register_android_hardware_UsbDeviceConnection),
- REG_JNI(register_android_hardware_UsbRequest),
- REG_JNI(register_android_hardware_location_ActivityRecognitionHardware),
- REG_JNI(register_android_media_AudioDeviceAddress),
- REG_JNI(register_android_media_AudioEffectDescriptor),
- REG_JNI(register_android_media_AudioSystem),
- REG_JNI(register_android_media_AudioRecord),
- REG_JNI(register_android_media_AudioTrack),
- REG_JNI(register_android_media_AudioAttributes),
- REG_JNI(register_android_media_AudioProductStrategies),
- REG_JNI(register_android_media_AudioVolumeGroups),
- REG_JNI(register_android_media_AudioVolumeGroupChangeHandler),
- REG_JNI(register_android_media_MediaMetrics),
- REG_JNI(register_android_media_MicrophoneInfo),
- REG_JNI(register_android_media_RemoteDisplay),
- REG_JNI(register_android_media_ToneGenerator),
- REG_JNI(register_android_media_midi),
+ REG_JNI(register_com_android_internal_os_RuntimeInit),
+ REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
+ REG_JNI(register_android_os_SystemClock),
+ REG_JNI(register_android_util_EventLog),
+ REG_JNI(register_android_util_Log),
+ REG_JNI(register_android_util_MemoryIntArray),
+ REG_JNI(register_android_util_StatsLog),
+ REG_JNI(register_android_util_StatsLogInternal),
+ REG_JNI(register_android_app_admin_SecurityLog),
+ REG_JNI(register_android_content_AssetManager),
+ REG_JNI(register_android_content_StringBlock),
+ REG_JNI(register_android_content_XmlBlock),
+ REG_JNI(register_android_content_res_ApkAssets),
+ REG_JNI(register_android_text_AndroidCharacter),
+ REG_JNI(register_android_text_Hyphenator),
+ REG_JNI(register_android_view_InputDevice),
+ REG_JNI(register_android_view_KeyCharacterMap),
+ REG_JNI(register_android_os_Process),
+ REG_JNI(register_android_os_SystemProperties),
+ REG_JNI(register_android_os_Binder),
+ REG_JNI(register_android_os_Parcel),
+ REG_JNI(register_android_os_HidlMemory),
+ REG_JNI(register_android_os_HidlSupport),
+ REG_JNI(register_android_os_HwBinder),
+ REG_JNI(register_android_os_HwBlob),
+ REG_JNI(register_android_os_HwParcel),
+ REG_JNI(register_android_os_HwRemoteBinder),
+ REG_JNI(register_android_os_NativeHandle),
+ REG_JNI(register_android_os_storage_StorageManager),
+ REG_JNI(register_android_os_VintfObject),
+ REG_JNI(register_android_os_VintfRuntimeInfo),
+ REG_JNI(register_android_service_DataLoaderService),
+ REG_JNI(register_android_view_DisplayEventReceiver),
+ REG_JNI(register_android_view_RenderNodeAnimator),
+ REG_JNI(register_android_view_InputApplicationHandle),
+ REG_JNI(register_android_view_InputWindowHandle),
+ REG_JNI(register_android_view_Surface),
+ REG_JNI(register_android_view_SurfaceControl),
+ REG_JNI(register_android_view_SurfaceSession),
+ REG_JNI(register_android_view_CompositionSamplingListener),
+ REG_JNI(register_android_view_TextureView),
+ REG_JNI(register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper),
+ REG_JNI(register_com_google_android_gles_jni_EGLImpl),
+ REG_JNI(register_com_google_android_gles_jni_GLImpl),
+ REG_JNI(register_android_opengl_jni_EGL14),
+ REG_JNI(register_android_opengl_jni_EGL15),
+ REG_JNI(register_android_opengl_jni_EGLExt),
+ REG_JNI(register_android_opengl_jni_GLES10),
+ REG_JNI(register_android_opengl_jni_GLES10Ext),
+ REG_JNI(register_android_opengl_jni_GLES11),
+ REG_JNI(register_android_opengl_jni_GLES11Ext),
+ REG_JNI(register_android_opengl_jni_GLES20),
+ REG_JNI(register_android_opengl_jni_GLES30),
+ REG_JNI(register_android_opengl_jni_GLES31),
+ REG_JNI(register_android_opengl_jni_GLES31Ext),
+ REG_JNI(register_android_opengl_jni_GLES32),
+ REG_JNI(register_android_graphics_classes),
+ REG_JNI(register_android_graphics_BLASTBufferQueue),
+ REG_JNI(register_android_graphics_GraphicBuffer),
+ REG_JNI(register_android_database_CursorWindow),
+ REG_JNI(register_android_database_SQLiteConnection),
+ REG_JNI(register_android_database_SQLiteGlobal),
+ REG_JNI(register_android_database_SQLiteDebug),
+ REG_JNI(register_android_os_Debug),
+ REG_JNI(register_android_os_FileObserver),
+ REG_JNI(register_android_os_GraphicsEnvironment),
+ REG_JNI(register_android_os_MessageQueue),
+ REG_JNI(register_android_os_SELinux),
+ REG_JNI(register_android_os_Trace),
+ REG_JNI(register_android_os_UEventObserver),
+ REG_JNI(register_android_net_LocalSocketImpl),
+ REG_JNI(register_android_net_NetworkUtils),
+ REG_JNI(register_android_os_MemoryFile),
+ REG_JNI(register_android_os_SharedMemory),
+ REG_JNI(register_android_os_incremental_IncrementalManager),
+ REG_JNI(register_com_android_internal_os_ClassLoaderFactory),
+ REG_JNI(register_com_android_internal_os_Zygote),
+ REG_JNI(register_com_android_internal_os_ZygoteInit),
+ REG_JNI(register_com_android_internal_util_VirtualRefBasePtr),
+ REG_JNI(register_android_hardware_Camera),
+ REG_JNI(register_android_hardware_camera2_CameraMetadata),
+ 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_HardwareBuffer),
+ REG_JNI(register_android_hardware_SensorManager),
+ REG_JNI(register_android_hardware_SerialPort),
+ REG_JNI(register_android_hardware_UsbDevice),
+ REG_JNI(register_android_hardware_UsbDeviceConnection),
+ REG_JNI(register_android_hardware_UsbRequest),
+ REG_JNI(register_android_hardware_location_ActivityRecognitionHardware),
+ REG_JNI(register_android_media_AudioDevice),
+ REG_JNI(register_android_media_AudioEffectDescriptor),
+ REG_JNI(register_android_media_AudioSystem),
+ REG_JNI(register_android_media_AudioRecord),
+ REG_JNI(register_android_media_AudioTrack),
+ REG_JNI(register_android_media_AudioAttributes),
+ REG_JNI(register_android_media_AudioProductStrategies),
+ REG_JNI(register_android_media_AudioVolumeGroups),
+ REG_JNI(register_android_media_AudioVolumeGroupChangeHandler),
+ REG_JNI(register_android_media_MediaMetrics),
+ REG_JNI(register_android_media_MicrophoneInfo),
+ REG_JNI(register_android_media_RemoteDisplay),
+ REG_JNI(register_android_media_ToneGenerator),
+ REG_JNI(register_android_media_midi),
- REG_JNI(register_android_opengl_classes),
- REG_JNI(register_android_server_NetworkManagementSocketTagger),
- REG_JNI(register_android_ddm_DdmHandleNativeHeap),
- REG_JNI(register_android_backup_BackupDataInput),
- REG_JNI(register_android_backup_BackupDataOutput),
- REG_JNI(register_android_backup_FileBackupHelperBase),
- REG_JNI(register_android_backup_BackupHelperDispatcher),
- REG_JNI(register_android_app_backup_FullBackup),
- REG_JNI(register_android_app_Activity),
- REG_JNI(register_android_app_ActivityThread),
- REG_JNI(register_android_app_NativeActivity),
- REG_JNI(register_android_util_jar_StrictJarFile),
- REG_JNI(register_android_view_InputChannel),
- REG_JNI(register_android_view_InputEventReceiver),
- REG_JNI(register_android_view_InputEventSender),
- REG_JNI(register_android_view_InputQueue),
- REG_JNI(register_android_view_KeyEvent),
- REG_JNI(register_android_view_MotionEvent),
- REG_JNI(register_android_view_PointerIcon),
- REG_JNI(register_android_view_VelocityTracker),
+ REG_JNI(register_android_opengl_classes),
+ REG_JNI(register_android_server_NetworkManagementSocketTagger),
+ REG_JNI(register_android_ddm_DdmHandleNativeHeap),
+ REG_JNI(register_android_backup_BackupDataInput),
+ REG_JNI(register_android_backup_BackupDataOutput),
+ REG_JNI(register_android_backup_FileBackupHelperBase),
+ REG_JNI(register_android_backup_BackupHelperDispatcher),
+ REG_JNI(register_android_app_backup_FullBackup),
+ REG_JNI(register_android_app_Activity),
+ REG_JNI(register_android_app_ActivityThread),
+ REG_JNI(register_android_app_NativeActivity),
+ REG_JNI(register_android_util_jar_StrictJarFile),
+ REG_JNI(register_android_view_InputChannel),
+ REG_JNI(register_android_view_InputEventReceiver),
+ REG_JNI(register_android_view_InputEventSender),
+ REG_JNI(register_android_view_InputQueue),
+ REG_JNI(register_android_view_KeyEvent),
+ REG_JNI(register_android_view_MotionEvent),
+ REG_JNI(register_android_view_PointerIcon),
+ REG_JNI(register_android_view_VelocityTracker),
- REG_JNI(register_android_content_res_ObbScanner),
- REG_JNI(register_android_content_res_Configuration),
+ REG_JNI(register_android_content_res_ObbScanner),
+ REG_JNI(register_android_content_res_Configuration),
- REG_JNI(register_android_animation_PropertyValuesHolder),
- REG_JNI(register_android_security_Scrypt),
- REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
- REG_JNI(register_com_android_internal_os_FuseAppLoop),
+ REG_JNI(register_android_animation_PropertyValuesHolder),
+ REG_JNI(register_android_security_Scrypt),
+ REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
+ REG_JNI(register_com_android_internal_os_FuseAppLoop),
};
/*
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index 8fc6afa..2a56fd6 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -34,9 +34,9 @@
#include <hwui/MinikinSkia.h>
#include <hwui/Typeface.h>
-#include <utils/FatVector.h>
#include <minikin/FontFamily.h>
#include <minikin/LocaleList.h>
+#include <ui/FatVector.h>
#include <memory>
@@ -109,7 +109,7 @@
static bool addSkTypeface(NativeFamilyBuilder* builder, sk_sp<SkData>&& data, int ttcIndex,
jint weight, jint italic) {
- uirenderer::FatVector<SkFontArguments::Axis, 2> skiaAxes;
+ FatVector<SkFontArguments::Axis, 2> skiaAxes;
for (const auto& axis : builder->axes) {
skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value});
}
diff --git a/core/jni/android/graphics/GraphicsStatsService.cpp b/core/jni/android/graphics/GraphicsStatsService.cpp
new file mode 100644
index 0000000..ef0aacc
--- /dev/null
+++ b/core/jni/android/graphics/GraphicsStatsService.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GraphicsStatsService"
+
+#include <JankTracker.h>
+#include <jni.h>
+#include <log/log.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/ScopedUtfChars.h>
+#include <service/GraphicsStatsService.h>
+#include <stats_event.h>
+#include <stats_pull_atom_callback.h>
+#include <statslog.h>
+#include "core_jni_helpers.h"
+
+namespace android {
+
+using namespace android::uirenderer;
+
+static jint getAshmemSize(JNIEnv*, jobject) {
+ return sizeof(ProfileData);
+}
+
+static jlong createDump(JNIEnv*, jobject, jint fd, jboolean isProto) {
+ GraphicsStatsService::Dump* dump =
+ GraphicsStatsService::createDump(fd,
+ isProto ? GraphicsStatsService::DumpType::Protobuf
+ : GraphicsStatsService::DumpType::Text);
+ return reinterpret_cast<jlong>(dump);
+}
+
+static void addToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath, jstring jpackage,
+ jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) {
+ std::string path;
+ const ProfileData* data = nullptr;
+ LOG_ALWAYS_FATAL_IF(jdata == nullptr && jpath == nullptr, "Path and data can't both be null");
+ ScopedByteArrayRO buffer{env};
+ if (jdata != nullptr) {
+ buffer.reset(jdata);
+ LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData),
+ "Buffer size %zu doesn't match expected %zu!", buffer.size(),
+ sizeof(ProfileData));
+ data = reinterpret_cast<const ProfileData*>(buffer.get());
+ }
+ if (jpath != nullptr) {
+ ScopedUtfChars pathChars(env, jpath);
+ LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(),
+ "Failed to get path chars");
+ path.assign(pathChars.c_str(), pathChars.size());
+ }
+ ScopedUtfChars packageChars(env, jpackage);
+ LOG_ALWAYS_FATAL_IF(packageChars.size() <= 0 || !packageChars.c_str(),
+ "Failed to get path chars");
+ GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
+ LOG_ALWAYS_FATAL_IF(!dump, "null passed for dump pointer");
+
+ const std::string package(packageChars.c_str(), packageChars.size());
+ GraphicsStatsService::addToDump(dump, path, package, versionCode, startTime, endTime, data);
+}
+
+static void addFileToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath) {
+ ScopedUtfChars pathChars(env, jpath);
+ LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), "Failed to get path chars");
+ const std::string path(pathChars.c_str(), pathChars.size());
+ GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
+ GraphicsStatsService::addToDump(dump, path);
+}
+
+static void finishDump(JNIEnv*, jobject, jlong dumpPtr) {
+ GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
+ GraphicsStatsService::finishDump(dump);
+}
+
+static void finishDumpInMemory(JNIEnv* env, jobject, jlong dumpPtr, jlong pulledData,
+ jboolean lastFullDay) {
+ GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
+ AStatsEventList* data = reinterpret_cast<AStatsEventList*>(pulledData);
+ GraphicsStatsService::finishDumpInMemory(dump, data, lastFullDay == JNI_TRUE);
+}
+
+static void saveBuffer(JNIEnv* env, jobject clazz, jstring jpath, jstring jpackage,
+ jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) {
+ ScopedByteArrayRO buffer(env, jdata);
+ LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData),
+ "Buffer size %zu doesn't match expected %zu!", buffer.size(),
+ sizeof(ProfileData));
+ ScopedUtfChars pathChars(env, jpath);
+ LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), "Failed to get path chars");
+ ScopedUtfChars packageChars(env, jpackage);
+ LOG_ALWAYS_FATAL_IF(packageChars.size() <= 0 || !packageChars.c_str(),
+ "Failed to get path chars");
+
+ const std::string path(pathChars.c_str(), pathChars.size());
+ const std::string package(packageChars.c_str(), packageChars.size());
+ const ProfileData* data = reinterpret_cast<const ProfileData*>(buffer.get());
+ GraphicsStatsService::saveBuffer(path, package, versionCode, startTime, endTime, data);
+}
+
+static jobject gGraphicsStatsServiceObject = nullptr;
+static jmethodID gGraphicsStatsService_pullGraphicsStatsMethodID;
+
+static JNIEnv* getJNIEnv() {
+ JavaVM* vm = AndroidRuntime::getJavaVM();
+ JNIEnv* env = nullptr;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ if (vm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
+ LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!");
+ }
+ }
+ return env;
+}
+
+// graphicsStatsPullCallback is invoked by statsd service to pull GRAPHICS_STATS atom.
+static AStatsManager_PullAtomCallbackReturn graphicsStatsPullCallback(int32_t atom_tag,
+ AStatsEventList* data,
+ void* cookie) {
+ JNIEnv* env = getJNIEnv();
+ if (!env) {
+ return false;
+ }
+ if (gGraphicsStatsServiceObject == nullptr) {
+ ALOGE("Failed to get graphicsstats service");
+ return AStatsManager_PULL_SKIP;
+ }
+
+ for (bool lastFullDay : {true, false}) {
+ env->CallVoidMethod(gGraphicsStatsServiceObject,
+ gGraphicsStatsService_pullGraphicsStatsMethodID,
+ (jboolean)(lastFullDay ? JNI_TRUE : JNI_FALSE),
+ reinterpret_cast<jlong>(data));
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ ALOGE("Failed to invoke graphicsstats service");
+ return AStatsManager_PULL_SKIP;
+ }
+ }
+ return AStatsManager_PULL_SUCCESS;
+}
+
+// Register a puller for GRAPHICS_STATS atom with the statsd service.
+static void nativeInit(JNIEnv* env, jobject javaObject) {
+ gGraphicsStatsServiceObject = env->NewGlobalRef(javaObject);
+ AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
+ AStatsManager_PullAtomMetadata_setCoolDownNs(metadata, 10 * 1000000); // 10 milliseconds
+ AStatsManager_PullAtomMetadata_setTimeoutNs(metadata, 2 * NS_PER_SEC); // 2 seconds
+
+ AStatsManager_registerPullAtomCallback(android::util::GRAPHICS_STATS,
+ &graphicsStatsPullCallback, metadata, nullptr);
+
+ AStatsManager_PullAtomMetadata_release(metadata);
+}
+
+static void nativeDestructor(JNIEnv* env, jobject javaObject) {
+ AStatsManager_unregisterPullAtomCallback(android::util::GRAPHICS_STATS);
+ env->DeleteGlobalRef(gGraphicsStatsServiceObject);
+ gGraphicsStatsServiceObject = nullptr;
+}
+
+static const JNINativeMethod sMethods[] =
+ {{"nGetAshmemSize", "()I", (void*)getAshmemSize},
+ {"nCreateDump", "(IZ)J", (void*)createDump},
+ {"nAddToDump", "(JLjava/lang/String;Ljava/lang/String;JJJ[B)V", (void*)addToDump},
+ {"nAddToDump", "(JLjava/lang/String;)V", (void*)addFileToDump},
+ {"nFinishDump", "(J)V", (void*)finishDump},
+ {"nFinishDumpInMemory", "(JJZ)V", (void*)finishDumpInMemory},
+ {"nSaveBuffer", "(Ljava/lang/String;Ljava/lang/String;JJJ[B)V", (void*)saveBuffer},
+ {"nativeInit", "()V", (void*)nativeInit},
+ {"nativeDestructor", "()V", (void*)nativeDestructor}};
+
+int register_android_graphics_GraphicsStatsService(JNIEnv* env) {
+ jclass graphicsStatsService_class =
+ FindClassOrDie(env, "android/graphics/GraphicsStatsService");
+ gGraphicsStatsService_pullGraphicsStatsMethodID =
+ GetMethodIDOrDie(env, graphicsStatsService_class, "pullGraphicsStats", "(ZJ)V");
+ return jniRegisterNativeMethods(env, "android/graphics/GraphicsStatsService", sMethods,
+ NELEM(sMethods));
+}
+
+} // namespace android
diff --git a/core/jni/android/graphics/fonts/Font.cpp b/core/jni/android/graphics/fonts/Font.cpp
index bb0654d..8d84e87 100644
--- a/core/jni/android/graphics/fonts/Font.cpp
+++ b/core/jni/android/graphics/fonts/Font.cpp
@@ -33,8 +33,8 @@
#include <hwui/MinikinSkia.h>
#include <hwui/Typeface.h>
-#include <utils/FatVector.h>
#include <minikin/FontFamily.h>
+#include <ui/FatVector.h>
#include <memory>
@@ -157,7 +157,7 @@
sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize,
release_global_ref, reinterpret_cast<void*>(fontRef)));
- uirenderer::FatVector<SkFontArguments::Axis, 2> skiaAxes;
+ FatVector<SkFontArguments::Axis, 2> skiaAxes;
for (const auto& axis : builder->axes) {
skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value});
}
diff --git a/core/jni/android_media_AudioDevice.cpp b/core/jni/android_media_AudioDevice.cpp
new file mode 100644
index 0000000..f6a0e4b
--- /dev/null
+++ b/core/jni/android_media_AudioDevice.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#include "android_media_AudioDevice.h"
+#include "android_media_AudioErrors.h"
+#include "core_jni_helpers.h"
+
+#include <media/AudioDeviceTypeAddr.h>
+
+using namespace android;
+
+static jclass gAudioDeviceClass;
+static jmethodID gAudioDeviceCstor;
+
+namespace android {
+
+jint createAudioDeviceFromNative(JNIEnv *env, jobject *jAudioDevice,
+ const AudioDeviceTypeAddr *devTypeAddr) {
+ jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
+ jint jNativeType = (jint)devTypeAddr->mType;
+ ScopedLocalRef<jstring> jAddress(env, env->NewStringUTF(devTypeAddr->mAddress.data()));
+
+ *jAudioDevice =
+ env->NewObject(gAudioDeviceClass, gAudioDeviceCstor, jNativeType, jAddress.get());
+
+ return jStatus;
+}
+
+} // namespace android
+
+int register_android_media_AudioDevice(JNIEnv *env) {
+ jclass audioDeviceTypeAddressClass = FindClassOrDie(env, "android/media/AudioDevice");
+ gAudioDeviceClass = MakeGlobalRefOrDie(env, audioDeviceTypeAddressClass);
+ gAudioDeviceCstor =
+ GetMethodIDOrDie(env, audioDeviceTypeAddressClass, "<init>", "(ILjava/lang/String;)V");
+
+ return 0;
+}
diff --git a/core/jni/android_media_AudioDeviceAddress.h b/core/jni/android_media_AudioDevice.h
similarity index 71%
rename from core/jni/android_media_AudioDeviceAddress.h
rename to core/jni/android_media_AudioDevice.h
index c66b179..fc92334 100644
--- a/core/jni/android_media_AudioDeviceAddress.h
+++ b/core/jni/android_media_AudioDevice.h
@@ -14,20 +14,20 @@
* limitations under the License.
*/
-#ifndef ANDROID_MEDIA_AUDIODEVICEADDRESS_H
-#define ANDROID_MEDIA_AUDIODEVICEADDRESS_H
+#ifndef ANDROID_MEDIA_AUDIODEVICE_H
+#define ANDROID_MEDIA_AUDIODEVICE_H
-#include <system/audio.h>
#include <media/AudioDeviceTypeAddr.h>
+#include <system/audio.h>
#include "jni.h"
namespace android {
-// Create a Java AudioDeviceAddress instance from a C++ AudioDeviceTypeAddress
+// Create a Java AudioDevice instance from a C++ AudioDeviceTypeAddress
-extern jint createAudioDeviceAddressFromNative(JNIEnv *env, jobject *jAudioDeviceAddress,
- const AudioDeviceTypeAddr *devTypeAddr);
+extern jint createAudioDeviceFromNative(JNIEnv *env, jobject *jAudioDevice,
+ const AudioDeviceTypeAddr *devTypeAddr);
} // namespace android
#endif
\ No newline at end of file
diff --git a/core/jni/android_media_AudioDeviceAddress.cpp b/core/jni/android_media_AudioDeviceAddress.cpp
deleted file mode 100644
index 5f39f7e..0000000
--- a/core/jni/android_media_AudioDeviceAddress.cpp
+++ /dev/null
@@ -1,53 +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.
- */
-
-#include "core_jni_helpers.h"
-#include "android_media_AudioDeviceAddress.h"
-#include "android_media_AudioErrors.h"
-
-#include <media/AudioDeviceTypeAddr.h>
-
-using namespace android;
-
-static jclass gAudioDeviceAddressClass;
-static jmethodID gAudioDeviceAddressCstor;
-
-namespace android {
-
-jint createAudioDeviceAddressFromNative(
- JNIEnv *env, jobject *jAudioDeviceAddress,
- const AudioDeviceTypeAddr *devTypeAddr) {
- jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
- jint jNativeType = (jint)devTypeAddr->mType;
- ScopedLocalRef<jstring> jAddress(env, env->NewStringUTF(devTypeAddr->mAddress.data()));
-
- *jAudioDeviceAddress = env->NewObject(gAudioDeviceAddressClass, gAudioDeviceAddressCstor,
- jNativeType, jAddress.get());
-
- return jStatus;
-}
-
-}
-
-int register_android_media_AudioDeviceAddress(JNIEnv *env)
-{
- jclass audioDeviceTypeAddressClass = FindClassOrDie(env, "android/media/AudioDeviceAddress");
- gAudioDeviceAddressClass = MakeGlobalRefOrDie(env, audioDeviceTypeAddressClass);
- gAudioDeviceAddressCstor = GetMethodIDOrDie(env, audioDeviceTypeAddressClass, "<init>",
- "(ILjava/lang/String;)V");
-
- return 0;
-}
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 0156e23..b4590f4 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -26,12 +26,6 @@
#include <nativehelper/JNIHelp.h>
#include "core_jni_helpers.h"
-#include "android_media_AudioAttributes.h"
-#include "android_media_AudioDeviceAddress.h"
-#include "android_media_AudioEffectDescriptor.h"
-#include "android_media_AudioErrors.h"
-#include "android_media_AudioFormat.h"
-#include "android_media_MicrophoneInfo.h"
#include <audiomanager/AudioManager.h>
#include <media/AudioPolicy.h>
#include <media/AudioSystem.h>
@@ -39,6 +33,12 @@
#include <nativehelper/ScopedLocalRef.h>
#include <system/audio.h>
#include <system/audio_policy.h>
+#include "android_media_AudioAttributes.h"
+#include "android_media_AudioDevice.h"
+#include "android_media_AudioEffectDescriptor.h"
+#include "android_media_AudioErrors.h"
+#include "android_media_AudioFormat.h"
+#include "android_media_MicrophoneInfo.h"
// ----------------------------------------------------------------------------
@@ -2349,7 +2349,7 @@
jint strategy, jobjectArray jDeviceArray)
{
if (jDeviceArray == nullptr || env->GetArrayLength(jDeviceArray) != 1) {
- ALOGE("%s invalid array to store AudioDeviceAddress", __FUNCTION__);
+ ALOGE("%s invalid array to store AudioDevice", __FUNCTION__);
return (jint)AUDIO_JAVA_BAD_VALUE;
}
@@ -2359,10 +2359,10 @@
if (status != NO_ERROR) {
return (jint) status;
}
- jobject jAudioDeviceAddress = NULL;
- jint jStatus = createAudioDeviceAddressFromNative(env, &jAudioDeviceAddress, &elDevice);
+ jobject jAudioDevice = NULL;
+ jint jStatus = createAudioDeviceFromNative(env, &jAudioDevice, &elDevice);
if (jStatus == AUDIO_JAVA_SUCCESS) {
- env->SetObjectArrayElement(jDeviceArray, 0, jAudioDeviceAddress);
+ env->SetObjectArrayElement(jDeviceArray, 0, jAudioDevice);
}
return jStatus;
}
@@ -2377,7 +2377,7 @@
// with reverse JNI to make the array grow as need as this would be less efficient, and some
// components call this method often
if (jDeviceArray == nullptr || maxResultSize == 0) {
- ALOGE("%s invalid array to store AudioDeviceAddress", __FUNCTION__);
+ ALOGE("%s invalid array to store AudioDevice", __FUNCTION__);
return (jint)AUDIO_JAVA_BAD_VALUE;
}
@@ -2398,105 +2398,133 @@
return AUDIO_JAVA_INVALID_OPERATION;
}
size_t index = 0;
- jobject jAudioDeviceAddress = NULL;
+ jobject jAudioDevice = NULL;
for (const auto& device : devices) {
- jStatus = createAudioDeviceAddressFromNative(env, &jAudioDeviceAddress, &device);
+ jStatus = createAudioDeviceFromNative(env, &jAudioDevice, &device);
if (jStatus != AUDIO_JAVA_SUCCESS) {
return jStatus;
}
- env->SetObjectArrayElement(jDeviceArray, index++, jAudioDeviceAddress);
+ env->SetObjectArrayElement(jDeviceArray, index++, jAudioDevice);
}
return jStatus;
}
// ----------------------------------------------------------------------------
-static const JNINativeMethod gMethods[] = {
- {"setParameters", "(Ljava/lang/String;)I", (void *)android_media_AudioSystem_setParameters},
- {"getParameters", "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_AudioSystem_getParameters},
- {"muteMicrophone", "(Z)I", (void *)android_media_AudioSystem_muteMicrophone},
- {"isMicrophoneMuted", "()Z", (void *)android_media_AudioSystem_isMicrophoneMuted},
- {"isStreamActive", "(II)Z", (void *)android_media_AudioSystem_isStreamActive},
- {"isStreamActiveRemotely","(II)Z", (void *)android_media_AudioSystem_isStreamActiveRemotely},
- {"isSourceActive", "(I)Z", (void *)android_media_AudioSystem_isSourceActive},
- {"newAudioSessionId", "()I", (void *)android_media_AudioSystem_newAudioSessionId},
- {"newAudioPlayerId", "()I", (void *)android_media_AudioSystem_newAudioPlayerId},
- {"newAudioRecorderId", "()I", (void *)android_media_AudioSystem_newAudioRecorderId},
- {"setDeviceConnectionState", "(IILjava/lang/String;Ljava/lang/String;I)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
- {"getDeviceConnectionState", "(ILjava/lang/String;)I", (void *)android_media_AudioSystem_getDeviceConnectionState},
- {"handleDeviceConfigChange", "(ILjava/lang/String;Ljava/lang/String;I)I", (void *)android_media_AudioSystem_handleDeviceConfigChange},
- {"setPhoneState", "(I)I", (void *)android_media_AudioSystem_setPhoneState},
- {"setForceUse", "(II)I", (void *)android_media_AudioSystem_setForceUse},
- {"getForceUse", "(I)I", (void *)android_media_AudioSystem_getForceUse},
- {"initStreamVolume", "(III)I", (void *)android_media_AudioSystem_initStreamVolume},
- {"setStreamVolumeIndex","(III)I", (void *)android_media_AudioSystem_setStreamVolumeIndex},
- {"getStreamVolumeIndex","(II)I", (void *)android_media_AudioSystem_getStreamVolumeIndex},
- {"setVolumeIndexForAttributes","(Landroid/media/AudioAttributes;II)I", (void *)android_media_AudioSystem_setVolumeIndexForAttributes},
- {"getVolumeIndexForAttributes","(Landroid/media/AudioAttributes;I)I", (void *)android_media_AudioSystem_getVolumeIndexForAttributes},
- {"getMinVolumeIndexForAttributes","(Landroid/media/AudioAttributes;)I", (void *)android_media_AudioSystem_getMinVolumeIndexForAttributes},
- {"getMaxVolumeIndexForAttributes","(Landroid/media/AudioAttributes;)I", (void *)android_media_AudioSystem_getMaxVolumeIndexForAttributes},
- {"setMasterVolume", "(F)I", (void *)android_media_AudioSystem_setMasterVolume},
- {"getMasterVolume", "()F", (void *)android_media_AudioSystem_getMasterVolume},
- {"setMasterMute", "(Z)I", (void *)android_media_AudioSystem_setMasterMute},
- {"getMasterMute", "()Z", (void *)android_media_AudioSystem_getMasterMute},
- {"setMasterMono", "(Z)I", (void *)android_media_AudioSystem_setMasterMono},
- {"getMasterMono", "()Z", (void *)android_media_AudioSystem_getMasterMono},
- {"setMasterBalance", "(F)I", (void *)android_media_AudioSystem_setMasterBalance},
- {"getMasterBalance", "()F", (void *)android_media_AudioSystem_getMasterBalance},
- {"getDevicesForStream", "(I)I", (void *)android_media_AudioSystem_getDevicesForStream},
- {"getPrimaryOutputSamplingRate", "()I", (void *)android_media_AudioSystem_getPrimaryOutputSamplingRate},
- {"getPrimaryOutputFrameCount", "()I", (void *)android_media_AudioSystem_getPrimaryOutputFrameCount},
- {"getOutputLatency", "(I)I", (void *)android_media_AudioSystem_getOutputLatency},
- {"setLowRamDevice", "(ZJ)I", (void *)android_media_AudioSystem_setLowRamDevice},
- {"checkAudioFlinger", "()I", (void *)android_media_AudioSystem_checkAudioFlinger},
- {"listAudioPorts", "(Ljava/util/ArrayList;[I)I",
- (void *)android_media_AudioSystem_listAudioPorts},
- {"createAudioPatch", "([Landroid/media/AudioPatch;[Landroid/media/AudioPortConfig;[Landroid/media/AudioPortConfig;)I",
- (void *)android_media_AudioSystem_createAudioPatch},
- {"releaseAudioPatch", "(Landroid/media/AudioPatch;)I",
- (void *)android_media_AudioSystem_releaseAudioPatch},
- {"listAudioPatches", "(Ljava/util/ArrayList;[I)I",
- (void *)android_media_AudioSystem_listAudioPatches},
- {"setAudioPortConfig", "(Landroid/media/AudioPortConfig;)I",
- (void *)android_media_AudioSystem_setAudioPortConfig},
- {"startAudioSource", "(Landroid/media/AudioPortConfig;Landroid/media/AudioAttributes;)I",
- (void *)android_media_AudioSystem_startAudioSource},
- {"stopAudioSource", "(I)I", (void *)android_media_AudioSystem_stopAudioSource},
- {"getAudioHwSyncForSession", "(I)I",
- (void *)android_media_AudioSystem_getAudioHwSyncForSession},
- {"registerPolicyMixes", "(Ljava/util/ArrayList;Z)I",
- (void *)android_media_AudioSystem_registerPolicyMixes},
- {"setUidDeviceAffinities", "(I[I[Ljava/lang/String;)I",
- (void *)android_media_AudioSystem_setUidDeviceAffinities},
- {"removeUidDeviceAffinities", "(I)I",
- (void *)android_media_AudioSystem_removeUidDeviceAffinities},
- {"native_register_dynamic_policy_callback", "()V",
- (void *)android_media_AudioSystem_registerDynPolicyCallback},
- {"native_register_recording_callback", "()V",
- (void *)android_media_AudioSystem_registerRecordingCallback},
- {"systemReady", "()I", (void *)android_media_AudioSystem_systemReady},
- {"getStreamVolumeDB", "(III)F", (void *)android_media_AudioSystem_getStreamVolumeDB},
- {"native_is_offload_supported", "(IIIII)Z", (void *)android_media_AudioSystem_isOffloadSupported},
- {"getMicrophones", "(Ljava/util/ArrayList;)I", (void *)android_media_AudioSystem_getMicrophones},
- {"getSurroundFormats", "(Ljava/util/Map;Z)I", (void *)android_media_AudioSystem_getSurroundFormats},
- {"setSurroundFormatEnabled", "(IZ)I", (void *)android_media_AudioSystem_setSurroundFormatEnabled},
- {"setAssistantUid", "(I)I", (void *)android_media_AudioSystem_setAssistantUid},
- {"setA11yServicesUids", "([I)I", (void *)android_media_AudioSystem_setA11yServicesUids},
- {"isHapticPlaybackSupported", "()Z", (void *)android_media_AudioSystem_isHapticPlaybackSupported},
- {"getHwOffloadEncodingFormatsSupportedForA2DP", "(Ljava/util/ArrayList;)I",
- (void*)android_media_AudioSystem_getHwOffloadEncodingFormatsSupportedForA2DP},
- {"setSupportedSystemUsages", "([I)I", (void *)android_media_AudioSystem_setSupportedSystemUsages},
- {"setAllowedCapturePolicy", "(II)I", (void *)android_media_AudioSystem_setAllowedCapturePolicy},
- {"setRttEnabled", "(Z)I", (void *)android_media_AudioSystem_setRttEnabled},
- {"setAudioHalPids", "([I)I", (void *)android_media_AudioSystem_setAudioHalPids},
- {"isCallScreeningModeSupported", "()Z", (void *)android_media_AudioSystem_isCallScreeningModeSupported},
- {"setPreferredDeviceForStrategy", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setPreferredDeviceForStrategy},
- {"removePreferredDeviceForStrategy", "(I)I", (void *)android_media_AudioSystem_removePreferredDeviceForStrategy},
- {"getPreferredDeviceForStrategy", "(I[Landroid/media/AudioDeviceAddress;)I", (void *)android_media_AudioSystem_getPreferredDeviceForStrategy},
- {"getDevicesForAttributes", "(Landroid/media/AudioAttributes;[Landroid/media/AudioDeviceAddress;)I", (void *)android_media_AudioSystem_getDevicesForAttributes},
- {"setUserIdDeviceAffinities", "(I[I[Ljava/lang/String;)I", (void *)android_media_AudioSystem_setUserIdDeviceAffinities},
- {"removeUserIdDeviceAffinities", "(I)I", (void *)android_media_AudioSystem_removeUserIdDeviceAffinities}
-};
+static const JNINativeMethod gMethods[] =
+ {{"setParameters", "(Ljava/lang/String;)I",
+ (void *)android_media_AudioSystem_setParameters},
+ {"getParameters", "(Ljava/lang/String;)Ljava/lang/String;",
+ (void *)android_media_AudioSystem_getParameters},
+ {"muteMicrophone", "(Z)I", (void *)android_media_AudioSystem_muteMicrophone},
+ {"isMicrophoneMuted", "()Z", (void *)android_media_AudioSystem_isMicrophoneMuted},
+ {"isStreamActive", "(II)Z", (void *)android_media_AudioSystem_isStreamActive},
+ {"isStreamActiveRemotely", "(II)Z",
+ (void *)android_media_AudioSystem_isStreamActiveRemotely},
+ {"isSourceActive", "(I)Z", (void *)android_media_AudioSystem_isSourceActive},
+ {"newAudioSessionId", "()I", (void *)android_media_AudioSystem_newAudioSessionId},
+ {"newAudioPlayerId", "()I", (void *)android_media_AudioSystem_newAudioPlayerId},
+ {"newAudioRecorderId", "()I", (void *)android_media_AudioSystem_newAudioRecorderId},
+ {"setDeviceConnectionState", "(IILjava/lang/String;Ljava/lang/String;I)I",
+ (void *)android_media_AudioSystem_setDeviceConnectionState},
+ {"getDeviceConnectionState", "(ILjava/lang/String;)I",
+ (void *)android_media_AudioSystem_getDeviceConnectionState},
+ {"handleDeviceConfigChange", "(ILjava/lang/String;Ljava/lang/String;I)I",
+ (void *)android_media_AudioSystem_handleDeviceConfigChange},
+ {"setPhoneState", "(I)I", (void *)android_media_AudioSystem_setPhoneState},
+ {"setForceUse", "(II)I", (void *)android_media_AudioSystem_setForceUse},
+ {"getForceUse", "(I)I", (void *)android_media_AudioSystem_getForceUse},
+ {"initStreamVolume", "(III)I", (void *)android_media_AudioSystem_initStreamVolume},
+ {"setStreamVolumeIndex", "(III)I", (void *)android_media_AudioSystem_setStreamVolumeIndex},
+ {"getStreamVolumeIndex", "(II)I", (void *)android_media_AudioSystem_getStreamVolumeIndex},
+ {"setVolumeIndexForAttributes", "(Landroid/media/AudioAttributes;II)I",
+ (void *)android_media_AudioSystem_setVolumeIndexForAttributes},
+ {"getVolumeIndexForAttributes", "(Landroid/media/AudioAttributes;I)I",
+ (void *)android_media_AudioSystem_getVolumeIndexForAttributes},
+ {"getMinVolumeIndexForAttributes", "(Landroid/media/AudioAttributes;)I",
+ (void *)android_media_AudioSystem_getMinVolumeIndexForAttributes},
+ {"getMaxVolumeIndexForAttributes", "(Landroid/media/AudioAttributes;)I",
+ (void *)android_media_AudioSystem_getMaxVolumeIndexForAttributes},
+ {"setMasterVolume", "(F)I", (void *)android_media_AudioSystem_setMasterVolume},
+ {"getMasterVolume", "()F", (void *)android_media_AudioSystem_getMasterVolume},
+ {"setMasterMute", "(Z)I", (void *)android_media_AudioSystem_setMasterMute},
+ {"getMasterMute", "()Z", (void *)android_media_AudioSystem_getMasterMute},
+ {"setMasterMono", "(Z)I", (void *)android_media_AudioSystem_setMasterMono},
+ {"getMasterMono", "()Z", (void *)android_media_AudioSystem_getMasterMono},
+ {"setMasterBalance", "(F)I", (void *)android_media_AudioSystem_setMasterBalance},
+ {"getMasterBalance", "()F", (void *)android_media_AudioSystem_getMasterBalance},
+ {"getDevicesForStream", "(I)I", (void *)android_media_AudioSystem_getDevicesForStream},
+ {"getPrimaryOutputSamplingRate", "()I",
+ (void *)android_media_AudioSystem_getPrimaryOutputSamplingRate},
+ {"getPrimaryOutputFrameCount", "()I",
+ (void *)android_media_AudioSystem_getPrimaryOutputFrameCount},
+ {"getOutputLatency", "(I)I", (void *)android_media_AudioSystem_getOutputLatency},
+ {"setLowRamDevice", "(ZJ)I", (void *)android_media_AudioSystem_setLowRamDevice},
+ {"checkAudioFlinger", "()I", (void *)android_media_AudioSystem_checkAudioFlinger},
+ {"listAudioPorts", "(Ljava/util/ArrayList;[I)I",
+ (void *)android_media_AudioSystem_listAudioPorts},
+ {"createAudioPatch",
+ "([Landroid/media/AudioPatch;[Landroid/media/AudioPortConfig;[Landroid/media/"
+ "AudioPortConfig;)I",
+ (void *)android_media_AudioSystem_createAudioPatch},
+ {"releaseAudioPatch", "(Landroid/media/AudioPatch;)I",
+ (void *)android_media_AudioSystem_releaseAudioPatch},
+ {"listAudioPatches", "(Ljava/util/ArrayList;[I)I",
+ (void *)android_media_AudioSystem_listAudioPatches},
+ {"setAudioPortConfig", "(Landroid/media/AudioPortConfig;)I",
+ (void *)android_media_AudioSystem_setAudioPortConfig},
+ {"startAudioSource", "(Landroid/media/AudioPortConfig;Landroid/media/AudioAttributes;)I",
+ (void *)android_media_AudioSystem_startAudioSource},
+ {"stopAudioSource", "(I)I", (void *)android_media_AudioSystem_stopAudioSource},
+ {"getAudioHwSyncForSession", "(I)I",
+ (void *)android_media_AudioSystem_getAudioHwSyncForSession},
+ {"registerPolicyMixes", "(Ljava/util/ArrayList;Z)I",
+ (void *)android_media_AudioSystem_registerPolicyMixes},
+ {"setUidDeviceAffinities", "(I[I[Ljava/lang/String;)I",
+ (void *)android_media_AudioSystem_setUidDeviceAffinities},
+ {"removeUidDeviceAffinities", "(I)I",
+ (void *)android_media_AudioSystem_removeUidDeviceAffinities},
+ {"native_register_dynamic_policy_callback", "()V",
+ (void *)android_media_AudioSystem_registerDynPolicyCallback},
+ {"native_register_recording_callback", "()V",
+ (void *)android_media_AudioSystem_registerRecordingCallback},
+ {"systemReady", "()I", (void *)android_media_AudioSystem_systemReady},
+ {"getStreamVolumeDB", "(III)F", (void *)android_media_AudioSystem_getStreamVolumeDB},
+ {"native_is_offload_supported", "(IIIII)Z",
+ (void *)android_media_AudioSystem_isOffloadSupported},
+ {"getMicrophones", "(Ljava/util/ArrayList;)I",
+ (void *)android_media_AudioSystem_getMicrophones},
+ {"getSurroundFormats", "(Ljava/util/Map;Z)I",
+ (void *)android_media_AudioSystem_getSurroundFormats},
+ {"setSurroundFormatEnabled", "(IZ)I",
+ (void *)android_media_AudioSystem_setSurroundFormatEnabled},
+ {"setAssistantUid", "(I)I", (void *)android_media_AudioSystem_setAssistantUid},
+ {"setA11yServicesUids", "([I)I", (void *)android_media_AudioSystem_setA11yServicesUids},
+ {"isHapticPlaybackSupported", "()Z",
+ (void *)android_media_AudioSystem_isHapticPlaybackSupported},
+ {"getHwOffloadEncodingFormatsSupportedForA2DP", "(Ljava/util/ArrayList;)I",
+ (void *)android_media_AudioSystem_getHwOffloadEncodingFormatsSupportedForA2DP},
+ {"setSupportedSystemUsages", "([I)I",
+ (void *)android_media_AudioSystem_setSupportedSystemUsages},
+ {"setAllowedCapturePolicy", "(II)I",
+ (void *)android_media_AudioSystem_setAllowedCapturePolicy},
+ {"setRttEnabled", "(Z)I", (void *)android_media_AudioSystem_setRttEnabled},
+ {"setAudioHalPids", "([I)I", (void *)android_media_AudioSystem_setAudioHalPids},
+ {"isCallScreeningModeSupported", "()Z",
+ (void *)android_media_AudioSystem_isCallScreeningModeSupported},
+ {"setPreferredDeviceForStrategy", "(IILjava/lang/String;)I",
+ (void *)android_media_AudioSystem_setPreferredDeviceForStrategy},
+ {"removePreferredDeviceForStrategy", "(I)I",
+ (void *)android_media_AudioSystem_removePreferredDeviceForStrategy},
+ {"getPreferredDeviceForStrategy", "(I[Landroid/media/AudioDevice;)I",
+ (void *)android_media_AudioSystem_getPreferredDeviceForStrategy},
+ {"getDevicesForAttributes",
+ "(Landroid/media/AudioAttributes;[Landroid/media/AudioDevice;)I",
+ (void *)android_media_AudioSystem_getDevicesForAttributes},
+ {"setUserIdDeviceAffinities", "(I[I[Ljava/lang/String;)I",
+ (void *)android_media_AudioSystem_setUserIdDeviceAffinities},
+ {"removeUserIdDeviceAffinities", "(I)I",
+ (void *)android_media_AudioSystem_removeUserIdDeviceAffinities}};
static const JNINativeMethod gEventHandlerMethods[] = {
{"native_setup",
diff --git a/core/proto/android/app/appexitinfo.proto b/core/proto/android/app/appexitinfo.proto
index e23f150..6a49220 100644
--- a/core/proto/android/app/appexitinfo.proto
+++ b/core/proto/android/app/appexitinfo.proto
@@ -178,8 +178,8 @@
}
optional Importance importance = 10;
- optional int32 pss = 11;
- optional int32 rss = 12;
+ optional int64 pss = 11;
+ optional int64 rss = 12;
optional int64 timestamp = 13;
optional string description = 14;
}
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index fc0a2ef..4625418 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -708,6 +708,12 @@
// ACTION: Deny "Access all files" for an app
APP_SPECIAL_PERMISSION_MANAGE_EXT_STRG_DENY = 1731;
+
+ // ACTION: Battery feature usage
+ ACTION_BATTERY_OPTION_FEATURE_USAGE = 1732;
+
+ // ACTION: Battery feature runtime event
+ ACTION_BATTERY_OPTION_RUNTIME_EVENT = 1733;
}
/**
@@ -2578,4 +2584,11 @@
// CATEGORY: SETTINGS
// OS: R
CONNECTION_DEVICE_ADVANCED_NFC = 1828;
+
+ // OPEN: Settings -> Apps & Notifications -> Special App Access
+ INTERACT_ACROSS_PROFILES = 1829;
+
+ // OPEN: Settings > Notifications > (app or conversations) > conversation
+ NOTIFICATION_CONVERSATION_SETTINGS = 1830;
+
}
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 303d62d..546c5a0 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -219,12 +219,8 @@
// The maximum number of background jobs we allow when the system is in a
// critical memory state.
optional int32 bg_critical_job_count = 14;
- // The maximum number of times we allow a job to have itself rescheduled
- // before giving up on it, for standard jobs.
- optional int32 max_standard_reschedule_count = 15;
- // The maximum number of times we allow a job to have itself rescheduled
- // before giving up on it, for jobs that are executing work.
- optional int32 max_work_reschedule_count = 16;
+ reserved 15; // max_standard_reschedule_count
+ reserved 16; // max_work_reschedule_count
// The minimum backoff time to allow for linear backoff.
optional int64 min_linear_backoff_time_ms = 17;
// The minimum backoff time to allow for exponential backoff.
diff --git a/core/proto/android/service/OWNERS b/core/proto/android/service/OWNERS
new file mode 100644
index 0000000..70cb50f
--- /dev/null
+++ b/core/proto/android/service/OWNERS
@@ -0,0 +1 @@
+per-file sensor_service.proto = arthuri@google.com, bduddie@google.com, stange@google.com
diff --git a/core/proto/android/service/sensor_service.proto b/core/proto/android/service/sensor_service.proto
index 8598f86..48f6670 100644
--- a/core/proto/android/service/sensor_service.proto
+++ b/core/proto/android/service/sensor_service.proto
@@ -39,7 +39,7 @@
OP_MODE_RESTRICTED = 2;
OP_MODE_DATA_INJECTION = 3;
}
-
+ optional sint32 init_status = 16;
optional int64 current_time_ms = 1;
optional SensorDeviceProto sensor_device = 2;
optional SensorListProto sensors = 3;
@@ -56,6 +56,8 @@
repeated SensorEventConnectionProto active_connections = 13;
repeated SensorDirectConnectionProto direct_connections = 14;
repeated SensorRegistrationInfoProto previous_registrations = 15;
+
+ // Next tag: 17
}
// Proto dump of android::SensorDevice
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6d63a53..ff69671 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1535,7 +1535,7 @@
@hide
-->
<permission android:name="android.permission.ACCESS_CONTEXT_HUB"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature|privileged" />
<uses-permission android:name="android.permission.ACCESS_CONTEXT_HUB"/>
<!-- @SystemApi Allows an application to create mock location providers for testing.
diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml
index 46e8f64..b01eb39 100644
--- a/core/res/res/drawable-nodpi/platlogo.xml
+++ b/core/res/res/drawable-nodpi/platlogo.xml
@@ -1,31 +1,50 @@
-<!--
-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="240dp"
- android:height="240dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
+ android:width="512dp"
+ android:height="512dp"
+ android:viewportWidth="512"
+ android:viewportHeight="512">
<path
- android:fillColor="#000"
- android:pathData="M16 4c-2.2 0-4 1.8-4 4v4H4V8c0-2.2 1.8-4 4-4h8z"/>
+ android:fillColor="#F86734"
+ android:pathData="M416.23 236.62h-10.67c-1.46 0-2.65-1.19-2.65-2.65v-9.85c0-1.47 1.19-2.65 2.65-2.65h23.37c1.47 0 2.66 1.19 2.66 2.65v66.9c0 1.46-1.2 2.65-2.66 2.65H418.9c-1.47 0-2.66-1.19-2.66-2.65v-54.4z"/>
<path
- android:fillColor="#000"
- android:pathData="M8 20c2.2 0 4-1.8 4-4v-4H4v8h4z"/>
+ android:fillColor="#F86734"
+ android:pathData="M455.51 236.62h-10.67c-1.47 0-2.65-1.19-2.65-2.65v-9.85c0-1.47 1.18-2.65 2.65-2.65h23.37c1.47 0 2.66 1.19 2.66 2.65v66.9c0 1.46-1.2 2.65-2.66 2.65h-10.05c-1.46 0-2.65-1.19-2.65-2.65v-54.4z"/>
<path
- android:fillColor="#80000000"
- android:pathData="M16 12c2.2 0 4-1.8 4-4V4h-8v8h4z"/>
+ android:fillColor="#D6F0FF"
+ android:pathData="M364.12 400.25a4.34 4.34 0 1 0 0 8.68a4.34 4.34 0 1 0 0-8.68z"/>
+ <path
+ android:fillColor="#D6F0FF"
+ android:pathData="M275.46 433.53a4.84 4.84 0 1 0 0 9.68a4.84 4.84 0 1 0 0-9.68z"/>
+ <path
+ android:fillColor="#D6F0FF"
+ android:pathData="M184.52 418.83a5.36 5.36 0 1 0 0 10.72a5.36 5.36 0 1 0 0-10.72z"/>
+ <path
+ android:fillColor="#D6F0FF"
+ android:pathData="M110.42 359.19a5.89 5.89 0 1 0 0 11.78a5.89 5.89 0 1 0 0-11.78z"/>
+ <path
+ android:fillColor="#D6F0FF"
+ android:pathData="M75.94 270.17a6.43 6.43 0 1 0 0 12.86a6.43 6.43 0 1 0 0-12.86z"/>
+ <path
+ android:fillColor="#D6F0FF"
+ android:pathData="M89.48 178.57a6.98 6.98 0 1 0 0 13.96a6.98 6.98 0 1 0 0-13.96z"/>
+ <path
+ android:fillColor="#D6F0FF"
+ android:pathData="M147.97 103.54a7.54 7.54 0 1 0 0 15.08a7.54 7.54 0 1 0 0-15.08z"/>
+ <path
+ android:fillColor="#D6F0FF"
+ android:pathData="M236.63 66.7a8.1 8.1 0 1 0 0 16.2a8.1 8.1 0 1 0 0-16.2z"/>
+ <path
+ android:fillColor="#D6F0FF"
+ android:pathData="M327.09 78.3a8.66 8.66 0 1 0 0 17.32a8.66 8.66 0 1 0 0-17.32z"/>
+ <path
+ android:fillColor="#D6F0FF"
+ android:pathData="M401.05 136.97a9.22 9.22 0 1 0 0 18.44a9.22 9.22 0 1 0 0-18.44z"/>
+ <group>
+ <path
+ android:fillColor="#3DDB85"
+ android:pathData="M255.45 129.46a128.11 128.11 0 1 0 0 256.22a128.11 128.11 0 1 0 0-256.22z"/>
+ <path
+ android:fillColor="#FFF"
+ android:pathData="M339.23 236.09a21.48 21.48 0 1 0 0 42.96a21.48 21.48 0 1 0 0-42.96z"/>
+ </group>
</vector>
-
diff --git a/core/res/res/drawable-nodpi/stat_sys_adb.xml b/core/res/res/drawable-nodpi/stat_sys_adb.xml
index 0e9aab2..700781b 100644
--- a/core/res/res/drawable-nodpi/stat_sys_adb.xml
+++ b/core/res/res/drawable-nodpi/stat_sys_adb.xml
@@ -1,17 +1,17 @@
-<!--
-Copyright (C) 2020 The Android Open Source Project
+<?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
+ 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
+ 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.
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
@@ -19,12 +19,22 @@
android:viewportWidth="24"
android:viewportHeight="24">
<path
- android:fillColor="#000"
- android:pathData="M16 4c-2.2 0-4 1.8-4 4v4H4V8c0-2.2 1.8-4 4-4h8z"/>
- <path
- android:fillColor="#000"
- android:pathData="M8 20c2.2 0 4-1.8 4-4v-4H4v8h4z"/>
- <path
- android:fillColor="#80000000"
- android:pathData="M16 12c2.2 0 4-1.8 4-4V4h-8v8h4z"/>
+ android:fillColor="#FFFFFF"
+ android:pathData="
+M 12,1
+A 11 11 0 0 0 1,12
+A 11 11 0 1 0 12,1
+Z
+
+M 12.5,8
+a 3,3 0 0 1 6,0
+a 3,3 0 0 1 -6,0
+Z
+
+M 5.5,8
+a 3,3 0 0 1 6,0
+l 0,8
+a 3,3 0 0 1 -6,0
+Z
+"/>
</vector>
diff --git a/core/res/res/drawable/tab_indicator_resolver.xml b/core/res/res/drawable/tab_indicator_resolver.xml
new file mode 100644
index 0000000..ff16d81a
--- /dev/null
+++ b/core/res/res/drawable/tab_indicator_resolver.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.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+ android:paddingMode="nest">
+ <item>
+ <ripple android:color="@color/tab_highlight_material">
+ <item android:id="@id/mask">
+ <color android:color="@color/white" />
+ </item>
+ </ripple>
+ </item>
+ <item android:gravity="bottom">
+ <shape android:shape="rectangle"
+ android:tint="@color/resolver_tabs_active_color">
+ <size android:height="2dp" />
+ <solid android:color="@color/tab_indicator_material" />
+ </shape>
+ </item>
+ <item android:bottom="2dp"
+ android:drawable="@color/transparent" />
+</layer-list>
diff --git a/core/res/res/layout/tab_indicator_resolver.xml b/core/res/res/layout/tab_indicator_resolver.xml
new file mode 100644
index 0000000..2038da6
--- /dev/null
+++ b/core/res/res/layout/tab_indicator_resolver.xml
@@ -0,0 +1,38 @@
+<?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_height="?android:attr/actionBarSize"
+ android:orientation="horizontal"
+ style="@android:style/Widget.Material.Resolver.Tab">
+
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:visibility="gone" />
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:textAllCaps="false"
+ style="@android:style/Widget.Material.TabText" />
+
+</LinearLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index d6c5a13..5e89533 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Skakel werkprofiel aan?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Jou werkprogramme, kennisgewings, data en ander werkprofielkenmerke sal aangeskakel word"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Skakel aan"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Program is nie beskikbaar nie"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is nie op die oomblik beskikbaar nie."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Hierdie program is vir \'n ouer weergawe van Android gebou en sal dalk nie behoorlik werk nie. Probeer kyk vir opdaterings, of kontak die ontwikkelaar."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Kyk vir opdatering"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Jy het nuwe boodskappe"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index e9409fb..b637a63 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ይህ መተግበሪያ ለቆየ የAndroid ስሪት ነው የተገነባው፣ እና በአግባቡ ላይሰራ ይችላል። ዝማኔዎች ካሉ ለመመልከት ይሞክሩ፣ ወይም ደግሞ ገንቢውን ያነጋግሩ።"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ዝማኔ ካለ አረጋግጥ"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"አዲስ መልዕክቶች አለዎት"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 23ffd7b..002d61e 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -915,7 +915,7 @@
<string name="factorytest_no_action" msgid="339252838115675515">"لم يتم العثور على أي حزمة توفر إجراء FACTORY_TEST."</string>
<string name="factorytest_reboot" msgid="2050147445567257365">"إعادة تشغيل"</string>
<string name="js_dialog_title" msgid="7464775045615023241">"تعرض الصفحة في \"<xliff:g id="TITLE">%s</xliff:g>\":"</string>
- <string name="js_dialog_title_default" msgid="3769524569903332476">"جافا سكريبت"</string>
+ <string name="js_dialog_title_default" msgid="3769524569903332476">"JavaScript"</string>
<string name="js_dialog_before_unload_title" msgid="7012587995876771246">"تأكيد الانتقال"</string>
<string name="js_dialog_before_unload_positive_button" msgid="4274257182303565509">"مغادرة هذه الصفحة"</string>
<string name="js_dialog_before_unload_negative_button" msgid="3873765747622415310">"البقاء في هذه الصفحة"</string>
@@ -1395,7 +1395,7 @@
<string name="test_harness_mode_notification_message" msgid="3039123743127958420">"يمكنك إجراء إعادة ضبط على الإعدادات الأصلية لإيقاف وضع \"مفعِّل اختبار\"."</string>
<string name="console_running_notification_title" msgid="6087888939261635904">"وحدة التحكّم التسلسلية مفعّلة"</string>
<string name="console_running_notification_message" msgid="7892751888125174039">"الأداء متأثر. لإيقاف وحدة التحكّم، تحقّق من برنامج الإقلاع."</string>
- <string name="usb_contaminant_detected_title" msgid="4359048603069159678">"السوائل والشوائب في منفذ USB"</string>
+ <string name="usb_contaminant_detected_title" msgid="4359048603069159678">"السوائل أو الشوائب في منفذ USB"</string>
<string name="usb_contaminant_detected_message" msgid="7346100585390795743">"تمّ إيقاف منفذ USB تلقائيًا. انقُر لمعرفة المزيد من المعلومات."</string>
<string name="usb_contaminant_not_detected_title" msgid="2651167729563264053">"مسموح باستخدام منفذ USB"</string>
<string name="usb_contaminant_not_detected_message" msgid="892863190942660462">"لم يَعُد الهاتف يكتشف سوائل أو شوائب."</string>
@@ -1981,6 +1981,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"تمّ إنشاء هذا التطبيق لإصدار قديم من Android وقد لا يعمل بشكل صحيح. جرِّب البحث عن تحديثات أو الاتصال بمطوّر البرامج."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"البحث عن تحديث"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"لديك رسائل جديدة"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index a09c377..bdf8fcf 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"এই এপটো Androidৰ এটা পুৰণা সংস্কৰণৰ বাবে প্ৰস্তুত কৰা হৈছিল, আৰু ই বিচৰাধৰণে কাম নকৰিবও পাৰে। ইয়াৰ আপডে’ট আছে নেকি চাওক, বা বিকাশকৰ্তাৰ সৈতে যোগাযোগ কৰক।"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"আপডে’ট আছে নেকি চাওক"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"আপুনি নতুন বার্তা লাভ কৰিছে"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index b1209b1..6f13024 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"İş profili aktiv edilsin?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"İş tətbiqləri, bildirişləri, data və digər iş profili funksiyaları aktiv ediləcək"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivləşdirin"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Tətbiq əlçatan deyil"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> hazırda əlçatan deyil."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Bu tətbiq köhnə Android versiyası üçün hazırlanıb və düzgün işləməyə bilər. Güncəlləməni yoxlayın və ya developer ilə əlaqə saxlayın."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Güncəlləməni yoxlayın"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Yeni mesajlarınız var"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 5600882..862495a 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1885,6 +1885,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Da uključimo profil za Work?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Uključiće se poslovne aplikacije, obaveštenja, podaci i druge funkcije profila za Work"</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> trenutno nije dostupna."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ova aplikacija je napravljena za stariju verziju Android-a, pa možda neće raditi ispravno. Potražite ažuriranja ili kontaktirajte programera."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Potraži ažuriranje"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Imate nove poruke"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index fb80e4b..8a02da2 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1917,6 +1917,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Гэта праграма была створана для больш старой версіі Android і можа не працаваць належным чынам. Праверце наяўнасць абнаўленняў або звярніцеся да распрацоўшчыка."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Праверыць на наяўнасць абнаўленняў"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"У вас ёсць новыя паведамленні"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 2892853..f7830c7 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Това приложение бе създадено за по-стара версия на Android и може да не работи правилно. Опитайте да проверите за актуализации или се свържете с програмиста."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Проверка за актуализация"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Имате нови съобщения"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 4c95081..af50b33 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1297,7 +1297,7 @@
<string name="no_permissions" msgid="5729199278862516390">"কোনো অনুমতির প্রয়োজন নেই"</string>
<string name="perm_costs_money" msgid="749054595022779685">"এর জন্য অর্থপ্রদান করতে হতে পারে"</string>
<string name="dlg_ok" msgid="5103447663504839312">"ঠিক আছে"</string>
- <string name="usb_charging_notification_title" msgid="1674124518282666955">"এই ডিভাইসটি USB এর মাধ্যমে চার্জ করুন"</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>
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"এই অ্যাপটি Android এর একটি পুরনো ভার্সনের জন্য তৈরি করা হয়েছিল, তাই এখানে সেটি ঠিকমতো কাজ নাও করতে পারে। আপডেট পাওয়া যাচ্ছে কিনা দেখুন বা ডেভেলপারের সাথে যোগাযোগ করুন।"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"আপডেট পাওয়া যাচ্ছে কিনা দেখুন"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"আপনার নতুন মেসেজ আছে"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index eaa212d..d436c5f 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1887,6 +1887,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Uključiti radni profil?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Uključit će se poslovne aplikacije, obavještenja, podaci i druge funkcije radnog 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> trenutno nije dostupna."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ova aplikacija je pravljena za stariju verziju Androida i možda neće ispravno raditi. Provjerite jesu li dostupna ažuriranja ili kontaktirajte programera."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Provjeri je li dostupno ažuriranje"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Imate nove poruke"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 0b58cae..f3b416c 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -182,11 +182,11 @@
<item quantity="one">Autoritat de certificació instal·lada</item>
</plurals>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Per un tercer desconegut"</string>
- <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Per l\'administrador del teu perfil professional"</string>
+ <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Per l\'administrador del teu perfil de treball"</string>
<string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Per <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
- <string name="work_profile_deleted" msgid="5891181538182009328">"S\'ha suprimit el perfil professional"</string>
- <string name="work_profile_deleted_details" msgid="3773706828364418016">"Falta l\'aplicació d\'administració del perfil professional o està malmesa. Com a conseqüència, s\'han suprimit el teu perfil professional i les dades relacionades. Contacta amb l\'administrador per obtenir ajuda."</string>
- <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"El teu perfil professional ja no està disponible en aquest dispositiu"</string>
+ <string name="work_profile_deleted" msgid="5891181538182009328">"S\'ha suprimit el perfil de treball"</string>
+ <string name="work_profile_deleted_details" msgid="3773706828364418016">"Falta l\'aplicació d\'administració del perfil de treball o està malmesa. Com a conseqüència, s\'han suprimit el teu perfil de treball i les dades relacionades. Contacta amb l\'administrador per obtenir ajuda."</string>
+ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"El teu perfil de treball ja no està disponible en aquest dispositiu"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Has intentat introduir la contrasenya massa vegades"</string>
<string name="device_ownership_relinquished" msgid="4080886992183195724">"L\'administrador ha cedit el dispositiu per a ús personal"</string>
<string name="network_logging_notification_title" msgid="554983187553845004">"El dispositiu està gestionat"</string>
@@ -280,7 +280,7 @@
<string name="safeMode" msgid="8974401416068943888">"Mode segur"</string>
<string name="android_system_label" msgid="5974767339591067210">"Sistema Android"</string>
<string name="user_owner_label" msgid="8628726904184471211">"Canvia al perfil personal"</string>
- <string name="managed_profile_label" msgid="7316778766973512382">"Canvia al perfil professional"</string>
+ <string name="managed_profile_label" msgid="7316778766973512382">"Canvia al perfil de treball"</string>
<string name="permgrouplab_contacts" msgid="4254143639307316920">"Contactes"</string>
<string name="permgroupdesc_contacts" msgid="9163927941244182567">"accedir als contactes"</string>
<string name="permgrouplab_location" msgid="1858277002233964394">"Ubicació"</string>
@@ -1406,8 +1406,8 @@
<string name="deny" msgid="6632259981847676572">"Denega"</string>
<string name="permission_request_notification_title" msgid="1810025922441048273">"Permís sol·licitat"</string>
<string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"S\'ha sol·licitat permís\nper al compte <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
- <string name="forward_intent_to_owner" msgid="4620359037192871015">"Estàs utilitzant aquesta aplicació fora del perfil professional."</string>
- <string name="forward_intent_to_work" msgid="3620262405636021151">"Estàs utilitzant l\'aplicació al perfil professional."</string>
+ <string name="forward_intent_to_owner" msgid="4620359037192871015">"Estàs utilitzant aquesta aplicació fora del perfil de treball."</string>
+ <string name="forward_intent_to_work" msgid="3620262405636021151">"Estàs utilitzant l\'aplicació al perfil de treball."</string>
<string name="input_method_binding_label" msgid="1166731601721983656">"Mètode d\'introducció de text"</string>
<string name="sync_binding_label" msgid="469249309424662147">"Sincronització"</string>
<string name="accessibility_binding_label" msgid="1974602776545801715">"Accessibilitat"</string>
@@ -1817,7 +1817,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"La sol·licitud SS s\'ha canviat per una videotrucada"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"La sol·licitud SS s\'ha canviat per una sol·licitud USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"S\'ha canviat a una nova sol·licitud SS"</string>
- <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil professional"</string>
+ <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil de treball"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"S\'ha enviat una alerta"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Desplega"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Replega"</string>
@@ -1850,15 +1850,17 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> no està disponible en aquests moments. Aquesta opció es gestiona a <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Més informació"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Reactiva l\'aplicació"</string>
- <string name="work_mode_off_title" msgid="5503291976647976560">"Activar el perfil professional?"</string>
- <string name="work_mode_off_message" msgid="8417484421098563803">"S\'activaran les teves aplicacions de treball, les notificacions, les dades i altres funcions del perfil professional"</string>
+ <string name="work_mode_off_title" msgid="5503291976647976560">"Activar el perfil de treball?"</string>
+ <string name="work_mode_off_message" msgid="8417484421098563803">"S\'activaran les teves aplicacions de treball, les notificacions, les dades i altres funcions del perfil de treball"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activa"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"L\'aplicació no està disponible"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"Ara mateix, <xliff:g id="APP_NAME">%1$s</xliff:g> no està disponible."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Aquesta aplicació es va crear per a una versió antiga d\'Android i pot ser que no funcioni correctament. Prova de cercar actualitzacions o contacta amb el desenvolupador."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Cerca actualitzacions"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Tens missatges nous"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"Obre l\'aplicació d\'SMS per veure\'ls"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"Algunes funcions poden ser limitades"</string>
- <string name="profile_encrypted_detail" msgid="5279730442756849055">"Perfil professional bloquejat"</string>
+ <string name="profile_encrypted_detail" msgid="5279730442756849055">"Perfil de treball bloquejat"</string>
<string name="profile_encrypted_message" msgid="1128512616293157802">"Toca per desbloquejar el perfil"</string>
<string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"S\'ha connectat a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"Toca per veure els fitxers"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 5874c24..754a020 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1917,6 +1917,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Zapnout pracovní profil?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Vaše pracovní aplikace, oznámení, data a ostatní funkce pracovního účtu budou zapnuty"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Zapnout"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Aplikace není k dispozici"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> v tuto chvíli není k dispozici."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Tato aplikace byla vytvořena pro starší verzi systému Android a nemusí fungovat správně. Zkuste vyhledat aktualizace, případně kontaktujte vývojáře."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Zkontrolovat aktualizace"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Máte nové zprávy"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index eb7ad1b..733c7f0 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Skal arbejdsprofilen slås til?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Dine arbejdsapps, notifikationer, data og andre funktioner til din arbejdsprofil deaktiveres"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Slå til"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Appen er ikke tilgængelig"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ikke tilgængelig lige nu."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Denne app er lavet til en ældre version af Android og fungerer muligvis ikke korrekt. Prøv at søge efter opdateringer, eller kontakt udvikleren."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Søg efter opdatering"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Du har nye beskeder"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 6b01af1..9a4c606 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Arbeitsprofil aktivieren?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Deine geschäftlichen Apps, Benachrichtigungen, Daten und andere Funktionen des Arbeitsprofils werden aktiviert"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivieren"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"App ist nicht verfügbar"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ist derzeit nicht verfügbar."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Diese App wurde für eine ältere Android-Version entwickelt und funktioniert möglicherweise nicht mehr richtig. Prüfe, ob Updates verfügbar sind oder kontaktiere den Entwickler."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Auf Updates prüfen"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Du hast neue Nachrichten"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 61ca692..30a8d61 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Αυτή η εφαρμογή δημιουργήθηκε για παλαιότερη έκδοση του Android και μπορεί να μην λειτουργεί σωστά. Δοκιμάστε να ελέγξετε εάν υπάρχουν ενημερώσεις ή επικοινωνήστε με τον προγραμματιστή."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Έλεγχος για ενημέρωση"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Έχετε νέα μηνύματα"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 15a059f..d15fc5a 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Turn on work profile?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Your work apps, notifications, data and other work profile features will be turned on"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"This app was built for an older version of Android and may not work properly. Try checking for updates or contact the developer."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Check for update"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"You have new messages"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index f3ab25a..bec2e34 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Turn on work profile?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Your work apps, notifications, data and other work profile features will be turned on"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"This app was built for an older version of Android and may not work properly. Try checking for updates or contact the developer."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Check for update"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"You have new messages"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 15a059f..d15fc5a 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Turn on work profile?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Your work apps, notifications, data and other work profile features will be turned on"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"This app was built for an older version of Android and may not work properly. Try checking for updates or contact the developer."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Check for update"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"You have new messages"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 15a059f..d15fc5a 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Turn on work profile?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Your work apps, notifications, data and other work profile features will be turned on"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"This app was built for an older version of Android and may not work properly. Try checking for updates or contact the developer."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Check for update"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"You have new messages"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 871e528..42ec932 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Turn on work profile?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Your work apps, notifications, data, and other work profile features will be turned on"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"This app was built for an older version of Android and may not work properly. Try checking for updates, or contact the developer."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Check for update"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"You have new messages"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 1cb9fde..ac555d5 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1853,6 +1853,8 @@
<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_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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Esta app se creó para una versión anterior de Android y es posible que no funcione correctamente. Busca actualizaciones o comunícate con el programador."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Buscar actualización"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Tienes mensajes nuevos"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index d8509a3..190664b 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -802,7 +802,7 @@
<string name="keyguard_password_enter_pin_password_code" msgid="7792964196473964340">"Introduce el código PIN para desbloquear."</string>
<string name="keyguard_password_wrong_pin_code" msgid="8583732939138432793">"Código PIN incorrecto"</string>
<string name="keyguard_label_text" msgid="3841953694564168384">"Para desbloquear el teléfono, pulsa la tecla de menú y, a continuación, pulsa 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="2978165477085612673">"Número de emergencia"</string>
+ <string name="emergency_call_dialog_number_for_display" msgid="2978165477085612673">"Llamada de emergencia"</string>
<string name="lockscreen_carrier_default" msgid="6192313772955399160">"Sin servicio"</string>
<string name="lockscreen_screen_locked" msgid="7364905540516041817">"Pantalla bloqueada"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pulsa la tecla de menú para desbloquear el teléfono o realizar una llamada de emergencia."</string>
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"¿Activar el perfil de trabajo?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Tus aplicaciones, notificaciones, datos y otras funciones del perfil de trabajo se activarán"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activar"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"La aplicación no está disponible"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"En estos momentos, <xliff:g id="APP_NAME">%1$s</xliff:g> no está disponible."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Esta aplicación se ha diseñado para una versión anterior de Android y es posible que no funcione correctamente. Busca actualizaciones o ponte en contacto con el desarrollador."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Buscar actualizaciones"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Tienes mensajes nuevos"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 2148c09..0c302ee 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Kas lülitada tööprofiil sisse?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Teie töörakendused, märguanded, andmed ja muud tööprofiili funktsioonid lülitatakse sisse"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Lülita sisse"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Rakendus ei ole saadaval"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei ole praegu saadaval."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"See rakendus on loodud Androidi vanema versiooni jaoks ega pruugi õigesti töötada. Otsige värskendusi või võtke ühendust arendajaga."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Otsi värskendust"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Teile on uusi sõnumeid"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 07bde5e..e7aedd5 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -517,7 +517,7 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Argazki-bilduma aldatzeko baimena ematen die aplikazioei."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"multimedia-edukien bildumako kokapena irakurri"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Multimedia-edukien bildumako kokapena irakurtzeko baimena ematen die aplikazioei."</string>
- <string name="biometric_dialog_default_title" msgid="5284880398508155088">"Egiaztatu zu zarela"</string>
+ <string name="biometric_dialog_default_title" msgid="5284880398508155088">"Egiaztatu zeu zarela"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biometrikoa ez dago erabilgarri"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Utzi da autentifikazioa"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Ez da ezagutu"</string>
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Laneko profila aktibatu?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Laneko aplikazioak, jakinarazpenak, datuak eta laneko profileko bestelako eginbideak aktibatuko dira"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktibatu"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Aplikazioa ez dago erabilgarri"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ez dago erabilgarri une honetan."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Aplikazioa Android-en bertsio zaharrago baterako sortu zenez, baliteke behar bezala ez funtzionatzea. Bilatu eguneratzerik baden, edo jarri garatzailearekin harremanetan."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Bilatu eguneratzeak"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Mezu berriak dituzu"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index d65357b..9d9a13c 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"این برنامه برای نسخه قدیمیتری از Android ساخته شده است و ممکن است درست کار نکند. وجود بهروزرسانی را بررسی کنید یا با برنامهنویس تماس بگیرید."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"بررسی وجود بهروزرسانی"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"پیامهای جدیدی دارید"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 17b3d33..35cc8b9 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Otetaanko työprofiili käyttöön?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Työsovellukset, ‑ilmoitukset, ‑tiedot ja muut työprofiiliominaisuudet otetaan käyttöön"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ota käyttöön"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Sovellus ei ole käytettävissä"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei ole nyt käytettävissä."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Tämä sovellus on suunniteltu vanhemmalle Android-versiolle eikä välttämättä toimi oikein. Kokeile tarkistaa päivitykset tai ottaa yhteyttä kehittäjään."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Tarkista päivitykset"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Sinulle on uusia viestejä"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 45b8613..caec9fa 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Activer le profil professionnel?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Vos applications professionnelles, vos notifications, vos données et les autres fonctionnalités de profil professionnel seront activées"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activer"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"L\'application n\'est pas accessible"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas accessible pour le moment."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Cette application a été conçue pour une ancienne version d\'Android et pourrait ne pas fonctionner correctement. Essayez de vérifier les mises à jour ou communiquez avec son concepteur."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Vérifier la présence de mises à jour"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Vous avez de nouveaux messages"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index c646aeb..601fe43 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Activer profil professionnel ?"</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>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas disponible pour le moment."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Cette application a été conçue pour une ancienne version d\'Android et risque de ne pas fonctionner correctement. Recherchez des mises à jour ou contactez le développeur."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Rechercher une mise à jour"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Vous avez de nouveaux messages"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 2a2d7c4..0aa6277 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Activar o perfil de traballo?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Activaranse as túas aplicacións de traballo, as notificacións, os datos e outras funcións do perfil de traballo"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activar"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"A aplicación non está dispoñible"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"A aplicación <xliff:g id="APP_NAME">%1$s</xliff:g> non está dispoñible neste momento."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Esta aplicación deseñouse para unha versión anterior de Android e quizais non funcione correctamente. Proba a buscar actualizacións ou contacta co programador."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Buscar actualización"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Tes mensaxes novas"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index aab09f7..85bf30e 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"આ ઍપ Androidના જૂના વર્ઝન માટે બનાવવામાં આવ્યું હતું અને તે કદાચ તે યોગ્ય રીતે કાર્ય કરી શકશે નહીં. અપડેટ માટે તપાસવાનો પ્રયાસ કરો અથવા ડેવલપરનો સંપર્ક કરો."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"અપડેટ માટે તપાસો"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"તમારી પાસે નવા સંદેશા છે"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index e1bb060..19e154e 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"यह ऐप्लिकेशन Android के पुराने वर्शन के लिए बनाया गया था, इसलिए हो सकता है कि यह सही से काम न करे. देखें कि अपडेट मौजूद हैं या नहीं, या फिर डेवलपर से संपर्क करें."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"देखें कि अपडेट मौजूद है या नहीं"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"आपके पास नए संदेश हैं"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 3839434..9a9357f 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1885,6 +1885,8 @@
<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_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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ova je aplikacija razvijena za stariju verziju Androida i možda neće funkcionirati pravilno. Potražite ažuriranja ili se obratite razvojnom programeru."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Provjeri ažuriranja"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Imate nove poruke"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index fcea1ec..d4ac7e2 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Bekapcsolja a munkaprofilt?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"A munkahelyi alkalmazások, értesítések, adatok és a munkaprofilhoz tartozó egyéb funkciók be lesznek kapcsolva"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Bekapcsolás"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Az alkalmazás nem hozzáférhető"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> jelenleg nem hozzáférhető."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ez az alkalmazás az Android egyik korábbi verziójához készült, így elképzelhető, hogy nem működik majd megfelelően ezen a rendszeren. Keressen frissítéseket, vagy vegye fel a kapcsolatot a fejlesztővel."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Frissítés keresése"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Új üzenetei érkeztek"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index cbd754f..5cd8e8e 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Այս հավելվածը ստեղծվել է Android-ի ավելի հին տարբերակի համար և կարող է պատշաճ չաշխատել: Ստուգեք թարմացումների առկայությունը կամ դիմեք մշակողին:"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Ստուգել նոր տարբերակի առկայությունը"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Դուք ունեք նոր հաղորդագրություններ"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index f1a94ff..3a1571d 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Aktifkan profil kerja?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Aplikasi kerja, notifikasi, data, dan fitur profil kerja lainnya akan diaktifkan"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktifkan"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Aplikasi tidak tersedia"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak tersedia saat ini."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Aplikasi ini dibuat untuk Android versi lama dan mungkin tidak berfungsi sebagaimana mestinya. Coba periksa apakah ada update, atau hubungi developer."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Periksa apakah ada update"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Ada pesan baru"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index b4cb76d3..eddb214 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Kveikja á vinnusniði?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Kveikt verður á vinnuforritum, tilkynningum, gögnum og öðrum eiginleikum vinnusniðsins"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Kveikja"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Forrit er ekki tiltækt"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ekki tiltækt núna."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Þetta forrit var hannað fyrir eldri útgáfu af Android og ekki er víst að það virki eðlilega. Athugaðu hvort uppfærslur séu í boði eða hafðu samband við þróunaraðilann."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Leita að uppfærslu"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Þú ert með ný skilaboð"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 23a62a8..135a226 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Attivare il profilo di lavoro?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Le tue app di lavoro, le notifiche, i dati e altri elementi del profilo di lavoro saranno attivati."</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Attiva"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"L\'app non è disponibile"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> non è al momento disponibile."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Questa app è stata realizzata per una versione precedente di Android e potrebbe non funzionare correttamente. Prova a verificare la disponibilità di aggiornamenti o contatta lo sviluppatore."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Verifica la presenza di aggiornamenti"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Hai nuovi messaggi"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 4319aa8..65b7384 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1917,6 +1917,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"האפליקציה הזו עוצבה לגרסה ישנה יותר של Android וייתכן שלא תפעל כראוי. ניתן לבדוק אם יש עדכונים או ליצור קשר עם המפתח."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"האם יש עדכון חדש?"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"יש לך הודעות חדשות"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 481af76..bda2064 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"仕事用プロファイルの有効化"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"仕事用のアプリ、通知、データなど、仕事用プロファイルの機能が ON になります"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ON にする"</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>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"アップデートを確認"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"新着メッセージがあります"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index c2c28e5..c47b710 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ეს აპი Android-ის ძველი ვერსიისთვის შეიქმნა და შესაძლოა სათანადოდ არ მუშაობდეს. გადაამოწმეთ განახლებები ან დაუკავშირდით დეველოპერს."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"განახლების შემოწმება"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"თქვენ ახალი შეტყობინებები გაქვთ"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 7cb0512..241cf08 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Қолданба Android жүйесінің ескі нұсқасына арналған және дұрыс жұмыс істемеуі мүмкін. Жаңартылған нұсқаны тексеріңіз немесе әзірлеушіге хабарласыңыз."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Жаңартылған нұсқаны тексеру"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Сізде жаңа хабарлар бар"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index e0267d3..483e236 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1855,6 +1855,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"កម្មវិធីនេះត្រូវបានបង្កើតឡើងសម្រាប់កំណែប្រព័ន្ធប្រតិបត្តិការ Android ចាស់ ហើយវាអាចដំណើរការខុសប្រក្រតី។ សូមសាកល្បងពិនិត្យមើលកំណែថ្មី ឬទាក់ទងទៅអ្នកអភិវឌ្ឍន៍។"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"រកមើលកំណែថ្មី"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"អ្នកមានសារថ្មី"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 4a2bc72..7133e89 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ಈ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು Android ನ ಹಳೆಯ ಆವೃತ್ತಿಗೆ ರಚಿಸಲಾಗಿದೆ ಮತ್ತು ಸರಿಯಾಗಿ ಕೆಲಸ ಮಾಡದಿರಬಹುದು. ಅಪ್ಡೇಟ್ಗಳನ್ನು ಪರಿಶೀಲಿಸಲು ಪ್ರಯತ್ನಿಸಿ ಅಥವಾ ಡೆವಲಪರ್ ಅನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ಅಪ್ಡೇಟ್ಗಾಗಿ ಪರಿಶೀಲಿಸಿ"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"ನೀವು ಹೊಸ ಸಂದೇಶಗಳನ್ನು ಹೊಂದಿರುವಿರಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 0ac7a14..12c05ba 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"이 앱은 Android 이전 버전에 맞게 개발되었기 때문에 제대로 작동하지 않을 수 있습니다. 업데이트를 확인하거나 개발자에게 문의하세요."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"업데이트 확인"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"새 메시지 있음"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 88e36ff..ccbf845 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -190,7 +190,7 @@
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Өтө көп жолу сырсөздү киргизүү аракети жасалды"</string>
<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="network_logging_notification_text" msgid="1327373071132562512">"Ишканаңыз бул түзмөктү башкарат жана тармак трафигин көзөмөлдөшү мүмкүн. Чоо-жайын билгиңиз келсе, таптап коюңуз."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Түзмөгүңүз тазаланат"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Түзмөктү башкаруучу колдонмо жараксыз. Түзмөгүңүз азыр тазаланат.\n\nСуроолоруңуз болсо, ишканаңыздын администраторуна кайрылыңыз."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Басып чыгаруу <xliff:g id="OWNER_APP">%s</xliff:g> тарабынан өчүрүлдү."</string>
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Бул колдонмо Android\'дин эски версиясы үчүн иштеп чыгарылган, андыктан туура эмес иштеши мүмкүн. Жаңыртууларды издеп көрүңүз же иштеп чыгуучуга кайрылыңыз."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Жаңыртууну издөө"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Сизге жаңы билдирүүлөр келди"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 63b87ac..e8bda53 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ແອັບນີ້ຖືກສ້າງຂຶ້ນສຳລັບ Android ເວີຊັນທີ່ເກົ່າກວ່າ ແລະ ອາດເຮັດວຽກໄດ້ບໍ່ປົກກະຕິ. ໃຫ້ລອງກວດສອບເບິ່ງອັບເດດ ຫຼື ຕິດຕໍ່ຜູ້ພັດທະນາ."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ກວດເບິ່ງອັບເດດ"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"ທ່ານມີຂໍ້ຄວາມໃໝ່"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index b8d848e..ad90ab3 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1917,6 +1917,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Įjungti darbo profilį?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Darbo programos, pranešimai, duomenys ir kitos darbo profilio funkcijos bus išjungtos"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Įjungti"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Programa nepasiekiama."</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ šiuo metu nepasiekiama."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ši programa sukurta naudoti senesnės versijos sistemoje „Android“ ir gali tinkamai neveikti. Pabandykite patikrinti, ar yra naujinių, arba susisiekite su kūrėju."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Tikrinti, ar yra naujinių"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Turite naujų pranešimų"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index f168bb4..6ffe39a 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1885,6 +1885,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Vai ieslēgt darba profilu?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Tiks ieslēgtas jūsu darba lietotnes, paziņojumi, dati un citas darba profila funkcijas."</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ieslēgt"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Lietotne nav pieejama"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> pašlaik nav pieejama."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Šī lietotne tika izstrādāta vecākai Android versijai un var nedarboties pareizi. Meklējiet atjauninājumus vai sazinieties ar izstrādātāju."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Meklēt atjauninājumu"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Jums ir jaunas īsziņas."</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index f94d191..bb1d9c6 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1855,6 +1855,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Апликацијава е создадена за постара верзија на Android и може да не функционира правилно. Проверете за ажурирања или контактирајте со програмерот."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Проверка за ажурирање"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Имате нови пораки"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 1efd211..31edd8c 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ഈ ആപ്പ് Android-ന്റെ പഴയ പതിപ്പിനായി നിർമ്മിച്ചിരിക്കുന്നതിനാൽ ശരിയായി പ്രവർത്തിച്ചേക്കില്ല. അപ്ഡേറ്റിനായി പരിശോധിക്കുക, അല്ലെങ്കിൽ ഡെവലപ്പറുമായി ബന്ധപ്പെടുക."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"അപ്ഡേറ്റിനായി പരിശോധിക്കുക"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"നിങ്ങൾക്ക് പുതിയ സന്ദേശങ്ങൾ ഉണ്ട്"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index cc03175..eb61a46 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Энэ аппыг Андройдын хуучин хувилбарт зориулсан бөгөөд буруу ажиллаж болзошгүй. Шинэчлэлтийг шалгаж эсвэл хөгжүүлэгчтэй холбогдоно уу."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Шинэчлэлтийг шалгах"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Танд шинэ зурвасууд байна"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index cd9b6fc..0a8f4af 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"हे अॅप Android च्या जुन्या आवृत्ती साठी तयार करण्यात आले होते आणि योग्यरितीने कार्य करू शकणार नाही. अपडेट आहेत का ते तपासून पाहा, किंवा डेव्हलपरशी संपर्क साधण्याचा प्रयत्न करा."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"अपडेट आहे का ते तपासा"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"आपल्याकडे नवीन मेसेज आहेत"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 0a40735..59c7d65 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Hidupkan profil kerja?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Apl kerja, pemberitahuan, data dan ciri profil kerja anda yang lain akan dihidupkan"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Hidupkan"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Apl tidak tersedia"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak tersedia sekarang."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Apl ini dibina untuk versi Android yang lebih lama dan mungkin tidak berfungsi dengan betul. Cuba semak kemas kini atau hubungi pembangun."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Semak kemas kini"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Anda mempunyai mesej baharu"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 9e04841..b3efcb1 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ဤအက်ပ်ကို Android ဗားရှင်းဟောင်းအတွက် ပြုလုပ်ထားခြင်းဖြစ်ပြီး ပုံမှန်အလုပ်မလုပ်နိုင်ပါ။ အပ်ဒိတ်များအတွက် ရှာကြည့်ပါ သို့မဟုတ် ဆော့ဖ်ဝဲအင်ဂျင်နီယာကို ဆက်သွယ်ပါ။"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"အပ်ဒိတ်စစ်ရန်"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"သင့်ထံတွင် စာအသစ်များရောက်နေသည်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 45ab3e5..5a3a588 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Vil du slå på jobbprofilen?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Jobbappene dine samt varsler, data og andre funksjoner i jobbprofilen din blir slått på"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Slå på"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Appen er ikke tilgjengelig"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ikke tilgjengelig for øyeblikket."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Denne appen er utviklet for en eldre versjon av Android og fungerer kanskje ikke som den skal. Prøv å se etter oppdateringer, eller kontakt utvikleren."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Se etter oppdateringer"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Du har nye meldinger"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 11033a7..e95866b 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1859,6 +1859,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"यो अनुप्रयोग Android को पुरानो संस्करणका लागि बनाइएको हुनाले यसले सही ढङ्गले काम नगर्न सक्छ। अद्यावधिकहरू उपलब्ध छन् वा छैनन् भनी जाँच गरी हेर्नुहोस् वा यसको विकासकर्तालाई सम्पर्क गर्नुहोस्।"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"अद्यावधिक उपलब्ध छ वा छैन भनी जाँच गर्नुहोस्"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"तपाईंलाई नयाँ सन्देश आएको छ"</string>
diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml
index c5e72f0..33caeb6 100644
--- a/core/res/res/values-night/colors.xml
+++ b/core/res/res/values-night/colors.xml
@@ -32,4 +32,6 @@
<color name="chooser_row_divider">@color/list_divider_color_dark</color>
<color name="chooser_gradient_background">@color/loading_gradient_background_color_dark</color>
<color name="chooser_gradient_highlight">@color/loading_gradient_highlight_color_dark</color>
+
+ <color name="resolver_tabs_active_color">#FF8AB4F8</color>
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 13f6725..e524c1b 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Werkprofiel inschakelen?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Je werk-apps, meldingen, gegevens en andere functies van je werkprofiel worden uitgeschakeld"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Inschakelen"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"App is niet beschikbaar"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is momenteel niet beschikbaar."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Deze app is ontwikkeld voor een oudere versie van Android en werkt mogelijk niet op de juiste manier. Controleer op updates of neem contact op met de ontwikkelaar."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Controleren op update"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Je hebt nieuwe berichten"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 4424af7..246b4d9 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ଏହି ଆପ୍କୁ Androidର ପୁରୁଣା ଭର୍ସନ୍ ପାଇଁ ନିର୍ମାଣ କରାଯାଇଥିଲା ଏବଂ ଠିକ୍ ଭାବେ କାମ କରିନପାରେ। ଏହାପାଇଁ ଅପଡେଟ୍ ଅଛି କି ନାହିଁ ଯାଞ୍ଚ କରନ୍ତୁ କିମ୍ବା ଡେଭେଲପର୍ଙ୍କ ସହିତ ସମ୍ପର୍କ କରନ୍ତୁ।"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ଅପଡେଟ୍ ପାଇଁ ଯାଞ୍ଚ କରନ୍ତୁ"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"ଆପଣଙ୍କ ପାଖରେ ନୂଆ ମେସେଜ୍ ରହିଛି"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 8c87581..3d68832 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ਇਹ ਐਪ Android ਦੇ ਕਿਸੇ ਵਧੇਰੇ ਪੁਰਾਣੇ ਵਰਜਨ ਲਈ ਬਣਾਈ ਗਈ ਸੀ ਅਤੇ ਸ਼ਾਇਦ ਸਹੀ ਢੰਗ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ। ਅੱਪਡੇਟਾਂ ਲਈ ਜਾਂਚ ਕਰੋ ਜਾਂ ਵਿਕਾਸਕਾਰ ਨਾਲ ਸੰਪਰਕ ਕਰੋ।"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ਅੱਪਡੇਟ ਦੀ ਜਾਂਚ ਕਰੋ"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"ਤੁਹਾਨੂੰ ਨਵੇਂ ਸੁਨੇਹੇ ਪ੍ਰਾਪਤ ਹੋਏ ਹਨ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 5efbfbe..2fb9ac2 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1917,6 +1917,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Włączyć profil służbowy?"</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>
+ <string name="app_blocked_message" msgid="542972921087873023">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest obecnie niedostępna."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ta aplikacja jest na starszą wersję Androida i może nie działać prawidłowo. Sprawdź dostępność aktualizacji lub skontaktuj się z programistą."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Sprawdź dostępność aktualizacji"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Masz nowe wiadomości"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index db48441..1ae0c36 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -509,8 +509,8 @@
<string name="permdesc_manageFingerprint" msgid="2025616816437339865">"Permite que o app execute métodos para adicionar e excluir modelos de impressão digital para uso."</string>
<string name="permlab_useFingerprint" msgid="1001421069766751922">"usar hardware de impressão digital"</string>
<string name="permdesc_useFingerprint" msgid="412463055059323742">"Permite que o app use hardware de impressão digital para autenticação."</string>
- <string name="permlab_audioWrite" msgid="8501705294265669405">"modificar sua coleção de músicas"</string>
- <string name="permdesc_audioWrite" msgid="8057399517013412431">"Permite que o app modifique sua coleção de músicas."</string>
+ <string name="permlab_audioWrite" msgid="8501705294265669405">"modificar sua biblioteca de música"</string>
+ <string name="permdesc_audioWrite" msgid="8057399517013412431">"Permite que o app modifique sua biblioteca de música."</string>
<string name="permlab_videoWrite" msgid="5940738769586451318">"modificar sua coleção de vídeos"</string>
<string name="permdesc_videoWrite" msgid="6124731210613317051">"Permite que o app modifique sua coleção de vídeos."</string>
<string name="permlab_imagesWrite" msgid="1774555086984985578">"modificar sua coleção de fotos"</string>
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Ativar o perfil de trabalho?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Seus apps, notificações, dados e outros recursos do perfil de trabalho serão ativados"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ativar"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"O app não está disponível"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível no momento."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Este app foi criado para uma versão mais antiga do Android e pode não funcionar corretamente. Tente verificar se há atualizações ou entre em contato com o desenvolvedor."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Procurar atualizações"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Você tem mensagens novas"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 04296fe..c381709 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Ativar o perfil de trabalho?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"As aplicações de trabalho, as notificações, os dados e outras funcionalidades do perfil de trabalho serão desativados"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ativar"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"A app não está disponível"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"De momento, a app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Esta aplicação foi concebida para uma versão mais antiga do Android e pode não funcionar corretamente. Experimente verificar se existem atualizações ou contacte o programador."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Verificar se existem atualizações"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Tem mensagens novas"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index db48441..1ae0c36 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -509,8 +509,8 @@
<string name="permdesc_manageFingerprint" msgid="2025616816437339865">"Permite que o app execute métodos para adicionar e excluir modelos de impressão digital para uso."</string>
<string name="permlab_useFingerprint" msgid="1001421069766751922">"usar hardware de impressão digital"</string>
<string name="permdesc_useFingerprint" msgid="412463055059323742">"Permite que o app use hardware de impressão digital para autenticação."</string>
- <string name="permlab_audioWrite" msgid="8501705294265669405">"modificar sua coleção de músicas"</string>
- <string name="permdesc_audioWrite" msgid="8057399517013412431">"Permite que o app modifique sua coleção de músicas."</string>
+ <string name="permlab_audioWrite" msgid="8501705294265669405">"modificar sua biblioteca de música"</string>
+ <string name="permdesc_audioWrite" msgid="8057399517013412431">"Permite que o app modifique sua biblioteca de música."</string>
<string name="permlab_videoWrite" msgid="5940738769586451318">"modificar sua coleção de vídeos"</string>
<string name="permdesc_videoWrite" msgid="6124731210613317051">"Permite que o app modifique sua coleção de vídeos."</string>
<string name="permlab_imagesWrite" msgid="1774555086984985578">"modificar sua coleção de fotos"</string>
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Ativar o perfil de trabalho?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Seus apps, notificações, dados e outros recursos do perfil de trabalho serão ativados"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ativar"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"O app não está disponível"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível no momento."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Este app foi criado para uma versão mais antiga do Android e pode não funcionar corretamente. Tente verificar se há atualizações ou entre em contato com o desenvolvedor."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Procurar atualizações"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Você tem mensagens novas"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 030e76a..7c5b63e 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1885,6 +1885,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Activați profilul de serviciu?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Se vor activa aplicațiile dvs. de serviciu, notificările, datele și alte funcții ale profilului de serviciu"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activați"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Aplicația nu este disponibilă"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu este disponibilă momentan."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Această aplicație a fost creată pentru o versiune Android mai veche și este posibil să nu funcționeze corect. Încercați să căutați actualizări sau contactați dezvoltatorul."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Căutați actualizări"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Aveți mesaje noi"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 94029f5..fa2c9f5 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1177,7 +1177,7 @@
<string name="whichEditApplication" msgid="6191568491456092812">"Редактировать с помощью приложения:"</string>
<string name="whichEditApplicationNamed" msgid="8096494987978521514">"Редактировать с помощью приложения \"%1$s\""</string>
<string name="whichEditApplicationLabel" msgid="1463288652070140285">"Изменить"</string>
- <string name="whichSendApplication" msgid="4143847974460792029">"Отправка данных"</string>
+ <string name="whichSendApplication" msgid="4143847974460792029">"Поделиться"</string>
<string name="whichSendApplicationNamed" msgid="4470386782693183461">"Поделиться через %1$s"</string>
<string name="whichSendApplicationLabel" msgid="7467813004769188515">"Поделиться"</string>
<string name="whichSendToApplication" msgid="77101541959464018">"Выберите приложение"</string>
@@ -1917,6 +1917,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Это приложение было создано для более ранней версии Android и может работать со сбоями. Проверьте наличие обновлений или свяжитесь с разработчиком."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Проверить обновления"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Новые сообщения"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 73cf018..dbe1f22 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1855,6 +1855,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"මෙම යෙදුම Android හි පැරණි අනුවාදයක් සඳහා තනා ඇති අතර නිසියාකාරව ක්රියා නොකරනු ඇත. යාවත්කාලීන සඳහා පරික්ෂා කිරීම උත්සාහ කරන්න, නැතහොත් සංවර්ධක අමතන්න."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"යාවත්කාලීන සඳහා පරික්ෂා කරන්න"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"ඔබට නව පණිවිඩ තිබේ"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index b86fc46..5483efd 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1917,6 +1917,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Zapnúť pracovný profil?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Pracovné aplikácie, upozornenia, dáta a ďalšie funkcie pracovného profilu sa zapnú"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Zapnúť"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Aplikácia nie je dostupná"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> nie je teraz dostupná."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Táto aplikácia bola zostavená pre staršiu verziu Androidu a nemusí správne fungovať. Skúste skontrolovať dostupnosť aktualizácií alebo kontaktovať vývojára."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Skontrolovať dostupnosť aktualizácie"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Máte nové správy."</string>
@@ -1944,7 +1946,7 @@
<string name="app_category_social" msgid="2278269325488344054">"Sociálne siete a komunikácia"</string>
<string name="app_category_news" msgid="1172762719574964544">"Noviny a časopisy"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Mapy a navigácia"</string>
- <string name="app_category_productivity" msgid="1844422703029557883">"Produktivita"</string>
+ <string name="app_category_productivity" msgid="1844422703029557883">"Kancelárske"</string>
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Úložisko zariadenia"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Ladenie cez USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"hodina"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index bc2bc3a..fed39e8 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1917,6 +1917,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Želite vklopiti delovni profil?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Vklopili boste svoje delovne aplikacije, obvestila, podatke in druge funkcije delovnega profila"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Vklop"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija ni na voljo"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno ni na voljo."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ta aplikacija je bila zasnovana za starejšo različico Androida in morda ne bo delovala pravilno. Preverite, ali so na voljo posodobitve, ali pa se obrnite na razvijalca."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Preveri, ali je na voljo posodobitev"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Imate nova sporočila."</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index a353288..ec61fb9 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Të aktivizohet profili i punës?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Aplikacionet e punës, njoftimet, të dhënat e tua dhe funksionet e tjera të profilit të punës do të aktivizohen"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivizo"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Aplikacioni nuk ofrohet"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk ofrohet për momentin."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ky aplikacion është ndërtuar për një version më të vjetër të Android dhe mund të mos funksionojë mirë. Provo të kontrollosh për përditësime ose kontakto me zhvilluesin."</string>
<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>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 8ee644a..e1c4e18 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1885,6 +1885,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Да укључимо профил за Work?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Укључиће се пословне апликације, обавештења, подаци и друге функције профила за Work"</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>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Потражи ажурирање"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Имате нове поруке"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 577933e6..0737b22 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Vill du aktivera jobbprofilen?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Jobbappar, aviseringar, data och andra funktioner i jobbprofilen aktiveras"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivera"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Appen är inte tillgänglig"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> är inte tillgängligt just nu."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Appen har utvecklats för en äldre version av Android och kanske inte fungerar som den ska. Testa att söka efter uppdateringar eller kontakta utvecklaren."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Sök efter uppdateringar"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Du har nya meddelanden"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index a6ee366..3c6b0fa 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Ungependa kuwasha wasifu wa kazini?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Hatua hii itawasha data, arifa, programu za kazini, arifa na vipengele vingine vya wasifu wa kazini"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Washa"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Programu haipatikani"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> haipatikani hivi sasa."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Programu hii iliundwa kwa ajili ya toleo la zamani la Android na huenda isifanye kazi vizuri. Jaribu kuangalia masasisho au uwasiliane na msanidi programu."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Angalia masasisho"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Una ujumbe mpya"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index a56465f..e80f37b 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"இந்த ஆப்ஸ் Android இன் பழைய பதிப்புக்காக உருவாக்கப்பட்டதால், சரியாக வேலை செய்யாமல் போகலாம். புதுப்பிப்புகள் ஏதேனும் உள்ளதா எனப் பார்க்கவும் அல்லது டெவெலப்பரைத் தொடர்புகொள்ளவும்."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"புதுப்பிப்பு உள்ளதா எனப் பார்"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"புதிய செய்திகள் வந்துள்ளன"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 7a0aece..81d4b4f 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ఈ యాప్ పాత వెర్షన్ Android కోసం రూపొందించబడింది మరియు అది సరిగ్గా పని చేయకపోవచ్చు. అప్డేట్ల కోసం తనిఖీ చేయడానికి ప్రయత్నించండి లేదా డెవలపర్ని సంప్రదించండి."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"అప్డేట్ కోసం తనిఖీ చేయండి"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"మీకు కొత్త సందేశాలు ఉన్నాయి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 98f2d88..46530ca 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"แอปนี้สร้างขึ้นเพื่อ Android เวอร์ชันเก่าและอาจทำงานผิดปกติ โปรดลองตรวจหาการอัปเดตหรือติดต่อนักพัฒนาซอฟต์แวร์"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ตรวจสอบอัปเดต"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"คุณมีข้อความใหม่"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index c38a6d5..b9f1f29 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"I-on ang profile sa trabaho?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Mao-on ang iyong mga app sa trabaho, notification, data, at iba pang feature sa profile sa trabaho"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"I-on"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Hindi available ang app"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"Hindi available sa ngayon ang <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ang app na ito ay ginawa para sa mas lumang bersyon ng Android at maaaring hindi gumana nang maayos. Subukang tingnan kung may mga update, o makipag-ugnayan sa developer."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Tingnan kung may update"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Mayroon kang mga bagong mensahe"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 5e09309..81fb079 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"İş profili açılsın mı?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"İş uygulamalarınız, bildirimleriniz, verileriniz ve diğer iş profili özellikleriniz açılacak"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aç"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Uygulama kullanılamıyor"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulaması şu anda kullanılamıyor."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Bu uygulama Android\'in daha eski bir sürümü için oluşturuldu ve düzgün çalışmayabilir. Güncellemeleri kontrol etmeyi deneyin veya geliştiriciyle iletişime geçin."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Güncellemeleri denetle"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Yeni mesajlarınız var"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 1096f97..c71ea74 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1917,6 +1917,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Цей додаток створений для старішої версії Android і може працювати неналежним чином. Спробуйте знайти оновлення або зв’яжіться з розробником."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Шукати оновлення"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"У вас є нові повідомлення"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 4c33191..8a0425b 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"یہ ایپ Android کے پرانے ورژن کے لئے بنائی گئی ہے اور ہو سکتا ہے صحیح طور پر کام نہ کرے۔ اپ ڈیٹس چیک کر کے آزمائیں یا ڈیولپر سے رابطہ کریں۔"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"اپ ڈیٹ چیک کریں"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"آپ کے پاس نئے پیغامات ہیں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 23873b5..b5c31c2 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1853,6 +1853,8 @@
<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_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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Bu ilova eskiroq Android versiyalariga chiqarilgan va xato ishlashi mumkin. Yangilanishlarini tekshiring yoki dasturchi bilan bog‘laning."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Yangilanish borligini tekshirish"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Sizga yangi SMS keldi"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 1ed30d7..970d41f 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1853,6 +1853,8 @@
<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_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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ứng dụng này được xây dựng cho một phiên bản Android cũ hơn và có thể hoạt động không bình thường. Hãy thử kiểm tra các bản cập nhật hoặc liên hệ với nhà phát triển."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Kiểm tra bản cập nhật"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Bạn có tin nhắn mới"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 7671063..c9bba59 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"此应用专为旧版 Android 打造,因此可能无法正常运行。请尝试检查更新或与开发者联系。"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"检查更新"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"您有新消息"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 89bea07..fc652e3 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"此應用程式專為舊版 Android 打造,因此可能無法正常運作。請嘗試檢查更新,或與開發人員聯絡。"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"檢查更新"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"您有新的訊息"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index c95ae37..75d05a2 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1853,6 +1853,8 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"這個應用程式是專為舊版 Android 所打造,因此可能無法正常運作。請嘗試檢查更新,或是與開發人員聯絡。"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"檢查更新"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"你有新訊息"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 0cd669b..0d2abc0 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1853,6 +1853,8 @@
<string name="work_mode_off_title" msgid="5503291976647976560">"Vula iphrofayela yomsebenzi?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Izinhlelo zakho zokusebenza zomsebenzi, izaziso, idatha, nezinye izici zephrofayela yomsebenzi kuzovulwa"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Vula"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"Uhlelo lokusebenza alutholakali"</string>
+ <string name="app_blocked_message" msgid="542972921087873023">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayitholakali khona manje."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Lolu hlelo lokusebenza belakhelwe inguqulo endala ye-Android futhi kungenzeka lungasebenzi kahle. Zama ukuhlolela izibuyekezo, noma uxhumane nonjiniyela."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Hlola izibuyekezo"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Unemilayezo emisha"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 31e68e8..f17cd45 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3402,8 +3402,8 @@
<!-- True if assistant app should be pinned via Pinner Service -->
<bool name="config_pinnerAssistantApp">false</bool>
- <!-- List of files pinned by the Pinner Service with the apex boot image b/119800099 -->
- <string-array translatable="false" name="config_apexBootImagePinnerServiceFiles">
+ <!-- List of files pinned by the Pinner Service with the JIT Zygote boot image b/119800099 -->
+ <string-array translatable="false" name="config_jitzygoteBootImagePinnerServiceFiles">
</string-array>
<!-- Number of days preloaded file cache should be preserved on a device before it can be
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 2453bb1..2dd62c1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3037,7 +3037,7 @@
<java-symbol type="bool" name="config_pinnerCameraApp" />
<java-symbol type="bool" name="config_pinnerHomeApp" />
<java-symbol type="bool" name="config_pinnerAssistantApp" />
- <java-symbol type="array" name="config_apexBootImagePinnerServiceFiles" />
+ <java-symbol type="array" name="config_jitzygoteBootImagePinnerServiceFiles" />
<java-symbol type="string" name="config_doubleTouchGestureEnableFile" />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index cef21db..81ec278 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -1679,6 +1679,15 @@
<item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item>
<item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item>
<item name="navigationBarColor">@android:color/transparent</item>
+ <item name="tabWidgetStyle">@style/Widget.DeviceDefault.Resolver.TabWidget</item>
+ </style>
+
+ <style name="Widget.DeviceDefault.Resolver.TabWidget" parent="Widget.DeviceDefault.TabWidget">
+ <item name="tabLayout">@layout/tab_indicator_resolver</item>
+ </style>
+
+ <style name="Widget.Material.Resolver.Tab" parent="Widget.Material.Tab">
+ <item name="background">@drawable/tab_indicator_resolver</item>
</style>
<style name="Theme.DeviceDefault.Resolver" parent="Theme.DeviceDefault.ResolverCommon">
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 9f15faf..e04d3de 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -52,9 +52,14 @@
"android.test.base",
"android.test.mock",
"framework-atb-backward-compatibility",
+ "framework-all",
+ "icing-java-proto-lite",
+ "ext",
+ "framework-res",
],
platform_apis: true,
+ sdk_version: "core_platform",
test_suites: ["device-tests"],
certificate: "platform",
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 59335a5..718ca46 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1330,6 +1330,12 @@
android:process=":FakeProvider">
</provider>
+ <provider
+ android:name="android.content.SlowProvider"
+ android:authorities="android.content.SlowProvider"
+ android:process=":SlowProvider">
+ </provider>
+
<!-- Application components used for os tests -->
<service android:name="android.os.MessengerService"
diff --git a/core/tests/coretests/src/android/app/NotificationHistoryTest.java b/core/tests/coretests/src/android/app/NotificationHistoryTest.java
index 0a21875..d1608d0 100644
--- a/core/tests/coretests/src/android/app/NotificationHistoryTest.java
+++ b/core/tests/coretests/src/android/app/NotificationHistoryTest.java
@@ -234,6 +234,40 @@
}
@Test
+ public void testRemoveNotificationFromWrite() {
+ NotificationHistory history = new NotificationHistory();
+
+ List<HistoricalNotification> postRemoveExpectedEntries = new ArrayList<>();
+ List<String> postRemoveExpectedStrings = new ArrayList<>();
+ for (int i = 1; i <= 10; i++) {
+ HistoricalNotification n = getHistoricalNotification("pkg", i);
+
+ if (987654323 != n.getPostedTimeMs()) {
+ postRemoveExpectedStrings.add(n.getPackage());
+ postRemoveExpectedStrings.add(n.getChannelName());
+ postRemoveExpectedStrings.add(n.getChannelId());
+ postRemoveExpectedEntries.add(n);
+ }
+
+ history.addNotificationToWrite(n);
+ }
+
+ history.poolStringsFromNotifications();
+
+ assertThat(history.getNotificationsToWrite().size()).isEqualTo(10);
+ // 1 package name and 10 unique channel names and ids
+ assertThat(history.getPooledStringsToWrite().length).isEqualTo(21);
+
+ history.removeNotificationFromWrite("pkg", 987654323);
+
+
+ // 1 package names and 9 * 2 unique channel names and ids
+ assertThat(history.getPooledStringsToWrite().length).isEqualTo(19);
+ assertThat(history.getNotificationsToWrite())
+ .containsExactlyElementsIn(postRemoveExpectedEntries);
+ }
+
+ @Test
public void testParceling() {
NotificationHistory history = new NotificationHistory();
diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java
index 9dcce1e..6dc7392 100644
--- a/core/tests/coretests/src/android/content/ContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ContentResolverTest.java
@@ -209,4 +209,13 @@
String type = mResolver.getType(Uri.parse("content://android.content.FakeProviderRemote"));
assertEquals("fake/remote", type);
}
+
+
+ @Test
+ public void testGetType_slowProvider() {
+ // This provider is running in a different process and is intentionally slow to start.
+ // We are trying to confirm that it does not cause an ANR
+ String type = mResolver.getType(Uri.parse("content://android.content.SlowProvider"));
+ assertEquals("slow", type);
+ }
}
diff --git a/core/tests/coretests/src/android/content/SlowProvider.java b/core/tests/coretests/src/android/content/SlowProvider.java
new file mode 100644
index 0000000..aba32e8
--- /dev/null
+++ b/core/tests/coretests/src/android/content/SlowProvider.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 android.content;
+
+import android.database.Cursor;
+import android.net.Uri;
+
+/**
+ * A dummy content provider for tests. This provider runs in a different process from the test and
+ * is intentionally slow.
+ */
+public class SlowProvider extends ContentProvider {
+
+ private static final int ON_CREATE_LATENCY_MILLIS = 3000;
+
+ @Override
+ public boolean onCreate() {
+ try {
+ Thread.sleep(ON_CREATE_LATENCY_MILLIS);
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ return true;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ return null;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return "slow";
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+}
diff --git a/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java b/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java
index 3273e5d..ea69176 100644
--- a/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java
+++ b/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java
@@ -29,6 +29,9 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import java.util.Arrays;
+import java.util.Collections;
+
@RunWith(JUnit4.class)
public class AtomicFormulaTest {
@@ -230,7 +233,7 @@
}
@Test
- public void testFormulaMatches_string_true() {
+ public void testFormulaMatches_string_packageNameFormula_true() {
StringAtomicFormula stringAtomicFormula =
new StringAtomicFormula(
AtomicFormula.PACKAGE_NAME, "com.test.app", /* isHashedValue= */
@@ -242,7 +245,7 @@
}
@Test
- public void testFormulaMatches_string_false() {
+ public void testFormulaMatches_string_packageNameFormula_false() {
StringAtomicFormula stringAtomicFormula =
new StringAtomicFormula(
AtomicFormula.PACKAGE_NAME, "com.test.app", /* isHashedValue= */
@@ -253,6 +256,63 @@
assertThat(stringAtomicFormula.matches(appInstallMetadata)).isFalse();
}
+ @Test
+ public void testFormulaMatches_string_multipleAppCertificates_true() {
+ StringAtomicFormula stringAtomicFormula =
+ new StringAtomicFormula(
+ AtomicFormula.APP_CERTIFICATE, "cert", /* isHashedValue= */ true);
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder()
+ .setPackageName("com.test.app")
+ .setAppCertificates(Arrays.asList("test-cert", "cert"))
+ .build();
+
+ assertThat(stringAtomicFormula.matches(appInstallMetadata)).isTrue();
+ }
+
+ @Test
+ public void testFormulaMatches_string_multipleAppCertificates_false() {
+ StringAtomicFormula stringAtomicFormula =
+ new StringAtomicFormula(
+ AtomicFormula.APP_CERTIFICATE, "cert", /* isHashedValue= */ true);
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder()
+ .setPackageName("com.test.app")
+ .setAppCertificates(Arrays.asList("test-cert", "another-cert"))
+ .build();
+
+ assertThat(stringAtomicFormula.matches(appInstallMetadata)).isFalse();
+ }
+
+ @Test
+ public void testFormulaMatches_string_multipleInstallerCertificates_true() {
+ StringAtomicFormula stringAtomicFormula =
+ new StringAtomicFormula(
+ AtomicFormula.INSTALLER_CERTIFICATE, "cert", /* isHashedValue= */ true);
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder()
+ .setPackageName("com.test.app")
+ .setAppCertificates(Collections.singletonList("abc"))
+ .setInstallerCertificates(Arrays.asList("test-cert", "cert"))
+ .build();
+
+ assertThat(stringAtomicFormula.matches(appInstallMetadata)).isTrue();
+ }
+
+ @Test
+ public void testFormulaMatches_string_multipleInstallerCertificates_false() {
+ StringAtomicFormula stringAtomicFormula =
+ new StringAtomicFormula(
+ AtomicFormula.INSTALLER_CERTIFICATE, "cert", /* isHashedValue= */ true);
+ AppInstallMetadata appInstallMetadata =
+ getAppInstallMetadataBuilder()
+ .setPackageName("com.test.app")
+ .setAppCertificates(Collections.singletonList("abc"))
+ .setInstallerCertificates(Arrays.asList("test-cert", "another-cert"))
+ .build();
+
+ assertThat(stringAtomicFormula.matches(appInstallMetadata)).isFalse();
+ }
@Test
public void testIsAppCertificateFormula_string_true() {
@@ -430,8 +490,8 @@
private AppInstallMetadata.Builder getAppInstallMetadataBuilder() {
return new AppInstallMetadata.Builder()
.setPackageName("abc")
- .setAppCertificate("abc")
- .setInstallerCertificate("abc")
+ .setAppCertificates(Collections.singletonList("abc"))
+ .setInstallerCertificates(Collections.singletonList("abc"))
.setInstallerName("abc")
.setVersionCode(-1)
.setIsPreInstalled(true);
diff --git a/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java b/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java
index f47dfdd..abc5fed 100644
--- a/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java
+++ b/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java
@@ -286,8 +286,8 @@
private AppInstallMetadata.Builder getAppInstallMetadataBuilder() {
return new AppInstallMetadata.Builder()
.setPackageName("abc")
- .setAppCertificate("abc")
- .setInstallerCertificate("abc")
+ .setAppCertificates(Collections.singletonList("abc"))
+ .setInstallerCertificates(Collections.singletonList("abc"))
.setInstallerName("abc")
.setVersionCode(-1)
.setIsPreInstalled(true);
diff --git a/core/tests/coretests/src/android/view/CutoutSpecificationTest.java b/core/tests/coretests/src/android/view/CutoutSpecificationTest.java
new file mode 100644
index 0000000..1f831bb
--- /dev/null
+++ b/core/tests/coretests/src/android/view/CutoutSpecificationTest.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.graphics.Rect;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class CutoutSpecificationTest {
+ private static final String WITHOUT_BIND_CUTOUT_SPECIFICATION = "M 0,0\n"
+ + "h 48\n"
+ + "v 48\n"
+ + "h -48\n"
+ + "z\n"
+ + "@left\n"
+ + "@center_vertical\n"
+ + "M 0,0\n"
+ + "h 48\n"
+ + "v 48\n"
+ + "h -48\n"
+ + "z\n"
+ + "@left\n"
+ + "@center_vertical\n"
+ + "M 0,0\n"
+ + "h -48\n"
+ + "v 48\n"
+ + "h 48\n"
+ + "z\n"
+ + "@right\n"
+ + "@dp";
+ private static final String WITH_BIND_CUTOUT_SPECIFICATION = "M 0,0\n"
+ + "h 48\n"
+ + "v 48\n"
+ + "h -48\n"
+ + "z\n"
+ + "@left\n"
+ + "@center_vertical\n"
+ + "M 0,0\n"
+ + "h 48\n"
+ + "v 48\n"
+ + "h -48\n"
+ + "z\n"
+ + "@left\n"
+ + "@bind_left_cutout\n"
+ + "@center_vertical\n"
+ + "M 0,0\n"
+ + "h -48\n"
+ + "v 48\n"
+ + "h 48\n"
+ + "z\n"
+ + "@right\n"
+ + "@bind_right_cutout\n"
+ + "@dp";
+ private static final String CORNER_CUTOUT_SPECIFICATION = "M 0,0\n"
+ + "h 1\n"
+ + "v 1\n"
+ + "h -1\n"
+ + "z\n"
+ + "@left\n"
+ + "@cutout\n"
+ + "M 0, 0\n"
+ + "h -2\n"
+ + "v 2\n"
+ + "h 2\n"
+ + "z\n"
+ + "@right\n"
+ + "@bind_right_cutout\n"
+ + "@cutout\n"
+ + "M 0, 200\n"
+ + "h 3\n"
+ + "v -3\n"
+ + "h -3\n"
+ + "z\n"
+ + "@left\n"
+ + "@bind_left_cutout\n"
+ + "@bottom\n"
+ + "M 0, 0\n"
+ + "h -4\n"
+ + "v -4\n"
+ + "h 4\n"
+ + "z\n"
+ + "@right\n"
+ + "@dp";
+
+ private CutoutSpecification.Parser mParser;
+
+ /**
+ * Setup the necessary member field used by test methods.
+ */
+ @Before
+ public void setUp() {
+ mParser = new CutoutSpecification.Parser(3.5f, 1080, 1920);
+ }
+
+ @Test
+ public void parse_nullString_shouldTriggerException() {
+ assertThrows(NullPointerException.class, () -> mParser.parse(null));
+ }
+
+ @Test
+ public void parse_emptyString_pathShouldBeNull() {
+ CutoutSpecification cutoutSpecification = mParser.parse("");
+ assertThat(cutoutSpecification.getPath()).isNull();
+ }
+
+ @Test
+ public void parse_withoutBindMarker_shouldHaveNoLeftBound() {
+ CutoutSpecification cutoutSpecification = mParser.parse(WITHOUT_BIND_CUTOUT_SPECIFICATION);
+ assertThat(cutoutSpecification.getLeftBound()).isNull();
+ }
+
+ @Test
+ public void parse_withoutBindMarker_shouldHaveNoRightBound() {
+ CutoutSpecification cutoutSpecification = mParser.parse(WITHOUT_BIND_CUTOUT_SPECIFICATION);
+ assertThat(cutoutSpecification.getRightBound()).isNull();
+ }
+
+ @Test
+ public void parse_withBindMarker_shouldHaveLeftBound() {
+ CutoutSpecification cutoutSpecification = mParser.parse(WITH_BIND_CUTOUT_SPECIFICATION);
+ assertThat(cutoutSpecification.getLeftBound()).isEqualTo(new Rect(0, 960, 168, 1128));
+ }
+
+ @Test
+ public void parse_withBindMarker_shouldHaveRightBound() {
+ CutoutSpecification cutoutSpecification = mParser.parse(WITH_BIND_CUTOUT_SPECIFICATION);
+ assertThat(cutoutSpecification.getRightBound()).isEqualTo(new Rect(912, 960, 1080, 1128));
+ }
+
+ @Test
+ public void parse_tallCutout_shouldBeDone() {
+ CutoutSpecification cutoutSpecification = mParser.parse("M 0,0\n"
+ + "L -48, 0\n"
+ + "L -44.3940446283, 36.0595537175\n"
+ + "C -43.5582133885, 44.4178661152 -39.6, 48.0 -31.2, 48.0\n"
+ + "L 31.2, 48.0\n"
+ + "C 39.6, 48.0 43.5582133885, 44.4178661152 44.3940446283, 36.0595537175\n"
+ + "L 48, 0\n"
+ + "Z\n"
+ + "@dp");
+
+ assertThat(cutoutSpecification.getTopBound().height()).isEqualTo(168);
+ }
+
+ @Test
+ public void parse_wideCutout_shouldBeDone() {
+ CutoutSpecification cutoutSpecification = mParser.parse("M 0,0\n"
+ + "L -72, 0\n"
+ + "L -69.9940446283, 20.0595537175\n"
+ + "C -69.1582133885, 28.4178661152 -65.2, 32.0 -56.8, 32.0\n"
+ + "L 56.8, 32.0\n"
+ + "C 65.2, 32.0 69.1582133885, 28.4178661152 69.9940446283, 20.0595537175\n"
+ + "L 72, 0\n"
+ + "Z\n"
+ + "@dp");
+
+ assertThat(cutoutSpecification.getTopBound().width()).isEqualTo(504);
+ }
+
+ @Test
+ public void parse_narrowCutout_shouldBeDone() {
+ CutoutSpecification cutoutSpecification = mParser.parse("M 0,0\n"
+ + "L -24, 0\n"
+ + "L -21.9940446283, 20.0595537175\n"
+ + "C -21.1582133885, 28.4178661152 -17.2, 32.0 -8.8, 32.0\n"
+ + "L 8.8, 32.0\n"
+ + "C 17.2, 32.0 21.1582133885, 28.4178661152 21.9940446283, 20.0595537175\n"
+ + "L 24, 0\n"
+ + "Z\n"
+ + "@dp");
+
+ assertThat(cutoutSpecification.getTopBound().width()).isEqualTo(168);
+ }
+
+ @Test
+ public void parse_doubleCutout_shouldBeDone() {
+ CutoutSpecification cutoutSpecification = mParser.parse("M 0,0\n"
+ + "L -72, 0\n"
+ + "L -69.9940446283, 20.0595537175\n"
+ + "C -69.1582133885, 28.4178661152 -65.2, 32.0 -56.8, 32.0\n"
+ + "L 56.8, 32.0\n"
+ + "C 65.2, 32.0 69.1582133885, 28.4178661152 69.9940446283, 20.0595537175\n"
+ + "L 72, 0\n"
+ + "Z\n"
+ + "@bottom\n"
+ + "M 0,0\n"
+ + "L -72, 0\n"
+ + "L -69.9940446283, -20.0595537175\n"
+ + "C -69.1582133885, -28.4178661152 -65.2, -32.0 -56.8, -32.0\n"
+ + "L 56.8, -32.0\n"
+ + "C 65.2, -32.0 69.1582133885, -28.4178661152 69.9940446283, -20"
+ + ".0595537175\n"
+ + "L 72, 0\n"
+ + "Z\n"
+ + "@dp");
+
+ assertThat(cutoutSpecification.getTopBound().height()).isEqualTo(112);
+ }
+
+ @Test
+ public void parse_cornerCutout_shouldBeDone() {
+ CutoutSpecification cutoutSpecification = mParser.parse("M 0,0\n"
+ + "L -48, 0\n"
+ + "C -48,48 -48,48 0,48\n"
+ + "Z\n"
+ + "@dp\n"
+ + "@right");
+
+ assertThat(cutoutSpecification.getTopBound().height()).isEqualTo(168);
+ }
+
+ @Test
+ public void parse_holeCutout_shouldBeDone() {
+ CutoutSpecification cutoutSpecification = mParser.parse("M 20.0,20.0\n"
+ + "h 136\n"
+ + "v 136\n"
+ + "h -136\n"
+ + "Z\n"
+ + "@left");
+
+ assertThat(cutoutSpecification.getSafeInset()).isEqualTo(new Rect(0, 156, 0, 0));
+ }
+
+ @Test
+ public void getSafeInset_shortEdgeIsTopBottom_shouldMatchExpectedInset() {
+ CutoutSpecification cutoutSpecification =
+ new CutoutSpecification.Parser(2f, 200, 400)
+ .parse(CORNER_CUTOUT_SPECIFICATION);
+
+ assertThat(cutoutSpecification.getSafeInset())
+ .isEqualTo(new Rect(0, 4, 0, 8));
+ }
+
+ @Test
+ public void getSafeInset_shortEdgeIsLeftRight_shouldMatchExpectedInset() {
+ CutoutSpecification cutoutSpecification =
+ new CutoutSpecification.Parser(2f, 400, 200)
+ .parse(CORNER_CUTOUT_SPECIFICATION);
+
+ assertThat(cutoutSpecification.getSafeInset())
+ .isEqualTo(new Rect(6, 0, 8, 0));
+ }
+}
diff --git a/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java
index 12c057f..02ffc00 100644
--- a/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java
@@ -20,11 +20,11 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyInt;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.UserHandle;
-import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
@@ -41,6 +41,7 @@
@RunWith(AndroidJUnit4.class)
public class EditorInfoTest {
private static final int TEST_USER_ID = 42;
+ private static final int LONG_EXP_TEXT_LENGTH = EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH * 2;
/**
* Makes sure that {@code null} {@link EditorInfo#targetInputMethodUser} can be copied via
@@ -79,8 +80,8 @@
}
@Test
- public void testNullTextInputComposeInitialSurroundingText() {
- final Spannable testText = null;
+ public void setInitialText_nullInputText_throwsException() {
+ final CharSequence testText = null;
final EditorInfo editorInfo = new EditorInfo();
try {
@@ -92,56 +93,75 @@
}
@Test
- public void testNonNullTextInputComposeInitialSurroundingText() {
- final Spannable testText = createTestText(/* prependLength= */ 0,
- EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH);
- final EditorInfo editorInfo = new EditorInfo();
+ public void setInitialText_cursorAtHead_dividesByCursorPosition() {
+ final CharSequence testText = createTestText(EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH);
- // Cursor at position 0.
- int selectionLength = 0;
+ final EditorInfo editorInfo = new EditorInfo();
+ final int selectionLength = 0;
editorInfo.initialSelStart = 0;
editorInfo.initialSelEnd = editorInfo.initialSelStart + selectionLength;
- int expectedTextBeforeCursorLength = 0;
- int expectedTextAfterCursorLength = testText.length();
+ final int expectedTextBeforeCursorLength = 0;
+ final int expectedTextAfterCursorLength = testText.length();
editorInfo.setInitialSurroundingText(testText);
assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength,
expectedTextAfterCursorLength);
+ }
- // Cursor at the end.
+ @Test
+ public void setInitialText_cursorAtTail_dividesByCursorPosition() {
+ final CharSequence testText = createTestText(EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH);
+ final EditorInfo editorInfo = new EditorInfo();
+ final int selectionLength = 0;
editorInfo.initialSelStart = testText.length() - selectionLength;
editorInfo.initialSelEnd = testText.length();
- expectedTextBeforeCursorLength = testText.length();
- expectedTextAfterCursorLength = 0;
+ final int expectedTextBeforeCursorLength = testText.length();
+ final int expectedTextAfterCursorLength = 0;
editorInfo.setInitialSurroundingText(testText);
assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength,
expectedTextAfterCursorLength);
+ }
- // Cursor at the middle.
- selectionLength = 2;
+ @Test
+ public void setInitialText_cursorAtMiddle_dividesByCursorPosition() {
+ final CharSequence testText = createTestText(EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH);
+ final EditorInfo editorInfo = new EditorInfo();
+ final int selectionLength = 2;
editorInfo.initialSelStart = testText.length() / 2;
editorInfo.initialSelEnd = editorInfo.initialSelStart + selectionLength;
- expectedTextBeforeCursorLength = editorInfo.initialSelStart;
- expectedTextAfterCursorLength = testText.length() - editorInfo.initialSelEnd;
+ final int expectedTextBeforeCursorLength = editorInfo.initialSelStart;
+ final int expectedTextAfterCursorLength = testText.length() - editorInfo.initialSelEnd;
editorInfo.setInitialSurroundingText(testText);
assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength,
expectedTextAfterCursorLength);
+ }
- // Accidentally swap selection start and end.
+ @Test
+ public void setInitialText_incorrectCursorOrder_correctsThenDivide() {
+ final CharSequence testText = createTestText(EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH);
+ final EditorInfo editorInfo = new EditorInfo();
+ final int selectionLength = 2;
editorInfo.initialSelEnd = testText.length() / 2;
editorInfo.initialSelStart = editorInfo.initialSelEnd + selectionLength;
+ final int expectedTextBeforeCursorLength = testText.length() / 2;
+ final int expectedTextAfterCursorLength = testText.length() - testText.length() / 2
+ - selectionLength;
editorInfo.setInitialSurroundingText(testText);
assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength,
expectedTextAfterCursorLength);
+ }
- // Invalid cursor position.
+ @Test
+ public void setInitialText_invalidCursorPosition_returnsNull() {
+ final CharSequence testText = createTestText(EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH);
+ final EditorInfo editorInfo = new EditorInfo();
editorInfo.initialSelStart = -1;
editorInfo.setInitialSurroundingText(testText);
@@ -153,64 +173,33 @@
}
@Test
- public void testTooLongTextInputComposeInitialSurroundingText() {
- final Spannable testText = createTestText(/* prependLength= */ 0,
- EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH + 2);
+ public void setOverSizeInitialText_cursorAtMiddle_dividesProportionately() {
+ final CharSequence testText = createTestText(EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH + 2);
final EditorInfo editorInfo = new EditorInfo();
-
- // Cursor at position 0.
- int selectionLength = 0;
- editorInfo.initialSelStart = 0;
- editorInfo.initialSelEnd = 0 + selectionLength;
- int expectedTextBeforeCursorLength = 0;
- int expectedTextAfterCursorLength = editorInfo.MEMORY_EFFICIENT_TEXT_LENGTH;
-
- editorInfo.setInitialSurroundingText(testText);
-
- assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength,
- expectedTextAfterCursorLength);
-
- // Cursor at the end.
- editorInfo.initialSelStart = testText.length() - selectionLength;
- editorInfo.initialSelEnd = testText.length();
- expectedTextBeforeCursorLength = editorInfo.MEMORY_EFFICIENT_TEXT_LENGTH;
- expectedTextAfterCursorLength = 0;
-
- editorInfo.setInitialSurroundingText(testText);
-
- assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength,
- expectedTextAfterCursorLength);
-
- // Cursor at the middle.
- selectionLength = 2;
+ final int selectionLength = 2;
editorInfo.initialSelStart = testText.length() / 2;
editorInfo.initialSelEnd = editorInfo.initialSelStart + selectionLength;
- expectedTextBeforeCursorLength = Math.min(editorInfo.initialSelStart,
+ final int expectedTextBeforeCursorLength = Math.min(editorInfo.initialSelStart,
(int) (0.8 * (EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH - selectionLength)));
- expectedTextAfterCursorLength = EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH
+ final int expectedTextAfterCursorLength = EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH
- expectedTextBeforeCursorLength - selectionLength;
editorInfo.setInitialSurroundingText(testText);
assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength,
expectedTextAfterCursorLength);
+ }
- // Accidentally swap selection start and end.
- editorInfo.initialSelEnd = testText.length() / 2;
- editorInfo.initialSelStart = editorInfo.initialSelEnd + selectionLength;
-
- editorInfo.setInitialSurroundingText(testText);
-
- assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength,
- expectedTextAfterCursorLength);
-
- // Selection too long, selected text should be dropped.
- selectionLength = EditorInfo.MAX_INITIAL_SELECTION_LENGTH + 1;
+ @Test
+ public void setOverSizeInitialText_overSizeSelection_dropsSelection() {
+ final CharSequence testText = createTestText(EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH + 2);
+ final EditorInfo editorInfo = new EditorInfo();
+ final int selectionLength = EditorInfo.MAX_INITIAL_SELECTION_LENGTH + 1;
editorInfo.initialSelStart = testText.length() / 2;
editorInfo.initialSelEnd = editorInfo.initialSelStart + selectionLength;
- expectedTextBeforeCursorLength = Math.min(editorInfo.initialSelStart,
+ final int expectedTextBeforeCursorLength = Math.min(editorInfo.initialSelStart,
(int) (0.8 * EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH));
- expectedTextAfterCursorLength = testText.length() - editorInfo.initialSelEnd;
+ final int expectedTextAfterCursorLength = testText.length() - editorInfo.initialSelEnd;
editorInfo.setInitialSurroundingText(testText);
@@ -219,34 +208,59 @@
}
@Test
- public void testTooLongSubTextInputComposeInitialSurroundingText() {
- final int prependLength = 5;
- final int subTextLength = EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH;
- final Spannable fullText = createTestText(prependLength, subTextLength);
+ public void setInitialSubText_trimmedSubText_dividesByOriginalCursorPosition() {
+ final String prefixString = "prefix";
+ final CharSequence subText = createTestText(EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH);
+ final CharSequence originalText = TextUtils.concat(prefixString, subText);
final EditorInfo editorInfo = new EditorInfo();
- // Cursor at the middle.
- final int selectionLength = 2;
- editorInfo.initialSelStart = fullText.length() / 2;
- editorInfo.initialSelEnd = editorInfo.initialSelStart + selectionLength;
- // #prependLength characters will be trimmed out.
- final Spannable expectedTextBeforeCursor = createExpectedText(/* startNumber= */0,
- editorInfo.initialSelStart - prependLength);
- final Spannable expectedSelectedText = createExpectedText(
- editorInfo.initialSelStart - prependLength, selectionLength);
- final Spannable expectedTextAfterCursor = createExpectedText(
- editorInfo.initialSelEnd - prependLength,
- fullText.length() - editorInfo.initialSelEnd);
+ final int selLength = 2;
+ editorInfo.initialSelStart = originalText.length() / 2;
+ editorInfo.initialSelEnd = editorInfo.initialSelStart + selLength;
+ final CharSequence expectedTextBeforeCursor = createExpectedText(/* startNumber= */0,
+ editorInfo.initialSelStart - prefixString.length());
+ final CharSequence expectedSelectedText = createExpectedText(
+ editorInfo.initialSelStart - prefixString.length(), selLength);
+ final CharSequence expectedTextAfterCursor = createExpectedText(
+ editorInfo.initialSelEnd - prefixString.length(),
+ originalText.length() - editorInfo.initialSelEnd);
- editorInfo.setInitialSurroundingSubText(fullText.subSequence(prependLength,
- fullText.length()), prependLength);
+ editorInfo.setInitialSurroundingSubText(subText, prefixString.length());
assertTrue(TextUtils.equals(expectedTextBeforeCursor,
- editorInfo.getInitialTextBeforeCursor(editorInfo.MEMORY_EFFICIENT_TEXT_LENGTH,
- InputConnection.GET_TEXT_WITH_STYLES)));
+ editorInfo.getInitialTextBeforeCursor(LONG_EXP_TEXT_LENGTH, anyInt())));
assertTrue(TextUtils.equals(expectedSelectedText,
- editorInfo.getInitialSelectedText(InputConnection.GET_TEXT_WITH_STYLES)));
+ editorInfo.getInitialSelectedText(anyInt())));
assertTrue(TextUtils.equals(expectedTextAfterCursor,
- editorInfo.getInitialTextAfterCursor(editorInfo.MEMORY_EFFICIENT_TEXT_LENGTH,
+ editorInfo.getInitialTextAfterCursor(LONG_EXP_TEXT_LENGTH, anyInt())));
+ }
+
+ @Test
+ public void initialSurroundingText_wrapIntoParcel_staysIntact() {
+ // EditorInfo.InitialSurroundingText is not visible to test class. But all its key elements
+ // must stay intact for its getter methods to return correct value and it will be wrapped
+ // into its outer class for parcel transfer, therefore we can verify its parcel
+ // wrapping/unwrapping logic through its outer class.
+ final CharSequence testText = createTestText(EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH);
+ final EditorInfo sourceEditorInfo = new EditorInfo();
+ final int selectionLength = 2;
+ sourceEditorInfo.initialSelStart = testText.length() / 2;
+ sourceEditorInfo.initialSelEnd = sourceEditorInfo.initialSelStart + selectionLength;
+ sourceEditorInfo.setInitialSurroundingText(testText);
+
+ final EditorInfo targetEditorInfo = cloneViaParcel(sourceEditorInfo);
+
+ assertTrue(TextUtils.equals(
+ sourceEditorInfo.getInitialTextBeforeCursor(LONG_EXP_TEXT_LENGTH,
+ InputConnection.GET_TEXT_WITH_STYLES),
+ targetEditorInfo.getInitialTextBeforeCursor(LONG_EXP_TEXT_LENGTH,
+ InputConnection.GET_TEXT_WITH_STYLES)));
+ assertTrue(TextUtils.equals(
+ sourceEditorInfo.getInitialSelectedText(InputConnection.GET_TEXT_WITH_STYLES),
+ targetEditorInfo.getInitialSelectedText(InputConnection.GET_TEXT_WITH_STYLES)));
+ assertTrue(TextUtils.equals(
+ sourceEditorInfo.getInitialTextAfterCursor(LONG_EXP_TEXT_LENGTH,
+ InputConnection.GET_TEXT_WITH_STYLES),
+ targetEditorInfo.getInitialTextAfterCursor(LONG_EXP_TEXT_LENGTH,
InputConnection.GET_TEXT_WITH_STYLES)));
}
@@ -254,12 +268,12 @@
@Nullable Integer expectBeforeCursorLength, @Nullable Integer expectSelectionLength,
@Nullable Integer expectAfterCursorLength) {
final CharSequence textBeforeCursor =
- editorInfo.getInitialTextBeforeCursor(editorInfo.MEMORY_EFFICIENT_TEXT_LENGTH,
+ editorInfo.getInitialTextBeforeCursor(LONG_EXP_TEXT_LENGTH,
InputConnection.GET_TEXT_WITH_STYLES);
final CharSequence selectedText =
editorInfo.getInitialSelectedText(InputConnection.GET_TEXT_WITH_STYLES);
final CharSequence textAfterCursor =
- editorInfo.getInitialTextAfterCursor(editorInfo.MEMORY_EFFICIENT_TEXT_LENGTH,
+ editorInfo.getInitialTextAfterCursor(LONG_EXP_TEXT_LENGTH,
InputConnection.GET_TEXT_WITH_STYLES);
if (expectBeforeCursorLength == null) {
@@ -281,19 +295,15 @@
}
}
- private static Spannable createTestText(int prependLength, int surroundingLength) {
+ private static CharSequence createTestText(int surroundingLength) {
final SpannableStringBuilder builder = new SpannableStringBuilder();
- for (int i = 0; i < prependLength; i++) {
- builder.append("a");
- }
-
for (int i = 0; i < surroundingLength; i++) {
builder.append(Integer.toString(i % 10));
}
return builder;
}
- private static Spannable createExpectedText(int startNumber, int length) {
+ private static CharSequence createExpectedText(int startNumber, int length) {
final SpannableStringBuilder builder = new SpannableStringBuilder();
for (int i = startNumber; i < startNumber + length; i++) {
builder.append(Integer.toString(i % 10));
diff --git a/services/core/java/com/android/server/GraphicsStatsService.java b/graphics/java/android/graphics/GraphicsStatsService.java
similarity index 85%
rename from services/core/java/com/android/server/GraphicsStatsService.java
rename to graphics/java/android/graphics/GraphicsStatsService.java
index 5179fa7..8dfd6ee 100644
--- a/services/core/java/com/android/server/GraphicsStatsService.java
+++ b/graphics/java/android/graphics/GraphicsStatsService.java
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-package com.android.server;
+package android.graphics;
+import android.annotation.SystemApi;
import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.content.Context;
@@ -26,13 +27,14 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
-import android.os.MemoryFile;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
+import android.os.SharedMemory;
import android.os.Trace;
import android.os.UserHandle;
+import android.system.ErrnoException;
import android.util.Log;
import android.view.IGraphicsStats;
import android.view.IGraphicsStatsCallback;
@@ -45,6 +47,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
@@ -84,8 +87,8 @@
// This isn't static because we need this to happen after registerNativeMethods, however
// the class is loaded (and thus static ctor happens) before that occurs.
- private final int ASHMEM_SIZE = nGetAshmemSize();
- private final byte[] ZERO_DATA = new byte[ASHMEM_SIZE];
+ private final int mAshmemSize = nGetAshmemSize();
+ private final byte[] mZeroData = new byte[mAshmemSize];
private final Context mContext;
private final AppOpsManager mAppOps;
@@ -97,6 +100,7 @@
private Handler mWriteOutHandler;
private boolean mRotateIsScheduled = false;
+ @SystemApi
public GraphicsStatsService(Context context) {
mContext = context;
mAppOps = context.getSystemService(AppOpsManager.class);
@@ -108,7 +112,8 @@
throw new IllegalStateException("Graphics stats directory does not exist: "
+ mGraphicsStatsDir.getAbsolutePath());
}
- HandlerThread bgthread = new HandlerThread("GraphicsStats-disk", Process.THREAD_PRIORITY_BACKGROUND);
+ HandlerThread bgthread = new HandlerThread("GraphicsStats-disk",
+ Process.THREAD_PRIORITY_BACKGROUND);
bgthread.start();
mWriteOutHandler = new Handler(bgthread.getLooper(), new Handler.Callback() {
@@ -159,7 +164,7 @@
active.mCallback.onRotateGraphicsStatsBuffer();
} catch (RemoteException e) {
Log.w(TAG, String.format("Failed to notify '%s' (pid=%d) to rotate buffers",
- active.mInfo.packageName, active.mPid), e);
+ active.mInfo.mPackageName, active.mPid), e);
}
}
// Give a few seconds for everyone to rotate before doing the cleanup
@@ -167,8 +172,8 @@
}
@Override
- public ParcelFileDescriptor requestBufferForProcess(String packageName, IGraphicsStatsCallback token)
- throws RemoteException {
+ public ParcelFileDescriptor requestBufferForProcess(String packageName,
+ IGraphicsStatsCallback token) throws RemoteException {
int uid = Binder.getCallingUid();
int pid = Binder.getCallingPid();
ParcelFileDescriptor pfd = null;
@@ -196,7 +201,7 @@
// current day.
// This method is invoked from native code only.
@SuppressWarnings({"UnusedDeclaration"})
- private long pullGraphicsStats(boolean lastFullDay) throws RemoteException {
+ private void pullGraphicsStats(boolean lastFullDay, long pulledData) throws RemoteException {
int uid = Binder.getCallingUid();
// DUMP and PACKAGE_USAGE_STATS permissions are required to invoke this method.
@@ -213,13 +218,13 @@
long callingIdentity = Binder.clearCallingIdentity();
try {
- return pullGraphicsStatsImpl(lastFullDay);
+ pullGraphicsStatsImpl(lastFullDay, pulledData);
} finally {
Binder.restoreCallingIdentity(callingIdentity);
}
}
- private long pullGraphicsStatsImpl(boolean lastFullDay) {
+ private void pullGraphicsStatsImpl(boolean lastFullDay, long pulledData) {
long targetDay;
if (lastFullDay) {
// Get stats from yesterday. Stats stay constant, because the day is over.
@@ -235,7 +240,7 @@
buffers = new ArrayList<>(mActive.size());
for (int i = 0; i < mActive.size(); i++) {
ActiveBuffer buffer = mActive.get(i);
- if (buffer.mInfo.startTime == targetDay) {
+ if (buffer.mInfo.mStartTime == targetDay) {
try {
buffers.add(new HistoricalBuffer(buffer));
} catch (IOException ex) {
@@ -267,18 +272,7 @@
}
}
} finally {
- return nFinishDumpInMemory(dump);
- }
- }
-
- private ParcelFileDescriptor getPfd(MemoryFile file) {
- try {
- if (!file.getFileDescriptor().valid()) {
- throw new IllegalStateException("Invalid file descriptor");
- }
- return ParcelFileDescriptor.dup(file.getFileDescriptor());
- } catch (IOException ex) {
- throw new IllegalStateException("Failed to get PFD from memory file", ex);
+ nFinishDumpInMemory(dump, pulledData, lastFullDay);
}
}
@@ -286,7 +280,7 @@
int uid, int pid, String packageName, long versionCode) throws RemoteException {
ActiveBuffer buffer = fetchActiveBuffersLocked(token, uid, pid, packageName, versionCode);
scheduleRotateLocked();
- return getPfd(buffer.mProcessBuffer);
+ return buffer.getPfd();
}
private Calendar normalizeDate(long timestamp) {
@@ -301,13 +295,15 @@
private File pathForApp(BufferInfo info) {
String subPath = String.format("%d/%s/%d/total",
- normalizeDate(info.startTime).getTimeInMillis(), info.packageName, info.versionCode);
+ normalizeDate(info.mStartTime).getTimeInMillis(), info.mPackageName,
+ info.mVersionCode);
return new File(mGraphicsStatsDir, subPath);
}
private void saveBuffer(HistoricalBuffer buffer) {
if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
- Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "saving graphicsstats for " + buffer.mInfo.packageName);
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER,
+ "saving graphicsstats for " + buffer.mInfo.mPackageName);
}
synchronized (mFileAccessLock) {
File path = pathForApp(buffer.mInfo);
@@ -317,8 +313,9 @@
Log.w(TAG, "Unable to create path: '" + parent.getAbsolutePath() + "'");
return;
}
- nSaveBuffer(path.getAbsolutePath(), buffer.mInfo.packageName, buffer.mInfo.versionCode,
- buffer.mInfo.startTime, buffer.mInfo.endTime, buffer.mData);
+ nSaveBuffer(path.getAbsolutePath(), buffer.mInfo.mPackageName,
+ buffer.mInfo.mVersionCode, buffer.mInfo.mStartTime, buffer.mInfo.mEndTime,
+ buffer.mData);
}
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
@@ -365,7 +362,7 @@
HistoricalBuffer data = new HistoricalBuffer(buffer);
Message.obtain(mWriteOutHandler, SAVE_BUFFER, data).sendToTarget();
} catch (IOException e) {
- Log.w(TAG, "Failed to copy graphicsstats from " + buffer.mInfo.packageName, e);
+ Log.w(TAG, "Failed to copy graphicsstats from " + buffer.mInfo.mPackageName, e);
}
buffer.closeAllBuffers();
}
@@ -386,7 +383,7 @@
if (buffer.mPid == pid
&& buffer.mUid == uid) {
// If the buffer is too old we remove it and return a new one
- if (buffer.mInfo.startTime < today) {
+ if (buffer.mInfo.mStartTime < today) {
buffer.binderDied();
break;
} else {
@@ -410,8 +407,8 @@
HistoricalBuffer buffer = buffers.get(i);
File path = pathForApp(buffer.mInfo);
skipFiles.add(path);
- nAddToDump(dump, path.getAbsolutePath(), buffer.mInfo.packageName,
- buffer.mInfo.versionCode, buffer.mInfo.startTime, buffer.mInfo.endTime,
+ nAddToDump(dump, path.getAbsolutePath(), buffer.mInfo.mPackageName,
+ buffer.mInfo.mVersionCode, buffer.mInfo.mStartTime, buffer.mInfo.mEndTime,
buffer.mData);
}
return skipFiles;
@@ -478,20 +475,20 @@
long versionCode, long startTime, long endTime, byte[] data);
private static native void nAddToDump(long dump, String path);
private static native void nFinishDump(long dump);
- private static native long nFinishDumpInMemory(long dump);
+ private static native void nFinishDumpInMemory(long dump, long pulledData, boolean lastFullDay);
private static native void nSaveBuffer(String path, String packageName, long versionCode,
long startTime, long endTime, byte[] data);
private final class BufferInfo {
- final String packageName;
- final long versionCode;
- long startTime;
- long endTime;
+ final String mPackageName;
+ final long mVersionCode;
+ long mStartTime;
+ long mEndTime;
BufferInfo(String packageName, long versionCode, long startTime) {
- this.packageName = packageName;
- this.versionCode = versionCode;
- this.startTime = startTime;
+ this.mPackageName = packageName;
+ this.mVersionCode = versionCode;
+ this.mStartTime = startTime;
}
}
@@ -501,7 +498,8 @@
final int mPid;
final IGraphicsStatsCallback mCallback;
final IBinder mToken;
- MemoryFile mProcessBuffer;
+ SharedMemory mProcessBuffer;
+ ByteBuffer mMapping;
ActiveBuffer(IGraphicsStatsCallback token, int uid, int pid, String packageName,
long versionCode)
@@ -512,8 +510,14 @@
mCallback = token;
mToken = mCallback.asBinder();
mToken.linkToDeath(this, 0);
- mProcessBuffer = new MemoryFile("GFXStats-" + pid, ASHMEM_SIZE);
- mProcessBuffer.writeBytes(ZERO_DATA, 0, 0, ASHMEM_SIZE);
+ try {
+ mProcessBuffer = SharedMemory.create("GFXStats-" + pid, mAshmemSize);
+ mMapping = mProcessBuffer.mapReadWrite();
+ } catch (ErrnoException ex) {
+ ex.rethrowAsIOException();
+ }
+ mMapping.position(0);
+ mMapping.put(mZeroData, 0, mAshmemSize);
}
@Override
@@ -523,20 +527,40 @@
}
void closeAllBuffers() {
+ if (mMapping != null) {
+ SharedMemory.unmap(mMapping);
+ mMapping = null;
+ }
if (mProcessBuffer != null) {
mProcessBuffer.close();
mProcessBuffer = null;
}
}
+
+ ParcelFileDescriptor getPfd() {
+ try {
+ return mProcessBuffer.getFdDup();
+ } catch (IOException ex) {
+ throw new IllegalStateException("Failed to get PFD from memory file", ex);
+ }
+ }
+
+ void readBytes(byte[] buffer, int count) throws IOException {
+ if (mMapping == null) {
+ throw new IOException("SharedMemory has been deactivated");
+ }
+ mMapping.position(0);
+ mMapping.get(buffer, 0, count);
+ }
}
private final class HistoricalBuffer {
final BufferInfo mInfo;
- final byte[] mData = new byte[ASHMEM_SIZE];
+ final byte[] mData = new byte[mAshmemSize];
HistoricalBuffer(ActiveBuffer active) throws IOException {
mInfo = active.mInfo;
- mInfo.endTime = System.currentTimeMillis();
- active.mProcessBuffer.readBytes(mData, 0, 0, ASHMEM_SIZE);
+ mInfo.mEndTime = System.currentTimeMillis();
+ active.readBytes(mData, mAshmemSize);
}
}
}
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 51270f5..301d1af 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -92,9 +92,12 @@
"libandroidfw",
"libcrypto",
"libsync",
+ "libstatspull",
+ "libstatssocket",
],
static_libs: [
"libEGL_blobCache",
+ "libprotoutil",
],
},
host: {
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 6761435..31e4555 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -27,7 +27,6 @@
#include "DamageAccumulator.h"
#include "pipeline/skia/SkiaDisplayList.h"
#endif
-#include "utils/FatVector.h"
#include "utils/MathUtils.h"
#include "utils/StringUtils.h"
#include "utils/TraceUtils.h"
@@ -37,6 +36,7 @@
#include <atomic>
#include <sstream>
#include <string>
+#include <ui/FatVector.h>
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index d55e5b0..c0ec217 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -27,6 +27,8 @@
#include <androidfw/ResourceTypes.h>
+#include <ui/FatVector.h>
+
#include "AnimatorManager.h"
#include "CanvasTransform.h"
#include "Debug.h"
@@ -35,7 +37,6 @@
#include "RenderProperties.h"
#include "pipeline/skia/SkiaDisplayList.h"
#include "pipeline/skia/SkiaLayer.h"
-#include "utils/FatVector.h"
#include <vector>
diff --git a/libs/hwui/hwui/ImageDecoder.cpp b/libs/hwui/hwui/ImageDecoder.cpp
index 4b2857f..afd82ac 100644
--- a/libs/hwui/hwui/ImageDecoder.cpp
+++ b/libs/hwui/hwui/ImageDecoder.cpp
@@ -24,6 +24,19 @@
using namespace android;
+sk_sp<SkColorSpace> ImageDecoder::getDefaultColorSpace() const {
+ const skcms_ICCProfile* encodedProfile = mCodec->getICCProfile();
+ if (encodedProfile) {
+ // If the profile maps directly to an SkColorSpace, that SkColorSpace
+ // will be returned. Otherwise, nullptr will be returned. In either
+ // case, using this SkColorSpace results in doing no color correction.
+ return SkColorSpace::Make(*encodedProfile);
+ }
+
+ // The image has no embedded color profile, and should be treated as SRGB.
+ return SkColorSpace::MakeSRGB();
+}
+
ImageDecoder::ImageDecoder(std::unique_ptr<SkAndroidCodec> codec, sk_sp<SkPngChunkReader> peeker)
: mCodec(std::move(codec))
, mPeeker(std::move(peeker))
@@ -31,7 +44,7 @@
, mDecodeSize(mTargetSize)
, mOutColorType(mCodec->computeOutputColorType(kN32_SkColorType))
, mUnpremultipliedRequired(false)
- , mOutColorSpace(mCodec->computeOutputColorSpace(mOutColorType, nullptr))
+ , mOutColorSpace(getDefaultColorSpace())
, mSampleSize(1)
{
}
diff --git a/libs/hwui/hwui/ImageDecoder.h b/libs/hwui/hwui/ImageDecoder.h
index 0c99f84..a1b5157 100644
--- a/libs/hwui/hwui/ImageDecoder.h
+++ b/libs/hwui/hwui/ImageDecoder.h
@@ -43,6 +43,7 @@
bool setUnpremultipliedRequired(bool unpremultipliedRequired);
+ sk_sp<SkColorSpace> getDefaultColorSpace() const;
void setOutColorSpace(sk_sp<SkColorSpace> cs);
// The size is the final size after scaling and cropping.
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
index cfc0f9b..d669f84 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
@@ -21,7 +21,7 @@
#include <SkCanvas.h>
#include <SkDrawable.h>
-#include <utils/FatVector.h>
+#include <ui/FatVector.h>
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index cae3e3b..206b58f 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -27,7 +27,6 @@
#include "pipeline/skia/SkiaOpenGLPipeline.h"
#include "pipeline/skia/SkiaVulkanPipeline.h"
#include "renderstate/RenderState.h"
-#include "utils/FatVector.h"
#include "utils/TimeUtils.h"
#include "utils/TraceUtils.h"
@@ -40,6 +39,8 @@
#include <utils/Mutex.h>
#include <thread>
+#include <ui/FatVector.h>
+
namespace android {
namespace uirenderer {
namespace renderthread {
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index a5355fc..ba70afc 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -23,13 +23,13 @@
#include <GrContext.h>
#include <GrTypes.h>
#include <android/sync.h>
+#include <ui/FatVector.h>
#include <vk/GrVkExtensions.h>
#include <vk/GrVkTypes.h>
#include "Properties.h"
#include "RenderThread.h"
#include "renderstate/RenderState.h"
-#include "utils/FatVector.h"
#include "utils/TraceUtils.h"
namespace android {
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index c418617..644d5fb 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -26,9 +26,9 @@
#include <sys/types.h>
#include <unistd.h>
-#include <algorithm>
-#include <map>
-#include <vector>
+#include <android/util/ProtoOutputStream.h>
+#include <stats_event.h>
+#include <statslog.h>
#include "JankTracker.h"
#include "protos/graphicsstats.pb.h"
@@ -61,7 +61,7 @@
}
}
bool valid() { return mFd != -1; }
- operator int() { return mFd; } // NOLINT(google-explicit-constructor)
+ operator int() { return mFd; } // NOLINT(google-explicit-constructor)
private:
int mFd;
@@ -485,79 +485,82 @@
delete dump;
}
-class MemOutputStreamLite : public io::ZeroCopyOutputStream {
-public:
- explicit MemOutputStreamLite() : mCopyAdapter(), mImpl(&mCopyAdapter) {}
- virtual ~MemOutputStreamLite() {}
+using namespace google::protobuf;
- virtual bool Next(void** data, int* size) override { return mImpl.Next(data, size); }
+// Field ids taken from FrameTimingHistogram message in atoms.proto
+#define TIME_MILLIS_BUCKETS_FIELD_NUMBER 1
+#define FRAME_COUNTS_FIELD_NUMBER 2
- virtual void BackUp(int count) override { mImpl.BackUp(count); }
-
- virtual int64 ByteCount() const override { return mImpl.ByteCount(); }
-
- bool Flush() { return mImpl.Flush(); }
-
- void copyData(const DumpMemoryFn& reader, void* param1, void* param2) {
- int bufferOffset = 0;
- int totalSize = mCopyAdapter.mBuffersSize - mCopyAdapter.mCurrentBufferUnusedSize;
- int totalDataLeft = totalSize;
- for (auto& it : mCopyAdapter.mBuffers) {
- int bufferSize = std::min(totalDataLeft, (int)it.size()); // last buffer is not full
- reader(it.data(), bufferOffset, bufferSize, totalSize, param1, param2);
- bufferOffset += bufferSize;
- totalDataLeft -= bufferSize;
- }
+static void writeCpuHistogram(AStatsEvent* event,
+ const uirenderer::protos::GraphicsStatsProto& stat) {
+ util::ProtoOutputStream proto;
+ for (int bucketIndex = 0; bucketIndex < stat.histogram_size(); bucketIndex++) {
+ auto& bucket = stat.histogram(bucketIndex);
+ proto.write(android::util::FIELD_TYPE_INT32 | android::util::FIELD_COUNT_REPEATED |
+ TIME_MILLIS_BUCKETS_FIELD_NUMBER /* field id */,
+ (int)bucket.render_millis());
}
-
-private:
- struct MemAdapter : public io::CopyingOutputStream {
- // Data is stored in an array of buffers.
- // JNI SetByteArrayRegion assembles data in one continuous Java byte[] buffer.
- std::vector<std::vector<unsigned char>> mBuffers;
- int mBuffersSize = 0; // total bytes allocated in mBuffers
- int mCurrentBufferUnusedSize = 0; // unused bytes in the last buffer mBuffers.back()
- unsigned char* mCurrentBuffer = nullptr; // pointer to next free byte in mBuffers.back()
-
- explicit MemAdapter() {}
- virtual ~MemAdapter() {}
-
- virtual bool Write(const void* buffer, int size) override {
- while (size > 0) {
- if (0 == mCurrentBufferUnusedSize) {
- mCurrentBufferUnusedSize =
- std::max(size, mBuffersSize ? 2 * mBuffersSize : 10000);
- mBuffers.emplace_back();
- mBuffers.back().resize(mCurrentBufferUnusedSize);
- mCurrentBuffer = mBuffers.back().data();
- mBuffersSize += mCurrentBufferUnusedSize;
- }
- int dataMoved = std::min(mCurrentBufferUnusedSize, size);
- memcpy(mCurrentBuffer, buffer, dataMoved);
- mCurrentBufferUnusedSize -= dataMoved;
- mCurrentBuffer += dataMoved;
- buffer = reinterpret_cast<const unsigned char*>(buffer) + dataMoved;
- size -= dataMoved;
- }
- return true;
- }
- };
-
- MemOutputStreamLite::MemAdapter mCopyAdapter;
- io::CopyingOutputStreamAdaptor mImpl;
-};
-
-void GraphicsStatsService::finishDumpInMemory(Dump* dump, const DumpMemoryFn& reader, void* param1,
- void* param2) {
- MemOutputStreamLite stream;
- dump->updateProto();
- bool success = dump->proto().SerializeToZeroCopyStream(&stream) && stream.Flush();
- delete dump;
- if (!success) {
- return;
+ for (int bucketIndex = 0; bucketIndex < stat.histogram_size(); bucketIndex++) {
+ auto& bucket = stat.histogram(bucketIndex);
+ proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED |
+ FRAME_COUNTS_FIELD_NUMBER /* field id */,
+ (long long)bucket.frame_count());
}
- stream.copyData(reader, param1, param2);
+ std::vector<uint8_t> outVector;
+ proto.serializeToVector(&outVector);
+ AStatsEvent_writeByteArray(event, outVector.data(), outVector.size());
}
+static void writeGpuHistogram(AStatsEvent* event,
+ const uirenderer::protos::GraphicsStatsProto& stat) {
+ util::ProtoOutputStream proto;
+ for (int bucketIndex = 0; bucketIndex < stat.gpu_histogram_size(); bucketIndex++) {
+ auto& bucket = stat.gpu_histogram(bucketIndex);
+ proto.write(android::util::FIELD_TYPE_INT32 | android::util::FIELD_COUNT_REPEATED |
+ TIME_MILLIS_BUCKETS_FIELD_NUMBER /* field id */,
+ (int)bucket.render_millis());
+ }
+ for (int bucketIndex = 0; bucketIndex < stat.gpu_histogram_size(); bucketIndex++) {
+ auto& bucket = stat.gpu_histogram(bucketIndex);
+ proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED |
+ FRAME_COUNTS_FIELD_NUMBER /* field id */,
+ (long long)bucket.frame_count());
+ }
+ std::vector<uint8_t> outVector;
+ proto.serializeToVector(&outVector);
+ AStatsEvent_writeByteArray(event, outVector.data(), outVector.size());
+}
+
+
+void GraphicsStatsService::finishDumpInMemory(Dump* dump, AStatsEventList* data,
+ bool lastFullDay) {
+ dump->updateProto();
+ auto& serviceDump = dump->proto();
+ for (int stat_index = 0; stat_index < serviceDump.stats_size(); stat_index++) {
+ auto& stat = serviceDump.stats(stat_index);
+ AStatsEvent* event = AStatsEventList_addStatsEvent(data);
+ AStatsEvent_setAtomId(event, android::util::GRAPHICS_STATS);
+ AStatsEvent_writeString(event, stat.package_name().c_str());
+ AStatsEvent_writeInt64(event, (int64_t)stat.version_code());
+ AStatsEvent_writeInt64(event, (int64_t)stat.stats_start());
+ AStatsEvent_writeInt64(event, (int64_t)stat.stats_end());
+ AStatsEvent_writeInt32(event, (int32_t)stat.pipeline());
+ AStatsEvent_writeInt32(event, (int32_t)stat.summary().total_frames());
+ AStatsEvent_writeInt32(event, (int32_t)stat.summary().missed_vsync_count());
+ AStatsEvent_writeInt32(event, (int32_t)stat.summary().high_input_latency_count());
+ AStatsEvent_writeInt32(event, (int32_t)stat.summary().slow_ui_thread_count());
+ AStatsEvent_writeInt32(event, (int32_t)stat.summary().slow_bitmap_upload_count());
+ AStatsEvent_writeInt32(event, (int32_t)stat.summary().slow_draw_count());
+ AStatsEvent_writeInt32(event, (int32_t)stat.summary().missed_deadline_count());
+ writeCpuHistogram(event, stat);
+ writeGpuHistogram(event, stat);
+ // TODO: fill in UI mainline module version, when the feature is available.
+ AStatsEvent_writeInt64(event, (int64_t)0);
+ AStatsEvent_writeBool(event, !lastFullDay);
+ AStatsEvent_build(event);
+ }
+}
+
+
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/service/GraphicsStatsService.h b/libs/hwui/service/GraphicsStatsService.h
index 4bed9633..59e21d0 100644
--- a/libs/hwui/service/GraphicsStatsService.h
+++ b/libs/hwui/service/GraphicsStatsService.h
@@ -20,6 +20,7 @@
#include "JankTracker.h"
#include "utils/Macros.h"
+#include <stats_pull_atom_callback.h>
namespace android {
namespace uirenderer {
@@ -27,9 +28,6 @@
class GraphicsStatsProto;
}
-typedef void (*DumpMemoryFn)(void* buffer, int bufferOffset, int bufferSize, int totalSize,
- void* param1, void* param2);
-
/*
* The exported entry points used by GraphicsStatsService.java in f/b/services/core
*
@@ -56,8 +54,8 @@
int64_t startTime, int64_t endTime, const ProfileData* data);
ANDROID_API static void addToDump(Dump* dump, const std::string& path);
ANDROID_API static void finishDump(Dump* dump);
- ANDROID_API static void finishDumpInMemory(Dump* dump, const DumpMemoryFn& reader, void* param1,
- void* param2);
+ ANDROID_API static void finishDumpInMemory(Dump* dump, AStatsEventList* data,
+ bool lastFullDay);
// Visible for testing
static bool parseFromFile(const std::string& path, protos::GraphicsStatsProto* output);
diff --git a/libs/hwui/tests/unit/FatVectorTests.cpp b/libs/hwui/tests/unit/FatVectorTests.cpp
index 8523e6c..6585a62 100644
--- a/libs/hwui/tests/unit/FatVectorTests.cpp
+++ b/libs/hwui/tests/unit/FatVectorTests.cpp
@@ -15,7 +15,7 @@
*/
#include <gtest/gtest.h>
-#include <utils/FatVector.h>
+#include <ui/FatVector.h>
#include <tests/common/TestUtils.h>
diff --git a/libs/hwui/utils/FatVector.h b/libs/hwui/utils/FatVector.h
deleted file mode 100644
index 8cc4d10..0000000
--- a/libs/hwui/utils/FatVector.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2015, The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ANDROID_FAT_VECTOR_H
-#define ANDROID_FAT_VECTOR_H
-
-#include "utils/Macros.h"
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <utils/Log.h>
-#include <type_traits>
-
-#include <vector>
-
-namespace android {
-namespace uirenderer {
-
-template <typename T, size_t SIZE>
-class InlineStdAllocator {
-public:
- struct Allocation {
- PREVENT_COPY_AND_ASSIGN(Allocation);
-
- public:
- Allocation(){};
- // char array instead of T array, so memory is uninitialized, with no destructors run
- char array[sizeof(T) * SIZE];
- bool inUse = false;
- };
-
- typedef T value_type; // needed to implement std::allocator
- typedef T* pointer; // needed to implement std::allocator
-
- explicit InlineStdAllocator(Allocation& allocation) : mAllocation(allocation) {}
- InlineStdAllocator(const InlineStdAllocator& other) : mAllocation(other.mAllocation) {}
- ~InlineStdAllocator() {}
-
- T* allocate(size_t num, const void* = 0) {
- if (!mAllocation.inUse && num <= SIZE) {
- mAllocation.inUse = true;
- return (T*)mAllocation.array;
- } else {
- return (T*)malloc(num * sizeof(T));
- }
- }
-
- void deallocate(pointer p, size_t num) {
- if (p == (T*)mAllocation.array) {
- mAllocation.inUse = false;
- } else {
- // 'free' instead of delete here - destruction handled separately
- free(p);
- }
- }
- Allocation& mAllocation;
-};
-
-/**
- * std::vector with SIZE elements preallocated into an internal buffer.
- *
- * Useful for avoiding the cost of malloc in cases where only SIZE or
- * fewer elements are needed in the common case.
- */
-template <typename T, size_t SIZE>
-class FatVector : public std::vector<T, InlineStdAllocator<T, SIZE>> {
-public:
- FatVector()
- : std::vector<T, InlineStdAllocator<T, SIZE>>(
- InlineStdAllocator<T, SIZE>(mAllocation)) {
- this->reserve(SIZE);
- }
-
- explicit FatVector(size_t capacity) : FatVector() { this->resize(capacity); }
-
-private:
- typename InlineStdAllocator<T, SIZE>::Allocation mAllocation;
-};
-
-} // namespace uirenderer
-} // namespace android
-
-#endif // ANDROID_FAT_VECTOR_H
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index e4348f2..3b494e9 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -251,19 +251,24 @@
void PointerController::setPresentation(Presentation presentation) {
AutoMutex _l(mLock);
- if (presentation == PRESENTATION_POINTER && mLocked.additionalMouseResources.empty()) {
- mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
- &mLocked.animationResources, mLocked.viewport.displayId);
+ if (mLocked.presentation == presentation) {
+ return;
}
- if (mLocked.presentation != presentation) {
- mLocked.presentation = presentation;
- mLocked.presentationChanged = true;
+ mLocked.presentation = presentation;
+ mLocked.presentationChanged = true;
- if (presentation != PRESENTATION_SPOT) {
- fadeOutAndReleaseAllSpotsLocked();
+ if (!mLocked.viewport.isValid()) {
+ return;
+ }
+
+ if (presentation == PRESENTATION_POINTER) {
+ if (mLocked.additionalMouseResources.empty()) {
+ mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
+ &mLocked.animationResources,
+ mLocked.viewport.displayId);
}
-
+ fadeOutAndReleaseAllSpotsLocked();
updatePointerLocked();
}
}
@@ -285,6 +290,9 @@
#endif
AutoMutex _l(mLock);
+ if (!mLocked.viewport.isValid()) {
+ return;
+ }
std::vector<Spot*> newSpots;
std::map<int32_t, std::vector<Spot*>>::const_iterator iter =
@@ -331,6 +339,9 @@
#endif
AutoMutex _l(mLock);
+ if (!mLocked.viewport.isValid()) {
+ return;
+ }
fadeOutAndReleaseAllSpotsLocked();
}
@@ -752,6 +763,10 @@
}
void PointerController::loadResourcesLocked() REQUIRES(mLock) {
+ if (!mLocked.viewport.isValid()) {
+ return;
+ }
+
mPolicy->loadPointerResources(&mResources, mLocked.viewport.displayId);
mPolicy->loadPointerIcon(&mLocked.pointerIcon, mLocked.viewport.displayId);
diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp
index b36406d..a157426 100644
--- a/libs/input/tests/PointerController_test.cpp
+++ b/libs/input/tests/PointerController_test.cpp
@@ -39,8 +39,8 @@
using ::testing::AllOf;
using ::testing::Field;
-using ::testing::NiceMock;
using ::testing::Mock;
+using ::testing::NiceMock;
using ::testing::Return;
using ::testing::Test;
@@ -57,12 +57,20 @@
virtual int32_t getDefaultPointerIconId() override;
virtual int32_t getCustomPointerIconId() override;
+ bool allResourcesAreLoaded();
+ bool noResourcesAreLoaded();
+
private:
void loadPointerIconForType(SpriteIcon* icon, int32_t cursorType);
+
+ bool pointerIconLoaded{false};
+ bool pointerResourcesLoaded{false};
+ bool additionalMouseResourcesLoaded{false};
};
void MockPointerControllerPolicyInterface::loadPointerIcon(SpriteIcon* icon, int32_t) {
loadPointerIconForType(icon, CURSOR_TYPE_DEFAULT);
+ pointerIconLoaded = true;
}
void MockPointerControllerPolicyInterface::loadPointerResources(PointerResources* outResources,
@@ -70,6 +78,7 @@
loadPointerIconForType(&outResources->spotHover, CURSOR_TYPE_HOVER);
loadPointerIconForType(&outResources->spotTouch, CURSOR_TYPE_TOUCH);
loadPointerIconForType(&outResources->spotAnchor, CURSOR_TYPE_ANCHOR);
+ pointerResourcesLoaded = true;
}
void MockPointerControllerPolicyInterface::loadAdditionalMouseResources(
@@ -91,6 +100,8 @@
anim.durationPerFrame = 10;
(*outResources)[cursorType] = icon;
(*outAnimationResources)[cursorType] = anim;
+
+ additionalMouseResourcesLoaded = true;
}
int32_t MockPointerControllerPolicyInterface::getDefaultPointerIconId() {
@@ -101,18 +112,27 @@
return CURSOR_TYPE_CUSTOM;
}
+bool MockPointerControllerPolicyInterface::allResourcesAreLoaded() {
+ return pointerIconLoaded && pointerResourcesLoaded && additionalMouseResourcesLoaded;
+}
+
+bool MockPointerControllerPolicyInterface::noResourcesAreLoaded() {
+ return !(pointerIconLoaded || pointerResourcesLoaded || additionalMouseResourcesLoaded);
+}
+
void MockPointerControllerPolicyInterface::loadPointerIconForType(SpriteIcon* icon, int32_t type) {
icon->style = type;
std::pair<float, float> hotSpot = getHotSpotCoordinatesForType(type);
icon->hotSpotX = hotSpot.first;
icon->hotSpotY = hotSpot.second;
}
-
class PointerControllerTest : public Test {
protected:
PointerControllerTest();
~PointerControllerTest();
+ void ensureDisplayViewportIsSet();
+
sp<MockSprite> mPointerSprite;
sp<MockPointerControllerPolicyInterface> mPolicy;
sp<MockSpriteController> mSpriteController;
@@ -141,7 +161,14 @@
.WillOnce(Return(mPointerSprite));
mPointerController = new PointerController(mPolicy, mLooper, mSpriteController);
+}
+PointerControllerTest::~PointerControllerTest() {
+ mRunning.store(false, std::memory_order_relaxed);
+ mThread.join();
+}
+
+void PointerControllerTest::ensureDisplayViewportIsSet() {
DisplayViewport viewport;
viewport.displayId = ADISPLAY_ID_DEFAULT;
viewport.logicalRight = 1600;
@@ -151,11 +178,9 @@
viewport.deviceWidth = 400;
viewport.deviceHeight = 300;
mPointerController->setDisplayViewport(viewport);
-}
-PointerControllerTest::~PointerControllerTest() {
- mRunning.store(false, std::memory_order_relaxed);
- mThread.join();
+ // The first call to setDisplayViewport should trigger the loading of the necessary resources.
+ EXPECT_TRUE(mPolicy->allResourcesAreLoaded());
}
void PointerControllerTest::loopThread() {
@@ -167,6 +192,7 @@
}
TEST_F(PointerControllerTest, useDefaultCursorTypeByDefault) {
+ ensureDisplayViewportIsSet();
mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
std::pair<float, float> hotspot = getHotSpotCoordinatesForType(CURSOR_TYPE_DEFAULT);
@@ -181,6 +207,7 @@
}
TEST_F(PointerControllerTest, updatePointerIcon) {
+ ensureDisplayViewportIsSet();
mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
int32_t type = CURSOR_TYPE_ADDITIONAL;
@@ -196,6 +223,7 @@
}
TEST_F(PointerControllerTest, setCustomPointerIcon) {
+ ensureDisplayViewportIsSet();
mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
int32_t style = CURSOR_TYPE_CUSTOM;
@@ -217,4 +245,18 @@
mPointerController->setCustomPointerIcon(icon);
}
+TEST_F(PointerControllerTest, doesNotGetResourcesBeforeSettingViewport) {
+ mPointerController->setPresentation(PointerController::PRESENTATION_POINTER);
+ mPointerController->setSpots(nullptr, nullptr, BitSet32(), -1);
+ mPointerController->clearSpots();
+ mPointerController->setPosition(1.0f, 1.0f);
+ mPointerController->move(1.0f, 1.0f);
+ mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
+ mPointerController->fade(PointerController::TRANSITION_IMMEDIATE);
+
+ EXPECT_TRUE(mPolicy->noResourcesAreLoaded());
+
+ ensureDisplayViewportIsSet();
+}
+
} // namespace android
diff --git a/libs/services/Android.bp b/libs/services/Android.bp
index 9b047ca..1e62107 100644
--- a/libs/services/Android.bp
+++ b/libs/services/Android.bp
@@ -20,7 +20,6 @@
":IDropBoxManagerService.aidl",
"src/content/ComponentName.cpp",
"src/os/DropBoxManager.cpp",
- "src/os/StatsDimensionsValue.cpp",
],
shared_libs: [
diff --git a/libs/services/include/android/os/StatsDimensionsValue.h b/libs/services/include/android/os/StatsDimensionsValue.h
deleted file mode 100644
index cc0b056..0000000
--- a/libs/services/include/android/os/StatsDimensionsValue.h
+++ /dev/null
@@ -1,70 +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.
- */
-#ifndef STATS_DIMENSIONS_VALUE_H
-#define STATS_DIMENSIONS_VALUE_H
-
-#include <binder/Parcel.h>
-#include <binder/Parcelable.h>
-#include <binder/Status.h>
-#include <utils/String16.h>
-#include <vector>
-
-namespace android {
-namespace os {
-
-// Represents a parcelable object. Used to send data from statsd to StatsCompanionService.java.
-class StatsDimensionsValue : public android::Parcelable {
-public:
- StatsDimensionsValue();
-
- StatsDimensionsValue(int32_t field, String16 value);
- StatsDimensionsValue(int32_t field, int32_t value);
- StatsDimensionsValue(int32_t field, int64_t value);
- StatsDimensionsValue(int32_t field, bool value);
- StatsDimensionsValue(int32_t field, float value);
- StatsDimensionsValue(int32_t field, std::vector<StatsDimensionsValue> value);
-
- virtual ~StatsDimensionsValue();
-
- virtual android::status_t writeToParcel(android::Parcel* out) const override;
- virtual android::status_t readFromParcel(const android::Parcel* in) override;
-
-private:
- // Keep constants in sync with android/os/StatsDimensionsValue.java
- // and stats_log.proto's DimensionValue.
- static const int kStrValueType = 2;
- static const int kIntValueType = 3;
- static const int kLongValueType = 4;
- static const int kBoolValueType = 5;
- static const int kFloatValueType = 6;
- static const int kTupleValueType = 7;
-
- int32_t mField;
- int32_t mValueType;
-
- // This isn't very clever, but it isn't used for long-term storage, so it'll do.
- String16 mStrValue;
- int32_t mIntValue;
- int64_t mLongValue;
- bool mBoolValue;
- float mFloatValue;
- std::vector<StatsDimensionsValue> mTupleValue;
-};
-
-} // namespace os
-} // namespace android
-
-#endif // STATS_DIMENSIONS_VALUE_H
diff --git a/libs/services/src/os/StatsDimensionsValue.cpp b/libs/services/src/os/StatsDimensionsValue.cpp
deleted file mode 100644
index 0052e0b..0000000
--- a/libs/services/src/os/StatsDimensionsValue.cpp
+++ /dev/null
@@ -1,126 +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.
- */
-
-#define LOG_TAG "StatsDimensionsValue"
-
-#include "android/os/StatsDimensionsValue.h"
-
-#include <cutils/log.h>
-
-using android::Parcel;
-using android::Parcelable;
-using android::status_t;
-using std::vector;
-
-namespace android {
-namespace os {
-
-StatsDimensionsValue::StatsDimensionsValue() {};
-
-StatsDimensionsValue::StatsDimensionsValue(int32_t field, String16 value) :
- mField(field),
- mValueType(kStrValueType),
- mStrValue(value) {
-}
-StatsDimensionsValue::StatsDimensionsValue(int32_t field, int32_t value) :
- mField(field),
- mValueType(kIntValueType),
- mIntValue(value) {
-}
-StatsDimensionsValue::StatsDimensionsValue(int32_t field, int64_t value) :
- mField(field),
- mValueType(kLongValueType),
- mLongValue(value) {
-}
-StatsDimensionsValue::StatsDimensionsValue(int32_t field, bool value) :
- mField(field),
- mValueType(kBoolValueType),
- mBoolValue(value) {
-}
-StatsDimensionsValue::StatsDimensionsValue(int32_t field, float value) :
- mField(field),
- mValueType(kFloatValueType),
- mFloatValue(value) {
-}
-StatsDimensionsValue::StatsDimensionsValue(int32_t field, vector<StatsDimensionsValue> value) :
- mField(field),
- mValueType(kTupleValueType),
- mTupleValue(value) {
-}
-
-StatsDimensionsValue::~StatsDimensionsValue() {}
-
-status_t
-StatsDimensionsValue::writeToParcel(Parcel* out) const {
- status_t err ;
-
- err = out->writeInt32(mField);
- if (err != NO_ERROR) {
- return err;
- }
- err = out->writeInt32(mValueType);
- if (err != NO_ERROR) {
- return err;
- }
- switch (mValueType) {
- case kStrValueType:
- err = out->writeString16(mStrValue);
- break;
- case kIntValueType:
- err = out->writeInt32(mIntValue);
- break;
- case kLongValueType:
- err = out->writeInt64(mLongValue);
- break;
- case kBoolValueType:
- err = out->writeBool(mBoolValue);
- break;
- case kFloatValueType:
- err = out->writeFloat(mFloatValue);
- break;
- case kTupleValueType:
- {
- int sz = mTupleValue.size();
- err = out->writeInt32(sz);
- if (err != NO_ERROR) {
- return err;
- }
- for (int i = 0; i < sz; ++i) {
- err = mTupleValue[i].writeToParcel(out);
- if (err != NO_ERROR) {
- return err;
- }
- }
- }
- break;
- default:
- err = UNKNOWN_ERROR;
- break;
- }
- return err;
-}
-
-status_t
-StatsDimensionsValue::readFromParcel(const Parcel* in)
-{
- // Implement me if desired. We don't currently use this.
- ALOGE("Cannot do c++ StatsDimensionsValue.readFromParcel(); it is not implemented.");
- (void)in; // To prevent compile error of unused parameter 'in'
- return UNKNOWN_ERROR;
-}
-
-} // namespace os
-} // namespace android
diff --git a/core/java/android/os/StatsDimensionsValue.aidl b/location/java/android/location/GnssRequest.aidl
similarity index 76%
rename from core/java/android/os/StatsDimensionsValue.aidl
rename to location/java/android/location/GnssRequest.aidl
index 81a14a4..581abcc 100644
--- a/core/java/android/os/StatsDimensionsValue.aidl
+++ b/location/java/android/location/GnssRequest.aidl
@@ -1,5 +1,5 @@
-/**
- * Copyright (c) 2018, The Android Open Source Project
+/*
+ * Copyright (C) 2020, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,9 @@
* limitations under the License.
*/
-package android.os;
+package android.location;
-/** @hide */
-parcelable StatsDimensionsValue cpp_header "android/os/StatsDimensionsValue.h";
\ No newline at end of file
+/**
+ * @hide
+ */
+parcelable GnssRequest;
diff --git a/location/java/android/location/GnssRequest.java b/location/java/android/location/GnssRequest.java
new file mode 100644
index 0000000..2afb265
--- /dev/null
+++ b/location/java/android/location/GnssRequest.java
@@ -0,0 +1,147 @@
+/*
+ * 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.location;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class contains extra parameters to pass to a GNSS provider implementation.
+ * @hide
+ */
+@SystemApi
+public final class GnssRequest implements Parcelable {
+ private final boolean mFullTracking;
+
+ /**
+ * Creates a {@link GnssRequest} with a full list of parameters.
+ */
+ private GnssRequest(boolean fullTracking) {
+ mFullTracking = fullTracking;
+ }
+
+ /**
+ * Represents whether to enable full GNSS tracking.
+ *
+ * <p>If true, GNSS chipset switches off duty cycling. In such a mode, no clock
+ * discontinuities are expected, and when supported, carrier phase should be continuous in
+ * good signal conditions. All non-blacklisted, healthy constellations, satellites and
+ * frequency bands that the chipset supports must be reported in this mode. The GNSS chipset
+ * is allowed to consume more power in this mode. If false, GNSS chipset optimizes power via
+ * duty cycling, constellations and frequency limits, etc.
+ */
+ public boolean isFullTracking() {
+ return mFullTracking;
+ }
+
+ @NonNull
+ public static final Creator<GnssRequest> CREATOR =
+ new Creator<GnssRequest>() {
+ @Override
+ @NonNull
+ public GnssRequest createFromParcel(@NonNull Parcel parcel) {
+ return new GnssRequest(parcel.readBoolean());
+ }
+
+ @Override
+ public GnssRequest[] newArray(int i) {
+ return new GnssRequest[i];
+ }
+ };
+
+ @NonNull
+ @Override
+ public String toString() {
+ StringBuilder s = new StringBuilder();
+ s.append("GnssRequest[");
+ s.append("FullTracking=").append(mFullTracking);
+ s.append(']');
+ return s.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (!(obj instanceof GnssRequest)) return false;
+
+ GnssRequest other = (GnssRequest) obj;
+ if (mFullTracking != other.mFullTracking) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return mFullTracking ? 1 : 0;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
+ parcel.writeBoolean(mFullTracking);
+ }
+
+ /** Builder for {@link GnssRequest} */
+ public static final class Builder {
+ private boolean mFullTracking;
+
+ /**
+ * Constructs a {@link Builder} instance.
+ */
+ public Builder() {
+ }
+
+ /**
+ * Constructs a {@link Builder} instance by copying a {@link GnssRequest}.
+ */
+ public Builder(@NonNull GnssRequest request) {
+ mFullTracking = request.isFullTracking();
+ }
+
+ /**
+ * Set the value of whether to enable full GNSS tracking, which is false by default.
+ *
+ * <p>If true, GNSS chipset switches off duty cycling. In such a mode, no clock
+ * discontinuities are expected, and when supported, carrier phase should be continuous in
+ * good signal conditions. All non-blacklisted, healthy constellations, satellites and
+ * frequency bands that the chipset supports must be reported in this mode. The GNSS chipset
+ * is allowed to consume more power in this mode. If false, GNSS chipset optimizes power via
+ * duty cycling, constellations and frequency limits, etc.
+ *
+ * <p>Full tracking requests always override non-full tracking requests. If any full
+ * tracking request occurs, all listeners on the device will receive full tracking GNSS
+ * measurements.
+ */
+ @NonNull public Builder setFullTracking(boolean value) {
+ mFullTracking = value;
+ return this;
+ }
+
+ /** Builds a {@link GnssRequest} instance as specified by this builder. */
+ @NonNull
+ public GnssRequest build() {
+ return new GnssRequest(mFullTracking);
+ }
+ }
+}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 1c10edb..7e6486c 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -2196,6 +2196,30 @@
}
/**
+ * Registers a GNSS Measurement callback.
+ *
+ * @param request extra parameters to pass to GNSS measurement provider. For example, if {@link
+ * GnssRequest#isFullTrackingEnabled()} is true, GNSS chipset switches off duty
+ * cycling.
+ * @param executor the executor that the callback runs on.
+ * @param callback a {@link GnssMeasurementsEvent.Callback} object to register.
+ * @return {@code true} if the callback was added successfully, {@code false} otherwise.
+ * @throws IllegalArgumentException if request is null
+ * @throws IllegalArgumentException if executor is null
+ * @throws IllegalArgumentException if callback is null
+ * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, LOCATION_HARDWARE})
+ public boolean registerGnssMeasurementsCallback(
+ @NonNull GnssRequest request,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull GnssMeasurementsEvent.Callback callback) {
+ throw new RuntimeException();
+ }
+
+ /**
* Injects GNSS measurement corrections into the GNSS chipset.
*
* @param measurementCorrections a {@link GnssMeasurementCorrections} object with the GNSS
diff --git a/media/java/android/media/AudioDeviceAddress.aidl b/media/java/android/media/AudioDevice.aidl
similarity index 94%
rename from media/java/android/media/AudioDeviceAddress.aidl
rename to media/java/android/media/AudioDevice.aidl
index 6a1a7f7..02071e5 100644
--- a/media/java/android/media/AudioDeviceAddress.aidl
+++ b/media/java/android/media/AudioDevice.aidl
@@ -15,4 +15,4 @@
package android.media;
-parcelable AudioDeviceAddress;
+parcelable AudioDevice;
diff --git a/media/java/android/media/AudioDeviceAddress.java b/media/java/android/media/AudioDevice.java
similarity index 84%
rename from media/java/android/media/AudioDeviceAddress.java
rename to media/java/android/media/AudioDevice.java
index 3d8fc37..31ecc7b 100644
--- a/media/java/android/media/AudioDeviceAddress.java
+++ b/media/java/android/media/AudioDevice.java
@@ -28,7 +28,7 @@
/**
* @hide
- * Class to represent device type (speaker, headset...), address and role (input, output)
+ * Class to represent device type (speaker, headset...), address (if known) and role (input, output)
* of an audio device.
* <p>Unlike {@link AudioDeviceInfo}, the device
* doesn't need to be connected to be uniquely identified, it can
@@ -39,7 +39,7 @@
* permission, APIs using one rely on MODIFY_AUDIO_ROUTING.
*/
@SystemApi
-public final class AudioDeviceAddress implements Parcelable {
+public final class AudioDevice implements Parcelable {
/**
* A role identifying input devices, such as microphones.
@@ -78,7 +78,7 @@
* type and address.
*/
@SystemApi
- public AudioDeviceAddress(@NonNull AudioDeviceInfo deviceInfo) {
+ public AudioDevice(@NonNull AudioDeviceInfo deviceInfo) {
Objects.requireNonNull(deviceInfo);
mRole = deviceInfo.isSink() ? ROLE_OUTPUT : ROLE_INPUT;
mType = deviceInfo.getType();
@@ -93,7 +93,7 @@
* @param address the address of the device, or an empty string for devices without one
*/
@SystemApi
- public AudioDeviceAddress(@Role int role, @AudioDeviceInfo.AudioDeviceType int type,
+ public AudioDevice(@Role int role, @AudioDeviceInfo.AudioDeviceType int type,
@NonNull String address) {
Objects.requireNonNull(address);
if (role != ROLE_OUTPUT && role != ROLE_INPUT) {
@@ -111,7 +111,7 @@
mAddress = address;
}
- /*package*/ AudioDeviceAddress(int nativeType, @NonNull String address) {
+ /*package*/ AudioDevice(int nativeType, @NonNull String address) {
mRole = (nativeType & AudioSystem.DEVICE_BIT_IN) != 0 ? ROLE_INPUT : ROLE_OUTPUT;
mType = AudioDeviceInfo.convertInternalDeviceToDeviceType(nativeType);
mAddress = address;
@@ -157,7 +157,7 @@
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
- AudioDeviceAddress that = (AudioDeviceAddress) o;
+ AudioDevice that = (AudioDevice) o;
return ((mRole == that.mRole)
&& (mType == that.mType)
&& mAddress.equals(that.mAddress));
@@ -170,7 +170,7 @@
@Override
public String toString() {
- return new String("AudioDeviceAddress:"
+ return new String("AudioDevice:"
+ " role:" + roleToString(mRole)
+ " type:" + (mRole == ROLE_OUTPUT ? AudioSystem.getOutputDeviceName(
AudioDeviceInfo.convertDeviceTypeToInternalDevice(mType))
@@ -191,25 +191,25 @@
dest.writeString(mAddress);
}
- private AudioDeviceAddress(@NonNull Parcel in) {
+ private AudioDevice(@NonNull Parcel in) {
mRole = in.readInt();
mType = in.readInt();
mAddress = in.readString();
}
- public static final @NonNull Parcelable.Creator<AudioDeviceAddress> CREATOR =
- new Parcelable.Creator<AudioDeviceAddress>() {
+ public static final @NonNull Parcelable.Creator<AudioDevice> CREATOR =
+ new Parcelable.Creator<AudioDevice>() {
/**
- * Rebuilds an AudioDeviceAddress previously stored with writeToParcel().
- * @param p Parcel object to read the AudioDeviceAddress from
- * @return a new AudioDeviceAddress created from the data in the parcel
+ * Rebuilds an AudioDevice previously stored with writeToParcel().
+ * @param p Parcel object to read the AudioDevice from
+ * @return a new AudioDevice created from the data in the parcel
*/
- public AudioDeviceAddress createFromParcel(Parcel p) {
- return new AudioDeviceAddress(p);
+ public AudioDevice createFromParcel(Parcel p) {
+ return new AudioDevice(p);
}
- public AudioDeviceAddress[] newArray(int size) {
- return new AudioDeviceAddress[size];
+ public AudioDevice[] newArray(int size) {
+ return new AudioDevice[size];
}
};
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 7b17f9f..4a1088b 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1596,7 +1596,7 @@
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy,
- @NonNull AudioDeviceAddress device) {
+ @NonNull AudioDevice device) {
Objects.requireNonNull(strategy);
Objects.requireNonNull(device);
try {
@@ -1611,7 +1611,7 @@
/**
* @hide
* Removes the preferred audio device previously set with
- * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAddress)}.
+ * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDevice)}.
* @param strategy the audio strategy whose routing will be affected
* @return true if the operation was successful, false otherwise (invalid strategy, or no
* device set for example)
@@ -1632,14 +1632,14 @@
/**
* @hide
* Return the preferred device for an audio strategy, previously set with
- * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAddress)}
+ * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDevice)}
* @param strategy the strategy to query
* @return the preferred device for that strategy, or null if none was ever set or if the
* strategy is invalid
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
- public @Nullable AudioDeviceAddress getPreferredDeviceForStrategy(
+ public @Nullable AudioDevice getPreferredDeviceForStrategy(
@NonNull AudioProductStrategy strategy) {
Objects.requireNonNull(strategy);
try {
@@ -4379,7 +4379,7 @@
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
- public @NonNull List<AudioDeviceAddress> getDevicesForAttributes(
+ public @NonNull List<AudioDevice> getDevicesForAttributes(
@NonNull AudioAttributes attributes) {
Objects.requireNonNull(attributes);
final IAudioService service = getService();
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 02cb8aa..0a0f7f6 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1085,18 +1085,18 @@
* @return an empty list if there was an issue with the request, a list of audio devices
* otherwise (typically one device, except for duplicated paths).
*/
- public static @NonNull ArrayList<AudioDeviceAddress> getDevicesForAttributes(
+ public static @NonNull ArrayList<AudioDevice> getDevicesForAttributes(
@NonNull AudioAttributes attributes) {
Objects.requireNonNull(attributes);
- final AudioDeviceAddress[] devices = new AudioDeviceAddress[MAX_DEVICE_ROUTING];
+ final AudioDevice[] devices = new AudioDevice[MAX_DEVICE_ROUTING];
final int res = getDevicesForAttributes(attributes, devices);
- final ArrayList<AudioDeviceAddress> routeDevices = new ArrayList<>();
+ final ArrayList<AudioDevice> routeDevices = new ArrayList<>();
if (res != SUCCESS) {
Log.e(TAG, "error " + res + " in getDevicesForAttributes for " + attributes);
return routeDevices;
}
- for (AudioDeviceAddress device : devices) {
+ for (AudioDevice device : devices) {
if (device != null) {
routeDevices.add(device);
}
@@ -1106,12 +1106,12 @@
/**
* Maximum number of audio devices a track is ever routed to, determines the size of the
- * array passed to {@link #getDevicesForAttributes(AudioAttributes, AudioDeviceAddress[])}
+ * array passed to {@link #getDevicesForAttributes(AudioAttributes, AudioDevice[])}
*/
private static final int MAX_DEVICE_ROUTING = 4;
private static native int getDevicesForAttributes(@NonNull AudioAttributes aa,
- @NonNull AudioDeviceAddress[] devices);
+ @NonNull AudioDevice[] devices);
/** @hide returns true if master mono is enabled. */
public static native boolean getMasterMono();
@@ -1246,7 +1246,7 @@
* @return {@link #SUCCESS} if successfully set
*/
public static int setPreferredDeviceForStrategy(
- int strategy, @NonNull AudioDeviceAddress device) {
+ int strategy, @NonNull AudioDevice device) {
return setPreferredDeviceForStrategy(strategy,
AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType()),
device.getAddress());
@@ -1277,7 +1277,7 @@
* and written to the array
*/
public static native int getPreferredDeviceForStrategy(int strategy,
- AudioDeviceAddress[] device);
+ AudioDevice[] device);
// Items shared with audio service
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 767b67b..d237975 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -1457,6 +1457,9 @@
private int mRw2JpgFromRawOffset;
private boolean mIsSupportedFile;
private boolean mModified;
+ // XMP data can be contained as either part of the EXIF data (tag number 700), or as a
+ // separate data marker (a separate MARKER_APP1).
+ private boolean mXmpIsFromSeparateMarker;
// Pattern to check non zero timestamp
private static final Pattern sNonZeroTimePattern = Pattern.compile(".*[1-9].*");
@@ -2837,10 +2840,12 @@
final long offset = start + IDENTIFIER_XMP_APP1.length;
final byte[] value = Arrays.copyOfRange(bytes,
IDENTIFIER_XMP_APP1.length, bytes.length);
-
+ // TODO: check if ignoring separate XMP data when tag 700 already exists is
+ // valid.
if (getAttribute(TAG_XMP) == null) {
mAttributes[IFD_TYPE_PRIMARY].put(TAG_XMP, new ExifAttribute(
IFD_FORMAT_BYTE, value.length, offset, value));
+ mXmpIsFromSeparateMarker = true;
}
}
break;
@@ -3445,11 +3450,24 @@
}
dataOutputStream.writeByte(MARKER_SOI);
+ // Remove XMP data if it is from a separate marker (IDENTIFIER_XMP_APP1, not
+ // IDENTIFIER_EXIF_APP1)
+ // Will re-add it later after the rest of the file is written
+ ExifAttribute xmpAttribute = null;
+ if (getAttribute(TAG_XMP) != null && mXmpIsFromSeparateMarker) {
+ xmpAttribute = (ExifAttribute) mAttributes[IFD_TYPE_PRIMARY].remove(TAG_XMP);
+ }
+
// Write EXIF APP1 segment
dataOutputStream.writeByte(MARKER);
dataOutputStream.writeByte(MARKER_APP1);
writeExifSegment(dataOutputStream);
+ // Re-add previously removed XMP data.
+ if (xmpAttribute != null) {
+ mAttributes[IFD_TYPE_PRIMARY].put(TAG_XMP, xmpAttribute);
+ }
+
byte[] bytes = new byte[4096];
while (true) {
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 64c5c05..0fbc0d2 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -18,7 +18,7 @@
import android.bluetooth.BluetoothDevice;
import android.media.AudioAttributes;
-import android.media.AudioDeviceAddress;
+import android.media.AudioDevice;
import android.media.AudioFocusInfo;
import android.media.AudioPlaybackConfiguration;
import android.media.AudioRecordingConfiguration;
@@ -274,13 +274,13 @@
boolean isCallScreeningModeSupported();
- int setPreferredDeviceForStrategy(in int strategy, in AudioDeviceAddress device);
+ int setPreferredDeviceForStrategy(in int strategy, in AudioDevice device);
int removePreferredDeviceForStrategy(in int strategy);
- AudioDeviceAddress getPreferredDeviceForStrategy(in int strategy);
+ AudioDevice getPreferredDeviceForStrategy(in int strategy);
- List<AudioDeviceAddress> getDevicesForAttributes(in AudioAttributes attributes);
+ List<AudioDevice> getDevicesForAttributes(in AudioAttributes attributes);
int setAllowedCapturePolicy(in int capturePolicy);
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index d7b74df..6418610 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -471,7 +471,8 @@
synchronized (sRouterLock) {
for (MediaRoute2Info route : routes) {
mRoutes.put(route.getId(), route);
- if (route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) {
+ if (route.isSystemRoute()
+ || route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) {
addedRoutes.add(route);
}
}
@@ -487,7 +488,8 @@
synchronized (sRouterLock) {
for (MediaRoute2Info route : routes) {
mRoutes.remove(route.getId());
- if (route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) {
+ if (route.isSystemRoute()
+ || route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) {
removedRoutes.add(route);
}
}
@@ -503,7 +505,8 @@
synchronized (sRouterLock) {
for (MediaRoute2Info route : routes) {
mRoutes.put(route.getId(), route);
- if (route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) {
+ if (route.isSystemRoute()
+ || route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) {
changedRoutes.add(route);
}
}
@@ -643,8 +646,8 @@
private List<MediaRoute2Info> filterRoutes(List<MediaRoute2Info> routes,
RouteDiscoveryPreference discoveryRequest) {
return routes.stream()
- .filter(
- route -> route.hasAnyFeatures(discoveryRequest.getPreferredFeatures()))
+ .filter(route -> route.isSystemRoute()
+ || route.hasAnyFeatures(discoveryRequest.getPreferredFeatures()))
.collect(Collectors.toList());
}
diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java
index c25a533..6157ef4 100644
--- a/media/java/android/media/audiofx/AudioEffect.java
+++ b/media/java/android/media/audiofx/AudioEffect.java
@@ -25,7 +25,7 @@
import android.annotation.TestApi;
import android.app.ActivityThread;
import android.compat.annotation.UnsupportedAppUsage;
-import android.media.AudioDeviceAddress;
+import android.media.AudioDevice;
import android.media.AudioDeviceInfo;
import android.media.AudioSystem;
import android.os.Build;
@@ -476,12 +476,12 @@
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
- public AudioEffect(@NonNull UUID uuid, @NonNull AudioDeviceAddress device) {
+ public AudioEffect(@NonNull UUID uuid, @NonNull AudioDevice device) {
this(EFFECT_TYPE_NULL, Objects.requireNonNull(uuid), 0, -2, Objects.requireNonNull(device));
}
private AudioEffect(UUID type, UUID uuid, int priority,
- int audioSession, @Nullable AudioDeviceAddress device)
+ int audioSession, @Nullable AudioDevice device)
throws IllegalArgumentException, UnsupportedOperationException,
RuntimeException {
int[] id = new int[1];
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 870c1b4..486c0c2 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -266,8 +266,12 @@
* playback after the session has been stopped. If your app is started in
* this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be sent via
* the pending intent.
+ * <p>
+ * The pending intent is recommended to be explicit to follow the security recommendation of
+ * {@link PendingIntent#getActivity}.
*
* @param mbr The {@link PendingIntent} to send the media button event to.
+ * @see PendingIntent#getActivity
*/
public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
try {
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
index c1b17d3..63de0334 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
@@ -41,8 +41,7 @@
FRONTEND_STATUS_TYPE_MODULATION, FRONTEND_STATUS_TYPE_SPECTRAL,
FRONTEND_STATUS_TYPE_LNB_VOLTAGE, FRONTEND_STATUS_TYPE_PLP_ID,
FRONTEND_STATUS_TYPE_EWBS, FRONTEND_STATUS_TYPE_AGC, FRONTEND_STATUS_TYPE_LNA,
- FRONTEND_STATUS_TYPE_LAYER_ERROR, FRONTEND_STATUS_TYPE_VBER_CN,
- FRONTEND_STATUS_TYPE_LBER_CN, FRONTEND_STATUS_TYPE_XER_CN, FRONTEND_STATUS_TYPE_MER,
+ FRONTEND_STATUS_TYPE_LAYER_ERROR, FRONTEND_STATUS_TYPE_MER,
FRONTEND_STATUS_TYPE_FREQ_OFFSET, FRONTEND_STATUS_TYPE_HIERARCHY,
FRONTEND_STATUS_TYPE_RF_LOCK, FRONTEND_STATUS_TYPE_ATSC3_PLP_INFO})
@Retention(RetentionPolicy.SOURCE)
@@ -125,18 +124,6 @@
public static final int FRONTEND_STATUS_TYPE_LAYER_ERROR =
Constants.FrontendStatusType.LAYER_ERROR;
/**
- * CN value by VBER.
- */
- public static final int FRONTEND_STATUS_TYPE_VBER_CN = Constants.FrontendStatusType.VBER_CN;
- /**
- * CN value by LBER.
- */
- public static final int FRONTEND_STATUS_TYPE_LBER_CN = Constants.FrontendStatusType.LBER_CN;
- /**
- * CN value by XER.
- */
- public static final int FRONTEND_STATUS_TYPE_XER_CN = Constants.FrontendStatusType.XER_CN;
- /**
* Modulation Error Ratio.
*/
public static final int FRONTEND_STATUS_TYPE_MER = Constants.FrontendStatusType.MER;
@@ -223,9 +210,6 @@
private Integer mAgc;
private Boolean mIsLnaOn;
private boolean[] mIsLayerErrors;
- private Integer mVberCn;
- private Integer mLberCn;
- private Integer mXerCn;
private Integer mMer;
private Integer mFreqOffset;
private Integer mHierarchy;
@@ -403,33 +387,6 @@
return mIsLayerErrors;
}
/**
- * Gets CN value by VBER in thousandths of a deciBel (0.001dB).
- */
- public int getVberCn() {
- if (mVberCn == null) {
- throw new IllegalStateException();
- }
- return mVberCn;
- }
- /**
- * Gets CN value by LBER in thousandths of a deciBel (0.001dB).
- */
- public int getLberCn() {
- if (mLberCn == null) {
- throw new IllegalStateException();
- }
- return mLberCn;
- }
- /**
- * Gets CN value by XER in thousandths of a deciBel (0.001dB).
- */
- public int getXerCn() {
- if (mXerCn == null) {
- throw new IllegalStateException();
- }
- return mXerCn;
- }
- /**
* Gets Modulation Error Ratio in thousandths of a deciBel (0.001dB).
*/
public int getMer() {
diff --git a/media/java/android/media/tv/tuner/frontend/ScanCallback.java b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
index f90144b..8105c74 100644
--- a/media/java/android/media/tv/tuner/frontend/ScanCallback.java
+++ b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
@@ -67,7 +67,7 @@
/** Frontend hierarchy. */
void onHierarchy(@DvbtFrontendSettings.Hierarchy int hierarchy);
- /** Frontend hierarchy. */
+ /** Frontend signal type. */
void onSignalType(@AnalogFrontendSettings.SignalType int signalType);
}
diff --git a/native/graphics/jni/imagedecoder.cpp b/native/graphics/jni/imagedecoder.cpp
index c1143ce..2e4d214 100644
--- a/native/graphics/jni/imagedecoder.cpp
+++ b/native/graphics/jni/imagedecoder.cpp
@@ -213,12 +213,12 @@
return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
}
- // Note: This recomputes the data space because it's possible the client has
- // changed the output color space, so we cannot rely on it. Alternatively,
+ // Note: This recomputes the color type because it's possible the client has
+ // changed the output color type, so we cannot rely on it. Alternatively,
// we could store the ADataSpace in the ImageDecoder.
const ImageDecoder* imageDecoder = toDecoder(info);
SkColorType colorType = imageDecoder->mCodec->computeOutputColorType(kN32_SkColorType);
- sk_sp<SkColorSpace> colorSpace = imageDecoder->mCodec->computeOutputColorSpace(colorType);
+ sk_sp<SkColorSpace> colorSpace = imageDecoder->getDefaultColorSpace();
return uirenderer::ColorSpaceToADataSpace(colorSpace.get(), colorType);
}
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 38cf5ab..617305c 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -38,7 +38,6 @@
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Path;
import android.provider.DocumentsContract.Root;
-import android.provider.MediaStore;
import android.provider.Settings;
import android.system.ErrnoException;
import android.system.Os;
@@ -100,7 +99,6 @@
private static final String ROOT_ID_PRIMARY_EMULATED =
DocumentsContract.EXTERNAL_STORAGE_PRIMARY_EMULATED_ROOT_ID;
- private static final String ROOT_ID_HOME = "home";
private static final String GET_DOCUMENT_URI_CALL = "get_document_uri";
private static final String GET_MEDIA_URI_CALL = "get_media_uri";
@@ -156,7 +154,6 @@
private void updateVolumesLocked() {
mRoots.clear();
- VolumeInfo primaryVolume = null;
final int userId = UserHandle.myUserId();
final List<VolumeInfo> volumes = mStorageManager.getVolumes();
for (VolumeInfo volume : volumes) {
@@ -234,8 +231,6 @@
}
if (volume.isPrimary()) {
- // save off the primary volume for subsequent "Home" dir initialization.
- primaryVolume = volume;
root.flags |= Root.FLAG_ADVANCED;
}
// Dunno when this would NOT be the case, but never hurts to be correct.
@@ -259,37 +254,6 @@
}
}
- // Finally, if primary storage is available we add the "Documents" directory.
- // If I recall correctly the actual directory is created on demand
- // by calling either getPathForUser, or getInternalPathForUser.
- if (primaryVolume != null && primaryVolume.isVisible()) {
- final RootInfo root = new RootInfo();
- root.rootId = ROOT_ID_HOME;
- mRoots.put(root.rootId, root);
- root.title = getContext().getString(R.string.root_documents);
-
- // Only report bytes on *volumes*...as a matter of policy.
- root.reportAvailableBytes = false;
- root.flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_SEARCH
- | Root.FLAG_SUPPORTS_IS_CHILD;
-
- // Dunno when this would NOT be the case, but never hurts to be correct.
- if (primaryVolume.isMountedWritable()) {
- root.flags |= Root.FLAG_SUPPORTS_CREATE;
- }
-
- // Create the "Documents" directory on disk (don't use the localized title).
- root.visiblePath = new File(
- primaryVolume.getPathForUser(userId), Environment.DIRECTORY_DOCUMENTS);
- root.path = new File(
- primaryVolume.getInternalPathForUser(userId), Environment.DIRECTORY_DOCUMENTS);
- try {
- root.docId = getDocIdForFile(root.path);
- } catch (FileNotFoundException e) {
- throw new IllegalStateException(e);
- }
- }
-
Log.d(TAG, "After updating volumes, found " + mRoots.size() + " active roots");
// Note this affects content://com.android.externalstorage.documents/root/39BD-07C5
diff --git a/packages/Incremental/NativeAdbDataLoader/AndroidManifest.xml b/packages/Incremental/NativeAdbDataLoader/AndroidManifest.xml
index a06dc54..c4d8f35 100644
--- a/packages/Incremental/NativeAdbDataLoader/AndroidManifest.xml
+++ b/packages/Incremental/NativeAdbDataLoader/AndroidManifest.xml
@@ -29,7 +29,7 @@
<service android:enabled="true"
android:name="com.android.incremental.nativeadb.NativeAdbDataLoaderService"
android:label="@string/app_name"
- android:exported="true">
+ android:exported="false">
<intent-filter>
<action android:name="android.intent.action.LOAD_DATA" />
</intent-filter>
diff --git a/packages/SettingsLib/LayoutPreference/res/drawable/ic_swap_horiz_blue.xml b/packages/SettingsLib/LayoutPreference/res/drawable/ic_swap_horiz_blue.xml
new file mode 100644
index 0000000..04de174
--- /dev/null
+++ b/packages/SettingsLib/LayoutPreference/res/drawable/ic_swap_horiz_blue.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M6.99,11L3,15l3.99,4v-3H14v-2H6.99v-3zM21,9l-3.99,-4v3H10v2h7.01v3L21,9z"
+ android:fillColor="#4285F4"/>
+</vector>
diff --git a/packages/SettingsLib/LayoutPreference/res/drawable/ic_swap_horiz_grey.xml b/packages/SettingsLib/LayoutPreference/res/drawable/ic_swap_horiz_grey.xml
new file mode 100644
index 0000000..b4145f2
--- /dev/null
+++ b/packages/SettingsLib/LayoutPreference/res/drawable/ic_swap_horiz_grey.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M6.99,11L3,15l3.99,4v-3H14v-2H6.99v-3zM21,9l-3.99,-4v3H10v2h7.01v3L21,9z"
+ android:fillColor="#757575"/>
+</vector>
diff --git a/packages/SettingsLib/LayoutPreference/res/layout/cross_profiles_settings_entity_header.xml b/packages/SettingsLib/LayoutPreference/res/layout/cross_profiles_settings_entity_header.xml
new file mode 100644
index 0000000..e6f8c01
--- /dev/null
+++ b/packages/SettingsLib/LayoutPreference/res/layout/cross_profiles_settings_entity_header.xml
@@ -0,0 +1,92 @@
+<?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.
+ -->
+
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/entity_header"
+ style="@style/EntityHeader"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:id="@+id/entity_header_content"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:gravity="center_horizontal"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:id="@+id/entity_header_content"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/entity_header_icon_personal"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:scaleType="fitCenter"
+ android:antialias="true"/>
+
+ <TextView
+ android:id="@+id/install_type"
+ style="@style/TextAppearance.EntityHeaderSummary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="2dp"
+ android:text="Personal"/>
+ </LinearLayout>
+
+ <ImageView
+ android:id="@+id/entity_header_swap_horiz"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:scaleType="fitCenter"
+ android:antialias="true"
+ android:src="@drawable/ic_swap_horiz_grey"/>
+
+ <LinearLayout
+ android:id="@+id/entity_header_content"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/entity_header_icon_work"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:scaleType="fitCenter"
+ android:antialias="true"/>
+ <TextView
+ android:id="@+id/install_type"
+ style="@style/TextAppearance.EntityHeaderSummary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="2dp"
+ android:text="Work"/>
+ </LinearLayout>
+ </LinearLayout>
+
+</RelativeLayout>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index b31841d..1a015a6 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Gekoppel via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Beskikbaar via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Tik om aan te meld"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Geen internet nie"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Daar kan nie by private DNS-bediener ingegaan word nie"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Beperkte verbinding"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Geen internet nie"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (rooi-groen)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (blou-geel)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Kleurregstelling"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Kleurregstelling help mense met kleurblindheid om akkurater kleure te sien"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Geneutraliseer deur <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> oor"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> tot battery gelaai is"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Onbekend"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Laai"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"laai tans"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Laai nie"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Ingeprop; kan nie op die oomblik laai nie"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Vol"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 4955ad8..05f0e1b 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"ምንም በይነመረብ የለም"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"የግል ዲኤንኤስ አገልጋይ ሊደረስበት አይችልም"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"የተገደበ ግንኙነት"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ምንም በይነመረብ የለም"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ፕሮታኖማሊ (ቀይ-አረንጓዴ)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ትራይታኖማሊ (ሰማያዊ-ቢጫ)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"የቀለም ማስተካከያ"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"ቀለም ማስተካከያ የቀለም ማየት የማይችሉ ሰዎች ተጨማሪ ትክክለኛ ቀለማትን እንዲመለከቱ ያስችላቸዋል"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"በ<xliff:g id="TITLE">%1$s</xliff:g> ተሽሯል"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ገደማ ቀርቷል"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ኃይል እስከሚሞላ ድረስ"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ያልታወቀ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ኃይል በመሙላት ላይ"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"ኃይል በመሙላት ላይ"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ባትሪ እየሞላ አይደለም"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"ተሰክቷል፣ አሁን ኃይል መሙላት አይቻልም"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"ሙሉነው"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 7b26be4..07befeb 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"لا يتوفر اتصال إنترنت."</string>
<string name="private_dns_broken" msgid="1984159464346556931">"لا يمكن الوصول إلى خادم أسماء نظام نطاقات خاص"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"اتصال محدود"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"لا يتوفر اتصال إنترنت."</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"غطش الأحمر (الأحمر والأخضر)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"غمش الأزرق (الأزرق والأصفر)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"تصحيح الألوان"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"تساعد ميزة تصحيح الألوان المصابين بعمى الألوان على رؤية الألوان بدقة أكبر"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"تم الاستبدال بـ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"يتبقى <xliff:g id="TIME_REMAINING">%1$s</xliff:g> تقريبًا"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> إلى أن يتم شحن الجهاز بالكامل"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"غير معروف"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"جارٍ الشحن"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"جارٍ الشحن"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"لا يتم الشحن"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"تم التوصيل، ولكن يتعذّر الشحن الآن"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"ممتلئة"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index dcebe5b..4d0d8cc 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"ইণ্টাৰনেট সংযোগ নাই"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"ব্যক্তিগত DNS ছাৰ্ভাৰ এক্সেছ কৰিব নোৱাৰি"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"ইণ্টাৰনেট সংযোগ সীমিত"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ইণ্টাৰনেট সংযোগ নাই"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"প্ৰ’টানোমালি (ৰঙা-সেউজীয়া)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ট্ৰাইটান\'মেলী (নীলা-হালধীয়া)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ৰং শুধৰণী"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"ৰং শুধৰণী কৰা কার্যই বর্ণান্ধলোকসকলক ৰংবোৰ অধিক সঠিককৈ দেখাত সহায় কৰে"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g>ৰ দ্বাৰা অগ্ৰাহ্য কৰা হৈছে"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"প্রায় <xliff:g id="TIME_REMAINING">%1$s</xliff:g> বাকী আছে"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> চাৰ্জ হ\'বলৈ"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"অজ্ঞাত"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"চাৰ্জ কৰি থকা হৈছে"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"চ্চাৰ্জ হৈ আছে"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"চ্চাৰ্জ কৰা নাই"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"প্লাগ কৰি থোৱা হৈছে, এই মুহূৰ্তত চ্চাৰ্জ কৰিব নোৱাৰি"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"পূৰ্ণ"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 7f3db37..73eb48a 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> ilə qoşulub"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s vasitəsilə əlçatandır"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Qeydiyyatdan keçmək üçün klikləyin"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"İnternet yoxdur"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Özəl DNS serverinə giriş mümkün deyil"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Məhdud bağlantı"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"İnternet yoxdur"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaliya (qırmızı-yaşıl)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaliya (göy-sarı)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Rəng düzəlişi"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Rəng düzəlişi rəng korluğu olanların daha yaxşı görməsinə kömək edir"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> tərəfindən qəbul edilmir"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Təxminən <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qalıb"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - Enerjinin dolmasına <xliff:g id="TIME">%2$s</xliff:g> qalıb"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Naməlum"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Enerji doldurma"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"enerji yığır"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Doldurulmur"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Cihaz hazırda batareya yığa bilmir"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Tam"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index b789cb0..dff657e 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Povezano preko: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Dostupna je preko pristupne tačke %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Dodirnite da biste se registrovali"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Nema interneta"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Pristup privatnom DNS serveru nije uspeo"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Ograničena veza"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Nema interneta"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (crveno-zeleno)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (plavo-žuto)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korekcija boja"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Korekcija boja pomaže ljudima koji su daltonisti da preciznije vide boje"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Zamenjuje ga <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>–<xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Preostalo je oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – napuniće se za <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Puni se"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"puni se"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ne puni se"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Priključeno je, ali punjenje trenutno nije moguće"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Puna"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index ce191eb..12c21a6 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Не падключана да інтэрнэту"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Не ўдалося атрымаць доступ да прыватнага DNS-сервера"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Абмежаваныя магчымасці падключэння"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Не падключана да інтэрнэту"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Пратанамалія (чырвоны-зялёны)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Трытанамалія (сіні-жоўты)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Карэкцыя колеру"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Карэкцыя колеру дазваляе людзям з парушэннямі колеравага зроку лепш распазнаваць выявы на экране"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Перавызначаны <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Зараду хопіць прыблізна на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> да поўнай зарадкі"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Невядома"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Зарадка"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"ідзе зарадка"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не зараджаецца"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Падключана да сеткі сілкавання, зарадзіць зараз немагчыма"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Акумулятар зараджаны"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 3e6f77d..6fda5b3 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Няма интернет"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Не може да се осъществи достъп до частния DNS сървър"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Ограничена връзка"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Няма връзка с интернет"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалия (червено – зелено)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалия (синьо – жълто)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Корекция на цветове"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Коригирането на цветовете помага на хората с цветна слепота да виждат по-точни цветове"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Заменено от „<xliff:g id="TITLE">%1$s</xliff:g>“"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Още около <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до пълно зареждане"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Неизвестно"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Зарежда се"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"зарежда се"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не се зарежда"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Включена в захранването, в момента не се зарежда"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Пълна"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 7f6938a..be2d1e0 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"ইন্টারনেট কানেকশন নেই"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"ব্যক্তিগত ডিএনএস সার্ভার অ্যাক্সেস করা যাবে না"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"সীমিত কানেকশন"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ইন্টারনেট কানেকশন নেই"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"প্রোটানোম্যালি (লাল-সবুজ)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ট্রিট্যানোম্যালি (নীল-হলুদ)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"রঙ সংশোধন"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"রঙ অ্যাডজাস্ট করার সেটিংস, বর্ণান্ধতা আছে এমন ব্যক্তিদের আরও সঠিকভাবে রঙ চিনতে সাহায্য করে"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> এর দ্বারা ওভাররাইড করা হয়েছে"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"আর আনুমানিক <xliff:g id="TIME_REMAINING">%1$s</xliff:g> চলবে"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>-এ সম্পূর্ণ চার্জ হয়ে যাবে"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"অজানা"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"চার্জ হচ্ছে"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"চার্জ হচ্ছে"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"চার্জ হচ্ছে না"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"প্লাগ-ইন করা হয়েছে কিন্তু এখনই চার্জ করা যাবে না"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"পূর্ণ"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 0563abd..c32df18 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Povezano preko <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Dostupan preko %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Dodirnite za prijavu"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Nema internetske veze"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Nije moguće pristupiti privatnom DNS serveru"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Ograničena veza"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Nema internetske veze"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (crveno-zeleno)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (plavo-žuto)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Ispravka boje"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Ispravka boje pomaže daltonistima da preciznije vide boje"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Zamjenjuje <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Preostalo je još oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – napunit će se za <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Punjenje"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"punjenje"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ne puni se"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Priključen, trenutno se ne može puniti"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Puna"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 71b2c5d..813fff4 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Connectat mitjançant <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Disponible mitjançant %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Toca per registrar-te"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Sense connexió a Internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"No es pot accedir al servidor DNS privat"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Connexió limitada"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Sense connexió a Internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (vermell-verd)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (blau-groc)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correcció del color"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"La correcció del color ajuda les persones daltòniques a veure colors més precisos"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"S\'ha substituït per <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>: <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Temps restant aproximat: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> per completar la càrrega"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconegut"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"S\'està carregant"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"s\'està carregant"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"No s\'està carregant"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"El dispositiu està endollat però en aquests moments no es pot carregar"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Completa"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index a381772..f116733 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Připojeno přes <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Dostupné prostřednictvím %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Klepnutím se zaregistrujete"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Nejste připojeni k internetu"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Nelze získat přístup k soukromému serveru DNS"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Omezené připojení"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Nejste připojeni k internetu"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomálie (červená a zelená)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomálie (modrá a žlutá)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korekce barev"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Korekce barev pomáhá barvoslepým lidem vidět přesnější barvy"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Přepsáno nastavením <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Zbývá asi <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do nabití"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Neznámé"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Nabíjí se"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"nabíjení"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nenabíjí se"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Zapojeno, ale nelze nabíjet"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Nabitá"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index f6e8576..e3b96a4 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Forbundet via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Tilgængelig via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Tryk for at registrere dig"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Intet internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Der er ikke adgang til den private DNS-server"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Begrænset forbindelse"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Intet internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanopi (rød-grøn)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanopi (blå-gul)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korriger farver"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Farvekorrigering gør det nemmere for farveblinde at se farver mere nøjagtigt"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Tilsidesat af <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Ca. <xliff:g id="TIME_REMAINING">%1$s</xliff:g> tilbage"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – opladet om <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Ukendt"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Oplader"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"oplader"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Oplader ikke"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Enheden er tilsluttet en strømkilde. Det er ikke muligt at oplade på nuværende tidspunkt."</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Fuldt"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 99a0910..1ddabcab 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Verbunden über <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Verfügbar über %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Zum Anmelden tippen"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Kein Internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Auf den privaten DNS-Server kann nicht zugegriffen werden"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Eingeschränkte Verbindung"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Kein Internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (Rot-Grün-Sehschwäche)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (Blau-Gelb-Sehschwäche)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Farbkorrektur"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Die Farbkorrektur hilft farbenblinden Menschen, Farben besser zu erkennen"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Außer Kraft gesetzt von \"<xliff:g id="TITLE">%1$s</xliff:g>\""</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Noch etwa <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> bis zur Aufladung"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Unbekannt"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Wird aufgeladen"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"wird aufgeladen..."</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Wird nicht geladen"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Angeschlossen, kann derzeit nicht geladen werden"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Voll"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index d37ea44..3a97d5a 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Χωρίς σύνδεση στο διαδίκτυο"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Δεν είναι δυνατή η πρόσβαση στον ιδιωτικό διακομιστή DNS."</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Περιορισμένη σύνδεση"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Δεν υπάρχει σύνδεση στο διαδίκτυο"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Πρωτανοπία (κόκκινο-πράσινο)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Τριτανοπία (μπλε-κίτρινο)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Διόρθωση χρωμάτων"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Η διόρθωση χρωμάτων βοηθάει τους ανθρώπους με αχρωματοψία να βλέπουν τα χρώματα με μεγαλύτερη ακρίβεια"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Αντικαταστάθηκε από <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Απομένει/ουν περίπου <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> για την ολοκλήρωση της φόρτισης"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Άγνωστο"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Φόρτιση"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"φόρτιση"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Δεν φορτίζει"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Συνδέθηκε, δεν είναι δυνατή η φόρτιση αυτήν τη στιγμή"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Πλήρης"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 429cd3e..ec0a129 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Connected via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Available via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Tap to sign up"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"No Internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Private DNS server cannot be accessed"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Limited connection"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"No Internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Colour correction"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Colour correction helps people with colour blindness to see more accurate colours"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until charged"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Unknown"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Charging"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"charging"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Not charging"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Plugged in, can\'t charge at the moment"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Full"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 429cd3e..ec0a129 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Connected via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Available via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Tap to sign up"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"No Internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Private DNS server cannot be accessed"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Limited connection"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"No Internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Colour correction"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Colour correction helps people with colour blindness to see more accurate colours"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until charged"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Unknown"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Charging"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"charging"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Not charging"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Plugged in, can\'t charge at the moment"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Full"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 429cd3e..ec0a129 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Connected via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Available via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Tap to sign up"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"No Internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Private DNS server cannot be accessed"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Limited connection"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"No Internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Colour correction"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Colour correction helps people with colour blindness to see more accurate colours"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until charged"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Unknown"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Charging"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"charging"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Not charging"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Plugged in, can\'t charge at the moment"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Full"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 429cd3e..ec0a129 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Connected via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Available via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Tap to sign up"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"No Internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Private DNS server cannot be accessed"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Limited connection"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"No Internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Colour correction"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Colour correction helps people with colour blindness to see more accurate colours"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until charged"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Unknown"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Charging"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"charging"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Not charging"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Plugged in, can\'t charge at the moment"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Full"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 1aa6cdb..3b286f7 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Connected via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Available via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Tap to sign up"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"No internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Private DNS server cannot be accessed"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Limited connection"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"No internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Color correction"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Color correction helps people with color blindness to see more accurate colors"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until charged"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Unknown"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Charging"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"charging"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Not charging"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Plugged in, can\'t charge right now"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Full"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 7d28a32..966f2f2 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Conexión a través de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Disponible a través de %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Presiona para registrarte"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Sin Internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"No se puede acceder al servidor DNS privado"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Conexión limitada"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Sin Internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalía (rojo-verde)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalía (azul-amarillo)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corrección de color"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"La corrección de colores ayuda a las personas con daltonismo a ver colores más exactos"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Reemplazado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Tiempo restante: aproximadamente <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> para completar la carga"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconocido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"cargando"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"No se está cargando."</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Conectado. No se puede cargar en este momento"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Cargado"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index b35696f5..1198722 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Conectado a través de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Disponible a través de %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Toca para registrarte"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Sin Internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"No se ha podido acceder al servidor DNS privado"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Conexión limitada"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Sin Internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalía (rojo-verde)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalía (azul-amarillo)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corrección de color"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"La corrección del color ayuda a las personas con daltonismo a ver los colores más reales"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>: <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Tiempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> (<xliff:g id="TIME">%2$s</xliff:g> hasta que termine de cargarse)"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconocido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"cargando"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"No se está cargando"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Se ha conectado, pero no se puede cargar en este momento"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Completa"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index b6c112b..9be72f9 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Ühendatud võrgu <xliff:g id="NAME">%1$s</xliff:g> kaudu"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Saadaval üksuse %1$s kaudu"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Puudutage registreerumiseks"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Interneti pole"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Privaatsele DNS-serverile ei pääse juurde"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Piiratud ühendus"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Interneti-ühendus puudub"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaalia (punane-roheline)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaalia (sinine-kollane)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Värvide korrigeerimine"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Värviparanduse funktsioon aitab värvipimedatel värve täpsemini näha"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Alistas <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Ligikaudu <xliff:g id="TIME_REMAINING">%1$s</xliff:g> jäänud"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> täislaadimiseni"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Tundmatu"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Laadimine"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"laadimine"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ei lae"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Vooluvõrgus, praegu ei saa laadida"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Täis"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 4fd9add..d0c6c52 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> bidez konektatuta"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s bidez erabilgarri"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Sakatu erregistratzeko"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Ez dago Interneteko konexiorik"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Ezin da atzitu DNS zerbitzari pribatua"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Konexio mugatua"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Ez dago Interneteko konexiorik"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanopia (gorri-berdeak)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanopia (urdin-horia)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Koloreen zuzenketa"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Kolore-zuzenketak kolore zehatzagoak ikusten laguntzen die koloreentzako itsutasuna duten pertsonei."</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> hobespena gainjarri zaio"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> inguru gelditzen dira"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> guztiz kargatu arte"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Ezezaguna"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Kargatzen"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"kargatzen"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ez da kargatzen ari"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Konektatuta dago. Ezin da kargatu une honetan."</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Beteta"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 32a98be..f15174a 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"عدم اتصال به اینترنت"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"سرور DNS خصوصی قابل دسترسی نیست"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"اتصال محدود"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"عدم دسترسی به اینترنت"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"قرمزدشواربینی (قرمز-سبز)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"آبیدشواربینی (آبی-زرد)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"تصحیح رنگ"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"تصحیح رنگ به افراد مبتلا به کوررنگی کمک میکند رنگها را دقیقتر ببینند"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"توسط <xliff:g id="TITLE">%1$s</xliff:g> لغو شد"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"تقریباً <xliff:g id="TIME_REMAINING">%1$s</xliff:g> شارژ باقی مانده است"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> تا شارژ کامل"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ناشناس"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"در حال شارژ شدن"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"درحال شارژ شدن"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"شارژ نمیشود"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"به برق وصل شده است، درحالحاضر شارژ نمیشود"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"پر"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 84c5372..1232db3 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Yhdistetty (<xliff:g id="NAME">%1$s</xliff:g>)"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Käytettävissä seuraavan kautta: %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Rekisteröidy napauttamalla"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Ei internetyhteyttä"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Ei pääsyä yksityiselle DNS-palvelimelle"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Rajallinen yhteys"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Ei internetyhteyttä"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (puna-vihersokeus)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (sini-keltasokeus)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Värikorjaus"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Värinkorjaus auttaa värisokeita tulkitsemaan värejä"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Tämän ohittaa <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Noin <xliff:g id="TIME_REMAINING">%1$s</xliff:g> jäljellä"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> täyteen lataukseen"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Tuntematon"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Ladataan"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"ladataan"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ei laturissa"</string>
<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>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 995eab6..6404df4 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Connecté sur le réseau <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Accessible par %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Toucher pour vous connecter"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Aucune connexion Internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Impossible d\'accéder au serveur DNS privé"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Connexion limitée"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Aucune connexion Internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (rouge/vert)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (bleu/jaune)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correction des couleurs"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"La correction des couleurs aide les personnes atteintes de daltonisme à mieux percevoir les couleurs"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> : <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Il reste environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> : <xliff:g id="TIME">%2$s</xliff:g> jusqu\'à la charge complète"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Inconnu"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Charge en cours…"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"en cours de charge"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"N\'est pas en charge"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"L\'appareil est branché, mais il ne peut pas être chargé pour le moment"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Pleine"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 2afacab..e75063b 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Connecté via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Disponible via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Appuyez ici pour vous connecter"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Aucun accès à Internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Impossible d\'accéder au serveur DNS privé"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Connexion limitée"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Aucun accès à Internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (rouge/vert)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (bleu-jaune)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correction couleur"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"La correction des couleurs aide les personnes atteintes de daltonisme à mieux percevoir les couleurs"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Temps restant : environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> jusqu\'à la charge complète"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Inconnu"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Batterie en charge"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"en charge…"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Pas en charge"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Appareil branché, mais impossible de le charger pour le moment"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Pleine"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index a106e60..7fd32f9 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Wifi conectada a través de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Dispoñible a través de %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Toca para rexistrarte"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Non hai conexión a Internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Non se puido acceder ao servidor DNS privado"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Pouca conexión"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Non hai conexión a Internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalía (vermello-verde)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalía (azul-amarelo)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corrección da cor"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"A corrección das cores axuda ás persoas con daltonismo a ver as cores con maior precisión"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> para completar a carga"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Descoñecido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"cargando"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Non se está cargando"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Conectouse, pero non se pode cargar neste momento"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Completa"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 5f2d5cd..1513c57 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"કોઈ ઇન્ટરનેટ નથી"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"ખાનગી DNS સર્વર ઍક્સેસ કરી શકાતા નથી"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"મર્યાદિત કનેક્શન"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ઇન્ટરનેટ ઍક્સેસ નથી"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"પ્રોટેનોમલી (લાલ-લીલો)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ટ્રાઇટેનોમલી(વાદળી-પીળો)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"રંગ સુધારણા"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"રંગ સુધારણા રંગ અંધત્વવાળા લોકોને વધુ સચોટ રંગો જોવામાં સહાય કરે છે"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> દ્વારા ઓવરરાઇડ થયું"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"લગભગ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> બાકી છે"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - ચાર્જ થવા માટે <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"અજાણ્યું"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ચાર્જ થઈ રહ્યું છે"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"ચાર્જ થઈ રહ્યું છે"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ચાર્જ થઈ રહ્યું નથી"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"પ્લગ ઇન કરેલ, હમણાં ચાર્જ કરી શકતા નથી"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"પૂર્ણ"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index d60eead..c79c4a4 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"इंटरनेट कनेक्शन नहीं है"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"निजी डीएनएस सर्वर को ऐक्सेस नहीं किया जा सकता"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"सीमित कनेक्शन"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"इंटरनेट कनेक्शन नहीं है"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"लाल रंग पहचान न पाना (लाल-हरा)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"नीला रंग पहचान न पाना (नीला-पीला)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"रंग सुधार"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"रंग में सुधार करने की सेटिंग, वर्णान्धता (कलर ब्लाइंडनेस) वाले लोगों को ज़्यादा सटीक रंग देखने में मदद करती है"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> के द्वारा ओवरराइड किया गया"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"बैटरी करीब <xliff:g id="TIME_REMAINING">%1$s</xliff:g> में खत्म हो जाएगी"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> में पूरा चार्ज हो जाएगा"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज हो रही है"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"चार्ज हो रही है"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"चार्ज नहीं हो रही है"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"प्लग इन है, अभी चार्ज नहीं हो सकती"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"पूरी"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 28e3460..3ab5678 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Povezan putem mreže <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Dostupno putem %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Dodirnite da biste se registrirali"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Nema interneta"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Nije moguće pristupiti privatnom DNS poslužitelju"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Ograničena veza"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Nema interneta"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (crveno – zeleno)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (plavo – žuto)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korekcija boje"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Korekcija boje pomaže slijepima za boje da vide preciznije boje"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Premošćeno postavkom <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Još otprilike <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – napunit će se za <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Punjenje"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"punjenje"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ne puni se"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Uključen, trenutačno se ne može puniti"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Puna"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 22e03a7..8d06f58 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Kapcsolódva a következőn keresztül: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Elérhető a következőn keresztül: %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Koppintson a regisztrációhoz"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Nincs internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"A privát DNS-kiszolgálóhoz nem lehet hozzáférni"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Korlátozott kapcsolat"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Nincs internetkapcsolat"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomália (piros– zöld)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomália (kék–sárga)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Színkorrekció"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"A színkorrekció segít a színtévesztőknek abban, hogy pontosabban lássák a színeket"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Felülírva erre: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Körülbelül <xliff:g id="TIME_REMAINING">%1$s</xliff:g> maradt hátra"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> a feltöltésig"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Ismeretlen"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Töltés"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"töltés"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nem tölt"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Csatlakoztatva, jelenleg nem tölt"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Feltöltve"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index ecb615a..99cef28 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Կապ չկա"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Մասնավոր DNS սերվերն անհասանելի է"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Սահմանափակ կապ"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Ինտերնետ կապ չկա"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Պրոտանոմալիա (կարմիր-կանաչ)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Տրիտանոմալիա (կապույտ-դեղին)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Գունաշտկում"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Գունաշտկումն օգնում է գունային դալտոնիզմ ունեցող մարդկանց ավելի ճշգրիտ տեսնել գույները"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Գերազանցված է <xliff:g id="TITLE">%1$s</xliff:g>-ից"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Լիցքը կբավարարի մոտ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> մինչև լիցքավորումը"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Անհայտ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Լիցքավորում"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"լիցքավորում"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Չի լիցքավորվում"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Միացված է հոսանքի աղբյուրին, սակայն այս պահին չի կարող լիցքավորվել"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Լիցքավորված է"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index cfbda04..25de382 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Tersambung melalui <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Tersedia melalui %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Ketuk untuk mendaftar"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Tidak ada internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Server DNS pribadi tidak dapat diakses"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Koneksi terbatas"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Tidak ada internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (merah-hijau)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (biru-kuning)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Koreksi warna"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Koreksi warna membantu orang penderita buta warna untuk melihat warna yang lebih akurat"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Digantikan oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Sekitar <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> lagi terisi penuh"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Tidak diketahui"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Mengisi daya"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"mengisi daya baterai"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Tidak mengisi daya"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Tercolok, tidak dapat mengisi baterai sekarang"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Penuh"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index ba4c009..8fe382a 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Tenging í gegnum <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Í boði í gegnum %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Ýttu til að skrá þig"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Engin nettenging"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Ekki næst í DNS-einkaþjón"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Takmörkuð tenging"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Engin nettenging"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Litblinda (rauðgræn)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Litblinda (blágul)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Litaleiðrétting"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Litaleiðrétting hjálpar fólki með litblindu að sjá réttari liti"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Hnekkt af <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Um það bil <xliff:g id="TIME_REMAINING">%1$s</xliff:g> eftir"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> að fullri hleðslu"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Óþekkt"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Í hleðslu"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"í hleðslu"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ekki í hleðslu"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Í sambandi, ekki hægt að hlaða eins og er"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Fullhlaðin"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 50e5777..c9abc74 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Connesso tramite <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Disponibile tramite %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Tocca per registrarti"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Internet assente"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Non è possibile accedere al server DNS privato"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Connessione limitata"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Nessuna connessione a Internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalìa (rosso-verde)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalìa (blu-giallo)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correzione del colore"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"La correzione del colore consente alle persone daltoniche di vedere colori più accurati"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Valore sostituito da <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo rimanente: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> circa"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> alla carica completa"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Sconosciuta"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"In carica"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"in carica"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Non in carica"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Collegato alla corrente. Impossibile caricare al momento"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Carica"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 9f1e457..1921d03 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"אין אינטרנט"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"לא ניתן לגשת לשרת DNS הפרטי"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"חיבור מוגבל"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"אין אינטרנט"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"פרוטנומליה (אדום-ירוק)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"טריטנומליה (כחול-צהוב)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"תיקון צבע"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"תיקון צבע עוזר למשתמשים עם עיוורון צבעים לראות צבעים מדויקים יותר"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"נעקף על ידי <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"הזמן הנותר: בערך <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> עד הטעינה"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"לא ידוע"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"בטעינה"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"בטעינה"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"לא בטעינה"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"המכשיר מחובר, אבל לא ניתן לטעון עכשיו"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"מלאה"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 47020ed..e4e1ab9 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"インターネットに接続されていません"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"プライベート DNS サーバーにアクセスできません"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"接続が制限されています"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"インターネット未接続"</string>
@@ -204,7 +203,7 @@
<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="bugreport_in_power" msgid="8664089072534638709">"バグレポートのショートカット"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"第一色弱(赤緑)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"第三色弱(青黄)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"色補正"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"色補正機能を利用すると、色覚異常のユーザーがより正確に色を判別できるようになります"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g>によって上書き済み"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"残り時間: 約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充電完了まで <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"不明"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"充電しています"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"充電していません"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"接続されていますが、現在、充電できません"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"フル"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 116488d..b2cfb17 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"ინტერნეტ-კავშირი არ არის"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"პირად DNS სერვერზე წვდომა შეუძლებელია"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"შეზღუდული კავშირი"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ინტერნეტ-კავშირი არ არის"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"პროტოანომალია (წითელი-მწვანე)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ტრიტანომალია (ლურჯი-ყვითელი)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ფერის კორექცია"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"ფერის კორექცია ეხმარება ფერითი სიბრმავის მქონე ადამიანებს, უფრო ზუსტად გაარჩიონ ფერები"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"უკუგებულია <xliff:g id="TITLE">%1$s</xliff:g>-ის მიერ"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"დარჩა დაახლოებით <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> დატენვამდე"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"უცნობი"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"იტენება"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"იტენება"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"არ იტენება"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"მიერთებულია, დატენვა ამჟამად ვერ ხერხდება"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"ბატარეა დატენილია"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 3c4fdb7..756bc06 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Интернетпен байланыс жоқ."</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Жеке DNS серверіне кіру мүмкін емес."</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Шектеулі байланыс"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Интернетпен байланыс жоқ"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалия (қызыл-жасыл)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалия (көк-сары)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Түсті түзету"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Түсті түзету түсті ажырата алмайтын адамдарға оларды дәлірек көруге көмектеседі"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> үстінен басқан"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Шамамен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> қалды"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – зарядталғанға дейін <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Белгісіз"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Зарядталуда"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"зарядталуда"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Зарядталу орындалып жатқан жоқ"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Қосылған, зарядталмайды"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Толы"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 87a4f19..cdf92b3 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"គ្មានអ៊ីនធឺណិតទេ"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"មិនអាចចូលប្រើម៉ាស៊ីនមេ DNS ឯកជនបានទេ"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"ការតភ្ជាប់មានកម្រិត"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"គ្មានអ៊ីនធឺណិតទេ"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (ក្រហមពណ៌បៃតង)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (ពណ៌ខៀវ-លឿង)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ការកែពណ៌"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"ការកែតម្រូវពណ៌ជួយដល់អ្នកដែលមិនអាចបែងចែកពណ៌ឱ្យមើលឃើញពណ៌ដែលត្រឹមត្រូវជាមុន"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"បដិសេធដោយ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"នៅសល់ប្រហែល <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ទៀត"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ទៀតទើបត្រូវសាក"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"មិនស្គាល់"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"កំពុងបញ្ចូលថ្ម"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"កំពុងសាកថ្ម"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"មិនកំពុងបញ្ចូលថ្ម"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"ដោតសាកថ្មរួចហើយ ប៉ុន្តែសាកថ្មមិនចូលទេឥឡូវនេះ"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"ពេញ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 144dddb..4a24691 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"ಇಂಟರ್ನೆಟ್ ಇಲ್ಲ"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"ಖಾಸಗಿ DNS ಸರ್ವರ್ ಅನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"ಸೀಮಿತ ಸಂಪರ್ಕ"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ಇಂಟರ್ನೆಟ್ ಇಲ್ಲ"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ಪ್ರೊಟನೋಮಲಿ (ಕೆಂಪು-ಹಸಿರು)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ಟ್ರಿಟನೋಮಲಿ (ನೀಲಿ-ಹಳದಿ)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ಬಣ್ಣದ ತಿದ್ದುಪಡಿ"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"ವರ್ಣ ಅಂಧತ್ವ ಹೊಂದಿರುವ ಜನರಿಗೆ ಬಣ್ಣಗಳನ್ನು ಹೆಚ್ಚು ನಿಖರವಾಗಿ ವೀಕ್ಷಿಸಲು ಬಣ್ಣ ತಿದ್ದುಪಡಿ ಸಹಾಯ ಮಾಡುತ್ತದೆ"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ಮೂಲಕ ಅತಿಕ್ರಮಿಸುತ್ತದೆ"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ಸಮಯ ಬಾಕಿ ಉಳಿದಿದೆ"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಚಾರ್ಜ್ ಆಗಲು <xliff:g id="TIME">%2$s</xliff:g> ಸಮಯ ಬೇಕು"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ಅಪರಿಚಿತ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ಚಾರ್ಜ್ ಆಗುತ್ತಿಲ್ಲ"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"ಪ್ಲಗ್ ಇನ್ ಮಾಡಲಾಗಿದೆ, ಇದೀಗ ಚಾರ್ಜ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"ಭರ್ತಿ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index df9f21d..51896e9 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"인터넷 연결 없음"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"비공개 DNS 서버에 액세스할 수 없습니다."</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"제한된 연결"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"인터넷 연결 없음"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"적색약(적녹)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"청색약(청황)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"색보정"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"색상 보정을 사용하면 색맹인 사용자가 색상을 정확하게 구분하는 데 도움이 됩니다."</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> 우선 적용됨"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>, <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"남은 시간 약 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - 충전 완료까지 <xliff:g id="TIME">%2$s</xliff:g> 남음"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"알 수 없음"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"충전 중"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"충전 중"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"충전 안함"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"전원이 연결되었지만 현재 충전할 수 없음"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"충전 완료"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 13c4144..061f6fd 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Интернет жок"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Жеке DNS сервери жеткиликсиз"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Байланыш чектелген"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Интернет жок"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалия (кызыл-жашыл)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалия (көк-сары)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Түсүн тууралоо"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Түстү тууралоо жөндөөсү түстөрдү айырмалап көрбөгөн адамдарга түстөрдү тагыраак билүүгө жардам берет"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> менен алмаштырылган"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Болжол менен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> калды"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> кийин кубатталат"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Белгисиз"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Кубатталууда"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"кубатталууда"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Кубат алган жок"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Сайылып турат, учурда кубаттоо мүмкүн эмес"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Толук"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 48224f4..bfbd8a9 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"ບໍ່ມີອິນເຕີເນັດ"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"ບໍ່ສາມາດເຂົ້າເຖິງເຊີບເວີ DNS ສ່ວນຕົວໄດ້"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"ການເຊື່ອມຕໍ່ຈຳກັດ"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ບໍ່ມີອິນເຕີເນັດ"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (ສີແດງ-ສີຂຽວ)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (ສີຟ້າ-ສີເຫຼືອງ)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ການປັບແຕ່ງສີ"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"ການແກ້ໄຂສີຈະຊ່ວຍໃຫ້ຄົນທີ່ຕາບອດສີເຫັນສີຕ່າງໆໄດ້ຖືກຕ້ອງຍິ່ງຂຶ້ນ"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"ຖືກແທນໂດຍ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"ເຫຼືອອີກປະມານ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ຈົນກວ່າຈະສາກເຕັມ"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ບໍ່ຮູ້ຈັກ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ກຳລັງສາກໄຟ"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"ກຳລັງສາກໄຟ"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ບໍ່ໄດ້ສາກໄຟ"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"ສຽບສາຍແລ້ວ, ບໍ່ສາມາດສາກໄດ້ໃນຕອນນີ້"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"ເຕັມ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index d080334..76d06fa 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Prisijungta naudojant programą „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Pasiekiama naudojant „%1$s“"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Palieskite, kad prisiregistruotumėte"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Nėra interneto ryšio"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Privataus DNS serverio negalima pasiekti"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Ribotas ryšys"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Nėra interneto ryšio"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (raudona, žalia)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (mėlyna, geltona)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Spalvų taisymas"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Naudojant spalvų taisymo funkciją daltonikai gali geriau matyti spalvas"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Nepaisyta naudojant nuostatą „<xliff:g id="TITLE">%1$s</xliff:g>“"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Liko maždaug <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – iki visiškos įkrovos liko <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nežinomas"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Kraunasi..."</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"įkraunama"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nekraunama"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Įjungta į maitinimo lizdą, bet šiuo metu įkrauti neįmanoma"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Visiškai įkrautas"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index e13a50d..e4652d1 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Savienojums ar <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Pieejams, izmantojot %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Pieskarieties, lai reģistrētos"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Nav interneta"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Nevar piekļūt privātam DNS serverim."</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Ierobežots savienojums"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Nav piekļuves internetam"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomālija (sarkans/zaļš)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomālija (zils/dzeltens)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Krāsu korekcija"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Krāsu korekcija palīdz cilvēkiem ar krāsu aklumu redzēt precīzākas krāsas."</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Jaunā preference: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> — <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Aptuvenais atlikušais laiks: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> — <xliff:g id="TIME">%2$s</xliff:g> līdz pilnai uzlādei"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nezināms"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Uzlāde"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"notiek uzlāde"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nenotiek uzlāde"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Pievienots, taču pašlaik nevar veikt uzlādi"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Pilns"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index d027ffe..21b2f96 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Нема интернет"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Не може да се пристапи до приватниот DNS-сервер"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Ограничена врска"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Нема интернет"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалија (слепило за црвена и зелена)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалија (слепило за сина и жолта)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Корекција на бои"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Корекцијата на бои им помага на луѓето со далтонизам попрецизно да ги гледаат боите"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Прескокнато според <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Уште околу <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> до целосно полнење"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Непознато"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Се полни"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"се полни"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не се полни"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Приклучен е, но батеријата не може да се полни во моментов"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Полна"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index e2a3d9f..85aa000 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"ഇന്റർനെറ്റ് ഇല്ല"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"സ്വകാര്യ DNS സെർവർ ആക്സസ് ചെയ്യാനാവില്ല"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"പരിമിത കണക്ഷൻ"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ഇന്റർനെറ്റ് ഇല്ല"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"പ്രോട്ടാനോമലി (ചുവപ്പ്-പച്ച)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ട്രിട്ടാനോമലി (നീല-മഞ്ഞ)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"വർണ്ണം ക്രമീകരിക്കൽ"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"വർണ്ണം ശരിയാക്കൽ, വർണ്ണാന്ധത ബാധിച്ച ആളുകൾക്ക് നിറങ്ങൾ കൂടുതൽ കൃത്യമായി കാണാൻ സഹായിക്കുന്നു"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ഉപയോഗിച്ച് അസാധുവാക്കി"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"ഏതാണ്ട് <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - പൂർണ്ണമായി ചാർജാവാൻ <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"അജ്ഞാതം"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ചാർജ് ചെയ്യുന്നു"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"ചാർജ് ചെയ്യുന്നു"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ചാർജ്ജുചെയ്യുന്നില്ല"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"പ്ലഗ് ഇൻ ചെയ്തു, ഇപ്പോൾ ചാർജ് ചെയ്യാനാവില്ല"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"നിറഞ്ഞു"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index dd08c9e..232148a 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Интернэт алга"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Хувийн DNS серверт хандах боломжгүй байна"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Хязгаарлагдмал холболт"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Интернэт алга"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномаль (улаан-ногоон)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомаль (цэнхэр-шар)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Өнгө тохируулах"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Өнгөний залруулга нь өнгөний сохортой хүмүүст илүү оновчтой өнгө харахад тусалдаг"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Давхарласан <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Ойролцоогоор <xliff:g id="TIME_REMAINING">%1$s</xliff:g> үлдсэн"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - цэнэглэх хүртэл <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Тодорхойгүй"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Цэнэглэж байна"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"цэнэглэж байна"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Цэнэглэхгүй байна"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Залгаастай тул одоо цэнэглэх боломжгүй"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Дүүрэн"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index fb7cd1f..8767b4f 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"इंटरनेट नाही"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"खाजगी DNS सर्व्हर ॲक्सेस करू शकत नाही"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"मर्यादित कनेक्शन"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"इंटरनेट नाही"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"क्षीण रक्तवर्णांधता (लाल-हिरवा)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"रंग दृष्टी कमतरता (निळा-पिवळा)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"रंग सुधारणा"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"रंग सुधारणा ही वर्णांधता असलेल्या लोकांना रंग अधिक अचूक दिसण्यात मदत करते"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारे अधिलिखित"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"अंदाजे <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाकी आहे"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> पर्यंत पूर्ण चार्ज होईल"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज होत आहे"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"चार्ज होत आहे"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"चार्ज होत नाही"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"प्लग इन केलेले आहे, आता चार्ज करू शकत नाही"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"पूर्ण"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 72b15ff..b79b801 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Disambungkan melalui <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Tersedia melalui %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Ketik untuk daftar"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Tiada Internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Pelayan DNS peribadi tidak boleh diakses"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Sambungan terhad"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Tiada Internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (merah-hijau)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (biru-kuning)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Pembetulan warna"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Pembetulan warna membantu orang yang mengalami kebutaan warna melihat warna yang lebih tepat"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Diatasi oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Kira-kira <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> sehingga dicas"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Tidak diketahui"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Mengecas"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"mengecas"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Tidak mengecas"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Dipalamkan, tidak boleh mengecas sekarang"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Penuh"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 24017ec..b2ad664 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"အင်တာနက် မရှိပါ"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"သီးသန့် ဒီအန်အက်စ် (DNS) ဆာဗာကို သုံး၍မရပါ။"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"ချိတ်ဆက်မှု ကန့်သတ်ထားသည်"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"အင်တာနက် မရှိပါ"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (အနီ-အစိမ်း)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (အပြာ-အဝါ)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"အရောင်ပြင်ဆင်မှု"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"အရောင်ပြင်ဆင်ခြင်းက အရောင်ကန်းသူများအတွက် ပိုမိုမှန်ကန်သော အရောင်များဖြင့် ကြည့်နိုင်ရန် ကူညီမည်"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> မှ ကျော်၍ လုပ်ထားသည်။"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ခန့် ကျန်သည်"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - အားပြည့်ရန် <xliff:g id="TIME">%2$s</xliff:g> ကျန်သည်"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"မသိ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"အားသွင်းနေပါသည်"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"အားသွင်းနေပါသည်"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"အားသွင်းမနေပါ"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"ပလပ်ထိုးထားသောကြောင့် ယခုအားသွင်း၍ မရသေးပါ"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"အပြည့်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index aca13a7..6a1f158 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Tilkoblet via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Tilgjengelig via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Trykk for å registrere deg"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Ingen internettilkobling"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Den private DNS-tjeneren kan ikke nås"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Begrenset tilkobling"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Ingen internettilkobling"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (rød-grønn)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (blå-gul)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Fargekorrigering"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Med fargekorrigering kan personer med fargeblindhet se mer nøyaktige farger"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overstyres av <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Omtrent <xliff:g id="TIME_REMAINING">%1$s</xliff:g> gjenstår"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> til batteriet er fulladet"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Ukjent"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Lader"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"lader"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Lader ikke"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Laderen er koblet til – kan ikke lade akkurat nå"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Fullt"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index b2c7518..9cd5e20 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"इन्टरनेट छैन"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"निजी DNS सर्भरमाथि पहुँच प्राप्त गर्न सकिँदैन"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"सीमित जडान"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"इन्टरनेटमाथिको पहुँच छैन"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"प्रोटानेमली (रातो, हरियो)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ट्रिटानोमेली (निलो-पंहेलो)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"रङ्ग सुधार"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"रङ सुधार गर्नुले रङ छुट्याउन नसक्ने मान्छेलाई थप सही रङ देख्न मद्दत गर्दछ"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारा अधिरोहित"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"लगभग <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाँकी छ"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"पूर्ण चार्ज हुन <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> लाग्छ"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज हुँदै"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"चार्ज हुँदै"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"चार्ज भइरहेको छैन"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"प्लगइन गरिएको छ, अहिले नै चार्ज गर्न सकिँदैन"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"पूर्ण चार्ज भएको स्थिति"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index c74683b..8d5dea4 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Verbonden via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Beschikbaar via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Tik om aan te melden"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Geen internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Geen toegang tot privé-DNS-server"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Beperkte verbinding"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Geen internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (rood-groen)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (blauw-geel)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Kleurcorrectie"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Met behulp van kleurcorrectie kunnen mensen die kleurenblind zijn, nauwkeurigere kleuren te zien krijgen"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overschreven door <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Nog ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> tot opgeladen"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Onbekend"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Opladen"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"opladen"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Wordt niet opgeladen"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Aangesloten, kan nu niet opladen"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Volledig"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 704fc42..c0489c1 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"ବ୍ୟକ୍ତିଗତ DNS ସର୍ଭର୍ ଆକ୍ସେସ୍ କରିହେବ ନାହିଁ"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"ସୀମିତ ସଂଯୋଗ"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"କୌଣସି ଇଣ୍ଟରନେଟ୍ ନାହିଁ"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ପ୍ରୋଟାନୋମାଲି (ଲାଲ୍-ସବୁଜ)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (ନୀଳ-ହଳଦିଆ)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ରଙ୍ଗ ସଠିକତା"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"କଲର୍ କରେକ୍ସନ୍ ରଙ୍ଗ ଚିହ୍ନିବାରେ ସମସ୍ୟା ଥିବା ଲୋକମାନଙ୍କୁ ଅଧିକ ସଠିକ୍ ରଙ୍ଗ ଦେଖିବାରେ ସାହାଯ୍ୟ କରିଥାଏ"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ଦ୍ୱାରା ଓଭର୍ରାଇଡ୍ କରାଯାଇଛି"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"ପାଖାପାଖି <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ବଳକା ଅଛି"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ଚାର୍ଜ ହେବା ପର୍ଯ୍ୟନ୍ତ"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ଅଜ୍ଞାତ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ଚାର୍ଜ ହେଉଛି"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"ଚାର୍ଜ ହେଉଛି"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ଚାର୍ଜ ହେଉନାହିଁ"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"ପ୍ଲଗ୍ରେ ଲାଗିଛି, ହେଲେ ଏବେ ଚାର୍ଜ କରିପାରିବ ନାହିଁ"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"ଚାର୍ଜ ସମ୍ପୂର୍ଣ୍ଣ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index bf5a32c..7355418 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"ਇੰਟਰਨੈੱਟ ਨਹੀਂ"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"ਨਿੱਜੀ ਡੋਮੇਨ ਨਾਮ ਪ੍ਰਣਾਲੀ (DNS) ਸਰਵਰ \'ਤੇ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"ਸੀਮਤ ਕਨੈਕਸ਼ਨ"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ਇੰਟਰਨੈੱਟ ਨਹੀਂ"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (ਲਾਲ-ਹਰਾ)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (ਨੀਲਾ-ਪੀਲਾ)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ਰੰਗ ਸੁਧਾਈ"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"ਰੰਗ ਸੁਧਾਈ ਨਾਲ ਰੰਗਾਂ ਦੇ ਅੰਨ੍ਹਾਪਣ ਦੇ ਸ਼ਿਕਾਰ ਲੋਕਾਂ ਦੀ ਵਧੇਰੇ ਸਟੀਕ ਰੰਗਾਂ ਨੂੰ ਦੇਖਣ ਵਿੱਚ ਮਦਦ ਕੀਤੀ ਜਾਂਦੀ ਹੈ"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ਦੁਆਰਾ ਓਵਰਰਾਈਡ ਕੀਤਾ"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"ਲਗਭਗ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ਬਾਕੀ"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ਤੱਕ ਚਾਰਜ ਹੋ ਜਾਵੇਗੀ"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ਅਗਿਆਤ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"ਚਾਰਜ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ਚਾਰਜ ਨਹੀਂ ਹੋ ਰਿਹਾ"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"ਪਲੱਗ ਲੱਗਾ ਹੋਇਆ ਹੈ, ਇਸ ਸਮੇਂ ਚਾਰਜ ਨਹੀਂ ਹੋ ਸਕਦੀ"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"ਪੂਰੀ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index d907760..a3ccb07 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Połączenie przez: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Dostępne przez %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Kliknij, by się zarejestrować"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Brak internetu"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Brak dostępu do prywatnego serwera DNS"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Ograniczone połączenie"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Brak internetu"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (czerwony-zielony)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (niebieski-żółty)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korekcja kolorów"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Korekcja kolorów pomaga osobom z zaburzeniami rozpoznawania barw lepiej je widzieć."</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Nadpisana przez <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Jeszcze około <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – do naładowania <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nieznane"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Ładowanie"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"ładowanie"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nie podłączony"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Podłączony. Nie można teraz ładować"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Naładowana"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index e61c84e..f4182bf 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Conectado via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Disponível via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Toque para se inscrever"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Sem Internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Não é possível acessar o servidor DNS privado"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Conexão limitada"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Sem Internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (vermelho-verde)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (azul-amarelo)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correção de cor"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"A correção de cores ajuda pessoas com daltonismo a ver cores de forma mais precisa"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> até a carga completa"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconhecido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Carregando"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"carregando"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Não está carregando"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Conectado. Não é possível carregar no momento"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Carregada"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 8ceeb63..2f206d4 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Ligado via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Disponível através de %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Toque para se inscrever"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Sem Internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Não é possível aceder ao servidor DNS."</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Ligação limitada"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Sem Internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (vermelho-verde)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (azul-amarelo)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correção da cor"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"A correção de cor ajuda as pessoas com daltonismo a ver cores mais precisas."</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Resta(m) cerca de <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> até ficar carregada"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconhecido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"A carregar"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"a carregar…"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Não está a carregar"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Ligada à corrente, não é possível carregar neste momento"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Completo"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index e61c84e..f4182bf 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Conectado via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Disponível via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Toque para se inscrever"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Sem Internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Não é possível acessar o servidor DNS privado"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Conexão limitada"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Sem Internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (vermelho-verde)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (azul-amarelo)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correção de cor"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"A correção de cores ajuda pessoas com daltonismo a ver cores de forma mais precisa"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> até a carga completa"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconhecido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Carregando"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"carregando"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Não está carregando"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Conectado. Não é possível carregar no momento"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Carregada"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 5ad8dfd..6e8bbd1 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Conectat prin <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Disponibilă prin %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Atingeți pentru a vă înscrie"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Fără conexiune la internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Serverul DNS privat nu poate fi accesat"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Conexiune limitată"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Fără conexiune la internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (roșu-verde)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (albastru-galben)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corecția culorii"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Corecția culorii ajută persoanele cu daltonism să vadă culori mai exacte"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Valoare înlocuită de <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Timp aproximativ rămas: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> până la încărcare"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Necunoscut"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Se încarcă"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"se încarcă"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nu se încarcă"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Conectat, nu se poate încărca chiar acum"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Complet"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 104efdc..87831c7 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Нет подключения к Интернету"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Доступа к частному DNS-серверу нет."</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Подключение к сети ограничено."</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Нет подключения к Интернету"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалия (красный/зеленый)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалия (синий/желтый)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Коррекция цвета"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Коррекция цвета помогает пользователям с нарушениями цветового зрения лучше различать изображение на экране."</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Новая настройка: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"Уровень заряда – <xliff:g id="PERCENTAGE">%1$s</xliff:g>. <xliff:g id="TIME_STRING">%2$s</xliff:g>."</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Заряда хватит примерно на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до полной зарядки"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Неизвестно"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Идет зарядка"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"заряжается"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не заряжается"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Подключено, не заряжается"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Батарея заряжена"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index f5dad87..f0a823a 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"අන්තර්ජාලය නැත"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"පුද්ගලික DNS සේවාදායකයට ප්රවේශ වීමට නොහැකිය"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"සීමිත සම්බන්ධතාව"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"අන්තර්ජාලය නැත"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"වර්ණ දුර්වලතාවය (රතු-කොළ)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"වර්ණ අන්ධතාවය (නිල්-කහ)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"වර්ණ නිවැරදි කිරීම"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"වර්ණ අන්ධතාවෙන් පෙළෙන පුද්ගලයන්ට වඩාත් නිරවද්ය වර්ණ බැලීමට වර්ණ නිවැරදි කිරීම සහාය වේ"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> මගින් ඉක්මවන ලදී"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ක් පමණ ඉතිරියි"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - ආරෝපණය වන තෙක් <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"නොදනී"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ආරෝපණය වෙමින්"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"ආරෝපණය වේ"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ආරෝපණය නොවේ"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"පේනුගත කර ඇත, මේ අවස්ථාවේදී ආරෝපණය කළ නොහැකිය"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"පූර්ණ"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 527dafb..fc2ba1d 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Pripojené prostredníctvom siete <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"K dispozícii prostredníctvom %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Prihláste sa klepnutím"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Bez internetu"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"K súkromnému serveru DNS sa nepodarilo získať prístup"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Obmedzené pripojenie"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Žiadny internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomália (červená a zelená)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomália (modrá a žltá)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Úprava farieb"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Korekcia farieb pomáha farboslepým ľuďom vidieť presnejšie farby"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Prekonané predvoľbou <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Zostáva približne <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabitia"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Neznáme"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Nabíja sa"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"nabíja sa"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nenabíja sa"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Pripojené, ale nie je možné nabíjať"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Nabitá"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 4816950..cda2e06 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Povezava vzpostavljena prek omrežja <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Na voljo prek: %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Dotaknite se, če se želite registrirati"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Ni internetne povezave"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Do zasebnega strežnika DNS ni mogoče dostopati"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Omejena povezava"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Brez internetne povezave"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (rdeča – zelena)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (modra – rumena)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Popravljanje barv"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Popravljanje barv osebam z barvno slepoto pomaga, da vidijo bolj prave barve"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Preglasila nastavitev: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Še približno <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do polne napolnjenosti"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Neznano"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Polnjenje"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"polnjenje"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Se ne polni"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Priključeno, trenutno ni mogoče polniti"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Poln"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 12511dd3..9854017 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Lidhur përmes <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"E mundshme përmes %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Trokit për t\'u regjistruar"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Nuk ka internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Serveri privat DNS nuk mund të qaset"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Lidhje e kufizuar"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Nuk ka internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (e kuqe - e gjelbër)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (e kaltër - e verdhë)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korrigjimi i ngjyrës"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Korrigjimi i ngjyrës i ndihmon njerëzit me daltonizëm të shohin ngjyra më të sakta"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Mbivendosur nga <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Rreth <xliff:g id="TIME_REMAINING">%1$s</xliff:g> të mbetura"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> deri sa të karikohen"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"I panjohur"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Po karikohet"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"po karikohet"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nuk po karikohet"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Në prizë, por nuk mund të ngarkohet për momentin"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"E mbushur"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 4724be5..b59a568 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Нема интернета"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Приступ приватном DNS серверу није успео"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Ограничена веза"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Нема интернета"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалија (црвено-зелено)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалија (плаво-жуто)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Корекција боја"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Корекција боја помаже људима који су далтонисти да прецизније виде боје"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Замењује га <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>–<xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Преостало је око <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – напуниће се за <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Непознато"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Пуни се"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"пуни се"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не пуни се"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Прикључено је, али пуњење тренутно није могуће"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Пуна"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 9d1bc42..f9ed6d4 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Anslutet via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Tillgängligt via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Tryck för att logga in"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Inget internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Det går inte att komma åt den privata DNS-servern."</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Begränsad anslutning"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Inget internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (rött-grönt)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (blått-gult)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Färgkorrigering"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Med färgkorrigering kan färgblinda personer se mer korrekta färger"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Har åsidosatts av <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Cirka <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kvar"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> till full laddning"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Okänd"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Laddar"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"laddas"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Laddar inte"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Inkopplad, kan inte laddas just nu"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Fullt"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 1e2489f..40e025a 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Imeunganishwa kupitia <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Inapatikana kupitia %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Gusa ili ujisajili"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Hakuna intaneti"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Seva ya faragha ya DNS haiwezi kufikiwa"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Muunganisho hafifu"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Hakuna intaneti"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (nyekundu-kijani)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (samawati-manjano)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Usahihishaji wa rangi"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Urekebishaji wa rangi huwasaidia watu wenye matatizo ya kutofautisha rangi ili waone rangi nyingi sahihi"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Imetanguliwa na <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Zimesalia takribani <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> hadi ijae chaji"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Haijulikani"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Inachaji"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"inachaji"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Haichaji"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Haiwezi kuchaji kwa sasa"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Imejaa"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index fcb801b..36a92ed 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"இணைய இணைப்பு இல்லை"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"தனிப்பட்ட DNS சேவையகத்தை அணுக இயலாது"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"வரம்பிற்கு உட்பட்ட இணைப்பு"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"இணைய இணைப்பு இல்லை"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"நிறம் அடையாளங்காண முடியாமை (சிவப்பு-பச்சை)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"நிறம் அடையாளங்காண முடியாமை (நீலம்-மஞ்சள்)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"வண்ணத்திருத்தம்"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"வண்ணத் திருத்தத்தால் நிறக்குருடு உள்ளவர்களால் வண்ணங்களை இன்னும் துல்லியமாகப் பார்க்க முடியும்"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> மூலம் மேலெழுதப்பட்டது"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"கிட்டத்தட்ட <xliff:g id="TIME_REMAINING">%1$s</xliff:g> மீதமுள்ளது"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - முழு சார்ஜாக <xliff:g id="TIME">%2$s</xliff:g> ஆகும்"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"அறியப்படாத"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"சார்ஜ் ஆகிறது"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"சார்ஜ் ஆகிறது"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"சார்ஜ் செய்யப்படவில்லை"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"செருகப்பட்டது, ஆனால் இப்போது சார்ஜ் செய்ய முடியவில்லை"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"முழுவதும் சார்ஜ் ஆனது"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 7a80451..5ea380c 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"ఇంటర్నెట్ లేదు"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"ప్రైవేట్ DNS సర్వర్ను యాక్సెస్ చేయడం సాధ్యపడదు"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"పరిమిత కనెక్షన్"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ఇంటర్నెట్ లేదు"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ప్రొటానోమలీ (ఎరుపు-ఆకుపచ్చ రంగు)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ట్రైటనోమలీ (నీలం-పసుపు రంగు)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"రంగు సవరణ"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"రంగు సవరణ అనేది వర్ణాంధత్వం ఉన్న వ్యక్తులకు మరింత ఖచ్చితమైన రంగులను చూడడానికి సహాయపడుతుంది"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ద్వారా భర్తీ చేయబడింది"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> సమయం మిగిలి ఉంది"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - ఛార్జ్ అవ్వడానికి <xliff:g id="TIME">%2$s</xliff:g> పడుతుంది"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"తెలియదు"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ఛార్జ్ అవుతోంది"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"ఛార్జ్ అవుతోంది"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ఛార్జ్ కావడం లేదు"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"ప్లగ్ ఇన్ చేయబడింది, ప్రస్తుతం ఛార్జ్ చేయడం సాధ్యం కాదు"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"నిండింది"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 130e1c4..15e74ae 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"ไม่มีอินเทอร์เน็ต"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"เข้าถึงเซิร์ฟเวอร์ DNS ไม่ได้"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"การเชื่อมต่อที่จำกัด"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ไม่มีอินเทอร์เน็ต"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ตาบอดจางสีแดง (สีแดง/เขียว)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ตาบอดจางสีน้ำเงิน (สีน้ำเงิน/เหลือง)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"การแก้สี"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"การแก้ไขสีช่วยให้ผู้ที่มีอาการตาบอดสีเห็นสีต่างๆ ได้ตรงตามจริงยิ่งขึ้น"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"แทนที่โดย <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"เหลืออีกประมาณ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> จนกว่าจะชาร์จ"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ไม่ทราบ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"กำลังชาร์จ"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"กำลังชาร์จ"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ไม่ได้ชาร์จ"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"เสียบอยู่ ไม่สามารถชาร์จได้ในขณะนี้"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"เต็ม"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index bc1a405..8012244 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Nakakonekta sa pamamagitan ng <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Available sa pamamagitan ng %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"I-tap para mag-sign up"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Walang internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Hindi ma-access ang pribadong DNS server"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Limitadong koneksyon"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Walang internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (pula-berde)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (asul-dilaw)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Pagtatama ng kulay"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Ang pagwawasto ng kulay ay nakakatulong sa mga taong may color blindness na makita ang mga mas tamang kulay"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Na-override ng <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Humigit-kumulang <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ang natitira"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> hanggang matapos mag-charge"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Hindi Kilala"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Nagcha-charge"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"nagcha-charge"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Hindi nagcha-charge"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Nakasaksak, hindi makapag-charge sa ngayon"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Puno"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 4e263ef..b83ffcb 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> ile bağlandı"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s üzerinden kullanılabilir"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Kaydolmak için dokunun"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"İnternet yok"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Gizli DNS sunucusuna erişilemiyor"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Sınırlı bağlantı"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"İnternet yok"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Kırmızı renk körlüğü (kırmızı-yeşil)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Mavi renk körlüğü (mavi-sarı)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Renk düzeltme"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Renk düzeltme, renk körlüğü olan kişilerin daha doğru renkler görmelerine yardımcı olur"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> tarafından geçersiz kılındı"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Yaklaşık <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kaldı"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - şarj olmaya <xliff:g id="TIME">%2$s</xliff:g> kaldı"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Bilinmiyor"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Şarj oluyor"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"şarj oluyor"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Şarj olmuyor"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Prize takıldı, şu anda şarj olamıyor"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Dolu"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index ad9f600..5fb46f8 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Немає Інтернету"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Немає доступу до приватного DNS-сервера"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Обмежене з’єднання"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Немає Інтернету"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалія (червоний – зелений)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалія (синій – жовтий)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Корекція кольору"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Корекція кольору допомагає людям із дальтонізмом бачити точніші кольори"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Замінено на <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Залишилося приблизно <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до повного заряду"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Невідомо"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Заряджається"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"заряджається"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не заряджається"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Підключено. Не вдається зарядити"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Акумулятор заряджено"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index b995da1..c6c10f0 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"انٹرنیٹ نہیں ہے"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"نجی DNS سرور تک رسائی حاصل نہیں کی جا سکی"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"محدود کنکشن"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"انٹرنیٹ نہیں ہے"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (سرخ سبز)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (نیلا پیلا)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"رنگ کی اصلاح"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"رنگ کی درستگی رنگ نہ دکھائی دینے والے لوگوں کی رنگوں کو مزید درست طریقے سے دیکھنے میں مدد کرتی ہے"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> کے ذریعہ منسوخ کردیا گیا"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"تقریباً <xliff:g id="TIME_REMAINING">%1$s</xliff:g> باقی ہے"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> چارج ہونے تک"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"نامعلوم"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"چارج ہو رہا ہے"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"چارج ہو رہا ہے"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"چارج نہیں ہو رہا ہے"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"پلگ ان ہے، ابھی چارج نہیں کر سکتے"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"مکمل"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index f02b639..07a6249 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> orqali ulandi"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s orqali ishlaydi"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Yozilish uchun bosing"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Internetga ulanmagansiz"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Xususiy DNS server ishlamayapti"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Cheklangan aloqa"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Internet yo‘q"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaliya (qizil/yashil)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaliya (ko‘k/sariq)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Rangni tuzatish"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Ranglarni sozlash ranglarni farqlashda muammosi bor insonlarga (masalan, daltoniklarga) aniq koʻrishda yordam beradi"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> bilan almashtirildi"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Taxminan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qoldi"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> ichida toʻliq quvvat oladi"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Noma’lum"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Quvvat olmoqda"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"quvvat olmoqda"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Quvvat olmayapti"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Ulangan, lekin quvvat olmayapti"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"To‘la"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 8fcf1f2..7e3944c 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Đã kết nối qua <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Có sẵn qua %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Nhấn để đăng ký"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Không có Internet"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Không thể truy cập máy chủ DNS riêng tư"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Kết nối giới hạn"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Không có Internet"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Mù màu đỏ không hoàn toàn (đỏ-xanh lục)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Mù màu (xanh lam-vàng)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Sửa màu"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Tùy chọn sửa màu giúp những người bị mù màu thấy màu sắc chính xác hơn"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Bị ghi đè bởi <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Còn khoảng <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> nữa là sạc xong"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Không xác định"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Đang sạc"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"đang sạc"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Hiện không sạc"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Đã cắm nhưng không thể sạc ngay"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Đầy"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 755cbee..3edbb4d 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"无法访问互联网"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"无法访问私人 DNS 服务器"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"网络连接受限"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"无法访问互联网"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"红色弱视(红绿不分)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"蓝色弱视(蓝黄不分)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"色彩校正"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"颜色校正功能有助于色盲用户看到更准确的颜色"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"已被“<xliff:g id="TITLE">%1$s</xliff:g>”覆盖"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"大约还可使用 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>后充满电"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"未知"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"正在充电"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"正在充电"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"未在充电"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"已插入电源,但是现在无法充电"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"电量充足"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index e50acf5..6174fe9 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"沒有互聯網連線"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"無法存取私人 DNS 伺服器"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"連線受限"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"沒有互聯網連線"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"紅色弱視 (紅綠)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"藍色弱視 (藍黃)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"色彩校正"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"色彩校正有助色盲人士看到更準確的顏色"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"已由「<xliff:g id="TITLE">%1$s</xliff:g>」覆寫"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"還有大約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - 還需 <xliff:g id="TIME">%2$s</xliff:g>才能充滿電"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"未知"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"正在充電"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"非充電中"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"已插入電源插座,但目前無法充電"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"電量已滿"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 7df6fed..a150d16 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -42,8 +42,7 @@
<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>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"沒有網際網路連線"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"無法存取私人 DNS 伺服器"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"連線能力受限"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"沒有網際網路連線"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"紅色弱視 (紅-綠)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"藍色弱視 (藍-黃)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"色彩校正"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"色彩校正可協助色盲使用者看見較準確的色彩"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"已改為<xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"還能使用約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>後充飽電"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"不明"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"充電中"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"非充電中"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"已接上電源,但現在無法充電"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"電力充足"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 46dffbe..003dda3 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -42,8 +42,7 @@
<string name="connected_via_app" msgid="3532267661404276584">"Ixhumeke nge-<xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Iyatholakala nge-%1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Thepha ukuze ubhalisele"</string>
- <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
- <skip />
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Ayikho i-inthanethi"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Iseva eyimfihlo ye-DNS ayikwazi ukufinyelelwa"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Iqoqo elikhawulelwe"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Ayikho i-inthanethi"</string>
@@ -384,7 +383,8 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"I-Protanomaly (bomvu-luhlaza)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"I-Tritanomaly (luhlaza okwesibhakabhaka-phuzi)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Ukulungiswa kombala"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Ukulungisa umbala kusiza abantu abangaboni imibala ukubona ngokuqondile"</string>
+ <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (6178138727195403796) -->
+ <skip />
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Igitshezwe ngaphezulu yi-<xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Cishe u-<xliff:g id="TIME_REMAINING">%1$s</xliff:g> osele"</string>
@@ -414,7 +414,10 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ize igcwale"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Akwaziwa"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Iyashaja"</string>
- <string name="battery_info_status_charging_lower" msgid="8696042568167401574">"iyashaja"</string>
+ <!-- no translation found for battery_info_status_charging_fast (8027559755902954885) -->
+ <skip />
+ <!-- no translation found for battery_info_status_charging_slow (3190803837168962319) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ayishaji"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Kuxhunyiwe, ayikwazi ukushaja khona manje"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Kugcwele"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 2e7a3c0..4d96251 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -970,7 +970,7 @@
<!-- Title for the accessibility preference to configure display color space correction. [CHAR LIMIT=NONE] -->
<string name="accessibility_display_daltonizer_preference_title">Color correction</string>
<!-- Subtitle for the accessibility preference to configure display color space correction. [CHAR LIMIT=NONE] -->
- <string name="accessibility_display_daltonizer_preference_subtitle">Color correction helps people with color blindness to see more accurate colors</string>
+ <string name="accessibility_display_daltonizer_preference_subtitle">Color correction helps people with colorblindness see more accurate colors</string>
<!-- Summary shown for color space correction preference when its value is overridden by another preference [CHAR LIMIT=35] -->
<string name="daltonizer_type_overridden">Overridden by <xliff:g id="title" example="Simulate color space">%1$s</xliff:g></string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index 93f77ca..580e086 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -22,8 +22,7 @@
import android.text.TextUtils;
import androidx.annotation.IntDef;
-
-import com.android.internal.annotations.VisibleForTesting;
+import androidx.annotation.VisibleForTesting;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index bfb79c0..954eb9b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -181,6 +181,7 @@
static final String KEY_SCANRESULTS = "key_scanresults";
static final String KEY_SCOREDNETWORKCACHE = "key_scorednetworkcache";
static final String KEY_CONFIG = "key_config";
+ static final String KEY_PASSPOINT_UNIQUE_ID = "key_passpoint_unique_id";
static final String KEY_FQDN = "key_fqdn";
static final String KEY_PROVIDER_FRIENDLY_NAME = "key_provider_friendly_name";
static final String KEY_EAPTYPE = "eap_psktype";
@@ -217,7 +218,7 @@
public static final int UNREACHABLE_RSSI = Integer.MIN_VALUE;
public static final String KEY_PREFIX_AP = "AP:";
- public static final String KEY_PREFIX_FQDN = "FQDN:";
+ public static final String KEY_PREFIX_PASSPOINT_UNIQUE_ID = "PASSPOINT:";
public static final String KEY_PREFIX_OSU = "OSU:";
private final Context mContext;
@@ -250,6 +251,7 @@
* Information associated with the {@link PasspointConfiguration}. Only maintaining
* the relevant info to preserve spaces.
*/
+ private String mPasspointUniqueId;
private String mFqdn;
private String mProviderFriendlyName;
private boolean mIsRoaming = false;
@@ -308,6 +310,9 @@
mScoredNetworkCache.put(timedScore.getScore().networkKey.wifiKey.bssid, timedScore);
}
}
+ if (savedState.containsKey(KEY_PASSPOINT_UNIQUE_ID)) {
+ mPasspointUniqueId = savedState.getString(KEY_PASSPOINT_UNIQUE_ID);
+ }
if (savedState.containsKey(KEY_FQDN)) {
mFqdn = savedState.getString(KEY_FQDN);
}
@@ -351,6 +356,7 @@
*/
public AccessPoint(Context context, PasspointConfiguration config) {
mContext = context;
+ mPasspointUniqueId = config.getUniqueId();
mFqdn = config.getHomeSp().getFqdn();
mProviderFriendlyName = config.getHomeSp().getFriendlyName();
mSubscriptionExpirationTimeInMillis = config.getSubscriptionExpirationTimeInMillis();
@@ -371,6 +377,7 @@
mContext = context;
networkId = config.networkId;
mConfig = config;
+ mPasspointUniqueId = config.getKey();
mFqdn = config.FQDN;
setScanResultsPasspoint(homeScans, roamingScans);
updateKey();
@@ -407,7 +414,7 @@
if (isPasspoint()) {
mKey = getKey(mConfig);
} else if (isPasspointConfig()) {
- mKey = getKey(mFqdn);
+ mKey = getKey(mPasspointUniqueId);
} else if (isOsuProvider()) {
mKey = getKey(mOsuProvider);
} else { // Non-Passpoint AP
@@ -677,19 +684,19 @@
*/
public static String getKey(WifiConfiguration config) {
if (config.isPasspoint()) {
- return getKey(config.FQDN);
+ return getKey(config.getKey());
} else {
return getKey(removeDoubleQuotes(config.SSID), config.BSSID, getSecurity(config));
}
}
/**
- * Returns the AccessPoint key corresponding to a Passpoint network by its FQDN.
+ * Returns the AccessPoint key corresponding to a Passpoint network by its unique identifier.
*/
- public static String getKey(String fqdn) {
+ public static String getKey(String passpointUniqueId) {
return new StringBuilder()
- .append(KEY_PREFIX_FQDN)
- .append(fqdn).toString();
+ .append(KEY_PREFIX_PASSPOINT_UNIQUE_ID)
+ .append(passpointUniqueId).toString();
}
/**
@@ -766,7 +773,7 @@
public boolean matches(WifiConfiguration config) {
if (config.isPasspoint()) {
- return (isPasspoint() && config.FQDN.equals(mConfig.FQDN));
+ return (isPasspoint() && config.getKey().equals(mConfig.getKey()));
}
if (!ssid.equals(removeDoubleQuotes(config.SSID))
@@ -1052,7 +1059,7 @@
public String getConfigName() {
if (mConfig != null && mConfig.isPasspoint()) {
return mConfig.providerFriendlyName;
- } else if (mFqdn != null) {
+ } else if (mPasspointUniqueId != null) {
return mProviderFriendlyName;
} else {
return ssid;
@@ -1254,7 +1261,7 @@
* Return true if this AccessPoint represents a Passpoint provider configuration.
*/
public boolean isPasspointConfig() {
- return mFqdn != null && mConfig == null;
+ return mPasspointUniqueId != null && mConfig == null;
}
/**
@@ -1310,8 +1317,12 @@
if (info.isOsuAp() || mOsuStatus != null) {
return (info.isOsuAp() && mOsuStatus != null);
} else if (info.isPasspointAp() || isPasspoint()) {
+ // TODO: Use TextUtils.equals(info.getPasspointUniqueId(), mConfig.getKey()) when API
+ // is available
return (info.isPasspointAp() && isPasspoint()
- && TextUtils.equals(info.getPasspointFqdn(), mConfig.FQDN));
+ && TextUtils.equals(info.getPasspointFqdn(), mConfig.FQDN)
+ && TextUtils.equals(info.getPasspointProviderFriendlyName(),
+ mConfig.providerFriendlyName));
}
if (networkId != WifiConfiguration.INVALID_NETWORK_ID) {
@@ -1377,6 +1388,9 @@
if (mNetworkInfo != null) {
savedState.putParcelable(KEY_NETWORKINFO, mNetworkInfo);
}
+ if (mPasspointUniqueId != null) {
+ savedState.putString(KEY_PASSPOINT_UNIQUE_ID, mPasspointUniqueId);
+ }
if (mFqdn != null) {
savedState.putString(KEY_FQDN, mFqdn);
}
@@ -1949,11 +1963,11 @@
return;
}
- String fqdn = passpointConfig.getHomeSp().getFqdn();
+ String uniqueId = passpointConfig.getUniqueId();
for (Pair<WifiConfiguration, Map<Integer, List<ScanResult>>> pairing :
wifiManager.getAllMatchingWifiConfigs(wifiManager.getScanResults())) {
WifiConfiguration config = pairing.first;
- if (TextUtils.equals(config.FQDN, fqdn)) {
+ if (TextUtils.equals(config.getKey(), uniqueId)) {
List<ScanResult> homeScans =
pairing.second.get(WifiManager.PASSPOINT_HOME_NETWORK);
List<ScanResult> roamingScans =
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java b/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java
index f21e466..2fb2481 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java
@@ -84,7 +84,7 @@
bundle.putParcelable(AccessPoint.KEY_NETWORKINFO, mNetworkInfo);
bundle.putParcelable(AccessPoint.KEY_WIFIINFO, mWifiInfo);
if (mFqdn != null) {
- bundle.putString(AccessPoint.KEY_FQDN, mFqdn);
+ bundle.putString(AccessPoint.KEY_PASSPOINT_UNIQUE_ID, mFqdn);
}
if (mProviderFriendlyName != null) {
bundle.putString(AccessPoint.KEY_PROVIDER_FRIENDLY_NAME, mProviderFriendlyName);
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 26abf71..586c154 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -606,7 +606,7 @@
List<ScanResult> cachedScanResults = new ArrayList<>(mScanResultCache.values());
- // Add a unique Passpoint AccessPoint for each Passpoint profile's FQDN.
+ // Add a unique Passpoint AccessPoint for each Passpoint profile's unique identifier.
accessPoints.addAll(updatePasspointAccessPoints(
mWifiManager.getAllMatchingWifiConfigs(cachedScanResults), cachedAccessPoints));
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 1d679c7..5946f21 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -308,6 +308,22 @@
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
new file mode 100644
index 0000000..5f9563a
--- /dev/null
+++ b/packages/Shell/res/layout/null_home_finishing_boot.xml
@@ -0,0 +1,44 @@
+<?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/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 48d405a..1814593 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -97,6 +97,7 @@
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -193,9 +194,7 @@
* <p>
* Must be a path supported by its FileProvider.
*/
- // TODO: use the same variable for both dir
- private static final String SCREENSHOT_DIR = "bugreports";
- private static final String BUGREPORT_DIR = "/bugreports";
+ private static final String BUGREPORT_DIR = "bugreports";
private static final String NOTIFICATION_CHANNEL_ID = "bugreports";
@@ -230,7 +229,7 @@
private final BugreportInfoDialog mInfoDialog = new BugreportInfoDialog();
- private File mScreenshotsDir;
+ private File mBugreportsDir;
private BugreportManager mBugreportManager;
@@ -263,11 +262,12 @@
mScreenshotHandler = new ScreenshotHandler("BugreportProgressServiceScreenshotThread");
startSelfIntent = new Intent(this, this.getClass());
- mScreenshotsDir = new File(getFilesDir(), SCREENSHOT_DIR);
- if (!mScreenshotsDir.exists()) {
- Log.i(TAG, "Creating directory " + mScreenshotsDir + " to store temporary screenshots");
- if (!mScreenshotsDir.mkdir()) {
- Log.w(TAG, "Could not create directory " + mScreenshotsDir);
+ mBugreportsDir = new File(getFilesDir(), BUGREPORT_DIR);
+ if (!mBugreportsDir.exists()) {
+ Log.i(TAG, "Creating directory " + mBugreportsDir
+ + " to store bugreports and screenshots");
+ if (!mBugreportsDir.mkdir()) {
+ Log.w(TAG, "Could not create directory " + mBugreportsDir);
}
}
final Configuration conf = mContext.getResources().getConfiguration();
@@ -372,7 +372,7 @@
@Override
public void onFinished() {
mInfo.renameBugreportFile();
- mInfo.renameScreenshots(mScreenshotsDir);
+ mInfo.renameScreenshots();
synchronized (mLock) {
sendBugreportFinishedBroadcastLocked();
}
@@ -406,7 +406,7 @@
mInfo.bugreportFile);
} else {
trackInfoWithIdLocked();
- cleanupOldFiles(MIN_KEEP_COUNT, MIN_KEEP_AGE);
+ cleanupOldFiles(MIN_KEEP_COUNT, MIN_KEEP_AGE, mBugreportsDir);
final Intent intent = new Intent(INTENT_BUGREPORT_FINISHED);
intent.putExtra(EXTRA_BUGREPORT, bugreportFilePath);
intent.putExtra(EXTRA_SCREENSHOT, getScreenshotForIntent(mInfo));
@@ -418,7 +418,8 @@
private static void sendRemoteBugreportFinishedBroadcast(Context context,
String bugreportFileName, File bugreportFile) {
- cleanupOldFiles(REMOTE_BUGREPORT_FILES_AMOUNT, REMOTE_MIN_KEEP_AGE);
+ cleanupOldFiles(REMOTE_BUGREPORT_FILES_AMOUNT, REMOTE_MIN_KEEP_AGE,
+ bugreportFile.getParentFile());
final Intent intent = new Intent(DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH);
final Uri bugreportUri = getUri(context, bugreportFile);
final String bugreportHash = generateFileHash(bugreportFileName);
@@ -468,12 +469,12 @@
return fileHash;
}
- static void cleanupOldFiles(final int minCount, final long minAge) {
+ static void cleanupOldFiles(final int minCount, final long minAge, File bugreportsDir) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
try {
- FileUtils.deleteOlderFiles(new File(BUGREPORT_DIR), minCount, minAge);
+ FileUtils.deleteOlderFiles(bugreportsDir, minCount, minAge);
} catch (RuntimeException e) {
Log.e(TAG, "RuntimeException deleting old files", e);
}
@@ -604,18 +605,25 @@
String name = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date());
BugreportInfo info = new BugreportInfo(mContext, baseName, name,
- shareTitle, shareDescription, bugreportType);
+ shareTitle, shareDescription, bugreportType, mBugreportsDir);
+ ParcelFileDescriptor bugreportFd;
+ ParcelFileDescriptor screenshotFd;
- ParcelFileDescriptor bugreportFd = info.createBugreportFd();
- if (bugreportFd == null) {
- Log.e(TAG, "Bugreport parcel file descriptor is null.");
- return;
- }
- ParcelFileDescriptor screenshotFd = info.createScreenshotFd();
- if (screenshotFd == null) {
- Log.e(TAG, "Screenshot parcel file descriptor is null. Deleting bugreport file");
- FileUtils.closeQuietly(bugreportFd);
- info.bugreportFile.delete();
+ try {
+ bugreportFd = info.createAndGetBugreportFd();
+ if (bugreportFd == null) {
+ Log.e(TAG, "Bugreport parcel file descriptor is null.");
+ return;
+ }
+ screenshotFd = info.createAndGetDefaultScreenshotFd();
+ if (screenshotFd == null) {
+ Log.e(TAG, "Screenshot parcel file descriptor is null. Deleting bugreport file");
+ FileUtils.closeQuietly(bugreportFd);
+ info.bugreportFile.delete();
+ return;
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Error in generating bugreport files: ", e);
return;
}
mBugreportManager = (BugreportManager) mContext.getSystemService(
@@ -639,21 +647,24 @@
}
}
- private static ParcelFileDescriptor createReadWriteFile(File file) {
+ private static ParcelFileDescriptor getFd(File file) {
try {
- file.createNewFile();
- file.setReadable(true, true);
- file.setWritable(true, true);
-
- ParcelFileDescriptor fd = ParcelFileDescriptor.open(file,
+ return ParcelFileDescriptor.open(file,
ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_APPEND);
- return fd;
- } catch (IOException e) {
+ } catch (FileNotFoundException e) {
Log.i(TAG, "Error in generating bugreports: ", e);
}
return null;
}
+ private static void createReadWriteFile(File file) throws IOException {
+ if (!file.exists()) {
+ file.createNewFile();
+ file.setReadable(true, true);
+ file.setWritable(true, true);
+ }
+ }
+
/**
* Updates the system notification for a given bugreport.
*/
@@ -874,7 +885,7 @@
return;
}
final String screenshotPath =
- new File(mScreenshotsDir, info.getPathNextScreenshot()).getAbsolutePath();
+ new File(mBugreportsDir, info.getPathNextScreenshot()).getAbsolutePath();
Message.obtain(mScreenshotHandler, MSG_SCREENSHOT_REQUEST, id, UNUSED_ARG2, screenshotPath)
.sendToTarget();
@@ -921,7 +932,7 @@
info.addScreenshot(screenshotFile);
if (info.finished) {
Log.d(TAG, "Screenshot finished after bugreport; updating share notification");
- info.renameScreenshots(mScreenshotsDir);
+ info.renameScreenshots();
sendBugreportNotification(info, mTakingScreenshot);
}
msg = mContext.getString(R.string.bugreport_screenshot_taken);
@@ -1030,11 +1041,10 @@
/**
* Build {@link Intent} that can be used to share the given bugreport.
*/
- private static Intent buildSendIntent(Context context, BugreportInfo info,
- File screenshotsDir) {
+ private static Intent buildSendIntent(Context context, BugreportInfo info) {
// Rename files (if required) before sharing
info.renameBugreportFile();
- info.renameScreenshots(screenshotsDir);
+ info.renameScreenshots();
// Files are kept on private storage, so turn into Uris that we can
// grant temporary permissions for.
final Uri bugreportUri;
@@ -1120,7 +1130,7 @@
addDetailsToZipFile(info);
- final Intent sendIntent = buildSendIntent(mContext, info, mScreenshotsDir);
+ final Intent sendIntent = buildSendIntent(mContext, info);
if (sendIntent == null) {
Log.w(TAG, "Stopping progres on ID " + id + " because share intent could not be built");
synchronized (mLock) {
@@ -1813,24 +1823,37 @@
*/
BugreportInfo(Context context, String baseName, String name,
@Nullable String shareTitle, @Nullable String shareDescription,
- @BugreportParams.BugreportMode int type) {
+ @BugreportParams.BugreportMode int type, File bugreportsDir) {
this.context = context;
this.name = this.initialName = name;
this.shareTitle = shareTitle == null ? "" : shareTitle;
this.shareDescription = shareDescription == null ? "" : shareDescription;
this.type = type;
this.baseName = baseName;
+ createBugreportFile(bugreportsDir);
+ createScreenshotFile(bugreportsDir);
}
- ParcelFileDescriptor createBugreportFd() {
- bugreportFile = new File(BUGREPORT_DIR, getFileName(this, ".zip"));
- return createReadWriteFile(bugreportFile);
+ void createBugreportFile(File bugreportsDir) {
+ bugreportFile = new File(bugreportsDir, getFileName(this, ".zip"));
}
- ParcelFileDescriptor createScreenshotFd() {
- File screenshotFile = new File(BUGREPORT_DIR, getScreenshotName("default"));
+ void createScreenshotFile(File bugreportsDir) {
+ File screenshotFile = new File(bugreportsDir, getScreenshotName("default"));
addScreenshot(screenshotFile);
- return createReadWriteFile(screenshotFile);
+ }
+
+ ParcelFileDescriptor createAndGetBugreportFd() throws IOException {
+ createReadWriteFile(bugreportFile);
+ return getFd(bugreportFile);
+ }
+
+ ParcelFileDescriptor createAndGetDefaultScreenshotFd() throws IOException {
+ if (screenshotFiles.isEmpty()) {
+ return null;
+ }
+ createReadWriteFile(screenshotFiles.get(0));
+ return getFd(screenshotFiles.get(0));
}
/**
@@ -1859,7 +1882,7 @@
* Rename all screenshots files so that they contain the new {@code name} instead of the
* {@code initialName} if user has changed it.
*/
- void renameScreenshots(File screenshotDir) {
+ void renameScreenshots() {
if (TextUtils.isEmpty(name)) {
return;
}
@@ -1869,7 +1892,7 @@
final String newName = oldName.replaceFirst(initialName, name);
final File newFile;
if (!newName.equals(oldName)) {
- final File renamedFile = new File(screenshotDir, newName);
+ final File renamedFile = new File(oldFile.getParentFile(), newName);
Log.d(TAG, "Renaming screenshot file " + oldFile + " to " + renamedFile);
newFile = oldFile.renameTo(renamedFile) ? renamedFile : oldFile;
} else {
@@ -1889,7 +1912,8 @@
* Rename bugreport file to include the name given by user via UI
*/
void renameBugreportFile() {
- File newBugreportFile = new File(BUGREPORT_DIR, getFileName(this, ".zip"));
+ File newBugreportFile = new File(bugreportFile.getParentFile(),
+ getFileName(this, ".zip"));
if (!newBugreportFile.getPath().equals(bugreportFile.getPath())) {
if (bugreportFile.renameTo(newBugreportFile)) {
bugreportFile = newBugreportFile;
diff --git a/packages/Shell/src/com/android/shell/NullHome.java b/packages/Shell/src/com/android/shell/NullHome.java
new file mode 100644
index 0000000..bd97561
--- /dev/null
+++ b/packages/Shell/src/com/android/shell/NullHome.java
@@ -0,0 +1,43 @@
+/*
+ * 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/res/drawable-nodpi/android_11_dial.xml b/packages/SystemUI/res/drawable-nodpi/android_11_dial.xml
new file mode 100644
index 0000000..73fd37f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/android_11_dial.xml
@@ -0,0 +1,63 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:pathData="M77.773,51.064h-1.583c-0.217,0 -0.393,-0.176 -0.393,-0.393v-1.46c0,-0.217 0.176,-0.393 0.393,-0.393h3.466c0.217,0 0.393,0.176 0.393,0.393v9.921c0,0.217 -0.176,0.393 -0.393,0.393h-1.49c-0.217,0 -0.393,-0.176 -0.393,-0.393V51.064z"
+ android:fillColor="#F86734"/>
+ <path
+ android:pathData="M83.598,51.064h-1.583c-0.217,0 -0.393,-0.176 -0.393,-0.393v-1.46c0,-0.217 0.176,-0.393 0.393,-0.393h3.466c0.217,0 0.393,0.176 0.393,0.393v9.921c0,0.217 -0.176,0.393 -0.393,0.393h-1.49c-0.217,0 -0.393,-0.176 -0.393,-0.393V51.064z"
+ android:fillColor="#F86734"/>
+ <path
+ android:pathData="M70.044,75.974m-0.644,0a0.644,0.644 0,1 1,1.288 0a0.644,0.644 0,1 1,-1.288 0"
+ android:fillColor="#d7effe"/>
+ <path
+ android:pathData="M56.896,80.985m-0.718,0a0.718,0.718 0,1 1,1.436 0a0.718,0.718 0,1 1,-1.436 0"
+ android:fillColor="#d7effe"/>
+ <path
+ android:pathData="M43.408,78.881m-0.795,0a0.795,0.795 0,1 1,1.59 0a0.795,0.795 0,1 1,-1.59 0"
+ android:fillColor="#d7effe"/>
+ <path
+ android:pathData="M32.419,70.115m-0.874,0a0.874,0.874 0,1 1,1.748 0a0.874,0.874 0,1 1,-1.748 0"
+ android:fillColor="#d7effe"/>
+ <path
+ android:pathData="M27.306,56.992m-0.954,0a0.954,0.954 0,1 1,1.908 0a0.954,0.954 0,1 1,-1.908 0"
+ android:fillColor="#d7effe"/>
+ <path
+ android:pathData="M29.313,43.489m-1.036,0a1.036,1.036 0,1 1,2.072 0a1.036,1.036 0,1 1,-2.072 0"
+ android:fillColor="#d7effe"/>
+ <path
+ android:pathData="M37.988,32.445m-1.118,0a1.118,1.118 0,1 1,2.236 0a1.118,1.118 0,1 1,-2.236 0"
+ android:fillColor="#d7effe"/>
+ <path
+ android:pathData="M51.137,27.064m-1.201,0a1.201,1.201 0,1 1,2.402 0a1.201,1.201 0,1 1,-2.402 0"
+ android:fillColor="#d7effe"/>
+ <path
+ android:pathData="M64.553,28.868m-1.284,0a1.284,1.284 0,1 1,2.568 0a1.284,1.284 0,1 1,-2.568 0"
+ android:fillColor="#d7effe"/>
+ <path
+ android:pathData="M75.522,37.652m-1.368,0a1.368,1.368 0,1 1,2.736 0a1.368,1.368 0,1 1,-2.736 0"
+ android:fillColor="#d7effe"/>
+ <path
+ android:pathData="M87.942,115.052l-47.557,-47.557l26.869,-26.87l47.557,47.558z">
+ <aapt:attr name="android:fillColor">
+ <gradient
+ android:startY="56.087"
+ android:startX="55.8464"
+ android:endY="100.0297"
+ android:endX="99.7891"
+ android:type="linear">
+ <item android:offset="0" android:color="#3F000000"/>
+ <item android:offset="1" android:color="#00000000"/>
+ </gradient>
+ </aapt:attr>
+ </path>
+ <path
+ android:pathData="M53.928,54.17m-18.999,0a18.999,18.999 0,1 1,37.998 0a18.999,18.999 0,1 1,-37.998 0"
+ android:fillColor="#3ddc84"/>
+ <path
+ android:pathData="M66.353,54.17m-3.185,0a3.185,3.185 0,1 1,6.37 0a3.185,3.185 0,1 1,-6.37 0"
+ android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable-nodpi/icon.xml b/packages/SystemUI/res/drawable-nodpi/icon.xml
index 7a68c03..7f8d4fa 100644
--- a/packages/SystemUI/res/drawable-nodpi/icon.xml
+++ b/packages/SystemUI/res/drawable-nodpi/icon.xml
@@ -15,5 +15,5 @@
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/icon_bg"/>
- <foreground android:drawable="@drawable/q"/>
+ <foreground android:drawable="@drawable/android_11_dial"/>
</adaptive-icon>
diff --git a/packages/SystemUI/res/drawable-nodpi/icon_bg.xml b/packages/SystemUI/res/drawable-nodpi/icon_bg.xml
index 2a54dfa..31b2a7f 100644
--- a/packages/SystemUI/res/drawable-nodpi/icon_bg.xml
+++ b/packages/SystemUI/res/drawable-nodpi/icon_bg.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
<color xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="#77C360" />
+ android:color="#073042" />
diff --git a/packages/SystemUI/res/drawable-nodpi/q.xml b/packages/SystemUI/res/drawable-nodpi/q.xml
deleted file mode 100644
index 0f42d2e..0000000
--- a/packages/SystemUI/res/drawable-nodpi/q.xml
+++ /dev/null
@@ -1,40 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="108dp"
- android:height="108dp"
- android:viewportWidth="108.0"
- android:viewportHeight="108.0">
- <group
- android:name="scale"
- android:pivotX="54" android:pivotY="54"
- android:scaleX="0.9"
- android:scaleY="0.9">
- <group
- android:name="nudge"
- android:translateX="24"
- android:translateY="23.5">
- <path
- android:name="tail"
- android:fillColor="#FFFFFF"
- android:pathData="M21.749674,34.122784l-9.431964,9.529709l-6.31771,-6.2529106l15.736504,-15.899582l64.765724,65.16436l-6.3046494,6.266083z"/>
- <path
- android:name="counter"
- android:fillColor="#FFFFFF"
- android:pathData="M30,9.32352941 C41.6954418,9.32352941 51.1764706,18.8045582 51.1764706,30.5 C51.1764706,42.1954418 41.6954418,51.6764706 30,51.6764706 C18.3045582,51.6764706 8.82352941,42.1954418 8.82352941,30.5 C8.82352941,18.8045582 18.3045582,9.32352941 30,9.32352941 L30,9.32352941 Z M30,0.5 C13.4314575,0.5 -5.53805368e-15,13.9314575 -7.10542736e-15,30.5 C-1.02401747e-14,47.0685425 13.4314575,60.5 30,60.5 C46.5685425,60.5 60,47.0685425 60,30.5 C59.9805514,13.9395201 46.5604799,0.519448617 30,0.5 Z"/>
- </group>
- </group>
-</vector>
diff --git a/media/java/android/media/AudioDeviceAddress.aidl b/packages/SystemUI/res/layout/controls_icon.xml
similarity index 60%
copy from media/java/android/media/AudioDeviceAddress.aidl
copy to packages/SystemUI/res/layout/controls_icon.xml
index 6a1a7f7..cc46ced 100644
--- a/media/java/android/media/AudioDeviceAddress.aidl
+++ b/packages/SystemUI/res/layout/controls_icon.xml
@@ -1,4 +1,7 @@
-/* Copyright 2019, The Android Open Source Project
+<?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.
@@ -12,7 +15,12 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
+-->
-package android.media;
-
-parcelable AudioDeviceAddress;
+<ImageView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="28dp"
+ android:layout_height="28dp"
+ android:scaleType="fitCenter"
+ android:layout_marginLeft="2dp"
+ android:layout_marginRight="2dp" />
diff --git a/packages/SystemUI/res/layout/controls_no_favorites.xml b/packages/SystemUI/res/layout/controls_no_favorites.xml
index 096f1f4..3e0699d 100644
--- a/packages/SystemUI/res/layout/controls_no_favorites.xml
+++ b/packages/SystemUI/res/layout/controls_no_favorites.xml
@@ -1,18 +1,52 @@
+<?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.
+*/
+-->
+
<merge
xmlns:android="http://schemas.android.com/apk/res/android">
- <TextView
- android:id="@+id/controls_title"
- android:text="@string/quick_controls_title"
+ <LinearLayout
+ android:id="@+id/controls_no_favorites_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:singleLine="true"
- android:gravity="center"
- android:textSize="25dp"
+ android:orientation="vertical"
android:paddingTop="40dp"
android:paddingBottom="40dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
- android:textColor="@*android:color/foreground_material_dark"
- android:fontFamily="@*android:string/config_headlineFontFamily"
- android:background="@drawable/control_no_favorites_background"/>
+ android:background="@drawable/control_no_favorites_background">
+
+ <LinearLayout
+ android:id="@+id/controls_icon_row"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:orientation="horizontal"
+ android:paddingBottom="8dp" />
+
+ <TextView
+ android:id="@+id/controls_title"
+ android:text="@string/quick_controls_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:layout_gravity="center"
+ android:textSize="25sp"
+ android:textColor="@*android:color/foreground_material_dark"
+ android:fontFamily="@*android:string/config_headlineFontFamily" />
+ </LinearLayout>
</merge>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index d72ce5e..8de2df5 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -487,9 +487,6 @@
<!-- Whether or not to add a "people" notifications section -->
<bool name="config_usePeopleFiltering">false</bool>
- <!-- Package name for controls plugin -->
- <string name="config_controlsPluginPackageName" translatable="false">com.android.systemui.controls.panel</string>
-
<!-- Defines the blacklist for system icons. That is to say, the icons in the status bar that
are part of the blacklist are never displayed. Each item in the blacklist must be a string
defined in core/res/res/config.xml to properly blacklist the icon.
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c4fa4e5..7a3395c 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1090,7 +1090,7 @@
<!-- Blur radius on status bar window and power menu -->
<dimen name="min_window_blur_radius">1px</dimen>
- <dimen name="max_window_blur_radius">250px</dimen>
+ <dimen name="max_window_blur_radius">150px</dimen>
<!-- How much into a DisplayCutout's bounds we can go, on each side -->
<dimen name="display_cutout_margin_consumption">0px</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index f61f585..f48210c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -42,7 +42,6 @@
import android.util.TypedValue;
import android.view.View;
import android.view.animation.Animation;
-import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -251,9 +250,9 @@
SliceItem item = rc.getSliceItem();
final Uri itemTag = item.getSlice().getUri();
// Try to reuse the view if already exists in the layout
- KeyguardSliceButton button = mRow.findViewWithTag(itemTag);
+ KeyguardSliceTextView button = mRow.findViewWithTag(itemTag);
if (button == null) {
- button = new KeyguardSliceButton(mContext);
+ button = new KeyguardSliceTextView(mContext);
button.setTextColor(blendedColor);
button.setTag(itemTag);
final int viewIndex = i - (mHasHeader ? 1 : 0);
@@ -316,8 +315,8 @@
int childCount = mRow.getChildCount();
for (int i = 0; i < childCount; i++) {
View v = mRow.getChildAt(i);
- if (v instanceof Button) {
- ((Button) v).setTextColor(blendedColor);
+ if (v instanceof TextView) {
+ ((TextView) v).setTextColor(blendedColor);
}
}
}
@@ -500,8 +499,8 @@
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
- if (child instanceof KeyguardSliceButton) {
- ((KeyguardSliceButton) child).setMaxWidth(width / childCount);
+ if (child instanceof KeyguardSliceTextView) {
+ ((KeyguardSliceTextView) child).setMaxWidth(width / childCount);
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -527,13 +526,13 @@
* Representation of an item that appears under the clock on main keyguard message.
*/
@VisibleForTesting
- static class KeyguardSliceButton extends Button implements
+ static class KeyguardSliceTextView extends TextView implements
ConfigurationController.ConfigurationListener {
@StyleRes
private static int sStyleId = R.style.TextAppearance_Keyguard_Secondary;
- public KeyguardSliceButton(Context context) {
+ KeyguardSliceTextView(Context context) {
super(context, null /* attrs */, 0 /* styleAttr */, sStyleId);
onDensityOrFontScaleChanged();
setEllipsize(TruncateAt.END);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 792b940..05838ab 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -16,7 +16,6 @@
package com.android.systemui.bubbles;
-import static android.app.Notification.FLAG_AUTOGROUP_SUMMARY;
import static android.app.Notification.FLAG_BUBBLE;
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
@@ -69,18 +68,28 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.DumpController;
+import com.android.systemui.Dumpable;
import com.android.systemui.R;
+import com.android.systemui.bubbles.BubbleController.BubbleExpandListener;
+import com.android.systemui.bubbles.BubbleController.BubbleStateChangeListener;
+import com.android.systemui.bubbles.BubbleController.NotifCallback;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.PinnedStackListenerForwarder;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.WindowManagerWrapper;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -106,7 +115,7 @@
* The controller manages addition, removal, and visible state of bubbles on screen.
*/
@Singleton
-public class BubbleController implements ConfigurationController.ConfigurationListener {
+public class BubbleController implements ConfigurationController.ConfigurationListener, Dumpable {
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleController" : TAG_BUBBLES;
@@ -130,6 +139,7 @@
private final Context mContext;
private final NotificationEntryManager mNotificationEntryManager;
+ private final NotifPipeline mNotifPipeline;
private final BubbleTaskStackListener mTaskStackListener;
private BubbleStateChangeListener mStateChangeListener;
private BubbleExpandListener mExpandListener;
@@ -220,16 +230,17 @@
*/
public interface NotifCallback {
/**
- * Called when the BubbleController wants to remove an entry that it was previously hiding
- * from the shade. See {@link BubbleController#isBubbleNotificationSuppressedFromShade}.
+ * Called when a bubbled notification that was hidden from the shade is now being removed
+ * This can happen when an app cancels a bubbled notification or when the user dismisses a
+ * bubble.
*/
- void removeNotification(NotificationEntry entry);
+ void removeNotification(NotificationEntry entry, int reason);
/**
* Called when a bubbled notification has changed whether it should be
* filtered from the shade.
*/
- void invalidateNotificationFilter(String reason);
+ void invalidateNotifications(String reason);
/**
* Called on a bubbled entry that has been removed when there are no longer
@@ -277,10 +288,14 @@
ZenModeController zenModeController,
NotificationLockscreenUserManager notifUserManager,
NotificationGroupManager groupManager,
- NotificationEntryManager entryManager) {
+ NotificationEntryManager entryManager,
+ NotifPipeline notifPipeline,
+ FeatureFlags featureFlags,
+ DumpController dumpController) {
this(context, notificationShadeWindowController, statusBarStateController, shadeController,
data, null /* synchronizer */, configurationController, interruptionStateProvider,
- zenModeController, notifUserManager, groupManager, entryManager);
+ zenModeController, notifUserManager, groupManager, entryManager,
+ notifPipeline, featureFlags, dumpController);
}
public BubbleController(Context context,
@@ -294,7 +309,11 @@
ZenModeController zenModeController,
NotificationLockscreenUserManager notifUserManager,
NotificationGroupManager groupManager,
- NotificationEntryManager entryManager) {
+ NotificationEntryManager entryManager,
+ NotifPipeline notifPipeline,
+ FeatureFlags featureFlags,
+ DumpController dumpController) {
+ dumpController.registerDumpable(TAG, this);
mContext = context;
mShadeController = shadeController;
mNotificationInterruptionStateProvider = interruptionStateProvider;
@@ -337,7 +356,13 @@
mNotificationEntryManager = entryManager;
mNotificationGroupManager = groupManager;
- setupNEM();
+ mNotifPipeline = notifPipeline;
+
+ if (!featureFlags.isNewNotifPipelineRenderingEnabled()) {
+ setupNEM();
+ } else {
+ setupNotifPipeline();
+ }
mNotificationShadeWindowController = notificationShadeWindowController;
mStatusBarStateListener = new StatusBarStateListener();
@@ -396,6 +421,14 @@
}
@Override
+ public void onEntryRemoved(
+ NotificationEntry entry,
+ @android.annotation.Nullable NotificationVisibility visibility,
+ boolean removedByUser) {
+ BubbleController.this.onEntryRemoved(entry);
+ }
+
+ @Override
public void onNotificationRankingUpdated(RankingMap rankingMap) {
onRankingUpdated(rankingMap);
}
@@ -405,8 +438,29 @@
new NotificationRemoveInterceptor() {
@Override
public boolean onNotificationRemoveRequested(
- String key, NotificationEntry entry, int reason) {
- return shouldInterceptDismissal(entry, reason);
+ String key,
+ NotificationEntry entry,
+ int dismissReason) {
+ final boolean isClearAll = dismissReason == REASON_CANCEL_ALL;
+ final boolean isUserDimiss = dismissReason == REASON_CANCEL
+ || dismissReason == REASON_CLICK;
+ final boolean isAppCancel = dismissReason == REASON_APP_CANCEL
+ || dismissReason == REASON_APP_CANCEL_ALL;
+ final boolean isSummaryCancel =
+ dismissReason == REASON_GROUP_SUMMARY_CANCELED;
+
+ // Need to check for !appCancel here because the notification may have
+ // previously been dismissed & entry.isRowDismissed would still be true
+ boolean userRemovedNotif =
+ (entry != null && entry.isRowDismissed() && !isAppCancel)
+ || isClearAll || isUserDimiss || isSummaryCancel;
+
+ if (userRemovedNotif || isUserCreatedBubble(key)
+ || isSummaryOfUserCreatedBubble(entry)) {
+ return handleDismissalInterception(entry);
+ }
+
+ return false;
}
});
@@ -430,13 +484,13 @@
addNotifCallback(new NotifCallback() {
@Override
- public void removeNotification(NotificationEntry entry) {
+ public void removeNotification(NotificationEntry entry, int reason) {
mNotificationEntryManager.performRemoveNotification(entry.getSbn(),
- UNDEFINED_DISMISS_REASON);
+ reason);
}
@Override
- public void invalidateNotificationFilter(String reason) {
+ public void invalidateNotifications(String reason) {
mNotificationEntryManager.updateNotifications(reason);
}
@@ -444,18 +498,28 @@
public void maybeCancelSummary(NotificationEntry entry) {
// Check if removed bubble has an associated suppressed group summary that needs
// to be removed now.
- final String groupKey = entry.getSbn().getGroup();
+ final String groupKey = entry.getSbn().getGroupKey();
if (mBubbleData.isSummarySuppressed(groupKey)) {
- mBubbleData.removeSuppressedSummary(entry.getSbn().getGroupKey());
+ mBubbleData.removeSuppressedSummary(groupKey);
final NotificationEntry summary =
mNotificationEntryManager.getActiveNotificationUnfiltered(
mBubbleData.getSummaryKey(groupKey));
- mNotificationEntryManager.performRemoveNotification(summary.getSbn(),
- UNDEFINED_DISMISS_REASON);
+ if (summary != null) {
+ mNotificationEntryManager.performRemoveNotification(summary.getSbn(),
+ UNDEFINED_DISMISS_REASON);
+ }
}
- // Check if summary should be removed from NoManGroup
+ // Check if we still need to remove the summary from NoManGroup because the summary
+ // may not be in the mBubbleData.mSuppressedGroupKeys list and removed above.
+ // For example:
+ // 1. Bubbled notifications (group) is posted to shade and are visible bubbles
+ // 2. User expands bubbles so now their respective notifications in the shade are
+ // hidden, including the group summary
+ // 3. User removes all bubbles
+ // 4. We expect all the removed bubbles AND the summary (note: the summary was
+ // never added to the suppressedSummary list in BubbleData, so we add this check)
NotificationEntry summary =
mNotificationGroupManager.getLogicalGroupSummary(entry.getSbn());
if (summary != null) {
@@ -472,6 +536,31 @@
});
}
+ private void setupNotifPipeline() {
+ mNotifPipeline.addCollectionListener(new NotifCollectionListener() {
+ @Override
+ public void onEntryAdded(NotificationEntry entry) {
+ BubbleController.this.onEntryAdded(entry);
+ }
+
+ @Override
+ public void onEntryUpdated(NotificationEntry entry) {
+ BubbleController.this.onEntryUpdated(entry);
+ }
+
+ @Override
+ public void onRankingUpdate(RankingMap rankingMap) {
+ onRankingUpdated(rankingMap);
+ }
+
+ @Override
+ public void onEntryRemoved(NotificationEntry entry,
+ @NotifCollection.CancellationReason int reason) {
+ BubbleController.this.onEntryRemoved(entry);
+ }
+ });
+ }
+
/**
* Sets whether to perform inflation on the same thread as the caller. This method should only
* be used in tests, not in production.
@@ -752,7 +841,7 @@
Log.d(TAG, "onUserDemotedBubble: " + entry.getKey());
}
entry.setFlagBubble(false);
- removeBubble(entry.getKey(), DISMISS_BLOCKED);
+ removeBubble(entry, DISMISS_BLOCKED);
mUserCreatedBubbles.remove(entry.getKey());
if (BubbleExperimentConfig.isPackageWhitelistedToAutoBubble(
mContext, entry.getSbn().getPackageName())) {
@@ -769,17 +858,29 @@
return mUserCreatedBubbles.contains(key);
}
+ boolean isSummaryOfUserCreatedBubble(NotificationEntry entry) {
+ if (isSummaryOfBubbles(entry)) {
+ List<Bubble> bubbleChildren =
+ mBubbleData.getBubblesInGroup(entry.getSbn().getGroupKey());
+ for (int i = 0; i < bubbleChildren.size(); i++) {
+ // Check if any are user-created (i.e. experimental bubbles)
+ if (isUserCreatedBubble(bubbleChildren.get(i).getKey())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
/**
- * Removes the bubble associated with the {@param uri}.
+ * Removes the bubble with the given NotificationEntry.
* <p>
* Must be called from the main thread.
*/
@MainThread
- void removeBubble(String key, int reason) {
- // TEMP: refactor to change this to pass entry
- Bubble bubble = mBubbleData.getBubbleWithKey(key);
- if (bubble != null) {
- mBubbleData.notificationEntryRemoved(bubble.getEntry(), reason);
+ void removeBubble(NotificationEntry entry, int reason) {
+ if (mBubbleData.hasBubbleWithKey(entry.getKey())) {
+ mBubbleData.notificationEntryRemoved(entry, reason);
}
}
@@ -809,7 +910,7 @@
&& (canLaunchInActivityView(mContext, entry) || wasAdjusted);
if (!shouldBubble && mBubbleData.hasBubbleWithKey(entry.getKey())) {
// It was previously a bubble but no longer a bubble -- lets remove it
- removeBubble(entry.getKey(), DISMISS_NO_LONGER_BUBBLE);
+ removeBubble(entry, DISMISS_NO_LONGER_BUBBLE);
} else if (shouldBubble) {
if (wasAdjusted && !previouslyUserCreated) {
// Gotta treat the auto-bubbled / whitelisted packaged bubbles as usercreated
@@ -819,6 +920,21 @@
}
}
+ private void onEntryRemoved(NotificationEntry entry) {
+ if (isSummaryOfBubbles(entry)) {
+ final String groupKey = entry.getSbn().getGroupKey();
+ mBubbleData.removeSuppressedSummary(groupKey);
+
+ // Remove any associated bubble children with the summary
+ final List<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(groupKey);
+ for (int i = 0; i < bubbleChildren.size(); i++) {
+ removeBubble(bubbleChildren.get(i).getEntry(), DISMISS_GROUP_CANCELLED);
+ }
+ } else {
+ removeBubble(entry, DISMISS_NOTIF_CANCEL);
+ }
+ }
+
private void onRankingUpdated(RankingMap rankingMap) {
// Forward to BubbleData to block any bubbles which should no longer be shown
mBubbleData.notificationRankingUpdated(rankingMap);
@@ -846,7 +962,6 @@
final Bubble bubble = removed.first;
@DismissReason final int reason = removed.second;
mStackView.removeBubble(bubble);
-
// If the bubble is removed for user switching, leave the notification in place.
if (reason != DISMISS_USER_CHANGED) {
if (!mBubbleData.hasBubbleWithKey(bubble.getKey())
@@ -854,7 +969,7 @@
// The bubble is now gone & the notification is hidden from the shade, so
// time to actually remove it
for (NotifCallback cb : mCallbacks) {
- cb.removeNotification(bubble.getEntry());
+ cb.removeNotification(bubble.getEntry(), REASON_CANCEL);
}
} else {
// Update the flag for SysUI
@@ -908,7 +1023,7 @@
}
for (NotifCallback cb : mCallbacks) {
- cb.invalidateNotificationFilter("BubbleData.Listener.applyUpdate");
+ cb.invalidateNotifications("BubbleData.Listener.applyUpdate");
}
updateStack();
@@ -930,124 +1045,85 @@
};
/**
- * We intercept notification entries cancelled by the user (i.e. dismissed) when there is an
- * active bubble associated with it. We do this so that developers can still cancel it
- * (and hence the bubbles associated with it). However, these intercepted notifications
- * should then be hidden from the shade since the user has cancelled them, so we update
- * {@link Bubble#showInShade}.
- *
- * The cancellation of summaries with children associated with bubbles are also handled in this
- * method. User-cancelled summaries are tracked by {@link BubbleData#addSummaryToSuppress}.
+ * We intercept notification entries (including group summaries) dismissed by the user when
+ * there is an active bubble associated with it. We do this so that developers can still
+ * cancel it (and hence the bubbles associated with it). However, these intercepted
+ * notifications should then be hidden from the shade since the user has cancelled them, so we
+ * {@link Bubble#setSuppressNotification}. For the case of suppressed summaries, we also add
+ * {@link BubbleData#addSummaryToSuppress}.
*
* @return true if we want to intercept the dismissal of the entry, else false.
*/
- public boolean shouldInterceptDismissal(NotificationEntry entry, int dismissReason) {
+ public boolean handleDismissalInterception(NotificationEntry entry) {
if (entry == null) {
return false;
}
- String key = entry.getKey();
- String groupKey = entry != null ? entry.getSbn().getGroupKey() : null;
- ArrayList<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(groupKey);
- boolean inBubbleData = mBubbleData.hasBubbleWithKey(key);
- boolean isSuppressedSummary = (mBubbleData.isSummarySuppressed(groupKey)
- && mBubbleData.getSummaryKey(groupKey).equals(key));
- boolean isSummary = entry != null
- && entry.getSbn().getNotification().isGroupSummary();
- boolean isSummaryOfBubbles = (isSuppressedSummary || isSummary)
- && bubbleChildren != null && !bubbleChildren.isEmpty();
+ final boolean interceptBubbleDismissal = mBubbleData.hasBubbleWithKey(entry.getKey())
+ && entry.isBubble();
+ final boolean interceptSummaryDismissal = isSummaryOfBubbles(entry);
- if (!inBubbleData && !isSummaryOfBubbles) {
- return false;
- }
-
- final boolean isClearAll = dismissReason == REASON_CANCEL_ALL;
- final boolean isUserDimiss = dismissReason == REASON_CANCEL
- || dismissReason == REASON_CLICK;
- final boolean isAppCancel = dismissReason == REASON_APP_CANCEL
- || dismissReason == REASON_APP_CANCEL_ALL;
- final boolean isSummaryCancel = dismissReason == REASON_GROUP_SUMMARY_CANCELED;
-
- // Need to check for !appCancel here because the notification may have
- // previously been dismissed & entry.isRowDismissed would still be true
- boolean userRemovedNotif = (entry != null && entry.isRowDismissed() && !isAppCancel)
- || isClearAll || isUserDimiss || isSummaryCancel;
- if (isSummaryOfBubbles) {
- return handleSummaryRemovalInterception(entry, userRemovedNotif);
- }
-
- // The bubble notification sticks around in the data as long as the bubble is
- // not dismissed and the app hasn't cancelled the notification.
- Bubble bubble = mBubbleData.getBubbleWithKey(key);
- boolean bubbleExtended = entry != null && entry.isBubble()
- && (userRemovedNotif || isUserCreatedBubble(bubble.getKey()));
- if (bubbleExtended) {
+ if (interceptSummaryDismissal) {
+ handleSummaryDismissalInterception(entry);
+ } else if (interceptBubbleDismissal) {
+ Bubble bubble = mBubbleData.getBubbleWithKey(entry.getKey());
bubble.setSuppressNotification(true);
bubble.setShowDot(false /* show */, true /* animate */);
- for (NotifCallback cb : mCallbacks) {
- cb.invalidateNotificationFilter("BubbleController"
- + ".shouldInterceptDismissal");
- }
- return true;
- } else if (!userRemovedNotif && entry != null) {
- // This wasn't a user removal so we should remove the bubble as well
- mBubbleData.notificationEntryRemoved(entry, DISMISS_NOTIF_CANCEL);
+ } else {
return false;
}
- return false;
+
+ // Update the shade
+ for (NotifCallback cb : mCallbacks) {
+ cb.invalidateNotifications("BubbleController.handleDismissalInterception");
+ }
+ return true;
}
- private boolean handleSummaryRemovalInterception(NotificationEntry summary,
- boolean userRemovedNotif) {
- String groupKey = summary.getSbn().getGroupKey();
- ArrayList<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(groupKey);
-
- if (userRemovedNotif) {
- // If it's a user dismiss we mark the children to be hidden from the shade.
- for (int i = 0; i < bubbleChildren.size(); i++) {
- Bubble bubbleChild = bubbleChildren.get(i);
- // As far as group manager is concerned, once a child is no longer shown
- // in the shade, it is essentially removed.
- mNotificationGroupManager.onEntryRemoved(bubbleChild.getEntry());
- bubbleChild.setSuppressNotification(true);
- bubbleChild.setShowDot(false /* show */, true /* animate */);
- }
- // And since all children are removed, remove the summary.
- mNotificationGroupManager.onEntryRemoved(summary);
-
- // If the summary was auto-generated we don't need to keep that notification around
- // because apps can't cancel it; so we only intercept & suppress real summaries.
- boolean isAutogroupSummary = (summary.getSbn().getNotification().flags
- & FLAG_AUTOGROUP_SUMMARY) != 0;
- if (!isAutogroupSummary) {
- // TODO: (b/145659174) remove references to mSuppressedGroupKeys once fully migrated
- mBubbleData.addSummaryToSuppress(summary.getSbn().getGroupKey(),
- summary.getKey());
- // Tell shade to update for the suppression
- mNotificationEntryManager.updateNotifications("BubbleController"
- + ".handleSummaryRemovalInterception");
- }
- return !isAutogroupSummary;
- } else {
- // If it's not a user dismiss it's a cancel.
- for (int i = 0; i < bubbleChildren.size(); i++) {
- // First check if any of these are user-created (i.e. experimental bubbles)
- if (mUserCreatedBubbles.contains(bubbleChildren.get(i).getKey())) {
- // Experimental bubble! Intercept the removal.
- return true;
- }
- }
-
- // Not an experimental bubble, safe to remove.
- mBubbleData.removeSuppressedSummary(groupKey);
- // Remove any associated bubble children with the summary.
- for (int i = 0; i < bubbleChildren.size(); i++) {
- Bubble bubbleChild = bubbleChildren.get(i);
- mBubbleData.notificationEntryRemoved(bubbleChild.getEntry(),
- DISMISS_GROUP_CANCELLED);
- }
+ private boolean isSummaryOfBubbles(NotificationEntry entry) {
+ if (entry == null) {
return false;
}
+
+ String groupKey = entry.getSbn().getGroupKey();
+ ArrayList<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(groupKey);
+ boolean isSuppressedSummary = (mBubbleData.isSummarySuppressed(groupKey)
+ && mBubbleData.getSummaryKey(groupKey).equals(entry.getKey()));
+ boolean isSummary = entry.getSbn().getNotification().isGroupSummary();
+ return (isSuppressedSummary || isSummary)
+ && bubbleChildren != null
+ && !bubbleChildren.isEmpty();
+ }
+
+ private void handleSummaryDismissalInterception(NotificationEntry summary) {
+ // current children in the row:
+ final List<NotificationEntry> children = summary.getChildren();
+ if (children != null) {
+ for (int i = 0; i < children.size(); i++) {
+ NotificationEntry child = children.get(i);
+ if (mBubbleData.hasBubbleWithKey(child.getKey())) {
+ // Suppress the bubbled child
+ // As far as group manager is concerned, once a child is no longer shown
+ // in the shade, it is essentially removed.
+ Bubble bubbleChild = mBubbleData.getBubbleWithKey(child.getKey());
+ mNotificationGroupManager.onEntryRemoved(bubbleChild.getEntry());
+ bubbleChild.setSuppressNotification(true);
+ bubbleChild.setShowDot(false /* show */, true /* animate */);
+ } else {
+ // non-bubbled children can be removed
+ for (NotifCallback cb : mCallbacks) {
+ cb.removeNotification(child, REASON_GROUP_SUMMARY_CANCELED);
+ }
+ }
+ }
+ }
+
+ // And since all children are removed, remove the summary.
+ mNotificationGroupManager.onEntryRemoved(summary);
+
+ // TODO: (b/145659174) remove references to mSuppressedGroupKeys once fully migrated
+ mBubbleData.addSummaryToSuppress(summary.getSbn().getGroupKey(),
+ summary.getKey());
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 50a5063..0d5261d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -19,9 +19,9 @@
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.view.Display.INVALID_DISPLAY;
-
import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
import static android.view.ViewRootImpl.sNewInsetsMode;
+
import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_EXPANDED_VIEW;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
@@ -56,6 +56,7 @@
import com.android.systemui.recents.TriangleShape;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.AlphaOptimizedButton;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
/**
* Container for the expanded bubble view, handles rendering the caret and settings icon.
@@ -146,7 +147,7 @@
// the bubble again so we'll just remove it.
Log.w(TAG, "Exception while displaying bubble: " + getBubbleKey()
+ ", " + e.getMessage() + "; removing bubble");
- mBubbleController.removeBubble(getBubbleKey(),
+ mBubbleController.removeBubble(getBubbleEntry(),
BubbleController.DISMISS_INVALID_INTENT);
}
});
@@ -190,7 +191,7 @@
}
if (mBubble != null && !mBubbleController.isUserCreatedBubble(mBubble.getKey())) {
// Must post because this is called from a binder thread.
- post(() -> mBubbleController.removeBubble(mBubble.getKey(),
+ post(() -> mBubbleController.removeBubble(mBubble.getEntry(),
BubbleController.DISMISS_TASK_FINISHED));
}
}
@@ -279,6 +280,10 @@
return mBubble != null ? mBubble.getKey() : "null";
}
+ private NotificationEntry getBubbleEntry() {
+ return mBubble != null ? mBubble.getEntry() : null;
+ }
+
void applyThemeAttrs() {
final TypedArray ta = mContext.obtainStyledAttributes(
new int[] {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
index 34d3c24..645696d0 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
@@ -198,9 +198,14 @@
if (isStack) {
mController.dismissStack(BubbleController.DISMISS_USER_GESTURE);
} else {
- mController.removeBubble(
- individualBubbleKey,
- BubbleController.DISMISS_USER_GESTURE);
+ final Bubble bubble =
+ mBubbleData.getBubbleWithKey(individualBubbleKey);
+ // bubble can be null if the user is in the middle of
+ // dismissing the bubble, but the app also sent a cancel
+ if (bubble != null) {
+ mController.removeBubble(bubble.getEntry(),
+ BubbleController.DISMISS_USER_GESTURE);
+ }
}
});
} else if (isFlyout) {
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 88b19b5..78e0e8b 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -39,7 +39,7 @@
const val MIN_LEVEL = 0
const val MAX_LEVEL = 10000
-private const val UPDATE_DELAY_IN_MILLIS = 2000L
+private const val UPDATE_DELAY_IN_MILLIS = 3000L
class ControlViewHolder(
val layout: ViewGroup,
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index ed521e3..f029dfb 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -22,6 +22,7 @@
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
+import android.graphics.drawable.Drawable
import android.os.IBinder
import android.service.controls.Control
import android.service.controls.TokenProvider
@@ -29,19 +30,24 @@
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.Space
-import android.widget.TextView
+import com.android.settingslib.widget.CandidateInfo
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.controller.ControlInfo
+import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.management.ControlsProviderSelectorActivity
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.R
import com.android.systemui.util.concurrency.DelayableExecutor
import dagger.Lazy
+import java.text.Collator
+
import javax.inject.Inject
import javax.inject.Singleton
@@ -110,7 +116,9 @@
class ControlsUiControllerImpl @Inject constructor (
val controlsController: Lazy<ControlsController>,
val context: Context,
- @Main val uiExecutor: DelayableExecutor
+ @Main val uiExecutor: DelayableExecutor,
+ @Background val bgExecutor: DelayableExecutor,
+ val controlsListingController: Lazy<ControlsListingController>
) : ControlsUiController {
private lateinit var controlInfos: List<ControlInfo>
@@ -121,6 +129,22 @@
override val available: Boolean
get() = controlsController.get().available
+ private val listingCallback = object : ControlsListingController.ControlsListingCallback {
+ override fun onServicesUpdated(candidates: List<CandidateInfo>) {
+ bgExecutor.execute {
+ val collator = Collator.getInstance(context.getResources()
+ .getConfiguration().locale)
+ val localeComparator = compareBy<CandidateInfo, CharSequence>(collator) {
+ it.loadLabel()
+ }
+
+ val mList = candidates.toMutableList()
+ mList.sortWith(localeComparator)
+ loadInitialSetupViewIcons(mList.map { it.loadLabel() to it.loadIcon() })
+ }
+ }
+ }
+
override fun show(parent: ViewGroup) {
Log.d(TAG, "show()")
@@ -153,8 +177,26 @@
val inflater = LayoutInflater.from(context)
inflater.inflate(R.layout.controls_no_favorites, parent, true)
- val textView = parent.requireViewById(R.id.controls_title) as TextView
- textView.setOnClickListener(launchSelectorActivityListener(context))
+ val viewGroup = parent.requireViewById(R.id.controls_no_favorites_group) as ViewGroup
+ viewGroup.setOnClickListener(launchSelectorActivityListener(context))
+
+ controlsListingController.get().addCallback(listingCallback)
+ }
+
+ private fun loadInitialSetupViewIcons(icons: List<Pair<CharSequence, Drawable>>) {
+ uiExecutor.execute {
+ val viewGroup = parent.requireViewById(R.id.controls_icon_row) as ViewGroup
+ viewGroup.removeAllViews()
+
+ val inflater = LayoutInflater.from(context)
+ icons.forEach {
+ val imageView = inflater.inflate(R.layout.controls_icon, viewGroup, false)
+ as ImageView
+ imageView.setContentDescription(it.first)
+ imageView.setImageDrawable(it.second)
+ viewGroup.addView(imageView)
+ }
+ }
}
private fun launchSelectorActivityListener(context: Context): (View) -> Unit {
@@ -206,6 +248,7 @@
parent.removeAllViews()
controlsById.clear()
controlViewsById.clear()
+ controlsListingController.get().removeCallback(listingCallback)
}
override fun onRefreshState(componentName: ComponentName, controls: List<Control>) {
@@ -231,9 +274,9 @@
}
}
- private fun createRow(inflater: LayoutInflater, parent: ViewGroup): ViewGroup {
- val row = inflater.inflate(R.layout.controls_row, parent, false) as ViewGroup
- parent.addView(row)
+ private fun createRow(inflater: LayoutInflater, listView: ViewGroup): ViewGroup {
+ val row = inflater.inflate(R.layout.controls_row, listView, false) as ViewGroup
+ listView.addView(row)
return row
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index c9c38d3..146f36b 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -36,8 +36,6 @@
import com.android.systemui.Dependency;
import com.android.systemui.plugins.GlobalActions;
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
-import com.android.systemui.plugins.PluginListener;
-import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -49,8 +47,7 @@
import dagger.Lazy;
-public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks,
- PluginListener<GlobalActionsPanelPlugin> {
+public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks {
private static final float SHUTDOWN_SCRIM_ALPHA = 0.95f;
@@ -60,12 +57,9 @@
private final DeviceProvisionedController mDeviceProvisionedController;
private final ExtensionController.Extension<GlobalActionsPanelPlugin> mPanelExtension;
private final BlurUtils mBlurUtils;
- private GlobalActionsPanelPlugin mPlugin;
private final CommandQueue mCommandQueue;
private GlobalActionsDialog mGlobalActionsDialog;
private boolean mDisabled;
- private final PluginManager mPluginManager;
- private final String mPluginPackageName;
@Inject
public GlobalActionsImpl(Context context, CommandQueue commandQueue,
@@ -74,7 +68,6 @@
mGlobalActionsDialogLazy = globalActionsDialogLazy;
mKeyguardStateController = Dependency.get(KeyguardStateController.class);
mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
- mPluginManager = Dependency.get(PluginManager.class);
mCommandQueue = commandQueue;
mBlurUtils = blurUtils;
mCommandQueue.addCallback(this);
@@ -82,17 +75,11 @@
.newExtension(GlobalActionsPanelPlugin.class)
.withPlugin(GlobalActionsPanelPlugin.class)
.build();
- mPluginPackageName = mContext.getString(
- com.android.systemui.R.string.config_controlsPluginPackageName);
- mPluginManager.addPluginListener(
- GlobalActionsPanelPlugin.ACTION, this, GlobalActionsPanelPlugin.class, true);
}
@Override
public void destroy() {
mCommandQueue.removeCallback(this);
- mPluginManager.removePluginListener(this);
- if (mPlugin != null) mPlugin.onDestroy();
if (mGlobalActionsDialog != null) {
mGlobalActionsDialog.destroy();
mGlobalActionsDialog = null;
@@ -105,7 +92,7 @@
mGlobalActionsDialog = mGlobalActionsDialogLazy.get();
mGlobalActionsDialog.showDialog(mKeyguardStateController.isShowing(),
mDeviceProvisionedController.isDeviceProvisioned(),
- mPlugin != null ? mPlugin : mPanelExtension.get());
+ mPanelExtension.get());
Dependency.get(KeyguardUpdateMonitor.class).requestFaceAuth();
}
@@ -205,16 +192,4 @@
mGlobalActionsDialog.dismissDialog();
}
}
-
- @Override
- public void onPluginConnected(GlobalActionsPanelPlugin plugin, Context pluginContext) {
- if (pluginContext.getPackageName().equals(mPluginPackageName)) {
- mPlugin = plugin;
- }
- }
-
- @Override
- public void onPluginDisconnected(GlobalActionsPanelPlugin plugin) {
- mPlugin = null;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java
index 657a308..11e215d 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java
@@ -153,11 +153,11 @@
return true;
}
- private boolean checkExtensionCapability(String extName) {
+ boolean checkExtensionCapability(String extName) {
return mExts.contains(extName);
}
- private int getWcgCapability() {
+ int getWcgCapability() {
if (checkExtensionCapability(EXT_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH)) {
return EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
}
@@ -212,7 +212,7 @@
if (wcg && checkExtensionCapability(KHR_GL_COLOR_SPACE) && wcgCapability > 0) {
attrs = new int[] {EGL_GL_COLORSPACE_KHR, wcgCapability, EGL_NONE};
}
- mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceHolder, attrs, 0);
+ mEglSurface = askCreatingEglWindowSurface(surfaceHolder, attrs, 0 /* offset */);
} else {
Log.w(TAG, "Create EglSurface failed: hasEglDisplay=" + hasEglDisplay()
+ ", has valid surface=" + surfaceHolder.getSurface().isValid());
@@ -235,6 +235,10 @@
return true;
}
+ EGLSurface askCreatingEglWindowSurface(SurfaceHolder holder, int[] attrs, int offset) {
+ return eglCreateWindowSurface(mEglDisplay, mEglConfig, holder, attrs, offset);
+ }
+
/**
* Destroy EglSurface.
*/
@@ -242,7 +246,7 @@
if (hasEglSurface()) {
eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroySurface(mEglDisplay, mEglSurface);
- mEglSurface = null;
+ mEglSurface = EGL_NO_SURFACE;
}
}
@@ -296,7 +300,7 @@
public void destroyEglContext() {
if (hasEglContext()) {
eglDestroyContext(mEglDisplay, mEglContext);
- mEglContext = null;
+ mEglContext = EGL_NO_CONTEXT;
}
}
@@ -340,11 +344,16 @@
destroyEglContext();
}
if (hasEglDisplay()) {
- eglTerminate(mEglDisplay);
+ terminateEglDisplay();
}
mEglReady = false;
}
+ void terminateEglDisplay() {
+ eglTerminate(mEglDisplay);
+ mEglDisplay = EGL_NO_DISPLAY;
+ }
+
/**
* Called to dump current state.
* @param prefix prefix.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 14eec59..9da99c4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -151,7 +151,7 @@
private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000;
private static final long KEYGUARD_DONE_PENDING_TIMEOUT_MS = 3000;
- private static final boolean DEBUG = KeyguardConstants.DEBUG;
+ private static final boolean DEBUG = true;
private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES;
private final static String TAG = "KeyguardViewMediator";
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
index 6498b91..ae380b7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
@@ -93,6 +93,7 @@
return mIatm.startActivityAsUser(
mContext.getIApplicationThread() /*caller*/,
mContext.getBasePackageName() /*callingPackage*/,
+ mContext.getFeatureId() /*callingFeatureId*/,
intent /*intent*/,
intent.resolveTypeIfNeeded(mContext.getContentResolver()) /*resolvedType*/,
null /*resultTo*/,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 411980b..ae61622 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -83,7 +83,7 @@
mTile = new Tile();
updateDefaultTileAndIcon();
mServiceManager = host.getTileServices().getTileWrapper(this);
- if (mServiceManager.isBooleanTile()) {
+ if (mServiceManager.isToggleableTile()) {
// Replace states with BooleanState
resetStates();
}
@@ -252,7 +252,7 @@
@Override
public State newTileState() {
- if (mServiceManager != null && mServiceManager.isBooleanTile()) {
+ if (mServiceManager != null && mServiceManager.isToggleableTile()) {
return new BooleanState();
}
return new State();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index ad79cad..17b0251 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -141,16 +141,16 @@
/**
* Determines whether the associated TileService is a Boolean Tile.
*
- * @return true if {@link TileService#META_DATA_BOOLEAN_TILE} is set to {@code true} for this
+ * @return true if {@link TileService#META_DATA_TOGGLEABLE_TILE} is set to {@code true} for this
* tile
- * @see TileService#META_DATA_BOOLEAN_TILE
+ * @see TileService#META_DATA_TOGGLEABLE_TILE
*/
- public boolean isBooleanTile() {
+ public boolean isToggleableTile() {
try {
ServiceInfo info = mPackageManagerAdapter.getServiceInfo(mIntent.getComponent(),
PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_META_DATA);
return info.metaData != null
- && info.metaData.getBoolean(TileService.META_DATA_BOOLEAN_TILE, false);
+ && info.metaData.getBoolean(TileService.META_DATA_TOGGLEABLE_TILE, false);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
index 1902d65..cfa8fb6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -124,8 +124,8 @@
return mStateManager.isActiveTile();
}
- public boolean isBooleanTile() {
- return mStateManager.isBooleanTile();
+ public boolean isToggleableTile() {
+ return mStateManager.isToggleableTile();
}
public void setShowingDialog(boolean dialog) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 001e094..42f8010 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -21,6 +21,7 @@
import android.content.Intent;
import android.os.UserManager;
import android.service.quicksettings.Tile;
+import android.util.Log;
import android.widget.Switch;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -200,6 +201,14 @@
mCallbackInfo.numConnectedDevices = numDevices;
refreshState(mCallbackInfo);
}
+
+ @Override
+ public void onHotspotAvailabilityChanged(boolean available) {
+ if (!available) {
+ Log.d(TAG, "Tile removed. Hotspot no longer available");
+ mHost.removeTile(getTileSpec());
+ }
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
index 7fe229c..3fa1954 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
@@ -123,6 +123,16 @@
.append(" ");
}
+ if (!notifEntry.mDismissInterceptors.isEmpty()) {
+ String[] interceptorsNames = new String[notifEntry.mDismissInterceptors.size()];
+ for (int i = 0; i < interceptorsNames.length; i++) {
+ interceptorsNames[i] = notifEntry.mDismissInterceptors.get(i).getName();
+ }
+ rksb.append("dismissInterceptors=")
+ .append(Arrays.toString(interceptorsNames))
+ .append(" ");
+ }
+
if (notifEntry.mExcludingFilter != null) {
rksb.append("filter=")
.append(notifEntry.mExcludingFilter)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index 3b2fe94..38d8d97 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -63,6 +63,7 @@
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionLogger;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.util.Assert;
@@ -116,6 +117,7 @@
@Nullable private CollectionReadyForBuildListener mBuildListener;
private final List<NotifCollectionListener> mNotifCollectionListeners = new ArrayList<>();
private final List<NotifLifetimeExtender> mLifetimeExtenders = new ArrayList<>();
+ private final List<NotifDismissInterceptor> mDismissInterceptors = new ArrayList<>();
private boolean mAttached = false;
private boolean mAmDispatchingToOtherCode;
@@ -176,10 +178,21 @@
extender.setCallback(this::onEndLifetimeExtension);
}
+ /** @see NotifPipeline#addNotificationDismissInterceptor(NotifDismissInterceptor) */
+ void addNotificationDismissInterceptor(NotifDismissInterceptor interceptor) {
+ Assert.isMainThread();
+ checkForReentrantCall();
+ if (mDismissInterceptors.contains(interceptor)) {
+ throw new IllegalArgumentException("Interceptor " + interceptor + " already added.");
+ }
+ mDismissInterceptors.add(interceptor);
+ interceptor.setCallback(this::onEndDismissInterception);
+ }
+
/**
* Dismiss a notification on behalf of the user.
*/
- void dismissNotification(NotificationEntry entry, @NonNull DismissedByUserStats stats) {
+ public void dismissNotification(NotificationEntry entry, @NonNull DismissedByUserStats stats) {
Assert.isMainThread();
requireNonNull(stats);
checkForReentrantCall();
@@ -192,6 +205,12 @@
return;
}
+ updateDismissInterceptors(entry);
+ if (isDismissIntercepted(entry)) {
+ mLogger.logNotifDismissedIntercepted(entry.getKey());
+ return;
+ }
+
// Optimistically mark the notification as dismissed -- we'll wait for the signal from
// system server before removing it from our notification set.
entry.setDismissState(DISMISSED);
@@ -236,7 +255,6 @@
for (NotificationEntry canceledEntry : canceledEntries) {
tryRemoveNotification(canceledEntry);
}
-
rebuildList();
}
@@ -307,11 +325,11 @@
// Update to an existing entry
mLogger.logNotifUpdated(sbn.getKey());
+ // Notification is updated so it is essentially re-added and thus alive again, so we
+ // can reset its state.
cancelLocalDismissal(entry);
-
- // Notification is updated so it is essentially re-added and thus alive again. Don't
- // need to keep its lifetime extended.
cancelLifetimeExtension(entry);
+ cancelDismissInterception(entry);
entry.mCancellationReason = REASON_NOT_CANCELED;
entry.setSbn(sbn);
@@ -348,6 +366,7 @@
if (!isLifetimeExtended(entry)) {
mNotificationSet.remove(entry.getKey());
+ cancelDismissInterception(entry);
dispatchOnEntryRemoved(entry, entry.mCancellationReason);
dispatchOnEntryCleanUp(entry);
return true;
@@ -436,6 +455,17 @@
mAmDispatchingToOtherCode = false;
}
+ private void updateDismissInterceptors(@NonNull NotificationEntry entry) {
+ entry.mDismissInterceptors.clear();
+ mAmDispatchingToOtherCode = true;
+ for (NotifDismissInterceptor interceptor : mDismissInterceptors) {
+ if (interceptor.shouldInterceptDismissal(entry)) {
+ entry.mDismissInterceptors.add(interceptor);
+ }
+ }
+ mAmDispatchingToOtherCode = false;
+ }
+
private void cancelLocalDismissal(NotificationEntry entry) {
if (isDismissedByUser(entry)) {
entry.setDismissState(NOT_DISMISSED);
@@ -450,6 +480,42 @@
}
}
+ private void onEndDismissInterception(
+ NotifDismissInterceptor interceptor,
+ NotificationEntry entry,
+ @NonNull DismissedByUserStats stats) {
+ Assert.isMainThread();
+ if (!mAttached) {
+ return;
+ }
+ checkForReentrantCall();
+
+ if (!entry.mDismissInterceptors.remove(interceptor)) {
+ throw new IllegalStateException(
+ String.format(
+ "Cannot end dismiss interceptor for interceptor \"%s\" (%s)",
+ interceptor.getName(),
+ interceptor));
+ }
+
+ if (!isDismissIntercepted(entry)) {
+ dismissNotification(entry, stats);
+ }
+ }
+
+ private void cancelDismissInterception(NotificationEntry entry) {
+ mAmDispatchingToOtherCode = true;
+ for (NotifDismissInterceptor interceptor : entry.mDismissInterceptors) {
+ interceptor.cancelDismissInterception(entry);
+ }
+ mAmDispatchingToOtherCode = false;
+ entry.mDismissInterceptors.clear();
+ }
+
+ private boolean isDismissIntercepted(NotificationEntry entry) {
+ return entry.mDismissInterceptors.size() > 0;
+ }
+
private void checkForReentrantCall() {
if (mAmDispatchingToOtherCode) {
throw new IllegalStateException("Reentrant call detected");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
index 5767ad9..d4d2369 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
@@ -25,6 +25,7 @@
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import java.util.Collection;
@@ -97,13 +98,21 @@
/**
* Registers a lifetime extender. Lifetime extenders can cause notifications that have been
- * dismissed or retracted to be temporarily retained in the collection.
+ * dismissed or retracted by system server to be temporarily retained in the collection.
*/
public void addNotificationLifetimeExtender(NotifLifetimeExtender extender) {
mNotifCollection.addNotificationLifetimeExtender(extender);
}
/**
+ * Registers a dismiss interceptor. Dismiss interceptors can cause notifications that have been
+ * dismissed by the user to be retained (won't send a dismissal to system server).
+ */
+ public void addNotificationDismissInterceptor(NotifDismissInterceptor interceptor) {
+ mNotifCollection.addNotificationDismissInterceptor(interceptor);
+ }
+
+ /**
* Registers a filter with the pipeline before grouping, promoting and sorting occurs. Filters
* are called on each notification in the order that they were registered. If any filter
* returns true, the notification is removed from the pipeline (and no other filters are
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 5dbf47e..41c1b7b 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
@@ -66,6 +66,7 @@
import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGuts;
@@ -104,6 +105,9 @@
/** List of lifetime extenders that are extending the lifetime of this notification. */
final List<NotifLifetimeExtender> mLifetimeExtenders = new ArrayList<>();
+ /** List of dismiss interceptors that are intercepting the dismissal of this notification. */
+ final List<NotifDismissInterceptor> mDismissInterceptors = new ArrayList<>();
+
/** If this notification was filtered out, then the filter that did the filtering. */
@Nullable NotifFilter mExcludingFilter;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
new file mode 100644
index 0000000..116c70c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator;
+
+import static android.service.notification.NotificationStats.DISMISSAL_OTHER;
+import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_UNKNOWN;
+
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Coordinates hiding, intercepting (the dismissal), and deletion of bubbled notifications.
+ *
+ * The typical "start state" for a bubbled notification is when a bubble-able notification is
+ * posted. It is visible as a bubble AND as a notification in the shade. From here, we can get
+ * into a few hidden-from-shade states described below:
+ *
+ * Start State -> Hidden from shade
+ * User expands the bubble so we hide its notification from the shade.
+ * OR
+ * User dismisses a group summary with a bubbled child. All bubbled children are now hidden from
+ * the shade. And the group summary's dismissal is intercepted + hidden from the shade (see below).
+ *
+ * Start State -> Dismissal intercepted + hidden from shade
+ * User dismisses the notification from the shade. We now hide the notification from the shade
+ * and intercept its dismissal (the removal signal is never sent to system server). We
+ * keep the notification alive in system server so that {@link BubbleController} can still
+ * respond to app-cancellations (ie: remove the bubble if the app cancels the notification).
+ *
+ */
+@Singleton
+public class BubbleCoordinator implements Coordinator {
+ private static final String TAG = "BubbleCoordinator";
+
+ private final BubbleController mBubbleController;
+ private final NotifCollection mNotifCollection;
+ private final Set<String> mInterceptedDismissalEntries = new HashSet<>();
+ private NotifPipeline mNotifPipeline;
+ private NotifDismissInterceptor.OnEndDismissInterception mOnEndDismissInterception;
+
+ @Inject
+ public BubbleCoordinator(
+ BubbleController bubbleController,
+ NotifCollection notifCollection) {
+ mBubbleController = bubbleController;
+ mNotifCollection = notifCollection;
+ }
+
+ @Override
+ public void attach(NotifPipeline pipeline) {
+ mNotifPipeline = pipeline;
+ mNotifPipeline.addNotificationDismissInterceptor(mDismissInterceptor);
+ mNotifPipeline.addPreRenderFilter(mNotifFilter);
+ mBubbleController.addNotifCallback(mNotifCallback);
+ }
+
+ private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
+ @Override
+ public boolean shouldFilterOut(NotificationEntry entry, long now) {
+ return mBubbleController.isBubbleNotificationSuppressedFromShade(entry);
+ }
+ };
+
+ private final NotifDismissInterceptor mDismissInterceptor = new NotifDismissInterceptor() {
+ @Override
+ public String getName() {
+ return TAG;
+ }
+
+ @Override
+ public void setCallback(OnEndDismissInterception callback) {
+ mOnEndDismissInterception = callback;
+ }
+
+ @Override
+ public boolean shouldInterceptDismissal(NotificationEntry entry) {
+ // TODO: b/149041810 add support for intercepting app-cancelled bubble notifications
+ // for experimental bubbles
+ if (mBubbleController.handleDismissalInterception(entry)) {
+ mInterceptedDismissalEntries.add(entry.getKey());
+ return true;
+ } else {
+ mInterceptedDismissalEntries.remove(entry.getKey());
+ return false;
+ }
+ }
+
+ @Override
+ public void cancelDismissInterception(NotificationEntry entry) {
+ mInterceptedDismissalEntries.remove(entry.getKey());
+ }
+ };
+
+ private final BubbleController.NotifCallback mNotifCallback =
+ new BubbleController.NotifCallback() {
+ @Override
+ public void removeNotification(NotificationEntry entry, int reason) {
+ if (isInterceptingDismissal(entry)) {
+ mInterceptedDismissalEntries.remove(entry.getKey());
+ mOnEndDismissInterception.onEndDismissInterception(mDismissInterceptor, entry,
+ createDismissedByUserStats(entry));
+ } else if (mNotifPipeline.getActiveNotifs().contains(entry)) {
+ // Bubbles are hiding the notifications from the shade, but the bubble was
+ // deleted; therefore, the notification should be cancelled as if it were a user
+ // dismissal (this won't re-enter handleInterceptDimissal because Bubbles
+ // will have already marked it as no longer a bubble)
+ mNotifCollection.dismissNotification(entry, createDismissedByUserStats(entry));
+ }
+ }
+
+ @Override
+ public void invalidateNotifications(String reason) {
+ mNotifFilter.invalidateList();
+ }
+
+ @Override
+ public void maybeCancelSummary(NotificationEntry entry) {
+ // no-op
+ }
+ };
+
+ private boolean isInterceptingDismissal(NotificationEntry entry) {
+ return mInterceptedDismissalEntries.contains(entry.getKey());
+ }
+
+ private DismissedByUserStats createDismissedByUserStats(NotificationEntry entry) {
+ return new DismissedByUserStats(
+ DISMISSAL_OTHER,
+ DISMISS_SENTIMENT_UNKNOWN,
+ NotificationVisibility.obtain(entry.getKey(),
+ entry.getRanking().getRank(),
+ mNotifPipeline.getActiveNotifs().size(),
+ true, // was visible as a bubble
+ NotificationLogger.getNotificationLocation(entry))
+ );
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
index 0a1e09f..7a9547c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
@@ -53,6 +53,7 @@
RankingCoordinator rankingCoordinator,
ForegroundCoordinator foregroundCoordinator,
DeviceProvisionedCoordinator deviceProvisionedCoordinator,
+ BubbleCoordinator bubbleCoordinator,
PreparationCoordinator preparationCoordinator) {
dumpController.registerDumpable(TAG, this);
@@ -61,6 +62,7 @@
mCoordinators.add(rankingCoordinator);
mCoordinators.add(foregroundCoordinator);
mCoordinators.add(deviceProvisionedCoordinator);
+ mCoordinators.add(bubbleCoordinator);
if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
mCoordinators.add(preparationCoordinator);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
index 14e1503..dc7a50d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
@@ -69,6 +69,14 @@
})
}
+ fun logNotifDismissedIntercepted(key: String) {
+ buffer.log(TAG, INFO, {
+ str1 = key
+ }, {
+ "DISMISS INTERCEPTED $str1"
+ })
+ }
+
fun logRankingMissing(key: String, rankingMap: RankingMap) {
buffer.log(TAG, WARNING, { str1 = key }, { "Ranking update is missing ranking for $str1" })
buffer.log(TAG, DEBUG, {}, { "Ranking map contents:" })
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifDismissInterceptor.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifDismissInterceptor.java
new file mode 100644
index 0000000..3354ad1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifDismissInterceptor.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.notifcollection;
+
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+/**
+ * A way for coordinators to temporarily intercept a user-dismissed notification before a message
+ * is sent to system server to officially remove this notification.
+ * See {@link NotifCollection#addNotificationDismissInterceptor(NotifDismissInterceptor)}.
+ */
+public interface NotifDismissInterceptor {
+ /** Name to associate with this interceptor (for the purposes of debugging) */
+ String getName();
+
+ /**
+ * Called on the interceptor immediately after it has been registered. The interceptor should
+ * hang on to this callback and execute it whenever it no longer needs to intercept the
+ * dismissal of the notification.
+ */
+ void setCallback(OnEndDismissInterception callback);
+
+ /**
+ * Called by the NotifCollection whenever a notification has been dismissed (by the user).
+ * If the interceptor returns true, it is considered to be intercepting the notification.
+ * Intercepted notifications will not be sent to system server for removal until it is no
+ * longer being intercepted. However, the notification can still be cancelled by the app.
+ * This method is called on all interceptors even if earlier ones return true.
+ */
+ boolean shouldInterceptDismissal(NotificationEntry entry);
+
+
+ /**
+ * Called by the NotifCollection to inform a DismissInterceptor that its interception of a notif
+ * is no longer valid (usually because the notif has been removed by means other than the
+ * user dismissing the notification from the shade, or the notification has been updated). The
+ * interceptor should clean up any references it has to the notif in question.
+ */
+ void cancelDismissInterception(NotificationEntry entry);
+
+ /**
+ * Callback for notifying the NotifCollection that it no longer is intercepting the dismissal.
+ * If the end of this dismiss interception triggers a dismiss (ie: no other
+ * NotifDismissInterceptors are intercepting the entry), NotifCollection will use stats
+ * in the message sent to system server for the notification's dismissal.
+ */
+ interface OnEndDismissInterception {
+ void onEndDismissInterception(
+ NotifDismissInterceptor interceptor,
+ NotificationEntry entry,
+ DismissedByUserStats stats);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index d3e44ea..72dfa18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -492,7 +492,7 @@
try {
result = ActivityTaskManager.getService().startActivityAsUser(
null, getContext().getBasePackageName(),
- intent,
+ getContext().getFeatureId(), intent,
intent.resolveTypeIfNeeded(getContext().getContentResolver()),
null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, o.toBundle(),
UserHandle.CURRENT.getIdentifier());
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 11f7079..4f01cc1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -2466,10 +2466,6 @@
pw.println(" mHeadsUpManager: null");
}
- if (mBubbleController != null) {
- mBubbleController.dump(fd, pw, args);
- }
-
if (mLightBarController != null) {
mLightBarController.dump(fd, pw, args);
}
@@ -2571,7 +2567,7 @@
}
try {
result = ActivityTaskManager.getService().startActivityAsUser(
- null, mContext.getBasePackageName(),
+ null, mContext.getBasePackageName(), mContext.getFeatureId(),
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
index 830b50e..8231f8b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
@@ -30,5 +30,6 @@
interface Callback {
void onHotspotChanged(boolean enabled, int numDevices);
+ default void onHotspotAvailabilityChanged(boolean available) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index df9c3f4..d090404 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -19,6 +19,7 @@
import android.app.ActivityManager;
import android.content.Context;
import android.net.ConnectivityManager;
+import android.net.TetheringManager;
import android.net.wifi.WifiClient;
import android.net.wifi.WifiManager;
import android.os.Handler;
@@ -26,6 +27,8 @@
import android.os.UserManager;
import android.util.Log;
+import com.android.internal.util.ConcurrentUtils;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import java.io.FileDescriptor;
@@ -46,36 +49,63 @@
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final ArrayList<Callback> mCallbacks = new ArrayList<>();
- private final ConnectivityManager mConnectivityManager;
+ private final TetheringManager mTetheringManager;
private final WifiManager mWifiManager;
private final Handler mMainHandler;
private final Context mContext;
private int mHotspotState;
private volatile int mNumConnectedDevices;
+ private volatile boolean mIsTetheringSupported;
+ private volatile boolean mHasTetherableWifiRegexs;
private boolean mWaitingForTerminalState;
+ private TetheringManager.TetheringEventCallback mTetheringCallback =
+ new TetheringManager.TetheringEventCallback() {
+ @Override
+ public void onTetheringSupported(boolean supported) {
+ super.onTetheringSupported(supported);
+ if (mIsTetheringSupported != supported) {
+ mIsTetheringSupported = supported;
+ fireHotspotAvailabilityChanged();
+ }
+ }
+
+ @Override
+ public void onTetherableInterfaceRegexpsChanged(
+ TetheringManager.TetheringInterfaceRegexps reg) {
+ super.onTetherableInterfaceRegexpsChanged(reg);
+ final boolean newValue = reg.getTetherableWifiRegexs().size() != 0;
+ if (mHasTetherableWifiRegexs != newValue) {
+ mHasTetherableWifiRegexs = newValue;
+ fireHotspotAvailabilityChanged();
+ }
+ }
+ };
+
/**
* Controller used to retrieve information related to a hotspot.
*/
@Inject
- public HotspotControllerImpl(Context context, @Main Handler mainHandler) {
+ public HotspotControllerImpl(Context context, @Main Handler mainHandler,
+ @Background Handler backgroundHandler) {
mContext = context;
- mConnectivityManager =
- (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ mTetheringManager = context.getSystemService(TetheringManager.class);
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
mMainHandler = mainHandler;
+ mTetheringManager.registerTetheringEventCallback(
+ new HandlerExecutor(backgroundHandler), mTetheringCallback);
}
@Override
public boolean isHotspotSupported() {
- return mConnectivityManager.isTetheringSupported()
- && mConnectivityManager.getTetherableWifiRegexs().length != 0
+ return mIsTetheringSupported && mHasTetherableWifiRegexs
&& UserManager.get(mContext).isUserAdmin(ActivityManager.getCurrentUser());
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("HotspotController state:");
+ pw.print(" available="); pw.println(isHotspotSupported());
pw.print(" mHotspotState="); pw.println(stateToString(mHotspotState));
pw.print(" mNumConnectedDevices="); pw.println(mNumConnectedDevices);
pw.print(" mWaitingForTerminalState="); pw.println(mWaitingForTerminalState);
@@ -152,17 +182,18 @@
if (enabled) {
mWaitingForTerminalState = true;
if (DEBUG) Log.d(TAG, "Starting tethering");
- mConnectivityManager.startTethering(ConnectivityManager.TETHERING_WIFI, false,
- new ConnectivityManager.OnStartTetheringCallback() {
+ mTetheringManager.startTethering(ConnectivityManager.TETHERING_WIFI,
+ ConcurrentUtils.DIRECT_EXECUTOR,
+ new TetheringManager.StartTetheringCallback() {
@Override
- public void onTetheringFailed() {
+ public void onTetheringFailed(final int result) {
if (DEBUG) Log.d(TAG, "onTetheringFailed");
maybeResetSoftApState();
fireHotspotChangedCallback();
}
});
} else {
- mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
+ mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
}
}
@@ -177,10 +208,25 @@
* (as it can be blocked).
*/
private void fireHotspotChangedCallback() {
+ List<Callback> list;
synchronized (mCallbacks) {
- for (Callback callback : mCallbacks) {
- callback.onHotspotChanged(isHotspotEnabled(), mNumConnectedDevices);
- }
+ list = new ArrayList<>(mCallbacks);
+ }
+ for (Callback callback : list) {
+ callback.onHotspotChanged(isHotspotEnabled(), mNumConnectedDevices);
+ }
+ }
+
+ /**
+ * Sends a hotspot available changed callback.
+ */
+ private void fireHotspotAvailabilityChanged() {
+ List<Callback> list;
+ synchronized (mCallbacks) {
+ list = new ArrayList<>(mCallbacks);
+ }
+ for (Callback callback : list) {
+ callback.onHotspotAvailabilityChanged(isHotspotSupported());
}
}
@@ -206,7 +252,7 @@
switch (mHotspotState) {
case WifiManager.WIFI_AP_STATE_FAILED:
// TODO(b/110697252): must be called to reset soft ap state after failure
- mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
+ mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
// Fall through
case WifiManager.WIFI_AP_STATE_ENABLED:
case WifiManager.WIFI_AP_STATE_DISABLED:
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 cfd77be..f4157f2 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
@@ -901,6 +901,23 @@
verboseLogging = debug
}
+ /**
+ * Estimates the end value of a fling that starts at the given value using the provided
+ * start velocity and fling configuration.
+ *
+ * This is only an estimate. Fling animations use a timing-based physics simulation that is
+ * non-deterministic, so this exact value may not be reached.
+ */
+ @JvmStatic
+ fun estimateFlingEndValue(
+ startValue: Float,
+ startVelocity: Float,
+ flingConfig: FlingConfig
+ ): Float {
+ val distance = startVelocity / (flingConfig.friction * FLING_FRICTION_SCALAR_MULTIPLIER)
+ return Math.min(flingConfig.max, Math.max(flingConfig.min, startValue + distance))
+ }
+
@JvmStatic
fun getReadablePropertyName(property: FloatPropertyCompat<*>): String {
return when (property) {
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 280d14e..c3b55e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -20,8 +20,7 @@
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
-
-import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;
+import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
import static com.google.common.truth.Truth.assertThat;
@@ -34,6 +33,7 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -55,10 +55,12 @@
import androidx.test.filters.SmallTest;
import com.android.internal.colorextraction.ColorExtractor;
+import com.android.systemui.DumpController;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
@@ -68,6 +70,7 @@
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -92,6 +95,13 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.List;
+
+/**
+ * Tests the NotificationEntryManager setup with BubbleController.
+ * The {@link NotifPipeline} setup with BubbleController is tested in
+ * {@link NewNotifPipelineBubbleControllerTest}.
+ */
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -152,6 +162,12 @@
private ShadeController mShadeController;
@Mock
private NotificationRowComponent mNotificationRowComponent;
+ @Mock
+ private NotifPipeline mNotifPipeline;
+ @Mock
+ private FeatureFlags mFeatureFlagsOldPipeline;
+ @Mock
+ private DumpController mDumpController;
private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
private BubbleData mBubbleData;
@@ -213,6 +229,7 @@
mock(HeadsUpManager.class),
mock(NotificationInterruptionStateProvider.HeadsUpSuppressor.class));
mBubbleData = new BubbleData(mContext);
+ when(mFeatureFlagsOldPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
mBubbleController = new TestableBubbleController(mContext,
mNotificationShadeWindowController,
mStatusBarStateController,
@@ -223,7 +240,10 @@
mZenModeController,
mLockscreenUserManager,
mNotificationGroupManager,
- mNotificationEntryManager);
+ mNotificationEntryManager,
+ mNotifPipeline,
+ mFeatureFlagsOldPipeline,
+ mDumpController);
mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
mBubbleController.setExpandListener(mBubbleExpandListener);
@@ -261,7 +281,7 @@
verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
mBubbleController.removeBubble(
- mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
assertFalse(mNotificationShadeWindowController.getBubblesShowing());
assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
verify(mNotificationEntryManager, times(2)).updateNotifications(anyString());
@@ -282,12 +302,12 @@
// Now remove the bubble
mBubbleController.removeBubble(
- mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
// Since the notif is dismissed, once the bubble is removed, performRemoveNotification gets
// called to really remove the notif
verify(mNotificationEntryManager, times(1)).performRemoveNotification(
- mRow.getEntry().getSbn(), UNDEFINED_DISMISS_REASON);
+ eq(mRow.getEntry().getSbn()), anyInt());
assertFalse(mBubbleController.hasBubbles());
}
@@ -467,7 +487,7 @@
mRow2.getEntry()));
// Dismiss currently expanded
- mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey(),
+ mBubbleController.removeBubble(stackView.getExpandedBubble().getEntry(),
BubbleController.DISMISS_USER_GESTURE);
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
@@ -476,7 +496,7 @@
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
// Dismiss that one
- mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey(),
+ mBubbleController.removeBubble(stackView.getExpandedBubble().getEntry(),
BubbleController.DISMISS_USER_GESTURE);
// Make sure state changes and collapse happens
@@ -604,7 +624,7 @@
@Test
public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException {
mBubbleController.updateBubble(mRow.getEntry());
- mBubbleController.removeBubble(mRow.getEntry().getKey(), BubbleController.DISMISS_AGED);
+ mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_AGED);
verify(mDeleteIntent, never()).send();
}
@@ -612,7 +632,7 @@
public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException {
mBubbleController.updateBubble(mRow.getEntry());
mBubbleController.removeBubble(
- mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
verify(mDeleteIntent, times(1)).send();
}
@@ -649,11 +669,22 @@
// Cancels always remove so no need to intercept
assertFalse(intercepted);
+ }
+
+ @Test
+ public void testRemoveBubble_entryListenerRemove() {
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
+ mBubbleController.updateBubble(mRow.getEntry());
+
+ assertTrue(mBubbleController.hasBubbles());
+
+ // Removes the notification
+ mEntryListener.onEntryRemoved(mRow.getEntry(), null, false);
assertFalse(mBubbleController.hasBubbles());
}
@Test
- public void removeBubble_fails_clearAll() {
+ public void removeBubble_clearAllIntercepted() {
mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
@@ -669,14 +700,10 @@
// Should update show in shade state
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
-
- verify(mNotificationEntryManager, never()).performRemoveNotification(
- any(), anyInt());
- assertTrue(mBubbleController.hasBubbles());
}
@Test
- public void removeBubble_fails_userDismissNotif() {
+ public void removeBubble_userDismissNotifIntercepted() {
mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
@@ -692,10 +719,6 @@
// Should update show in shade state
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
-
- verify(mNotificationEntryManager, never()).performRemoveNotification(
- any(), anyInt());
- assertTrue(mBubbleController.hasBubbles());
}
@Test
@@ -709,7 +732,7 @@
// Dismiss the bubble
mBubbleController.removeBubble(
- mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
+ mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
assertFalse(mBubbleController.hasBubbles());
// Dismiss the notification
@@ -767,6 +790,74 @@
mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
}
+ @Test
+ public void testBubbleSummaryDismissal_suppressesSummaryAndBubbleFromShade() throws Exception {
+ // GIVEN a group summary with a bubble child
+ ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(0);
+ ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
+ mEntryListener.onPendingEntryAdded(groupedBubble.getEntry());
+ groupSummary.addChildNotification(groupedBubble);
+ assertTrue(mBubbleData.hasBubbleWithKey(groupedBubble.getEntry().getKey()));
+
+ // WHEN the summary is dismissed
+ mBubbleController.handleDismissalInterception(groupSummary.getEntry());
+
+ // THEN the summary and bubbled child are suppressed from the shade
+ assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ groupedBubble.getEntry()));
+ assertTrue(mBubbleData.isSummarySuppressed(groupSummary.getEntry().getSbn().getGroupKey()));
+ }
+
+ @Test
+ public void testAppRemovesSummary_removesAllBubbleChildren() throws Exception {
+ // GIVEN a group summary with a bubble child
+ ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(0);
+ ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
+ mEntryListener.onPendingEntryAdded(groupedBubble.getEntry());
+ groupSummary.addChildNotification(groupedBubble);
+ assertTrue(mBubbleData.hasBubbleWithKey(groupedBubble.getEntry().getKey()));
+
+ // GIVEN the summary is dismissed
+ mBubbleController.handleDismissalInterception(groupSummary.getEntry());
+
+ // WHEN the summary is cancelled by the app
+ mEntryListener.onEntryRemoved(groupSummary.getEntry(), null, true);
+
+ // THEN the summary and its children are removed from bubble data
+ assertFalse(mBubbleData.hasBubbleWithKey(groupedBubble.getEntry().getKey()));
+ assertFalse(mBubbleData.isSummarySuppressed(
+ groupSummary.getEntry().getSbn().getGroupKey()));
+ }
+
+ @Test
+ public void testSummaryDismissal_marksBubblesHiddenFromShadeAndDismissesNonBubbledChildren()
+ throws Exception {
+ // GIVEN a group summary with two (non-bubble) children and one bubble child
+ ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(2);
+ ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
+ mEntryListener.onPendingEntryAdded(groupedBubble.getEntry());
+ groupSummary.addChildNotification(groupedBubble);
+
+ // WHEN the summary is dismissed
+ mBubbleController.handleDismissalInterception(groupSummary.getEntry());
+
+ // THEN only the NON-bubble children are dismissed
+ List<ExpandableNotificationRow> childrenRows = groupSummary.getNotificationChildren();
+ verify(mNotificationEntryManager, times(1)).performRemoveNotification(
+ childrenRows.get(0).getEntry().getSbn(), REASON_GROUP_SUMMARY_CANCELED);
+ verify(mNotificationEntryManager, times(1)).performRemoveNotification(
+ childrenRows.get(1).getEntry().getSbn(), REASON_GROUP_SUMMARY_CANCELED);
+ verify(mNotificationEntryManager, never()).performRemoveNotification(
+ eq(groupedBubble.getEntry().getSbn()), anyInt());
+
+ // THEN the bubble child is suppressed from the shade
+ assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ groupedBubble.getEntry()));
+
+ // THEN the summary is removed from GroupManager
+ verify(mNotificationGroupManager, times(1)).onEntryRemoved(groupSummary.getEntry());
+ }
+
static class TestableBubbleController extends BubbleController {
// Let's assume surfaces can be synchronized immediately.
TestableBubbleController(Context context,
@@ -779,11 +870,15 @@
ZenModeController zenModeController,
NotificationLockscreenUserManager lockscreenUserManager,
NotificationGroupManager groupManager,
- NotificationEntryManager entryManager) {
+ NotificationEntryManager entryManager,
+ NotifPipeline notifPipeline,
+ FeatureFlags featureFlags,
+ DumpController dumpController) {
super(context,
notificationShadeWindowController, statusBarStateController, shadeController,
data, Runnable::run, configurationController, interruptionStateProvider,
- zenModeController, lockscreenUserManager, groupManager, entryManager);
+ zenModeController, lockscreenUserManager, groupManager, entryManager,
+ notifPipeline, featureFlags, dumpController);
setInflateSynchronously(true);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
new file mode 100644
index 0000000..72405fc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -0,0 +1,842 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.bubbles;
+
+import static android.app.Notification.FLAG_BUBBLE;
+import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+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.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.IActivityManager;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.res.Resources;
+import android.hardware.face.FaceManager;
+import android.service.notification.ZenModeConfig;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.colorextraction.ColorExtractor;
+import com.android.systemui.DumpController;
+import com.android.systemui.SystemUIFactory;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationPresenter;
+import com.android.systemui.statusbar.SuperStatusBarViewFactory;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
+import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
+import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.util.InjectionInflationController;
+
+import org.junit.Before;
+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;
+
+import java.util.List;
+
+/**
+ * Tests the NotifPipeline setup with BubbleController.
+ * The NotificationEntryManager setup with BubbleController is tested in
+ * {@link BubbleControllerTest}.
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
+ @Mock
+ private NotificationEntryManager mNotificationEntryManager;
+ @Mock
+ private NotificationGroupManager mNotificationGroupManager;
+ @Mock
+ private BubbleController.NotifCallback mNotifCallback;
+ @Mock
+ private WindowManager mWindowManager;
+ @Mock
+ private IActivityManager mActivityManager;
+ @Mock
+ private DozeParameters mDozeParameters;
+ @Mock
+ private ConfigurationController mConfigurationController;
+ @Mock
+ private ZenModeController mZenModeController;
+ @Mock
+ private ZenModeConfig mZenModeConfig;
+ @Mock
+ private FaceManager mFaceManager;
+ @Mock
+ private NotificationLockscreenUserManager mLockscreenUserManager;
+ @Mock
+ private SysuiStatusBarStateController mStatusBarStateController;
+ @Mock
+ private KeyguardBypassController mKeyguardBypassController;
+
+ @Captor
+ private ArgumentCaptor<NotifCollectionListener> mNotifListenerCaptor;
+
+ private TestableBubbleController mBubbleController;
+ private NotificationShadeWindowController mNotificationShadeWindowController;
+ private NotifCollectionListener mEntryListener;
+
+ private NotificationTestHelper mNotificationTestHelper;
+ private ExpandableNotificationRow mRow;
+ private ExpandableNotificationRow mRow2;
+ private ExpandableNotificationRow mNonBubbleNotifRow;
+
+ @Mock
+ private BubbleController.BubbleStateChangeListener mBubbleStateChangeListener;
+ @Mock
+ private BubbleController.BubbleExpandListener mBubbleExpandListener;
+ @Mock
+ private PendingIntent mDeleteIntent;
+ @Mock
+ private SysuiColorExtractor mColorExtractor;
+ @Mock
+ ColorExtractor.GradientColors mGradientColors;
+ @Mock
+ private Resources mResources;
+ @Mock
+ private ShadeController mShadeController;
+ @Mock
+ private NotificationRowComponent mNotificationRowComponent;
+ @Mock
+ private NotifPipeline mNotifPipeline;
+ @Mock
+ private FeatureFlags mFeatureFlagsNewPipeline;
+ @Mock
+ private DumpController mDumpController;
+
+ private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
+ private BubbleData mBubbleData;
+
+ private TestableLooper mTestableLooper;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mTestableLooper = TestableLooper.get(this);
+
+ mContext.addMockSystemService(FaceManager.class, mFaceManager);
+ when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
+
+ mSuperStatusBarViewFactory = new SuperStatusBarViewFactory(mContext,
+ new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()),
+ new NotificationRowComponent.Builder() {
+ @Override
+ public NotificationRowComponent.Builder activatableNotificationView(
+ ActivatableNotificationView view) {
+ return this;
+ }
+
+ @Override
+ public NotificationRowComponent build() {
+ return mNotificationRowComponent;
+ }
+ });
+
+ // Bubbles get added to status bar window view
+ mNotificationShadeWindowController = new NotificationShadeWindowController(mContext,
+ mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController,
+ mConfigurationController, mKeyguardBypassController, mColorExtractor,
+ mSuperStatusBarViewFactory);
+ mNotificationShadeWindowController.attach();
+
+ // Need notifications for bubbles
+ mNotificationTestHelper = new NotificationTestHelper(mContext, mDependency);
+ mRow = mNotificationTestHelper.createBubble(mDeleteIntent);
+ mRow2 = mNotificationTestHelper.createBubble(mDeleteIntent);
+ mNonBubbleNotifRow = mNotificationTestHelper.createRow();
+
+ mZenModeConfig.suppressedVisualEffects = 0;
+ when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
+
+ TestableNotificationInterruptionStateProvider interruptionStateProvider =
+ new TestableNotificationInterruptionStateProvider(mContext,
+ mock(NotificationFilter.class),
+ mock(StatusBarStateController.class),
+ mock(BatteryController.class));
+ interruptionStateProvider.setUpWithPresenter(
+ mock(NotificationPresenter.class),
+ mock(HeadsUpManager.class),
+ mock(NotificationInterruptionStateProvider.HeadsUpSuppressor.class));
+ mBubbleData = new BubbleData(mContext);
+ when(mFeatureFlagsNewPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(true);
+ mBubbleController = new TestableBubbleController(mContext,
+ mNotificationShadeWindowController,
+ mStatusBarStateController,
+ mShadeController,
+ mBubbleData,
+ mConfigurationController,
+ interruptionStateProvider,
+ mZenModeController,
+ mLockscreenUserManager,
+ mNotificationGroupManager,
+ mNotificationEntryManager,
+ mNotifPipeline,
+ mFeatureFlagsNewPipeline,
+ mDumpController);
+ mBubbleController.addNotifCallback(mNotifCallback);
+ mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
+ mBubbleController.setExpandListener(mBubbleExpandListener);
+
+ // Get a reference to the BubbleController's entry listener
+ verify(mNotifPipeline, atLeastOnce())
+ .addCollectionListener(mNotifListenerCaptor.capture());
+ mEntryListener = mNotifListenerCaptor.getValue();
+ }
+
+ @Test
+ public void testAddBubble() {
+ mBubbleController.updateBubble(mRow.getEntry());
+ assertTrue(mBubbleController.hasBubbles());
+
+ verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
+ }
+
+ @Test
+ public void testHasBubbles() {
+ assertFalse(mBubbleController.hasBubbles());
+ mBubbleController.updateBubble(mRow.getEntry());
+ assertTrue(mBubbleController.hasBubbles());
+ }
+
+ @Test
+ public void testRemoveBubble() {
+ mBubbleController.updateBubble(mRow.getEntry());
+ assertNotNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
+ assertTrue(mBubbleController.hasBubbles());
+ verify(mNotifCallback, times(1)).invalidateNotifications(anyString());
+ verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
+
+ mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
+ assertFalse(mNotificationShadeWindowController.getBubblesShowing());
+ assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
+ verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
+ verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
+ }
+
+ @Test
+ public void testRemoveBubble_withDismissedNotif() {
+ mEntryListener.onEntryAdded(mRow.getEntry());
+ mBubbleController.updateBubble(mRow.getEntry());
+
+ assertTrue(mBubbleController.hasBubbles());
+ assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
+
+ // Make it look like dismissed notif
+ mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
+
+ // Now remove the bubble
+ mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
+
+ // Since the notif is dismissed, once the bubble is removed, removeNotification gets
+ // called to really remove the notif
+ verify(mNotifCallback, times(1)).removeNotification(eq(mRow.getEntry()), anyInt());
+ assertFalse(mBubbleController.hasBubbles());
+ }
+
+ @Test
+ public void testDismissStack() {
+ mBubbleController.updateBubble(mRow.getEntry());
+ verify(mNotifCallback, times(1)).invalidateNotifications(anyString());
+ assertNotNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
+ mBubbleController.updateBubble(mRow2.getEntry());
+ verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
+ assertNotNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey()));
+ assertTrue(mBubbleController.hasBubbles());
+
+ mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE);
+ assertFalse(mNotificationShadeWindowController.getBubblesShowing());
+ verify(mNotifCallback, times(3)).invalidateNotifications(anyString());
+ assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
+ assertNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey()));
+ }
+
+ @Test
+ public void testExpandCollapseStack() {
+ assertFalse(mBubbleController.isStackExpanded());
+
+ // Mark it as a bubble and add it explicitly
+ mEntryListener.onEntryAdded(mRow.getEntry());
+ mBubbleController.updateBubble(mRow.getEntry());
+
+ // We should have bubbles & their notifs should not be suppressed
+ assertTrue(mBubbleController.hasBubbles());
+ assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow.getEntry()));
+ assertFalse(mNotificationShadeWindowController.getBubbleExpanded());
+
+ // Expand the stack
+ BubbleStackView stackView = mBubbleController.getStackView();
+ mBubbleController.expandStack();
+ assertTrue(mBubbleController.isStackExpanded());
+ verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
+ assertTrue(mNotificationShadeWindowController.getBubbleExpanded());
+
+ // Make sure the notif is suppressed
+ assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
+
+ // Collapse
+ mBubbleController.collapseStack();
+ verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
+ assertFalse(mBubbleController.isStackExpanded());
+ assertFalse(mNotificationShadeWindowController.getBubbleExpanded());
+ }
+
+ @Test
+ public void testCollapseAfterChangingExpandedBubble() {
+ // Mark it as a bubble and add it explicitly
+ mEntryListener.onEntryAdded(mRow.getEntry());
+ mEntryListener.onEntryAdded(mRow2.getEntry());
+ mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mRow2.getEntry());
+
+ // We should have bubbles & their notifs should not be suppressed
+ assertTrue(mBubbleController.hasBubbles());
+ assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow.getEntry()));
+ assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow2.getEntry()));
+
+ // Expand
+ BubbleStackView stackView = mBubbleController.getStackView();
+ mBubbleController.expandStack();
+ assertTrue(mBubbleController.isStackExpanded());
+ verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
+
+ // Last added is the one that is expanded
+ assertEquals(mRow2.getEntry(), mBubbleData.getSelectedBubble().getEntry());
+ assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow2.getEntry()));
+
+ // Switch which bubble is expanded
+ mBubbleController.selectBubble(mRow.getEntry().getKey());
+ mBubbleData.setExpanded(true);
+ assertEquals(mRow.getEntry(), stackView.getExpandedBubble().getEntry());
+ assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow.getEntry()));
+
+ // collapse for previous bubble
+ verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
+ // expand for selected bubble
+ verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
+
+ // Collapse
+ mBubbleController.collapseStack();
+ assertFalse(mBubbleController.isStackExpanded());
+ }
+
+ @Test
+ public void testExpansionRemovesShowInShadeAndDot() {
+ // Mark it as a bubble and add it explicitly
+ mEntryListener.onEntryAdded(mRow.getEntry());
+ mBubbleController.updateBubble(mRow.getEntry());
+
+ // We should have bubbles & their notifs should not be suppressed
+ assertTrue(mBubbleController.hasBubbles());
+ assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
+
+ mTestableLooper.processAllMessages();
+ assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+
+ // Expand
+ mBubbleController.expandStack();
+ assertTrue(mBubbleController.isStackExpanded());
+ verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
+
+ // Notif is suppressed after expansion
+ assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow.getEntry()));
+ // Notif shouldn't show dot after expansion
+ assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+ }
+
+ @Test
+ public void testUpdateWhileExpanded_DoesntChangeShowInShadeAndDot() {
+ // Mark it as a bubble and add it explicitly
+ mEntryListener.onEntryAdded(mRow.getEntry());
+ mBubbleController.updateBubble(mRow.getEntry());
+
+ // We should have bubbles & their notifs should not be suppressed
+ assertTrue(mBubbleController.hasBubbles());
+ assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow.getEntry()));
+
+ mTestableLooper.processAllMessages();
+ assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+
+ // Expand
+ mBubbleController.expandStack();
+ assertTrue(mBubbleController.isStackExpanded());
+ verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
+
+ // Notif is suppressed after expansion
+ assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow.getEntry()));
+ // Notif shouldn't show dot after expansion
+ assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+
+ // Send update
+ mEntryListener.onEntryUpdated(mRow.getEntry());
+
+ // Nothing should have changed
+ // Notif is suppressed after expansion
+ assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow.getEntry()));
+ // Notif shouldn't show dot after expansion
+ assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+ }
+
+ @Test
+ public void testRemoveLastExpandedCollapses() {
+ // Mark it as a bubble and add it explicitly
+ mEntryListener.onEntryAdded(mRow.getEntry());
+ mEntryListener.onEntryAdded(mRow2.getEntry());
+ mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mRow2.getEntry());
+ verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
+
+ // Expand
+ BubbleStackView stackView = mBubbleController.getStackView();
+ mBubbleController.expandStack();
+
+ assertTrue(mBubbleController.isStackExpanded());
+ verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
+
+ // Last added is the one that is expanded
+ assertEquals(mRow2.getEntry(), stackView.getExpandedBubble().getEntry());
+ assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow2.getEntry()));
+
+ // Dismiss currently expanded
+ mBubbleController.removeBubble(stackView.getExpandedBubble().getEntry(),
+ BubbleController.DISMISS_USER_GESTURE);
+ verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
+
+ // Make sure first bubble is selected
+ assertEquals(mRow.getEntry(), stackView.getExpandedBubble().getEntry());
+ verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
+
+ // Dismiss that one
+ mBubbleController.removeBubble(stackView.getExpandedBubble().getEntry(),
+ BubbleController.DISMISS_USER_GESTURE);
+
+ // Make sure state changes and collapse happens
+ verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
+ verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
+ assertFalse(mBubbleController.hasBubbles());
+ }
+
+ @Test
+ public void testAutoExpand_fails_noFlag() {
+ assertFalse(mBubbleController.isStackExpanded());
+ setMetadataFlags(mRow.getEntry(),
+ Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, false /* enableFlag */);
+
+ // Add the auto expand bubble
+ mEntryListener.onEntryAdded(mRow.getEntry());
+ mBubbleController.updateBubble(mRow.getEntry());
+
+ // Expansion shouldn't change
+ verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */,
+ mRow.getEntry().getKey());
+ assertFalse(mBubbleController.isStackExpanded());
+
+ // # of bubbles should change
+ verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
+ }
+
+ @Test
+ public void testAutoExpand_succeeds_withFlag() {
+ setMetadataFlags(mRow.getEntry(),
+ Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, true /* enableFlag */);
+
+ // Add the auto expand bubble
+ mEntryListener.onEntryAdded(mRow.getEntry());
+ mBubbleController.updateBubble(mRow.getEntry());
+
+ // Expansion should change
+ verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */,
+ mRow.getEntry().getKey());
+ assertTrue(mBubbleController.isStackExpanded());
+
+ // # of bubbles should change
+ verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
+ }
+
+ @Test
+ public void testSuppressNotif_onInitialNotif() {
+ setMetadataFlags(mRow.getEntry(),
+ Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
+
+ // Add the suppress notif bubble
+ mEntryListener.onEntryAdded(mRow.getEntry());
+ mBubbleController.updateBubble(mRow.getEntry());
+
+ // Notif should be suppressed because we were foreground
+ assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow.getEntry()));
+ // Dot + flyout is hidden because notif is suppressed
+ assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+ assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showFlyout());
+
+ // # of bubbles should change
+ verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
+ }
+
+ @Test
+ public void testSuppressNotif_onUpdateNotif() {
+ mBubbleController.updateBubble(mRow.getEntry());
+
+ // Should not be suppressed
+ assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow.getEntry()));
+ // Should show dot
+ assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+
+ // Update to suppress notif
+ setMetadataFlags(mRow.getEntry(),
+ Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
+ mBubbleController.updateBubble(mRow.getEntry());
+
+ // Notif should be suppressed
+ assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow.getEntry()));
+ // Dot + flyout is hidden because notif is suppressed
+ assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+ assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showFlyout());
+
+ // # of bubbles should change
+ verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
+ }
+
+ @Test
+ public void testMarkNewNotificationAsShowInShade() {
+ mEntryListener.onEntryAdded(mRow.getEntry());
+ assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow.getEntry()));
+
+ mTestableLooper.processAllMessages();
+ assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+ }
+
+ @Test
+ public void testAddNotif_notBubble() {
+ mEntryListener.onEntryAdded(mNonBubbleNotifRow.getEntry());
+ mEntryListener.onEntryUpdated(mNonBubbleNotifRow.getEntry());
+
+ verify(mBubbleStateChangeListener, never()).onHasBubblesChanged(anyBoolean());
+ assertThat(mBubbleController.hasBubbles()).isFalse();
+ }
+
+ @Test
+ public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException {
+ mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_AGED);
+ verify(mDeleteIntent, never()).send();
+ }
+
+ @Test
+ public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException {
+ mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.removeBubble(
+ mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
+ verify(mDeleteIntent, times(1)).send();
+ }
+
+ @Test
+ public void testDeleteIntent_dismissStack() throws PendingIntent.CanceledException {
+ mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.updateBubble(mRow2.getEntry());
+ mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE);
+ verify(mDeleteIntent, times(2)).send();
+ }
+
+ @Test
+ public void testRemoveBubble_noLongerBubbleAfterUpdate()
+ throws PendingIntent.CanceledException {
+ mBubbleController.updateBubble(mRow.getEntry());
+ assertTrue(mBubbleController.hasBubbles());
+
+ mRow.getEntry().getSbn().getNotification().flags &= ~FLAG_BUBBLE;
+ mEntryListener.onEntryUpdated(mRow.getEntry());
+
+ assertFalse(mBubbleController.hasBubbles());
+ verify(mDeleteIntent, never()).send();
+ }
+
+ @Test
+ public void testRemoveBubble_entryListenerRemove() {
+ mEntryListener.onEntryAdded(mRow.getEntry());
+ mBubbleController.updateBubble(mRow.getEntry());
+
+ assertTrue(mBubbleController.hasBubbles());
+
+ // Removes the notification
+ mEntryListener.onEntryRemoved(mRow.getEntry(), 0);
+ assertFalse(mBubbleController.hasBubbles());
+ }
+
+ @Test
+ public void removeBubble_intercepted() {
+ mEntryListener.onEntryAdded(mRow.getEntry());
+ mBubbleController.updateBubble(mRow.getEntry());
+
+ assertTrue(mBubbleController.hasBubbles());
+ assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow.getEntry()));
+
+ boolean intercepted = mBubbleController.handleDismissalInterception(mRow.getEntry());
+
+ // Intercept!
+ assertTrue(intercepted);
+ // Should update show in shade state
+ assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
+ }
+
+ @Test
+ public void removeBubble_succeeds_userDismissBubble_userDimissNotif() {
+ mEntryListener.onEntryAdded(mRow.getEntry());
+ mBubbleController.updateBubble(mRow.getEntry());
+
+ assertTrue(mBubbleController.hasBubbles());
+ assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow.getEntry()));
+
+ // Dismiss the bubble
+ mBubbleController.removeBubble(
+ mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
+ assertFalse(mBubbleController.hasBubbles());
+
+ // Dismiss the notification
+ boolean intercepted = mBubbleController.handleDismissalInterception(mRow.getEntry());
+
+ // It's no longer a bubble so we shouldn't intercept
+ assertFalse(intercepted);
+ }
+
+ @Test
+ public void testNotifyShadeSuppressionChange_notificationDismiss() {
+ BubbleController.NotificationSuppressionChangedListener listener =
+ mock(BubbleController.NotificationSuppressionChangedListener.class);
+ mBubbleData.setSuppressionChangedListener(listener);
+
+ mEntryListener.onEntryAdded(mRow.getEntry());
+
+ assertTrue(mBubbleController.hasBubbles());
+ assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow.getEntry()));
+
+ mBubbleController.handleDismissalInterception(mRow.getEntry());
+
+ // Should update show in shade state
+ assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow.getEntry()));
+
+ // Should notify delegate that shade state changed
+ verify(listener).onBubbleNotificationSuppressionChange(
+ mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
+ }
+
+ @Test
+ public void testNotifyShadeSuppressionChange_bubbleExpanded() {
+ BubbleController.NotificationSuppressionChangedListener listener =
+ mock(BubbleController.NotificationSuppressionChangedListener.class);
+ mBubbleData.setSuppressionChangedListener(listener);
+
+ mEntryListener.onEntryAdded(mRow.getEntry());
+
+ assertTrue(mBubbleController.hasBubbles());
+ assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow.getEntry()));
+
+ mBubbleData.setExpanded(true);
+
+ // Once a bubble is expanded the notif is suppressed
+ assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ mRow.getEntry()));
+
+ // Should notify delegate that shade state changed
+ verify(listener).onBubbleNotificationSuppressionChange(
+ mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
+ }
+
+ @Test
+ public void testBubbleSummaryDismissal_suppressesSummaryAndBubbleFromShade() throws Exception {
+ // GIVEN a group summary with a bubble child
+ ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(0);
+ ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
+ mEntryListener.onEntryAdded(groupedBubble.getEntry());
+ groupSummary.addChildNotification(groupedBubble);
+ assertTrue(mBubbleData.hasBubbleWithKey(groupedBubble.getEntry().getKey()));
+
+ // WHEN the summary is dismissed
+ mBubbleController.handleDismissalInterception(groupSummary.getEntry());
+
+ // THEN the summary and bubbled child are suppressed from the shade
+ assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ groupedBubble.getEntry()));
+ assertTrue(mBubbleData.isSummarySuppressed(groupSummary.getEntry().getSbn().getGroupKey()));
+ }
+
+ @Test
+ public void testAppRemovesSummary_removesAllBubbleChildren() throws Exception {
+ // GIVEN a group summary with a bubble child
+ ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(0);
+ ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
+ mEntryListener.onEntryAdded(groupedBubble.getEntry());
+ groupSummary.addChildNotification(groupedBubble);
+ assertTrue(mBubbleData.hasBubbleWithKey(groupedBubble.getEntry().getKey()));
+
+ // GIVEN the summary is dismissed
+ mBubbleController.handleDismissalInterception(groupSummary.getEntry());
+
+ // WHEN the summary is cancelled by the app
+ mEntryListener.onEntryRemoved(groupSummary.getEntry(), 0);
+
+ // THEN the summary and its children are removed from bubble data
+ assertFalse(mBubbleData.hasBubbleWithKey(groupedBubble.getEntry().getKey()));
+ assertFalse(mBubbleData.isSummarySuppressed(
+ groupSummary.getEntry().getSbn().getGroupKey()));
+ }
+
+ @Test
+ public void testSummaryDismissalMarksBubblesHiddenFromShadeAndDismissesNonBubbledChildren()
+ throws Exception {
+ // GIVEN a group summary with two (non-bubble) children and one bubble child
+ ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(2);
+ ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
+ mEntryListener.onEntryAdded(groupedBubble.getEntry());
+ groupSummary.addChildNotification(groupedBubble);
+
+ // WHEN the summary is dismissed
+ mBubbleController.handleDismissalInterception(groupSummary.getEntry());
+
+ // THEN only the NON-bubble children are dismissed
+ List<ExpandableNotificationRow> childrenRows = groupSummary.getNotificationChildren();
+ verify(mNotifCallback, times(1)).removeNotification(
+ childrenRows.get(0).getEntry(), REASON_GROUP_SUMMARY_CANCELED);
+ verify(mNotifCallback, times(1)).removeNotification(
+ childrenRows.get(1).getEntry(), REASON_GROUP_SUMMARY_CANCELED);
+ verify(mNotifCallback, never()).removeNotification(eq(groupedBubble.getEntry()), anyInt());
+
+ // THEN the bubble child still exists as a bubble and is suppressed from the shade
+ assertTrue(mBubbleData.hasBubbleWithKey(groupedBubble.getEntry().getKey()));
+ assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ groupedBubble.getEntry()));
+
+ // THEN the summary is also suppressed from the shade
+ assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
+ groupSummary.getEntry()));
+ }
+
+ static class TestableBubbleController extends BubbleController {
+ // Let's assume surfaces can be synchronized immediately.
+ TestableBubbleController(Context context,
+ NotificationShadeWindowController notificationShadeWindowController,
+ StatusBarStateController statusBarStateController,
+ ShadeController shadeController,
+ BubbleData data,
+ ConfigurationController configurationController,
+ NotificationInterruptionStateProvider interruptionStateProvider,
+ ZenModeController zenModeController,
+ NotificationLockscreenUserManager lockscreenUserManager,
+ NotificationGroupManager groupManager,
+ NotificationEntryManager entryManager,
+ NotifPipeline notifPipeline,
+ FeatureFlags featureFlags,
+ DumpController dumpController) {
+ super(context,
+ notificationShadeWindowController, statusBarStateController, shadeController,
+ data, Runnable::run, configurationController, interruptionStateProvider,
+ zenModeController, lockscreenUserManager, groupManager, entryManager,
+ notifPipeline, featureFlags, dumpController);
+ setInflateSynchronously(true);
+ }
+ }
+
+ static class TestableNotificationInterruptionStateProvider extends
+ NotificationInterruptionStateProvider {
+
+ TestableNotificationInterruptionStateProvider(Context context,
+ NotificationFilter filter, StatusBarStateController controller,
+ BatteryController batteryController) {
+ super(context, filter, controller, batteryController);
+ mUseHeadsUp = true;
+ }
+ }
+
+ /**
+ * Sets the bubble metadata flags for this entry. These flags are normally set by
+ * NotificationManagerService when the notification is sent, however, these tests do not
+ * go through that path so we set them explicitly when testing.
+ */
+ private void setMetadataFlags(NotificationEntry entry, int flag, boolean enableFlag) {
+ Notification.BubbleMetadata bubbleMetadata =
+ entry.getSbn().getNotification().getBubbleMetadata();
+ int flags = bubbleMetadata.getFlags();
+ if (enableFlag) {
+ flags |= flag;
+ } else {
+ flags &= ~flag;
+ }
+ bubbleMetadata.setFlags(flags);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java
index a5722e2..4b47093 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java
@@ -16,52 +16,116 @@
package com.android.systemui.glwallpaper;
-import static org.junit.Assert.*;
-import static org.mockito.Mockito.RETURNS_DEFAULTS;
-import static org.mockito.Mockito.mock;
+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.atMost;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.graphics.PixelFormat;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
+import android.view.Surface;
+import android.view.SurfaceControl;
import android.view.SurfaceHolder;
+import android.view.SurfaceSession;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
-
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
public class EglHelperTest extends SysuiTestCase {
- @Mock
+ @Spy
private EglHelper mEglHelper;
+
@Mock
private SurfaceHolder mSurfaceHolder;
@Before
public void setUp() throws Exception {
- mEglHelper = mock(EglHelper.class, RETURNS_DEFAULTS);
- mSurfaceHolder = mock(SurfaceHolder.class, RETURNS_DEFAULTS);
+ MockitoAnnotations.initMocks(this);
+ prepareSurface();
+ }
+
+ @After
+ public void tearDown() {
+ mSurfaceHolder.getSurface().destroy();
+ mSurfaceHolder = null;
+ }
+
+ private void prepareSurface() {
+ final SurfaceSession session = new SurfaceSession();
+ final SurfaceControl control = new SurfaceControl.Builder(session)
+ .setName("Test")
+ .setBufferSize(100, 100)
+ .setFormat(PixelFormat.RGB_888)
+ .build();
+ final Surface surface = new Surface();
+ surface.copyFrom(control);
+ when(mSurfaceHolder.getSurface()).thenReturn(surface);
+ assertThat(mSurfaceHolder.getSurface()).isNotNull();
+ assertThat(mSurfaceHolder.getSurface().isValid()).isTrue();
}
@Test
public void testInit_finish() {
mEglHelper.init(mSurfaceHolder, false /* wideColorGamut */);
+ assertThat(mEglHelper.hasEglDisplay()).isTrue();
+ assertThat(mEglHelper.hasEglContext()).isTrue();
+ assertThat(mEglHelper.hasEglSurface()).isTrue();
+ verify(mEglHelper).askCreatingEglWindowSurface(
+ any(SurfaceHolder.class), eq(null), anyInt());
+
+ mEglHelper.finish();
+ assertThat(mEglHelper.hasEglSurface()).isFalse();
+ assertThat(mEglHelper.hasEglContext()).isFalse();
+ assertThat(mEglHelper.hasEglDisplay()).isFalse();
+ }
+
+ @Test
+ public void testInit_finish_wide_gamut() {
+ // In EglHelper, EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT = 0x3490;
+ doReturn(0x3490).when(mEglHelper).getWcgCapability();
+ // In EglHelper, KHR_GL_COLOR_SPACE = "EGL_KHR_gl_colorspace";
+ doReturn(true).when(mEglHelper).checkExtensionCapability("EGL_KHR_gl_colorspace");
+ ArgumentCaptor<int[]> ac = ArgumentCaptor.forClass(int[].class);
+ // {EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT, EGL_NONE}
+ final int[] expectedArgument = new int[] {0x309D, 0x3490, 0x3038};
+
+ mEglHelper.init(mSurfaceHolder, true /* wideColorGamut */);
+ verify(mEglHelper)
+ .askCreatingEglWindowSurface(any(SurfaceHolder.class), ac.capture(), anyInt());
+ assertThat(ac.getValue()).isNotNull();
+ assertThat(ac.getValue()).isEqualTo(expectedArgument);
mEglHelper.finish();
}
@Test
public void testFinish_shouldNotCrash() {
- assertFalse(mEglHelper.hasEglDisplay());
- assertFalse(mEglHelper.hasEglSurface());
- assertFalse(mEglHelper.hasEglContext());
+ mEglHelper.terminateEglDisplay();
+ assertThat(mEglHelper.hasEglDisplay()).isFalse();
+ assertThat(mEglHelper.hasEglSurface()).isFalse();
+ assertThat(mEglHelper.hasEglContext()).isFalse();
mEglHelper.finish();
+ verify(mEglHelper, never()).destroyEglContext();
+ verify(mEglHelper, never()).destroyEglSurface();
+ verify(mEglHelper, atMost(1)).terminateEglDisplay();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java b/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java
new file mode 100644
index 0000000..d881fd5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.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 com.android.systemui.glwallpaper;
+
+import static com.android.systemui.glwallpaper.GLWallpaperRenderer.SurfaceProxy;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.app.WallpaperManager;
+import android.app.WallpaperManager.ColorManagementProxy;
+import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class ImageWallpaperRendererTest extends SysuiTestCase {
+
+ private WallpaperManager mWpmSpy;
+ private SurfaceProxy mSurfaceProxy;
+
+ @Before
+ public void setUp() throws Exception {
+ final WallpaperManager wpm = mContext.getSystemService(WallpaperManager.class);
+ mWpmSpy = spy(wpm);
+ mContext.addMockSystemService(WallpaperManager.class, mWpmSpy);
+
+ mSurfaceProxy = new SurfaceProxy() {
+ @Override
+ public void requestRender() {
+ // NO-op
+ }
+
+ @Override
+ public void preRender() {
+ // No-op
+ }
+
+ @Override
+ public void postRender() {
+ // No-op
+ }
+ };
+ }
+
+ @Test
+ public void testWcgContent() throws IOException {
+ final Bitmap srgbBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+ final Bitmap p3Bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888,
+ false /* hasAlpha */, ColorSpace.get(ColorSpace.Named.DISPLAY_P3));
+
+ final ColorManagementProxy proxy = new ColorManagementProxy(mContext);
+ final ColorManagementProxy cmProxySpy = spy(proxy);
+ final Set<ColorSpace> supportedWideGamuts = new HashSet<>();
+ supportedWideGamuts.add(ColorSpace.get(ColorSpace.Named.DISPLAY_P3));
+
+ try {
+ doReturn(true).when(mWpmSpy).shouldEnableWideColorGamut();
+ doReturn(cmProxySpy).when(mWpmSpy).getColorManagementProxy();
+ doReturn(supportedWideGamuts).when(cmProxySpy).getSupportedColorSpaces();
+
+ mWpmSpy.setBitmap(p3Bitmap);
+ ImageWallpaperRenderer rendererP3 = new ImageWallpaperRenderer(mContext, mSurfaceProxy);
+ assertThat(rendererP3.isWcgContent()).isTrue();
+
+ mWpmSpy.setBitmap(srgbBitmap);
+ ImageWallpaperRenderer renderer = new ImageWallpaperRenderer(mContext, mSurfaceProxy);
+ assertThat(renderer.isWcgContent()).isFalse();
+ } finally {
+ srgbBitmap.recycle();
+ p3Bitmap.recycle();
+ }
+ }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
index d26ae6a..3439fe5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
@@ -119,6 +119,7 @@
doReturn(code).when(mIActivityTaskManager).startActivityAsUser(
eq((IApplicationThread) null),
eq((String) null),
+ eq((String) null),
any(Intent.class),
eq((String) null),
eq((IBinder) null),
@@ -134,6 +135,7 @@
verify(mIActivityTaskManager).startActivityAsUser(
eq((IApplicationThread) null),
eq((String) null),
+ eq((String) null),
any(Intent.class),
eq((String) null),
eq((IBinder) null),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
index 4becd52..9fe2569 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
@@ -88,8 +88,8 @@
}
@Test
- fun testBooleanTileHasBooleanState() {
- `when`(mTileServiceManager.isBooleanTile).thenReturn(true)
+ fun testToggleableTileHasBooleanState() {
+ `when`(mTileServiceManager.isToggleableTile).thenReturn(true)
customTile = CustomTile.create(mTileHost, TILE_SPEC)
assertTrue(customTile.state is QSTile.BooleanState)
@@ -104,7 +104,7 @@
@Test
fun testValueUpdatedInBooleanTile() {
- `when`(mTileServiceManager.isBooleanTile).thenReturn(true)
+ `when`(mTileServiceManager.isToggleableTile).thenReturn(true)
customTile = CustomTile.create(mTileHost, TILE_SPEC)
customTile.qsTile.icon = mock(Icon::class.java)
`when`(customTile.qsTile.icon.loadDrawable(any(Context::class.java)))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
index 9e5e582..42fd288 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
@@ -105,7 +105,7 @@
defaultServiceInfo = new ServiceInfo();
defaultServiceInfo.metaData = new Bundle();
defaultServiceInfo.metaData.putBoolean(TileService.META_DATA_ACTIVE_TILE, true);
- defaultServiceInfo.metaData.putBoolean(TileService.META_DATA_BOOLEAN_TILE, true);
+ defaultServiceInfo.metaData.putBoolean(TileService.META_DATA_TOGGLEABLE_TILE, true);
}
when(mMockPackageManagerAdapter.getServiceInfo(any(), anyInt(), anyInt()))
.thenReturn(defaultServiceInfo);
@@ -244,7 +244,7 @@
}
@Test
- public void testBooleanTile() throws Exception {
- assertTrue(mStateManager.isBooleanTile());
+ public void testToggleableTile() throws Exception {
+ assertTrue(mStateManager.isToggleableTile());
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index 7c94ed2..abc0f3e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -34,6 +34,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyObject;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
@@ -47,6 +48,7 @@
import android.annotation.Nullable;
import android.os.RemoteException;
import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationStats;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.ArrayMap;
@@ -69,6 +71,7 @@
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionLogger;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.util.Assert;
@@ -98,11 +101,19 @@
@Spy private RecordingCollectionListener mCollectionListener;
@Mock private CollectionReadyForBuildListener mBuildListener;
@Mock private FeatureFlags mFeatureFlags;
+ @Mock private DismissedByUserStats mDismissedByUserStats;
@Spy private RecordingLifetimeExtender mExtender1 = new RecordingLifetimeExtender("Extender1");
@Spy private RecordingLifetimeExtender mExtender2 = new RecordingLifetimeExtender("Extender2");
@Spy private RecordingLifetimeExtender mExtender3 = new RecordingLifetimeExtender("Extender3");
+ @Spy private RecordingDismissInterceptor mInterceptor1 = new RecordingDismissInterceptor(
+ "Interceptor1");
+ @Spy private RecordingDismissInterceptor mInterceptor2 = new RecordingDismissInterceptor(
+ "Interceptor2");
+ @Spy private RecordingDismissInterceptor mInterceptor3 = new RecordingDismissInterceptor(
+ "Interceptor3");
+
@Captor private ArgumentCaptor<BatchableNotificationHandler> mListenerCaptor;
@Captor private ArgumentCaptor<NotificationEntry> mEntryCaptor;
@Captor private ArgumentCaptor<Collection<NotificationEntry>> mBuildListCaptor;
@@ -441,6 +452,169 @@
assertEquals(NOT_DISMISSED, entry3.getDismissState());
}
+ @Test
+ public void testDismissInterceptorsAreCalled() throws RemoteException {
+ // GIVEN a collection with notifications with multiple dismiss interceptors
+ mInterceptor1.shouldInterceptDismissal = true;
+ mInterceptor2.shouldInterceptDismissal = true;
+ mInterceptor3.shouldInterceptDismissal = false;
+ mCollection.addNotificationDismissInterceptor(mInterceptor1);
+ mCollection.addNotificationDismissInterceptor(mInterceptor2);
+ mCollection.addNotificationDismissInterceptor(mInterceptor3);
+
+ NotifEvent notif = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
+ NotificationEntry entry = mCollectionListener.getEntry(notif.key);
+
+ // WHEN a notification is manually dismissed
+ DismissedByUserStats stats = new DismissedByUserStats(
+ NotificationStats.DISMISSAL_SHADE,
+ NotificationStats.DISMISS_SENTIMENT_NEUTRAL,
+ NotificationVisibility.obtain(entry.getKey(), 7, 2, true));
+ mCollection.dismissNotification(entry, stats);
+
+ // THEN all interceptors get checked
+ verify(mInterceptor1).shouldInterceptDismissal(entry);
+ verify(mInterceptor2).shouldInterceptDismissal(entry);
+ verify(mInterceptor3).shouldInterceptDismissal(entry);
+ assertEquals(List.of(mInterceptor1, mInterceptor2), entry.mDismissInterceptors);
+
+ // THEN we never send the dismissal to system server
+ verify(mStatusBarService, never()).onNotificationClear(
+ notif.sbn.getPackageName(),
+ notif.sbn.getTag(),
+ 47,
+ notif.sbn.getUser().getIdentifier(),
+ notif.sbn.getKey(),
+ stats.dismissalSurface,
+ stats.dismissalSentiment,
+ stats.notificationVisibility);
+ }
+
+ @Test
+ public void testDismissInterceptorsCanceledWhenNotifIsUpdated() throws RemoteException {
+ // GIVEN a few lifetime extenders and a couple notifications
+ mCollection.addNotificationDismissInterceptor(mInterceptor1);
+ mCollection.addNotificationDismissInterceptor(mInterceptor2);
+
+ mInterceptor1.shouldInterceptDismissal = true;
+ mInterceptor2.shouldInterceptDismissal = true;
+
+ NotifEvent notif = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
+ NotificationEntry entry = mCollectionListener.getEntry(notif.key);
+
+ // WHEN a notification is manually dismissed and intercepted
+ DismissedByUserStats stats = new DismissedByUserStats(
+ NotificationStats.DISMISSAL_SHADE,
+ NotificationStats.DISMISS_SENTIMENT_NEUTRAL,
+ NotificationVisibility.obtain(entry.getKey(), 7, 2, true));
+ mCollection.dismissNotification(entry, stats);
+ assertEquals(List.of(mInterceptor1, mInterceptor2), entry.mDismissInterceptors);
+ clearInvocations(mInterceptor1, mInterceptor2);
+
+ // WHEN the notification is reposted
+ mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
+
+ // THEN all of the active dismissal interceptors are canceled
+ verify(mInterceptor1).cancelDismissInterception(entry);
+ verify(mInterceptor2).cancelDismissInterception(entry);
+ assertEquals(List.of(), entry.mDismissInterceptors);
+
+ // THEN the notification is never sent to system server to dismiss
+ verify(mStatusBarService, never()).onNotificationClear(
+ eq(notif.sbn.getPackageName()),
+ eq(notif.sbn.getTag()),
+ eq(47),
+ eq(notif.sbn.getUser().getIdentifier()),
+ eq(notif.sbn.getKey()),
+ anyInt(),
+ anyInt(),
+ anyObject());
+ }
+
+ @Test
+ public void testEndingAllDismissInterceptorsSendsDismiss() throws RemoteException {
+ // GIVEN a collection with notifications a dismiss interceptor
+ mInterceptor1.shouldInterceptDismissal = true;
+ mCollection.addNotificationDismissInterceptor(mInterceptor1);
+
+ NotifEvent notif = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
+ NotificationEntry entry = mCollectionListener.getEntry(notif.key);
+
+ // GIVEN a notification is manually dismissed
+ DismissedByUserStats stats = new DismissedByUserStats(
+ NotificationStats.DISMISSAL_SHADE,
+ NotificationStats.DISMISS_SENTIMENT_NEUTRAL,
+ NotificationVisibility.obtain(entry.getKey(), 7, 2, true));
+ mCollection.dismissNotification(entry, stats);
+
+ // WHEN all interceptors end their interception dismissal
+ mInterceptor1.shouldInterceptDismissal = false;
+ mInterceptor1.onEndInterceptionCallback.onEndDismissInterception(mInterceptor1, entry,
+ mDismissedByUserStats);
+
+ // THEN we send the dismissal to system server
+ verify(mStatusBarService, times(1)).onNotificationClear(
+ eq(notif.sbn.getPackageName()),
+ eq(notif.sbn.getTag()),
+ eq(47),
+ eq(notif.sbn.getUser().getIdentifier()),
+ eq(notif.sbn.getKey()),
+ anyInt(),
+ anyInt(),
+ anyObject());
+ }
+
+ @Test
+ public void testEndDismissInterceptionUpdatesDismissInterceptors() throws RemoteException {
+ // GIVEN a collection with notifications with multiple dismiss interceptors
+ mInterceptor1.shouldInterceptDismissal = true;
+ mInterceptor2.shouldInterceptDismissal = true;
+ mInterceptor3.shouldInterceptDismissal = false;
+ mCollection.addNotificationDismissInterceptor(mInterceptor1);
+ mCollection.addNotificationDismissInterceptor(mInterceptor2);
+ mCollection.addNotificationDismissInterceptor(mInterceptor3);
+
+ NotifEvent notif = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
+ NotificationEntry entry = mCollectionListener.getEntry(notif.key);
+
+ // GIVEN a notification is manually dismissed
+ DismissedByUserStats stats = new DismissedByUserStats(
+ NotificationStats.DISMISSAL_SHADE,
+ NotificationStats.DISMISS_SENTIMENT_NEUTRAL,
+ NotificationVisibility.obtain(entry.getKey(), 7, 2, true));
+ mCollection.dismissNotification(entry, stats);
+
+ // WHEN an interceptor ends its interception
+ mInterceptor1.shouldInterceptDismissal = false;
+ mInterceptor1.onEndInterceptionCallback.onEndDismissInterception(mInterceptor1, entry,
+ mDismissedByUserStats);
+
+ // THEN all interceptors get checked
+ verify(mInterceptor1).shouldInterceptDismissal(entry);
+ verify(mInterceptor2).shouldInterceptDismissal(entry);
+ verify(mInterceptor3).shouldInterceptDismissal(entry);
+
+ // THEN mInterceptor2 is the only dismiss interceptor
+ assertEquals(List.of(mInterceptor2), entry.mDismissInterceptors);
+ }
+
+
+ @Test(expected = IllegalStateException.class)
+ public void testEndingDismissalOfNonInterceptedThrows() throws RemoteException {
+ // GIVEN a collection with notifications with a dismiss interceptor that hasn't been called
+ mInterceptor1.shouldInterceptDismissal = false;
+ mCollection.addNotificationDismissInterceptor(mInterceptor1);
+
+ NotifEvent notif = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
+ NotificationEntry entry = mCollectionListener.getEntry(notif.key);
+
+ // WHEN we try to end the dismissal of an interceptor that didn't intercept the notif
+ mInterceptor1.onEndInterceptionCallback.onEndDismissInterception(mInterceptor1, entry,
+ mDismissedByUserStats);
+
+ // THEN an exception is thrown
+ }
+
@Test(expected = IllegalStateException.class)
public void testDismissingNonExistentNotificationThrows() {
// GIVEN a collection that originally had three notifs, but where one was dismissed
@@ -894,6 +1068,36 @@
}
}
+ private static class RecordingDismissInterceptor implements NotifDismissInterceptor {
+ private final String mName;
+
+ public @Nullable OnEndDismissInterception onEndInterceptionCallback;
+ public boolean shouldInterceptDismissal = false;
+
+ private RecordingDismissInterceptor(String name) {
+ mName = name;
+ }
+
+ @Override
+ public String getName() {
+ return mName;
+ }
+
+ @Override
+ public void setCallback(OnEndDismissInterception callback) {
+ this.onEndInterceptionCallback = callback;
+ }
+
+ @Override
+ public boolean shouldInterceptDismissal(NotificationEntry entry) {
+ return shouldInterceptDismissal;
+ }
+
+ @Override
+ public void cancelDismissInterception(NotificationEntry entry) {
+ }
+ }
+
private static final String TEST_PACKAGE = "com.android.test.collection";
private static final String TEST_PACKAGE2 = "com.android.test.collection2";
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 3d9832d..9b2e0c3 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
@@ -199,9 +199,17 @@
/**
* Returns an {@link ExpandableNotificationRow} that should be shown as a bubble.
*/
+ public ExpandableNotificationRow createBubbleInGroup()
+ throws Exception {
+ return createBubble(makeBubbleMetadata(null), PKG, true);
+ }
+
+ /**
+ * Returns an {@link ExpandableNotificationRow} that should be shown as a bubble.
+ */
public ExpandableNotificationRow createBubble()
throws Exception {
- return createBubble(makeBubbleMetadata(null), PKG);
+ return createBubble(makeBubbleMetadata(null), PKG, false);
}
/**
@@ -211,7 +219,7 @@
*/
public ExpandableNotificationRow createBubble(@Nullable PendingIntent deleteIntent)
throws Exception {
- return createBubble(makeBubbleMetadata(deleteIntent), PKG);
+ return createBubble(makeBubbleMetadata(deleteIntent), PKG, false);
}
/**
@@ -221,8 +229,14 @@
*/
public ExpandableNotificationRow createBubble(BubbleMetadata bubbleMetadata, String pkg)
throws Exception {
+ return createBubble(bubbleMetadata, pkg, false);
+ }
+
+ private ExpandableNotificationRow createBubble(BubbleMetadata bubbleMetadata, String pkg,
+ boolean inGroup)
+ throws Exception {
Notification n = createNotification(false /* isGroupSummary */,
- null /* groupKey */, bubbleMetadata);
+ inGroup ? GROUP_KEY : null /* groupKey */, bubbleMetadata);
n.flags |= FLAG_BUBBLE;
ExpandableNotificationRow row = generateRow(n, pkg, UID, USER_HANDLE,
0 /* extraInflationFlags */, IMPORTANCE_HIGH);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
index 631c580..cd91f22 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.policy;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -24,10 +26,12 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
-import android.net.ConnectivityManager;
+import android.net.TetheringManager;
import android.net.wifi.WifiManager;
import android.os.Handler;
+import android.os.UserManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -38,11 +42,14 @@
import org.junit.Before;
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;
import org.mockito.invocation.InvocationOnMock;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.concurrent.Executor;
@SmallTest
@@ -51,13 +58,19 @@
public class HotspotControllerImplTest extends SysuiTestCase {
@Mock
- private ConnectivityManager mConnectivityManager;
+ private TetheringManager mTetheringManager;
@Mock
private WifiManager mWifiManager;
@Mock
+ private UserManager mUserManager;
+ @Mock
private HotspotController.Callback mCallback1;
@Mock
private HotspotController.Callback mCallback2;
+ @Mock
+ private TetheringManager.TetheringInterfaceRegexps mTetheringInterfaceRegexps;
+ @Captor
+ private ArgumentCaptor<TetheringManager.TetheringEventCallback> mTetheringCallbackCaptor;
private HotspotControllerImpl mController;
private TestableLooper mLooper;
@@ -66,8 +79,13 @@
MockitoAnnotations.initMocks(this);
mLooper = TestableLooper.get(this);
- mContext.addMockSystemService(ConnectivityManager.class, mConnectivityManager);
mContext.addMockSystemService(WifiManager.class, mWifiManager);
+ mContext.addMockSystemService(TetheringManager.class, mTetheringManager);
+ mContext.addMockSystemService(UserManager.class, mUserManager);
+
+ when(mUserManager.isUserAdmin(anyInt())).thenReturn(true);
+ when(mTetheringInterfaceRegexps.getTetherableWifiRegexs()).thenReturn(
+ Collections.singletonList("test"));
doAnswer((InvocationOnMock invocation) -> {
((WifiManager.SoftApCallback) invocation.getArgument(1))
@@ -76,7 +94,11 @@
}).when(mWifiManager).registerSoftApCallback(any(Executor.class),
any(WifiManager.SoftApCallback.class));
- mController = new HotspotControllerImpl(mContext, new Handler(mLooper.getLooper()));
+ Handler handler = new Handler(mLooper.getLooper());
+
+ mController = new HotspotControllerImpl(mContext, handler, handler);
+ verify(mTetheringManager)
+ .registerTetheringEventCallback(any(), mTetheringCallbackCaptor.capture());
}
@Test
@@ -117,4 +139,28 @@
verify(mWifiManager, never()).unregisterSoftApCallback(any());
}
+ @Test
+ public void testDefault_hotspotNotSupported() {
+ assertFalse(mController.isHotspotSupported());
+ }
+
+ @Test
+ public void testHotspotSupported_rightConditions() {
+ mTetheringCallbackCaptor.getValue().onTetheringSupported(true);
+ mTetheringCallbackCaptor.getValue()
+ .onTetherableInterfaceRegexpsChanged(mTetheringInterfaceRegexps);
+
+ assertTrue(mController.isHotspotSupported());
+ }
+
+ @Test
+ public void testHotspotSupported_callbackCalledOnChange() {
+ mController.addCallback(mCallback1);
+ mTetheringCallbackCaptor.getValue().onTetheringSupported(true);
+ mTetheringCallbackCaptor.getValue()
+ .onTetherableInterfaceRegexpsChanged(mTetheringInterfaceRegexps);
+
+ verify(mCallback1).onHotspotAvailabilityChanged(true);
+ }
+
}
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index cf2b1f06..285f4ab 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -60,7 +60,6 @@
"android.hardware.tetheroffload.config@1.0",
"liblog",
"libbase",
- "libbinderthreadstate",
"libcutils",
"libhidlbase",
"libjsoncpp",
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
index e0adb34d..8c4f733 100644
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -59,16 +59,33 @@
],
hostdex: true, // for hiddenapi check
- visibility: [
- "//frameworks/base/packages/Tethering:__subpackages__",
- //TODO(b/147200698) remove below lines when the platform is built with stubs
- "//frameworks/base",
- "//frameworks/base/services",
- "//frameworks/base/services/core",
- ],
+ visibility: ["//frameworks/base/packages/Tethering:__subpackages__"],
apex_available: ["com.android.tethering"],
}
+droidstubs {
+ name: "framework-tethering-stubs-sources",
+ defaults: ["framework-module-stubs-defaults-module_libs_api"],
+ srcs: [
+ "src/android/net/TetheredClient.java",
+ "src/android/net/TetheringManager.java",
+ "src/android/net/TetheringConstants.java",
+ ],
+ libs: [
+ "tethering-aidl-interfaces-java",
+ "framework-all",
+ ],
+ sdk_version: "core_platform",
+}
+
+java_library {
+ name: "framework-tethering-stubs",
+ srcs: [":framework-tethering-stubs-sources"],
+ libs: ["framework-all"],
+ static_libs: ["tethering-aidl-interfaces-java"],
+ sdk_version: "core_platform",
+}
+
filegroup {
name: "framework-tethering-srcs",
srcs: [
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java
index 6514688..ca5ef09 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java
@@ -16,6 +16,8 @@
package android.net;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -34,6 +36,7 @@
* @hide
*/
@SystemApi
+@SystemApi(client = MODULE_LIBRARIES)
@TestApi
public final class TetheredClient implements Parcelable {
@NonNull
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
index 00cf98e..df87ac9 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
@@ -16,6 +16,9 @@
package android.net;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
+import android.annotation.SystemApi;
import android.os.ResultReceiver;
/**
@@ -28,39 +31,30 @@
* symbols from framework-tethering even when they are in a non-hidden class.
* @hide
*/
+@SystemApi(client = MODULE_LIBRARIES)
public class TetheringConstants {
/**
* Extra used for communicating with the TetherService. Includes the type of tethering to
* enable if any.
- *
- * {@hide}
*/
public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
/**
* Extra used for communicating with the TetherService. Includes the type of tethering for
* which to cancel provisioning.
- *
- * {@hide}
*/
public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
/**
* Extra used for communicating with the TetherService. True to schedule a recheck of tether
* provisioning.
- *
- * {@hide}
*/
public static final String EXTRA_SET_ALARM = "extraSetAlarm";
/**
* Tells the TetherService to run a provision check now.
- *
- * {@hide}
*/
public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
/**
* Extra used for communicating with the TetherService. Contains the {@link ResultReceiver}
* which will receive provisioning results. Can be left empty.
- *
- * {@hide}
*/
public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index 53a358f..6a9f010 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -15,6 +15,8 @@
*/
package android.net;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -50,6 +52,7 @@
* @hide
*/
@SystemApi
+@SystemApi(client = MODULE_LIBRARIES)
@TestApi
public class TetheringManager {
private static final String TAG = TetheringManager.class.getSimpleName();
@@ -177,6 +180,7 @@
* service is not connected.
* {@hide}
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public TetheringManager(@NonNull final Context context,
@NonNull Supplier<IBinder> connectorSupplier) {
mContext = context;
@@ -395,6 +399,7 @@
* {@hide}
*/
@Deprecated
+ @SystemApi(client = MODULE_LIBRARIES)
public int tether(@NonNull final String iface) {
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "tether caller:" + callerPkg);
@@ -418,6 +423,7 @@
* {@hide}
*/
@Deprecated
+ @SystemApi(client = MODULE_LIBRARIES)
public int untether(@NonNull final String iface) {
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "untether caller:" + callerPkg);
@@ -444,6 +450,7 @@
* {@hide}
*/
@Deprecated
+ @SystemApi(client = MODULE_LIBRARIES)
public int setUsbTethering(final boolean enable) {
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "setUsbTethering caller:" + callerPkg);
@@ -702,6 +709,7 @@
* {@hide}
*/
// TODO: improve the usage of ResultReceiver, b/145096122
+ @SystemApi(client = MODULE_LIBRARIES)
public void requestLatestTetheringEntitlementResult(final int type,
@NonNull final ResultReceiver receiver, final boolean showEntitlementUi) {
final String callerPkg = mContext.getOpPackageName();
@@ -982,6 +990,7 @@
* interface
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public int getLastTetherError(@NonNull final String iface) {
mCallback.waitForStarted();
if (mTetherStatesParcel == null) return TETHER_ERROR_NO_ERROR;
@@ -1004,6 +1013,7 @@
* what interfaces are considered tetherable usb interfaces.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public @NonNull String[] getTetherableUsbRegexs() {
mCallback.waitForStarted();
return mTetheringConfiguration.tetherableUsbRegexs;
@@ -1018,6 +1028,7 @@
* what interfaces are considered tetherable wifi interfaces.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public @NonNull String[] getTetherableWifiRegexs() {
mCallback.waitForStarted();
return mTetheringConfiguration.tetherableWifiRegexs;
@@ -1032,6 +1043,7 @@
* what interfaces are considered tetherable bluetooth interfaces.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public @NonNull String[] getTetherableBluetoothRegexs() {
mCallback.waitForStarted();
return mTetheringConfiguration.tetherableBluetoothRegexs;
@@ -1044,6 +1056,7 @@
* @return an array of 0 or more Strings of tetherable interface names.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public @NonNull String[] getTetherableIfaces() {
mCallback.waitForStarted();
if (mTetherStatesParcel == null) return new String[0];
@@ -1057,6 +1070,7 @@
* @return an array of 0 or more String of currently tethered interface names.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public @NonNull String[] getTetheredIfaces() {
mCallback.waitForStarted();
if (mTetherStatesParcel == null) return new String[0];
@@ -1076,6 +1090,7 @@
* which failed to tether.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public @NonNull String[] getTetheringErroredIfaces() {
mCallback.waitForStarted();
if (mTetherStatesParcel == null) return new String[0];
@@ -1103,6 +1118,7 @@
* @return a boolean - {@code true} indicating Tethering is supported.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public boolean isTetheringSupported() {
final String callerPkg = mContext.getOpPackageName();
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index 39c402b..64c16e4 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -1944,7 +1944,8 @@
parcel.tetheringSupported = mDeps.isTetheringSupported();
parcel.upstreamNetwork = mTetherUpstream;
parcel.config = mConfig.toStableParcelable();
- parcel.states = mTetherStatesParcel;
+ parcel.states =
+ mTetherStatesParcel != null ? mTetherStatesParcel : emptyTetherStatesParcel();
try {
callback.onCallbackStarted(parcel);
} catch (RemoteException e) {
@@ -1953,6 +1954,17 @@
});
}
+ private TetherStatesParcel emptyTetherStatesParcel() {
+ final TetherStatesParcel parcel = new TetherStatesParcel();
+ parcel.availableList = new String[0];
+ parcel.tetheredList = new String[0];
+ parcel.localOnlyList = new String[0];
+ parcel.erroredIfaceList = new String[0];
+ parcel.lastErrorList = new int[0];
+
+ return parcel;
+ }
+
/** Unregister tethering event callback */
void unregisterTetheringEventCallback(ITetheringEventCallback callback) {
mHandler.post(() -> {
diff --git a/packages/Tethering/tests/unit/Android.bp b/packages/Tethering/tests/unit/Android.bp
index 13174c5..c6905ec 100644
--- a/packages/Tethering/tests/unit/Android.bp
+++ b/packages/Tethering/tests/unit/Android.bp
@@ -34,7 +34,15 @@
"TetheringApiCurrentLib",
"testables",
],
+ // TODO(b/147200698) change sdk_version to module-current and
+ // remove framework-minus-apex, ext, and framework-res
+ sdk_version: "core_platform",
libs: [
+ "framework-minus-apex",
+ "ext",
+ "framework-res",
+ "framework-wifi-stubs",
+ "framework-telephony-stubs",
"android.test.runner",
"android.test.base",
"android.test.mock",
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
index 4710287..6d49e20 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
@@ -127,6 +127,7 @@
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.networkstack.tethering.R;
+import com.android.testutils.MiscAssertsKt;
import org.junit.After;
import org.junit.Before;
@@ -1220,6 +1221,16 @@
}
}
+ private void assertTetherStatesNotNullButEmpty(final TetherStatesParcel parcel) {
+ assertFalse(parcel == null);
+ assertEquals(0, parcel.availableList.length);
+ assertEquals(0, parcel.tetheredList.length);
+ assertEquals(0, parcel.localOnlyList.length);
+ assertEquals(0, parcel.erroredIfaceList.length);
+ assertEquals(0, parcel.lastErrorList.length);
+ MiscAssertsKt.assertFieldCountEquals(5, TetherStatesParcel.class);
+ }
+
@Test
public void testRegisterTetheringEventCallback() throws Exception {
TestTetheringEventCallback callback = new TestTetheringEventCallback();
@@ -1232,7 +1243,7 @@
callback.expectConfigurationChanged(
mTethering.getTetheringConfiguration().toStableParcelable());
TetherStatesParcel tetherState = callback.pollTetherStatesChanged();
- assertEquals(tetherState, null);
+ assertTetherStatesNotNullButEmpty(tetherState);
// 2. Enable wifi tethering.
UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState();
when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
diff --git a/services/Android.bp b/services/Android.bp
index 28c8aee..416f448 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -30,6 +30,7 @@
":services.usb-sources",
":services.voiceinteraction-sources",
":service-permission-sources",
+ ":service-statsd-sources",
],
visibility: ["//visibility:private"],
}
@@ -75,7 +76,7 @@
libs: [
"android.hidl.manager-V1.0-java",
- "framework-tethering"
+ "framework-tethering-stubs",
],
plugins: [
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 1cb9313..4474f60 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -82,6 +82,7 @@
import com.android.server.autofill.AutofillManagerService.AutofillCompatState;
import com.android.server.autofill.RemoteAugmentedAutofillService.RemoteAugmentedAutofillServiceCallbacks;
import com.android.server.autofill.ui.AutoFillUI;
+import com.android.server.contentcapture.ContentCaptureManagerInternal;
import com.android.server.infra.AbstractPerUserSystemService;
import com.android.server.inputmethod.InputMethodManagerInternal;
@@ -180,6 +181,8 @@
private final InputMethodManagerInternal mInputMethodManagerInternal;
+ private final ContentCaptureManagerInternal mContentCaptureManagerInternal;
+
AutofillManagerServiceImpl(AutofillManagerService master, Object lock,
LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
AutofillCompatState autofillCompatState,
@@ -192,10 +195,22 @@
mFieldClassificationStrategy = new FieldClassificationStrategy(getContext(), userId);
mAutofillCompatState = autofillCompatState;
mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class);
+ mContentCaptureManagerInternal = LocalServices.getService(
+ ContentCaptureManagerInternal.class);
updateLocked(disabled);
}
+ boolean sendActivityAssistDataToContentCapture(@NonNull IBinder activityToken,
+ @NonNull Bundle data) {
+ if (mContentCaptureManagerInternal != null) {
+ mContentCaptureManagerInternal.sendActivityAssistData(getUserId(), activityToken, data);
+ return true;
+ }
+
+ return false;
+ }
+
@GuardedBy("mLock")
void onBackKeyPressed() {
final RemoteAugmentedAutofillService remoteService =
diff --git a/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java b/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java
new file mode 100644
index 0000000..1fc48d2
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill;
+
+import static com.android.server.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.autofill.AutofillId;
+import android.view.inputmethod.InlineSuggestionsRequest;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.view.IInlineSuggestionsRequestCallback;
+import com.android.internal.view.IInlineSuggestionsResponseCallback;
+import com.android.server.inputmethod.InputMethodManagerInternal;
+
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Maintains an inline suggestion autofill session.
+ *
+ * <p> This class is thread safe.
+ */
+final class InlineSuggestionSession {
+
+ private static final String TAG = "InlineSuggestionSession";
+ private static final int INLINE_REQUEST_TIMEOUT_MS = 1000;
+
+ @NonNull
+ private final InputMethodManagerInternal mInputMethodManagerInternal;
+ private final int mUserId;
+ @NonNull
+ private final ComponentName mComponentName;
+ @NonNull
+ private final Object mLock;
+
+ @GuardedBy("mLock")
+ @Nullable
+ private CompletableFuture<ImeResponse> mPendingImeResponse;
+
+ InlineSuggestionSession(InputMethodManagerInternal inputMethodManagerInternal,
+ int userId, ComponentName componentName) {
+ mInputMethodManagerInternal = inputMethodManagerInternal;
+ mUserId = userId;
+ mComponentName = componentName;
+ mLock = new Object();
+ }
+
+ public void createRequest(@NonNull AutofillId currentViewId) {
+ synchronized (mLock) {
+ cancelCurrentRequest();
+ mPendingImeResponse = new CompletableFuture<>();
+ mInputMethodManagerInternal.onCreateInlineSuggestionsRequest(
+ mUserId, mComponentName, currentViewId,
+ new InlineSuggestionsRequestCallbackImpl(mPendingImeResponse));
+ }
+ }
+
+ @Nullable
+ public ImeResponse waitAndGetImeResponse() {
+ CompletableFuture<ImeResponse> pendingImeResponse = getPendingImeResponse();
+ if (pendingImeResponse == null || pendingImeResponse.isCancelled()) {
+ return null;
+ }
+ try {
+ return pendingImeResponse.get(INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException e) {
+ Log.w(TAG, "Exception getting inline suggestions request in time: " + e);
+ } catch (CancellationException e) {
+ Log.w(TAG, "Inline suggestions request cancelled");
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException(e);
+ }
+ return null;
+ }
+
+ private void cancelCurrentRequest() {
+ CompletableFuture<ImeResponse> pendingImeResponse = getPendingImeResponse();
+ if (pendingImeResponse != null) {
+ pendingImeResponse.cancel(true);
+ }
+ }
+
+ @Nullable
+ @GuardedBy("mLock")
+ private CompletableFuture<ImeResponse> getPendingImeResponse() {
+ synchronized (mLock) {
+ return mPendingImeResponse;
+ }
+ }
+
+ private static final class InlineSuggestionsRequestCallbackImpl
+ extends IInlineSuggestionsRequestCallback.Stub {
+
+ private final CompletableFuture<ImeResponse> mResponse;
+
+ private InlineSuggestionsRequestCallbackImpl(CompletableFuture<ImeResponse> response) {
+ mResponse = response;
+ }
+
+ @Override
+ public void onInlineSuggestionsUnsupported() throws RemoteException {
+ if (sDebug) {
+ Log.d(TAG, "onInlineSuggestionsUnsupported() called.");
+ }
+ mResponse.cancel(true);
+ }
+
+ @Override
+ public void onInlineSuggestionsRequest(InlineSuggestionsRequest request,
+ IInlineSuggestionsResponseCallback callback) throws RemoteException {
+ if (sDebug) {
+ Log.d(TAG, "onInlineSuggestionsRequest() received: " + request);
+ }
+ if (request != null && callback != null) {
+ mResponse.complete(new ImeResponse(request, callback));
+ } else {
+ mResponse.cancel(true);
+ }
+ }
+ }
+
+ /**
+ * A data class wrapping IME responses for the inline suggestion request.
+ */
+ public static class ImeResponse {
+ @NonNull
+ private final InlineSuggestionsRequest mRequest;
+
+ @NonNull
+ private final IInlineSuggestionsResponseCallback mCallback;
+
+ ImeResponse(@NonNull InlineSuggestionsRequest request,
+ @NonNull IInlineSuggestionsResponseCallback callback) {
+ mRequest = request;
+ mCallback = callback;
+ }
+
+ public InlineSuggestionsRequest getRequest() {
+ return mRequest;
+ }
+
+ public IInlineSuggestionsResponseCallback getCallback() {
+ return mCallback;
+ }
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 2fc116e..53f85ea 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -100,7 +100,6 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ArrayUtils;
-import com.android.internal.view.IInlineSuggestionsRequestCallback;
import com.android.internal.view.IInlineSuggestionsResponseCallback;
import com.android.server.autofill.ui.AutoFillUI;
import com.android.server.autofill.ui.InlineSuggestionFactory;
@@ -114,11 +113,6 @@
import java.util.Collections;
import java.util.List;
import java.util.Objects;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -159,9 +153,6 @@
/** uid the session is for */
public final int uid;
- /** user id the session is for */
- public final int userId;
-
/** ID of the task associated with this session's activity */
public final int taskId;
@@ -310,12 +301,8 @@
@GuardedBy("mLock")
private boolean mForAugmentedAutofillOnly;
- @NonNull
- private final InputMethodManagerInternal mInputMethodManagerInternal;
-
@Nullable
- @GuardedBy("mLock")
- private InlineSuggestionsRequestCallbackImpl mInlineSuggestionsRequestCallback;
+ private final InlineSuggestionSession mInlineSuggestionSession;
/**
* Receiver of assist data from the app's {@link Activity}.
@@ -416,14 +403,16 @@
final ArrayList<FillContext> contexts =
mergePreviousSessionLocked(/* forSave= */ false);
- final InlineSuggestionsRequest suggestionsRequest =
- mInlineSuggestionsRequestCallback != null
- ? mInlineSuggestionsRequestCallback.getRequest() : null;
+ final InlineSuggestionSession.ImeResponse imeResponse =
+ mInlineSuggestionSession.waitAndGetImeResponse();
request = new FillRequest(requestId, contexts, mClientState, flags,
- suggestionsRequest);
+ imeResponse != null ? imeResponse.getRequest() : null);
}
+ if (mActivityToken != null) {
+ mService.sendActivityAssistDataToContentCapture(mActivityToken, resultData);
+ }
mRemoteFillService.onFillRequest(request);
}
@@ -616,75 +605,12 @@
private void maybeRequestInlineSuggestionsRequestThenFillLocked(@NonNull ViewState viewState,
int newState, int flags) {
if (isInlineSuggestionsEnabled()) {
- mInlineSuggestionsRequestCallback = new InlineSuggestionsRequestCallbackImpl();
- mInputMethodManagerInternal.onCreateInlineSuggestionsRequest(userId,
- mComponentName, mCurrentViewId, mInlineSuggestionsRequestCallback);
+ mInlineSuggestionSession.createRequest(mCurrentViewId);
}
requestNewFillResponseLocked(viewState, newState, flags);
}
- private static final class InlineSuggestionsRequestCallbackImpl
- extends IInlineSuggestionsRequestCallback.Stub {
- private static final int INLINE_REQUEST_TIMEOUT_MS = 1000;
-
- private final CompletableFuture<InlineSuggestionsRequest> mRequest;
- private final CompletableFuture<IInlineSuggestionsResponseCallback> mResponseCallback;
-
- private InlineSuggestionsRequestCallbackImpl() {
- mRequest = new CompletableFuture<>();
- mResponseCallback = new CompletableFuture<>();
- }
-
- @Override
- public void onInlineSuggestionsUnsupported() throws RemoteException {
- if (sDebug) {
- Log.d(TAG, "inline suggestions request unsupported, "
- + "falling back to regular autofill");
- }
- mRequest.cancel(true);
- mResponseCallback.cancel(true);
- }
-
- @Override
- public void onInlineSuggestionsRequest(InlineSuggestionsRequest request,
- IInlineSuggestionsResponseCallback callback) throws RemoteException {
- if (sDebug) {
- Log.d(TAG, "onInlineSuggestionsRequest() received: " + request);
- }
- mRequest.complete(request);
- mResponseCallback.complete(callback);
- }
-
- @Nullable
- private InlineSuggestionsRequest getRequest() {
- try {
- return mRequest.get(INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (TimeoutException e) {
- Log.w(TAG, "Exception getting inline suggestions request in time: " + e);
- } catch (CancellationException e) {
- Log.w(TAG, "Inline suggestions request cancelled");
- } catch (InterruptedException | ExecutionException e) {
- throw new RuntimeException(e);
- }
- return null;
- }
-
- @Nullable
- private IInlineSuggestionsResponseCallback getResponseCallback() {
- try {
- return mResponseCallback.get(INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (TimeoutException e) {
- Log.w(TAG, "Exception getting inline suggestions callback in time: " + e);
- } catch (CancellationException e) {
- Log.w(TAG, "Inline suggestions callback cancelled");
- } catch (InterruptedException | ExecutionException e) {
- throw new RuntimeException(e);
- }
- return null;
- }
- }
-
/**
* Reads a new structure and then request a new fill response from the fill service.
*/
@@ -764,7 +690,6 @@
mFlags = flags;
this.taskId = taskId;
this.uid = uid;
- this.userId = userId;
mStartTime = SystemClock.elapsedRealtime();
mService = service;
mLock = lock;
@@ -783,7 +708,8 @@
mForAugmentedAutofillOnly = forAugmentedAutofillOnly;
setClientLocked(client);
- mInputMethodManagerInternal = inputMethodManagerInternal;
+ mInlineSuggestionSession = new InlineSuggestionSession(inputMethodManagerInternal, userId,
+ componentName);
mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags));
@@ -2676,7 +2602,7 @@
if (response.supportsInlineSuggestions()) {
synchronized (mLock) {
- if (requestShowInlineSuggestions(response, mInlineSuggestionsRequestCallback)) {
+ if (requestShowInlineSuggestionsLocked(response)) {
//TODO(b/137800469): Fix it to log showed only when IME asks for inflation,
// rather than here where framework sends back the response.
mService.logDatasetShown(id, mClientState);
@@ -2719,21 +2645,21 @@
/**
* Returns whether we made a request to show inline suggestions.
*/
- private boolean requestShowInlineSuggestions(@NonNull FillResponse response,
- @Nullable InlineSuggestionsRequestCallbackImpl callback) {
+ private boolean requestShowInlineSuggestionsLocked(@NonNull FillResponse response) {
final List<Dataset> datasets = response.getDatasets();
if (datasets == null) {
Log.w(TAG, "response returned null datasets");
return false;
}
- if (callback == null || callback.getRequest() == null
- || callback.getResponseCallback() == null) {
+ final InlineSuggestionSession.ImeResponse imeResponse =
+ mInlineSuggestionSession.waitAndGetImeResponse();
+ if (imeResponse == null) {
Log.w(TAG, "Session input method callback is not set yet");
return false;
}
- final InlineSuggestionsRequest request = callback.getRequest();
+ final InlineSuggestionsRequest request = imeResponse.getRequest();
InlineSuggestionsResponse inlineSuggestionsResponse =
InlineSuggestionFactory.createInlineSuggestionsResponse(request,
response.getRequestId(),
@@ -2744,7 +2670,7 @@
}
});
try {
- callback.getResponseCallback().onInlineSuggestionsResponse(inlineSuggestionsResponse);
+ imeResponse.getCallback().onInlineSuggestionsResponse(inlineSuggestionsResponse);
} catch (RemoteException e) {
Log.w(TAG, "onFillReady() remote error calling onInlineSuggestionsResponse()");
return false;
@@ -3026,12 +2952,21 @@
final AutofillId focusedId = AutofillId.withoutSession(mCurrentViewId);
+ // There are 3 cases when augmented autofill should ask IME for a new request:
+ // 1. standard autofill provider is None
+ // 2. standard autofill provider doesn't support inline (and returns null response)
+ // 3. standard autofill provider supports inline, but isn't called because the field
+ // doesn't want autofill
+ if (mForAugmentedAutofillOnly || !isInlineSuggestionsEnabled()) {
+ if (sDebug) Slog.d(TAG, "Create inline request for augmented autofill");
+ mInlineSuggestionSession.createRequest(mCurrentViewId);
+ }
+ InlineSuggestionSession.ImeResponse imeResponse =
+ mInlineSuggestionSession.waitAndGetImeResponse();
final InlineSuggestionsRequest inlineSuggestionsRequest =
- mInlineSuggestionsRequestCallback != null
- ? mInlineSuggestionsRequestCallback.getRequest() : null;
+ imeResponse != null ? imeResponse.getRequest() : null;
final IInlineSuggestionsResponseCallback inlineSuggestionsResponseCallback =
- mInlineSuggestionsRequestCallback != null
- ? mInlineSuggestionsRequestCallback.getResponseCallback() : null;
+ imeResponse != null ? imeResponse.getCallback() : null;
remoteService.onRequestAutofillLocked(id, mClient, taskId, mComponentName, focusedId,
currentValue, inlineSuggestionsRequest, inlineSuggestionsResponseCallback, () -> {
synchronized (mLock) {
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionRoot.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionRoot.java
index 8d476d7..e813dae 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionRoot.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionRoot.java
@@ -48,6 +48,7 @@
super(context);
mOnErrorCallback = onErrorCallback;
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+ setFocusable(false);
}
@Override
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index 583c5b5..32bca35 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -426,18 +426,26 @@
public boolean sendActivityAssistDataLocked(@NonNull IBinder activityToken,
@NonNull Bundle data) {
final int id = getSessionId(activityToken);
+ final Bundle assistData = data.getBundle(ASSIST_KEY_DATA);
+ final AssistStructure assistStructure = data.getParcelable(ASSIST_KEY_STRUCTURE);
+ final AssistContent assistContent = data.getParcelable(ASSIST_KEY_CONTENT);
+ final SnapshotData snapshotData = new SnapshotData(assistData,
+ assistStructure, assistContent);
if (id != NO_SESSION_ID) {
final ContentCaptureServerSession session = mSessions.get(id);
- final Bundle assistData = data.getBundle(ASSIST_KEY_DATA);
- final AssistStructure assistStructure = data.getParcelable(ASSIST_KEY_STRUCTURE);
- final AssistContent assistContent = data.getParcelable(ASSIST_KEY_CONTENT);
- final SnapshotData snapshotData = new SnapshotData(assistData,
- assistStructure, assistContent);
session.sendActivitySnapshotLocked(snapshotData);
return true;
- } else {
- Slog.e(TAG, "Failed to notify activity assist data for activity: " + activityToken);
}
+
+ // We want to send an activity snapshot regardless of whether a content capture session is
+ // present or not since a content capture session is not required for this functionality
+ if (mRemoteService != null) {
+ mRemoteService.onActivitySnapshotRequest(NO_SESSION_ID, snapshotData);
+ Slog.d(TAG, "Notified activity assist data for activity: "
+ + activityToken + " without a session Id");
+ return true;
+ }
+
return false;
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index f33237f..6fc6084 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -98,7 +98,7 @@
"android.hardware.tv.cec-V1.0-java",
"android.hardware.vibrator-java",
"app-compat-annotations",
- "framework-tethering",
+ "framework-tethering-stubs",
],
required: [
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index bdcd832..63d0924 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -396,6 +396,7 @@
* @param origIntent The original intent that triggered ephemeral resolution
* @param resolvedType The resolved type of the intent
* @param callingPkg The app requesting the ephemeral application
+ * @param callingFeatureId The feature in the package
* @param isRequesterInstantApp Whether or not the app requesting the ephemeral application
* is an instant app
* @param verificationBundle Optional bundle to pass to the installer for additional
@@ -404,7 +405,8 @@
*/
public abstract void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
Intent origIntent, String resolvedType, String callingPkg,
- boolean isRequesterInstantApp, Bundle verificationBundle, int userId);
+ @Nullable String callingFeatureId, boolean isRequesterInstantApp,
+ Bundle verificationBundle, int userId);
/**
* Grants implicit access based on an interaction between two apps. This grants the target app
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index caacf13..687fb7d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3123,7 +3123,13 @@
handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties));
}
- private void updateLingerState(NetworkAgentInfo nai, long now) {
+ /**
+ * Updates the linger state from the network requests inside the NAI.
+ * @param nai the agent info to update
+ * @param now the timestamp of the event causing this update
+ * @return whether the network was lingered as a result of this update
+ */
+ private boolean updateLingerState(@NonNull final NetworkAgentInfo nai, final long now) {
// 1. Update the linger timer. If it's changed, reschedule or cancel the alarm.
// 2. If the network was lingering and there are now requests, unlinger it.
// 3. If this network is unneeded (which implies it is not lingering), and there is at least
@@ -3134,12 +3140,15 @@
nai.unlinger();
logNetworkEvent(nai, NetworkEvent.NETWORK_UNLINGER);
} else if (unneeded(nai, UnneededFor.LINGER) && nai.getLingerExpiry() > 0) {
- int lingerTime = (int) (nai.getLingerExpiry() - now);
- if (DBG) log("Lingering " + nai.name() + " for " + lingerTime + "ms");
+ if (DBG) {
+ final int lingerTime = (int) (nai.getLingerExpiry() - now);
+ log("Lingering " + nai.name() + " for " + lingerTime + "ms");
+ }
nai.linger();
logNetworkEvent(nai, NetworkEvent.NETWORK_LINGER);
- notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING, lingerTime);
+ return true;
}
+ return false;
}
private void handleAsyncChannelHalfConnect(Message msg) {
@@ -3483,7 +3492,10 @@
}
// If there are still lingered requests on this network, don't tear it down,
// but resume lingering instead.
- updateLingerState(nai, SystemClock.elapsedRealtime());
+ final long now = SystemClock.elapsedRealtime();
+ if (updateLingerState(nai, now)) {
+ notifyNetworkLosing(nai, now);
+ }
if (unneeded(nai, UnneededFor.TEARDOWN)) {
if (DBG) log("no live requests for " + nai.name() + "; disconnecting");
teardownUnneededNetwork(nai);
@@ -6620,11 +6632,16 @@
}
if (currentNetwork == null || currentNetwork.getCurrentScore() < score) {
reassignedRequests.put(nri, newNetwork);
+ changes.addRequestReassignment(new NetworkReassignment.RequestReassignment(
+ nri, currentNetwork, newNetwork));
}
} else if (newNetwork == currentNetwork) {
reassignedRequests.put(nri, null);
+ changes.addRequestReassignment(new NetworkReassignment.RequestReassignment(
+ nri, currentNetwork, null));
}
}
+
return reassignedRequests;
}
@@ -6663,41 +6680,39 @@
final NetworkRequestInfo nri = entry.getKey();
final NetworkAgentInfo previousSatisfier = nri.mSatisfier;
final NetworkAgentInfo newSatisfier = entry.getValue();
- changes.addRequestReassignment(new NetworkReassignment.RequestReassignment(
- nri, previousSatisfier, newSatisfier));
- if (newSatisfier != null) {
- if (VDBG) log("rematch for " + newSatisfier.name());
- if (previousSatisfier != null) {
- if (VDBG || DDBG) {
- log(" accepting network in place of " + previousSatisfier.name());
- }
- previousSatisfier.removeRequest(nri.request.requestId);
- previousSatisfier.lingerRequest(nri.request, now, mLingerDelayMs);
- } else {
- if (VDBG || DDBG) log(" accepting network in place of null");
- }
- newSatisfier.unlingerRequest(nri.request);
- if (!newSatisfier.addRequest(nri.request)) {
- Slog.wtf(TAG, "BUG: " + newSatisfier.name() + " already has " + nri.request);
- }
- } else {
- // If "newNetwork" is listed as satisfying "nri" but no longer satisfies "nri",
- // mark it as no longer satisfying "nri". Because networks are processed by
- // rematchAllNetworksAndRequests() in descending score order, "currentNetwork" will
- // match "newNetwork" before this loop will encounter a "currentNetwork" with higher
- // score than "newNetwork" and where "currentNetwork" no longer satisfies "nri".
- // This means this code doesn't have to handle the case where "currentNetwork" no
- // longer satisfies "nri" when "currentNetwork" does not equal "newNetwork".
- if (DBG) {
- log("Network " + newNetwork.name() + " stopped satisfying" +
- " request " + nri.request.requestId);
- }
- newNetwork.removeRequest(nri.request.requestId);
- }
- nri.mSatisfier = newSatisfier;
+ updateSatisfiersForRematchRequest(nri, previousSatisfier, newSatisfier, now);
}
}
+ private void updateSatisfiersForRematchRequest(@NonNull final NetworkRequestInfo nri,
+ @Nullable final NetworkAgentInfo previousSatisfier,
+ @Nullable final NetworkAgentInfo newSatisfier,
+ final long now) {
+ if (newSatisfier != null) {
+ if (VDBG) log("rematch for " + newSatisfier.name());
+ if (previousSatisfier != null) {
+ if (VDBG || DDBG) {
+ log(" accepting network in place of " + previousSatisfier.name());
+ }
+ previousSatisfier.removeRequest(nri.request.requestId);
+ previousSatisfier.lingerRequest(nri.request, now, mLingerDelayMs);
+ } else {
+ if (VDBG || DDBG) log(" accepting network in place of null");
+ }
+ newSatisfier.unlingerRequest(nri.request);
+ if (!newSatisfier.addRequest(nri.request)) {
+ Slog.wtf(TAG, "BUG: " + newSatisfier.name() + " already has " + nri.request);
+ }
+ } else {
+ if (DBG) {
+ log("Network " + previousSatisfier.name() + " stopped satisfying"
+ + " request " + nri.request.requestId);
+ }
+ previousSatisfier.removeRequest(nri.request.requestId);
+ }
+ nri.mSatisfier = newSatisfier;
+ }
+
/**
* Attempt to rematch all Networks with NetworkRequests. This may result in Networks
* being disconnected.
@@ -6773,13 +6788,20 @@
processNewlySatisfiedListenRequests(event.mNetwork);
}
+ final ArrayList<NetworkAgentInfo> lingeredNetworks = new ArrayList<>();
for (final NetworkAgentInfo nai : nais) {
// Rematching may have altered the linger state of some networks, so update all linger
// timers. updateLingerState reads the state from the network agent and does nothing
// if the state has not changed : the source of truth is controlled with
// NetworkAgentInfo#lingerRequest and NetworkAgentInfo#unlingerRequest, which have been
// called while rematching the individual networks above.
- updateLingerState(nai, now);
+ if (updateLingerState(nai, now)) {
+ lingeredNetworks.add(nai);
+ }
+ }
+
+ for (final NetworkAgentInfo nai : lingeredNetworks) {
+ notifyNetworkLosing(nai, now);
}
updateLegacyTypeTrackerAndVpnLockdownForRematch(oldDefaultNetwork, newDefaultNetwork, nais);
@@ -6795,7 +6817,9 @@
// and became unneeded due to another network improving its score to the
// point where this network will no longer be able to satisfy any requests
// even if it validates.
- updateLingerState(nai, now);
+ if (updateLingerState(nai, now)) {
+ notifyNetworkLosing(nai, now);
+ }
} else {
if (DBG) log("Reaping " + nai.name());
teardownUnneededNetwork(nai);
@@ -7048,6 +7072,12 @@
callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, blocked ? 1 : 0);
}
+ // Notify the requests on this NAI that the network is now lingered.
+ private void notifyNetworkLosing(@NonNull final NetworkAgentInfo nai, final long now) {
+ final int lingerTime = (int) (nai.getLingerExpiry() - now);
+ notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING, lingerTime);
+ }
+
/**
* Notify of the blocked state apps with a registered callback matching a given NAI.
*
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 135f6f3..6fb7b26 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -272,10 +272,11 @@
private void handlePinOnStart() {
final String bootImage = SystemProperties.get("dalvik.vm.boot-image", "");
String[] filesToPin = null;
- if (bootImage.endsWith("apex.art")) {
- // Use the files listed for that specific boot image
+ if (bootImage.endsWith("boot-image.prof")) {
+ // Use the files listed for that specific boot image.
+ // TODO: find a better way to know we're using the JIT zygote configuration.
filesToPin = mContext.getResources().getStringArray(
- com.android.internal.R.array.config_apexBootImagePinnerServiceFiles);
+ com.android.internal.R.array.config_jitzygoteBootImagePinnerServiceFiles);
} else {
// Files to pin come from the overlay and can be specified per-device config
filesToPin = mContext.getResources().getStringArray(
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index cbf6c27..0e5a6bb 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -284,17 +284,17 @@
static final int ENFORCE_PHONE_STATE_PERMISSION_MASK =
PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
| PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
- | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST
+ | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST;
+
+ static final int ENFORCE_PRECISE_PHONE_STATE_PERMISSION_MASK =
+ PhoneStateListener.LISTEN_PRECISE_CALL_STATE
+ | PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE
+ | PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES
+ | PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED
+ | PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES
| PhoneStateListener.LISTEN_REGISTRATION_FAILURE
| PhoneStateListener.LISTEN_BARRING_INFO;
- static final int PRECISE_PHONE_STATE_PERMISSION_MASK =
- PhoneStateListener.LISTEN_PRECISE_CALL_STATE
- | PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE
- | PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES
- | PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED
- | PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES;
-
static final int READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK =
PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL
| PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_SMS;
@@ -2535,7 +2535,7 @@
}
}
- if ((events & PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) {
+ if ((events & ENFORCE_PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) {
// check if calling app has either permission READ_PRECISE_PHONE_STATE
// or with carrier privileges
try {
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index b994e6c..0eedf8a 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -1261,8 +1261,9 @@
if (Sandman.shouldStartDockApp(getContext(), homeIntent)) {
try {
int result = ActivityTaskManager.getService().startActivityWithConfig(
- null, getContext().getBasePackageName(), homeIntent, null, null, null,
- 0, 0, mConfiguration, null, UserHandle.USER_CURRENT);
+ null, getContext().getBasePackageName(), getContext().getFeatureId(),
+ homeIntent, null, null, null, 0, 0, mConfiguration, null,
+ UserHandle.USER_CURRENT);
if (ActivityManager.isStartResultSuccessful(result)) {
dockAppStarted = true;
} else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 982466d..97b5eaa 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -417,22 +417,23 @@
}
private boolean appRestrictedAnyInBackground(final int uid, final String packageName) {
- final int mode = mAm.mAppOpsService.checkOperation(
+ final int mode = mAm.getAppOpsManager().checkOpNoThrow(
AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName);
return (mode != AppOpsManager.MODE_ALLOWED);
}
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
- int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
+ int callingPid, int callingUid, boolean fgRequired, String callingPackage,
+ @Nullable String callingFeatureId, final int userId)
throws TransactionTooLargeException {
return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired,
- callingPackage, userId, false);
+ callingPackage, callingFeatureId, userId, false);
}
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage,
- final int userId, boolean allowBackgroundActivityStarts)
- throws TransactionTooLargeException {
+ @Nullable String callingFeatureId, final int userId,
+ boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
+ " type=" + resolvedType + " args=" + service.getExtras());
@@ -488,7 +489,7 @@
// If this is a direct-to-foreground start, make sure it is allowed as per the app op.
boolean forceSilentAbort = false;
if (fgRequired) {
- final int mode = mAm.mAppOpsService.checkOperation(
+ final int mode = mAm.getAppOpsManager().checkOpNoThrow(
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);
switch (mode) {
case AppOpsManager.MODE_ALLOWED:
@@ -566,7 +567,7 @@
// review is completed.
// XXX This is not dealing with fgRequired!
- if (!requestStartTargetPermissionsReviewIfNeededLocked(r, callingPackage,
+ if (!requestStartTargetPermissionsReviewIfNeededLocked(r, callingPackage, callingFeatureId,
callingUid, service, callerFg, userId)) {
return null;
}
@@ -673,8 +674,8 @@
}
private boolean requestStartTargetPermissionsReviewIfNeededLocked(ServiceRecord r,
- String callingPackage, int callingUid, Intent service, boolean callerFg,
- final int userId) {
+ String callingPackage, @Nullable String callingFeatureId, int callingUid,
+ Intent service, boolean callerFg, final int userId) {
if (mAm.getPackageManagerInternalLocked().isPermissionsReviewRequired(
r.packageName, r.userId)) {
@@ -686,7 +687,7 @@
}
IIntentSender target = mAm.mPendingIntentController.getIntentSender(
- ActivityManager.INTENT_SENDER_SERVICE, callingPackage,
+ ActivityManager.INTENT_SENDER_SERVICE, callingPackage, callingFeatureId,
callingUid, userId, null, null, 0, new Intent[]{service},
new String[]{service.resolveType(mAm.mContext.getContentResolver())},
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
@@ -1287,7 +1288,7 @@
}
// Instant apps need permission to create foreground services.
if (r.appInfo.isInstantApp()) {
- final int mode = mAm.mAppOpsService.checkOperation(
+ final int mode = mAm.getAppOpsManager().checkOpNoThrow(
AppOpsManager.OP_INSTANT_APP_START_FOREGROUND,
r.appInfo.uid,
r.appInfo.packageName);
@@ -1354,7 +1355,7 @@
try {
boolean ignoreForeground = false;
- final int mode = mAm.mAppOpsService.checkOperation(
+ final int mode = mAm.getAppOpsManager().checkOpNoThrow(
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);
switch (mode) {
case AppOpsManager.MODE_ALLOWED:
@@ -2289,7 +2290,7 @@
return new ServiceLookupResult(null, r.permission);
} else if (r.permission != null && callingPackage != null) {
final int opCode = AppOpsManager.permissionToOpCode(r.permission);
- if (opCode != AppOpsManager.OP_NONE && mAm.mAppOpsService.checkOperation(
+ if (opCode != AppOpsManager.OP_NONE && mAm.getAppOpsManager().checkOpNoThrow(
opCode, callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: Accessing service " + r.shortInstanceName
+ " from pid=" + callingPid
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3ad96ea..d5a7253 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -466,18 +466,9 @@
// How long we wait for a launched process to attach to the activity manager
// before we decide it's never going to come up for real.
static final int PROC_START_TIMEOUT = 10*1000;
- // How long we wait for an attached process to publish its content providers
- // before we decide it must be hung.
- static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000;
-
// How long we wait to kill an application zygote, after the last process using
// it has gone away.
static final int KILL_APP_ZYGOTE_DELAY_MS = 5 * 1000;
- /**
- * How long we wait for an provider to be published. Should be longer than
- * {@link #CONTENT_PROVIDER_PUBLISH_TIMEOUT}.
- */
- static final int CONTENT_PROVIDER_WAIT_TIMEOUT = 20 * 1000;
// How long we wait for a launched process to attach to the activity manager
// before we decide it's never going to come up for real, when the process was
@@ -1240,6 +1231,7 @@
* Information about and control over application operations
*/
final AppOpsService mAppOpsService;
+ private AppOpsManager mAppOpsManager;
/**
* List of initialization arguments to pass to all processes when binding applications to them.
@@ -2109,7 +2101,7 @@
new IAppOpsCallback.Stub() {
@Override public void opChanged(int op, int uid, String packageName) {
if (op == AppOpsManager.OP_RUN_IN_BACKGROUND && packageName != null) {
- if (mAppOpsService.checkOperation(op, uid, packageName)
+ if (getAppOpsManager().checkOpNoThrow(op, uid, packageName)
!= AppOpsManager.MODE_ALLOWED) {
runInBackgroundDisabled(uid);
}
@@ -2400,6 +2392,13 @@
}
}
+ AppOpsManager getAppOpsManager() {
+ if (mAppOpsManager == null) {
+ mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
+ }
+ return mAppOpsManager;
+ }
+
/**
* Provides the basic functionality for activity task related tests when a handler thread is
* given to initialize the dependency members.
@@ -2908,7 +2907,7 @@
@Override
public void batterySendBroadcast(Intent intent) {
synchronized (this) {
- broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+ broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
Binder.getCallingPid(), UserHandle.USER_ALL);
}
@@ -3512,30 +3511,56 @@
}
+ /**
+ * @deprecated use {@link #startActivityWithFeature} instead
+ */
+ @Deprecated
@Override
public int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
- return mActivityTaskManager.startActivity(caller, callingPackage, intent, resolvedType,
- resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions);
+ return mActivityTaskManager.startActivity(caller, callingPackage, null, intent,
+ resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions);
}
@Override
+ public int startActivityWithFeature(IApplicationThread caller, String callingPackage,
+ String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
+ String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
+ Bundle bOptions) {
+ return mActivityTaskManager.startActivity(caller, callingPackage, callingFeatureId, intent,
+ resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions);
+ }
+
+ /**
+ * @deprecated use {@link #startActivityAsUserWithFeature} instead
+ */
+ @Deprecated
+ @Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
+ return startActivityAsUserWithFeature(caller, callingPackage, null, intent, resolvedType,
+ resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, userId);
+ }
- return mActivityTaskManager.startActivityAsUser(caller, callingPackage, intent,
- resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo,
- bOptions, userId);
+ @Override
+ public final int startActivityAsUserWithFeature(IApplicationThread caller,
+ String callingPackage, String callingFeatureId, Intent intent, String resolvedType,
+ IBinder resultTo, String resultWho, int requestCode, int startFlags,
+ ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
+ return mActivityTaskManager.startActivityAsUser(caller, callingPackage,
+ callingFeatureId, intent, resolvedType, resultTo, resultWho, requestCode,
+ startFlags, profilerInfo, bOptions, userId);
}
WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
- Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
- int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
- return mActivityTaskManager.startActivityAndWait(caller, callingPackage, intent,
- resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo,
- bOptions, userId);
+ @Nullable String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
+ String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
+ Bundle bOptions, int userId) {
+ return mActivityTaskManager.startActivityAndWait(caller, callingPackage,
+ callingFeatureId, intent, resolvedType, resultTo, resultWho, requestCode,
+ startFlags, profilerInfo, bOptions, userId);
}
@Override
@@ -4106,12 +4131,12 @@
intent.putExtra(Intent.EXTRA_USER_HANDLE, resolvedUserId);
if (isInstantApp) {
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
- broadcastIntentInPackage("android", SYSTEM_UID, uid, pid, intent, null,
- null, 0, null, null, permission.ACCESS_INSTANT_APPS, null, false,
- false, resolvedUserId, false);
+ broadcastIntentInPackage("android", null, SYSTEM_UID, uid, pid, intent,
+ null, null, 0, null, null, permission.ACCESS_INSTANT_APPS, null,
+ false, false, resolvedUserId, false);
} else {
- broadcastIntentInPackage("android", SYSTEM_UID, uid, pid, intent, null,
- null, 0, null, null, null, null, false, false, resolvedUserId,
+ broadcastIntentInPackage("android", null, SYSTEM_UID, uid, pid, intent,
+ null, null, 0, null, null, null, null, false, false, resolvedUserId,
false);
}
@@ -4559,7 +4584,7 @@
}
intent.putExtra(Intent.EXTRA_UID, uid);
intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid));
- broadcastIntentLocked(null, null, intent,
+ broadcastIntentLocked(null, null, null, intent,
null, null, 0, null, null, null, OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
Binder.getCallingPid(), UserHandle.getUserId(uid));
@@ -4934,7 +4959,8 @@
if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
msg.obj = app;
- mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT);
+ mHandler.sendMessageDelayed(msg,
+ ContentResolver.CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS);
}
checkTime(startTime, "attachApplicationLocked: before bindApplication");
@@ -5416,12 +5442,23 @@
}
}
+ /**
+ * @deprecated Use {@link #getIntentSenderWithFeature} instead
+ */
+ @Deprecated
@Override
public IIntentSender getIntentSender(int type,
String packageName, IBinder token, String resultWho,
int requestCode, Intent[] intents, String[] resolvedTypes,
int flags, Bundle bOptions, int userId) {
+ return getIntentSenderWithFeature(type, packageName, null, token, resultWho, requestCode,
+ intents, resolvedTypes, flags, bOptions, userId);
+ }
+ @Override
+ public IIntentSender getIntentSenderWithFeature(int type, String packageName, String featureId,
+ IBinder token, String resultWho, int requestCode, Intent[] intents,
+ String[] resolvedTypes, int flags, Bundle bOptions, int userId) {
// NOTE: The service lock isn't held in this method because nothing in the method requires
// the service lock to be held.
@@ -5483,12 +5520,13 @@
}
if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {
- return mAtmInternal.getIntentSender(type, packageName, callingUid, userId,
- token, resultWho, requestCode, intents, resolvedTypes, flags, bOptions);
+ return mAtmInternal.getIntentSender(type, packageName, featureId, callingUid,
+ userId, token, resultWho, requestCode, intents, resolvedTypes, flags,
+ bOptions);
}
- return mPendingIntentController.getIntentSender(type, packageName, callingUid,
- userId, token, resultWho, requestCode, intents, resolvedTypes, flags,
- bOptions);
+ return mPendingIntentController.getIntentSender(type, packageName, featureId,
+ callingUid, userId, token, resultWho, requestCode, intents, resolvedTypes,
+ flags, bOptions);
} catch (RemoteException e) {
throw new SecurityException(e);
}
@@ -6054,8 +6092,8 @@
return ActivityManager.APP_START_MODE_DELAYED;
}
// Not in the RESTRICTED bucket so policy is based on AppOp check.
- int appop = mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND,
- uid, packageName, null, false, "");
+ int appop = getAppOpsManager().noteOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND,
+ uid, packageName, null, "");
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "Legacy app " + uid + "/" + packageName + " bg appop " + appop);
}
@@ -7201,7 +7239,8 @@
}
// Wait for the provider to be published...
- final long timeout = SystemClock.uptimeMillis() + CONTENT_PROVIDER_WAIT_TIMEOUT;
+ final long timeout =
+ SystemClock.uptimeMillis() + ContentResolver.CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS;
boolean timedOut = false;
synchronized (cpr) {
while (cpr.provider == null) {
@@ -7238,12 +7277,14 @@
}
}
if (timedOut) {
- // Note we do it afer releasing the lock.
+ // Note we do it after releasing the lock.
String callerName = "unknown";
- synchronized (this) {
- final ProcessRecord record = mProcessList.getLRURecordForAppLocked(caller);
- if (record != null) {
- callerName = record.processName;
+ if (caller != null) {
+ synchronized (this) {
+ final ProcessRecord record = mProcessList.getLRURecordForAppLocked(caller);
+ if (record != null) {
+ callerName = record.processName;
+ }
}
}
@@ -7961,7 +8002,7 @@
}
boolean isBackgroundRestrictedNoCheck(final int uid, final String packageName) {
- final int mode = mAppOpsService.checkOperation(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
+ final int mode = getAppOpsManager().checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
uid, packageName);
return mode != AppOpsManager.MODE_ALLOWED;
}
@@ -9439,14 +9480,14 @@
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
- broadcastIntentLocked(null, null, intent,
+ broadcastIntentLocked(null, null, null, intent,
null, null, 0, null, null, null, OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
currentUserId);
intent = new Intent(Intent.ACTION_USER_STARTING);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
- broadcastIntentLocked(null, null, intent, null,
+ broadcastIntentLocked(null, null, null, intent, null,
new IIntentReceiver.Stub() {
@Override
public void performReceive(Intent intent, int resultCode,
@@ -14585,7 +14626,8 @@
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
- String resolvedType, boolean requireForeground, String callingPackage, int userId)
+ String resolvedType, boolean requireForeground, String callingPackage,
+ String callingFeatureId, int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("startService");
// Refuse possible leaked file descriptors
@@ -14607,7 +14649,7 @@
try {
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
- requireForeground, callingPackage, userId);
+ requireForeground, callingPackage, callingFeatureId, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -15085,9 +15127,20 @@
return didSomething;
}
+ /**
+ * @deprecated Use {@link #registerReceiverWithFeature}
+ */
+ @Deprecated
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
int flags) {
+ return registerReceiverWithFeature(caller, callerPackage, null, receiver, filter,
+ permission, userId, flags);
+ }
+
+ public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
+ String callerFeatureId, IIntentReceiver receiver, IntentFilter filter,
+ String permission, int userId, int flags) {
enforceNotIsolatedCaller("registerReceiver");
ArrayList<Intent> stickyIntents = null;
ProcessRecord callerApp = null;
@@ -15223,7 +15276,7 @@
+ " was previously registered for user " + rl.userId
+ " callerPackage is " + callerPackage);
}
- BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
+ BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
permission, callingUid, userId, instantApp, visibleToInstantApps);
if (rl.containsFilter(filter)) {
Slog.w(TAG, "Receiver with filter " + filter
@@ -15248,7 +15301,7 @@
Intent intent = allSticky.get(i);
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
- null, -1, -1, false, null, null, OP_NONE, null, receivers,
+ null, null, -1, -1, false, null, null, OP_NONE, null, receivers,
null, 0, null, null, false, true, true, -1, false,
false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);
queue.enqueueParallelBroadcastLocked(r);
@@ -15478,20 +15531,20 @@
@GuardedBy("this")
final int broadcastIntentLocked(ProcessRecord callerApp,
- String callerPackage, Intent intent, String resolvedType,
+ String callerPackage, String callerFeatureId, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
int realCallingPid, int userId) {
- return broadcastIntentLocked(callerApp, callerPackage, intent, resolvedType, resultTo,
- resultCode, resultData, resultExtras, requiredPermissions, appOp, bOptions, ordered,
- sticky, callingPid, callingUid, realCallingUid, realCallingPid, userId,
- false /* allowBackgroundActivityStarts */);
+ return broadcastIntentLocked(callerApp, callerPackage, callerFeatureId, intent,
+ resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions,
+ appOp, bOptions, ordered, sticky, callingPid, callingUid, realCallingUid,
+ realCallingPid, userId, false /* allowBackgroundActivityStarts */);
}
@GuardedBy("this")
- final int broadcastIntentLocked(ProcessRecord callerApp,
- String callerPackage, Intent intent, String resolvedType,
+ final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage,
+ @Nullable String callerFeatureId, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
@@ -16028,8 +16081,8 @@
isProtectedBroadcast, registeredReceivers);
}
final BroadcastQueue queue = broadcastQueueForIntent(intent);
- BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
- callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
+ BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
+ callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
resultCode, resultData, resultExtras, ordered, sticky, false, userId,
allowBackgroundActivityStarts, timeoutExempt);
@@ -16125,8 +16178,8 @@
if ((receivers != null && receivers.size() > 0)
|| resultTo != null) {
BroadcastQueue queue = broadcastQueueForIntent(intent);
- BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
- callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
+ BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
+ callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
resultData, resultExtras, ordered, sticky, false, userId,
allowBackgroundActivityStarts, timeoutExempt);
@@ -16245,11 +16298,25 @@
return intent;
}
+ /**
+ * @deprecated Use {@link #broadcastIntentWithFeature}
+ */
+ @Deprecated
public final int broadcastIntent(IApplicationThread caller,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle resultExtras,
String[] requiredPermissions, int appOp, Bundle bOptions,
boolean serialized, boolean sticky, int userId) {
+ return broadcastIntentWithFeature(caller, null, intent, resolvedType, resultTo, resultCode,
+ resultData, resultExtras, requiredPermissions, appOp, bOptions, serialized, sticky,
+ userId);
+ }
+
+ public final int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId,
+ Intent intent, String resolvedType, IIntentReceiver resultTo,
+ int resultCode, String resultData, Bundle resultExtras,
+ String[] requiredPermissions, int appOp, Bundle bOptions,
+ boolean serialized, boolean sticky, int userId) {
enforceNotIsolatedCaller("broadcastIntent");
synchronized(this) {
intent = verifyBroadcastLocked(intent);
@@ -16261,7 +16328,7 @@
final long origId = Binder.clearCallingIdentity();
try {
return broadcastIntentLocked(callerApp,
- callerApp != null ? callerApp.info.packageName : null,
+ callerApp != null ? callerApp.info.packageName : null, callingFeatureId,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
requiredPermissions, appOp, bOptions, serialized, sticky,
callingPid, callingUid, callingUid, callingPid, userId);
@@ -16271,9 +16338,9 @@
}
}
- int broadcastIntentInPackage(String packageName, int uid, int realCallingUid,
- int realCallingPid, Intent intent, String resolvedType, IIntentReceiver resultTo,
- int resultCode, String resultData, Bundle resultExtras,
+ int broadcastIntentInPackage(String packageName, @Nullable String featureId, int uid,
+ int realCallingUid, int realCallingPid, Intent intent, String resolvedType,
+ IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras,
String requiredPermission, Bundle bOptions, boolean serialized, boolean sticky,
int userId, boolean allowBackgroundActivityStarts) {
synchronized(this) {
@@ -16283,11 +16350,10 @@
String[] requiredPermissions = requiredPermission == null ? null
: new String[] {requiredPermission};
try {
- return broadcastIntentLocked(null, packageName, intent, resolvedType,
- resultTo, resultCode, resultData, resultExtras,
- requiredPermissions, OP_NONE, bOptions, serialized,
- sticky, -1, uid, realCallingUid, realCallingPid, userId,
- allowBackgroundActivityStarts);
+ return broadcastIntentLocked(null, packageName, featureId, intent, resolvedType,
+ resultTo, resultCode, resultData, resultExtras, requiredPermissions,
+ OP_NONE, bOptions, serialized, sticky, -1, uid, realCallingUid,
+ realCallingPid, userId, allowBackgroundActivityStarts);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -18891,23 +18957,24 @@
}
@Override
- public int broadcastIntentInPackage(String packageName, int uid, int realCallingUid,
- int realCallingPid, Intent intent, String resolvedType, IIntentReceiver resultTo,
- int resultCode, String resultData, Bundle resultExtras, String requiredPermission,
- Bundle bOptions, boolean serialized, boolean sticky, int userId,
- boolean allowBackgroundActivityStarts) {
+ public int broadcastIntentInPackage(String packageName, @Nullable String featureId, int uid,
+ int realCallingUid, int realCallingPid, Intent intent, String resolvedType,
+ IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras,
+ String requiredPermission, Bundle bOptions, boolean serialized, boolean sticky,
+ int userId, boolean allowBackgroundActivityStarts) {
synchronized (ActivityManagerService.this) {
- return ActivityManagerService.this.broadcastIntentInPackage(packageName, uid,
- realCallingUid, realCallingPid, intent, resolvedType, resultTo, resultCode,
- resultData, resultExtras, requiredPermission, bOptions, serialized, sticky,
- userId, allowBackgroundActivityStarts);
+ return ActivityManagerService.this.broadcastIntentInPackage(packageName, featureId,
+ uid, realCallingUid, realCallingPid, intent, resolvedType, resultTo,
+ resultCode, resultData, resultExtras, requiredPermission, bOptions,
+ serialized, sticky, userId, allowBackgroundActivityStarts);
}
}
@Override
public ComponentName startServiceInPackage(int uid, Intent service, String resolvedType,
- boolean fgRequired, String callingPackage, int userId,
- boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
+ boolean fgRequired, String callingPackage, @Nullable String callingFeatureId,
+ int userId, boolean allowBackgroundActivityStarts)
+ throws TransactionTooLargeException {
synchronized(ActivityManagerService.this) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"startServiceInPackage: " + service + " type=" + resolvedType);
@@ -18915,8 +18982,8 @@
ComponentName res;
try {
res = mServices.startServiceLocked(null, service,
- resolvedType, -1, uid, fgRequired, callingPackage, userId,
- allowBackgroundActivityStarts);
+ resolvedType, -1, uid, fgRequired, callingPackage,
+ callingFeatureId, userId, allowBackgroundActivityStarts);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -19009,7 +19076,7 @@
| Intent.FLAG_RECEIVER_REPLACE_PENDING
| Intent.FLAG_RECEIVER_FOREGROUND
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
- broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+ broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
OP_NONE, null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
Binder.getCallingPid(), UserHandle.USER_ALL);
if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
@@ -19020,7 +19087,7 @@
if (initLocale || !mProcessesReady) {
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
}
- broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+ broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
OP_NONE, null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
Binder.getCallingPid(), UserHandle.USER_ALL);
}
@@ -19035,7 +19102,7 @@
// Typically only app stores will have this permission.
String[] permissions =
new String[] { android.Manifest.permission.INSTALL_PACKAGES };
- broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
+ broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null,
permissions, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
Binder.getCallingUid(), Binder.getCallingPid(), UserHandle.USER_ALL);
}
@@ -19060,7 +19127,7 @@
intent.putExtra("reason", reason);
}
- broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+ broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
Binder.getCallingPid(), UserHandle.USER_ALL);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 53a967b..c0e98cd 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -534,13 +534,13 @@
options.setLockTaskEnabled(true);
}
if (mWaitOption) {
- result = mInternal.startActivityAndWait(null, SHELL_PACKAGE_NAME, intent, mimeType,
- null, null, 0, mStartFlags, profilerInfo,
+ result = mInternal.startActivityAndWait(null, SHELL_PACKAGE_NAME, null, intent,
+ mimeType, null, null, 0, mStartFlags, profilerInfo,
options != null ? options.toBundle() : null, mUserId);
res = result.result;
} else {
- res = mInternal.startActivityAsUser(null, SHELL_PACKAGE_NAME, intent, mimeType,
- null, null, 0, mStartFlags, profilerInfo,
+ res = mInternal.startActivityAsUserWithFeature(null, SHELL_PACKAGE_NAME, null,
+ intent, mimeType, null, null, 0, mStartFlags, profilerInfo,
options != null ? options.toBundle() : null, mUserId);
}
final long endTime = SystemClock.uptimeMillis();
@@ -652,7 +652,7 @@
pw.println("Starting service: " + intent);
pw.flush();
ComponentName cn = mInterface.startService(null, intent, intent.getType(),
- asForeground, SHELL_PACKAGE_NAME, mUserId);
+ asForeground, SHELL_PACKAGE_NAME, null, mUserId);
if (cn == null) {
err.println("Error: Not found; no service started.");
return -1;
@@ -742,8 +742,9 @@
pw.println("Broadcasting: " + intent);
pw.flush();
Bundle bundle = mBroadcastOptions == null ? null : mBroadcastOptions.toBundle();
- mInterface.broadcastIntent(null, intent, null, receiver, 0, null, null, requiredPermissions,
- android.app.AppOpsManager.OP_NONE, bundle, true, false, mUserId);
+ mInterface.broadcastIntentWithFeature(null, null, intent, null, receiver, 0, null, null,
+ requiredPermissions, android.app.AppOpsManager.OP_NONE, bundle, true, false,
+ mUserId);
receiver.waitForFinish();
return 0;
}
diff --git a/services/core/java/com/android/server/am/BroadcastFilter.java b/services/core/java/com/android/server/am/BroadcastFilter.java
index 1ec8db0..578db6f 100644
--- a/services/core/java/com/android/server/am/BroadcastFilter.java
+++ b/services/core/java/com/android/server/am/BroadcastFilter.java
@@ -27,6 +27,7 @@
// Back-pointer to the list this filter is in.
final ReceiverList receiverList;
final String packageName;
+ final String featureId;
final String requiredPermission;
final int owningUid;
final int owningUserId;
@@ -34,11 +35,12 @@
final boolean visibleToInstantApp;
BroadcastFilter(IntentFilter _filter, ReceiverList _receiverList,
- String _packageName, String _requiredPermission, int _owningUid, int _userId,
+ String _packageName, String _featureId, String _requiredPermission, int _owningUid, int _userId,
boolean _instantApp, boolean _visibleToInstantApp) {
super(_filter);
receiverList = _receiverList;
packageName = _packageName;
+ featureId = _featureId;
requiredPermission = _requiredPermission;
owningUid = _owningUid;
owningUserId = _userId;
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 6697b5a..26ef707 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -648,10 +648,10 @@
skip = true;
} else {
final int opCode = AppOpsManager.permissionToOpCode(filter.requiredPermission);
- // TODO moltmann: Set featureId from caller
if (opCode != AppOpsManager.OP_NONE
- && mService.mAppOpsService.noteOperation(opCode, r.callingUid,
- r.callerPackage, null, false, "") != AppOpsManager.MODE_ALLOWED) {
+ && mService.getAppOpsManager().noteOpNoThrow(opCode, r.callingUid,
+ r.callerPackage, r.callerFeatureId, "")
+ != AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid="
@@ -681,10 +681,9 @@
break;
}
int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
- // TODO moltmann: Set featureId from caller
if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
- && mService.mAppOpsService.noteOperation(appOp,
- filter.receiverList.uid, filter.packageName, null, false, "")
+ && mService.getAppOpsManager().noteOpNoThrow(appOp,
+ filter.receiverList.uid, filter.packageName, filter.featureId, "")
!= AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: receiving "
+ r.intent.toString()
@@ -714,10 +713,9 @@
skip = true;
}
}
- // TODO moltmann: Set featureId from caller
if (!skip && r.appOp != AppOpsManager.OP_NONE
- && mService.mAppOpsService.noteOperation(r.appOp,
- filter.receiverList.uid, filter.packageName, null, false, "")
+ && mService.getAppOpsManager().noteOpNoThrow(r.appOp,
+ filter.receiverList.uid, filter.packageName, filter.featureId, "")
!= AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: receiving "
+ r.intent.toString()
@@ -863,7 +861,8 @@
if (callerForeground && receiverRecord.intent.getComponent() != null) {
IIntentSender target = mService.mPendingIntentController.getIntentSender(
ActivityManager.INTENT_SENDER_BROADCAST, receiverRecord.callerPackage,
- receiverRecord.callingUid, receiverRecord.userId, null, null, 0,
+ receiverRecord.callerFeatureId, receiverRecord.callingUid,
+ receiverRecord.userId, null, null, 0,
new Intent[]{receiverRecord.intent},
new String[]{receiverRecord.intent.resolveType(mService.mContext
.getContentResolver())},
@@ -1371,10 +1370,9 @@
skip = true;
} else if (!skip && info.activityInfo.permission != null) {
final int opCode = AppOpsManager.permissionToOpCode(info.activityInfo.permission);
- // TODO moltmann: Set featureId from caller
if (opCode != AppOpsManager.OP_NONE
- && mService.mAppOpsService.noteOperation(opCode, r.callingUid, r.callerPackage,
- null, false, "") != AppOpsManager.MODE_ALLOWED) {
+ && mService.getAppOpsManager().noteOpNoThrow(opCode, r.callingUid, r.callerPackage,
+ r.callerFeatureId, "") != AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid="
@@ -1410,11 +1408,10 @@
break;
}
int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
- // TODO moltmann: Set featureId from caller
if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
- && mService.mAppOpsService.noteOperation(appOp,
- info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, null,
- false, "")
+ && mService.getAppOpsManager().noteOpNoThrow(appOp,
+ info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
+ null /* default featureId */, "")
!= AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: receiving "
+ r.intent + " to "
@@ -1428,11 +1425,10 @@
}
}
}
- // TODO moltmann: Set featureId from caller
if (!skip && r.appOp != AppOpsManager.OP_NONE
- && mService.mAppOpsService.noteOperation(r.appOp,
- info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, null, false,
- "")
+ && mService.getAppOpsManager().noteOpNoThrow(r.appOp,
+ info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
+ null /* default featureId */, "")
!= AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: receiving "
+ r.intent + " to "
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index f263886..8ef67f9 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
import android.content.ComponentName;
@@ -51,6 +52,7 @@
final ComponentName targetComp; // original component name set on the intent
final ProcessRecord callerApp; // process that sent this
final String callerPackage; // who sent this
+ final @Nullable String callerFeatureId; // which feature in the package sent this
final int callingPid; // the pid of who sent this
final int callingUid; // the uid of who sent this
final boolean callerInstantApp; // caller is an Instant App?
@@ -233,7 +235,8 @@
BroadcastRecord(BroadcastQueue _queue,
Intent _intent, ProcessRecord _callerApp, String _callerPackage,
- int _callingPid, int _callingUid, boolean _callerInstantApp, String _resolvedType,
+ @Nullable String _callerFeatureId, int _callingPid, int _callingUid,
+ boolean _callerInstantApp, String _resolvedType,
String[] _requiredPermissions, int _appOp, BroadcastOptions _options, List _receivers,
IIntentReceiver _resultTo, int _resultCode, String _resultData, Bundle _resultExtras,
boolean _serialized, boolean _sticky, boolean _initialSticky, int _userId,
@@ -246,6 +249,7 @@
targetComp = _intent.getComponent();
callerApp = _callerApp;
callerPackage = _callerPackage;
+ callerFeatureId = _callerFeatureId;
callingPid = _callingPid;
callingUid = _callingUid;
callerInstantApp = _callerInstantApp;
@@ -280,6 +284,7 @@
callerApp = from.callerApp;
callerPackage = from.callerPackage;
+ callerFeatureId = from.callerFeatureId;
callingPid = from.callingPid;
callingUid = from.callingUid;
callerInstantApp = from.callerInstantApp;
@@ -343,8 +348,8 @@
}
// build a new BroadcastRecord around that single-target list
- BroadcastRecord split = new BroadcastRecord(queue, intent, callerApp,
- callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
+ BroadcastRecord split = new BroadcastRecord(queue, intent, callerApp, callerPackage,
+ callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, options, splitReceivers, resultTo, resultCode,
resultData, resultExtras, ordered, sticky, initialSticky, userId,
allowBackgroundActivityStarts, timeoutExempt);
diff --git a/services/core/java/com/android/server/am/PendingIntentController.java b/services/core/java/com/android/server/am/PendingIntentController.java
index df76713..eacf088 100644
--- a/services/core/java/com/android/server/am/PendingIntentController.java
+++ b/services/core/java/com/android/server/am/PendingIntentController.java
@@ -23,6 +23,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
@@ -88,9 +89,9 @@
}
}
- public PendingIntentRecord getIntentSender(int type, String packageName, int callingUid,
- int userId, IBinder token, String resultWho, int requestCode, Intent[] intents,
- String[] resolvedTypes, int flags, Bundle bOptions) {
+ public PendingIntentRecord getIntentSender(int type, String packageName,
+ @Nullable String featureId, int callingUid, int userId, IBinder token, String resultWho,
+ int requestCode, Intent[] intents, String[] resolvedTypes, int flags, Bundle bOptions) {
synchronized (mLock) {
if (DEBUG_MU) Slog.v(TAG_MU, "getIntentSender(): uid=" + callingUid);
@@ -109,8 +110,8 @@
flags &= ~(PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_CANCEL_CURRENT
| PendingIntent.FLAG_UPDATE_CURRENT);
- PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, token,
- resultWho, requestCode, intents, resolvedTypes, flags,
+ PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, featureId,
+ token, resultWho, requestCode, intents, resolvedTypes, flags,
SafeActivityOptions.fromBundle(bOptions), userId);
WeakReference<PendingIntentRecord> ref;
ref = mIntentSenderRecords.get(key);
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 3ba2210..d54d2d7 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -17,14 +17,16 @@
package com.android.server.am;
import static android.app.ActivityManager.START_SUCCESS;
+
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
-import android.content.IIntentSender;
-import android.content.IIntentReceiver;
import android.app.PendingIntent;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
@@ -72,6 +74,7 @@
final static class Key {
final int type;
final String packageName;
+ final String featureId;
final IBinder activity;
final String who;
final int requestCode;
@@ -86,10 +89,11 @@
private static final int ODD_PRIME_NUMBER = 37;
- Key(int _t, String _p, IBinder _a, String _w,
+ Key(int _t, String _p, @Nullable String _featureId, IBinder _a, String _w,
int _r, Intent[] _i, String[] _it, int _f, SafeActivityOptions _o, int _userId) {
type = _t;
packageName = _p;
+ featureId = _featureId;
activity = _a;
who = _w;
requestCode = _r;
@@ -140,6 +144,9 @@
if (!Objects.equals(packageName, other.packageName)) {
return false;
}
+ if (!Objects.equals(featureId, other.featureId)) {
+ return false;
+ }
if (activity != other.activity) {
return false;
}
@@ -175,7 +182,8 @@
}
public String toString() {
- return "Key{" + typeName() + " pkg=" + packageName
+ return "Key{" + typeName()
+ + " pkg=" + packageName + (featureId != null ? "/" + featureId : "")
+ " intent="
+ (requestIntent != null
? requestIntent.toShortString(false, true, false, false) : "<null>")
@@ -403,19 +411,20 @@
if (key.allIntents != null && key.allIntents.length > 1) {
res = controller.mAtmInternal.startActivitiesInPackage(
- uid, callingPid, callingUid, key.packageName, allIntents,
- allResolvedTypes, resultTo, mergedOptions, userId,
+ uid, callingPid, callingUid, key.packageName, key.featureId,
+ allIntents, allResolvedTypes, resultTo, mergedOptions, userId,
false /* validateIncomingUser */,
this /* originatingPendingIntent */,
mAllowBgActivityStartsForActivitySender.contains(whitelistToken));
} else {
- res = controller.mAtmInternal.startActivityInPackage(
- uid, callingPid, callingUid, key.packageName, finalIntent,
+ res = controller.mAtmInternal.startActivityInPackage(uid, callingPid,
+ callingUid, key.packageName, key.featureId, finalIntent,
resolvedType, resultTo, resultWho, requestCode, 0,
mergedOptions, userId, null, "PendingIntentRecord",
false /* validateIncomingUser */,
this /* originatingPendingIntent */,
- mAllowBgActivityStartsForActivitySender.contains(whitelistToken));
+ mAllowBgActivityStartsForActivitySender.contains(
+ whitelistToken));
}
} catch (RuntimeException e) {
Slog.w(TAG, "Unable to send startActivity intent", e);
@@ -430,11 +439,12 @@
// If a completion callback has been requested, require
// that the broadcast be delivered synchronously
int sent = controller.mAmInternal.broadcastIntentInPackage(key.packageName,
- uid, callingUid, callingPid, finalIntent, resolvedType,
- finishedReceiver, code, null, null, requiredPermission, options,
- (finishedReceiver != null), false, userId,
+ key.featureId, uid, callingUid, callingPid, finalIntent,
+ resolvedType, finishedReceiver, code, null, null,
+ requiredPermission, options, (finishedReceiver != null), false,
+ userId,
mAllowBgActivityStartsForBroadcastSender.contains(whitelistToken)
- || allowTrampoline);
+ || allowTrampoline);
if (sent == ActivityManager.BROADCAST_SUCCESS) {
sendFinish = false;
}
@@ -447,7 +457,7 @@
try {
controller.mAmInternal.startServiceInPackage(uid, finalIntent, resolvedType,
key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE,
- key.packageName, userId,
+ key.packageName, key.featureId, userId,
mAllowBgActivityStartsForServiceSender.contains(whitelistToken)
|| allowTrampoline);
} catch (RuntimeException e) {
@@ -496,6 +506,7 @@
public void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("uid="); pw.print(uid);
pw.print(" packageName="); pw.print(key.packageName);
+ pw.print(" featureId="); pw.print(key.featureId);
pw.print(" type="); pw.print(key.typeName());
pw.print(" flags=0x"); pw.println(Integer.toHexString(key.flags));
if (key.activity != null || key.who != null) {
@@ -545,6 +556,10 @@
sb.append(Integer.toHexString(System.identityHashCode(this)));
sb.append(' ');
sb.append(key.packageName);
+ if (key.featureId != null) {
+ sb.append('/');
+ sb.append(key.featureId);
+ }
sb.append(' ');
sb.append(key.typeName());
if (whitelistDuration != null) {
diff --git a/services/core/java/com/android/server/am/PreBootBroadcaster.java b/services/core/java/com/android/server/am/PreBootBroadcaster.java
index beb0e47..747e8a8 100644
--- a/services/core/java/com/android/server/am/PreBootBroadcaster.java
+++ b/services/core/java/com/android/server/am/PreBootBroadcaster.java
@@ -108,8 +108,8 @@
mIntent.setComponent(componentName);
synchronized (mService) {
- mService.broadcastIntentLocked(null, null, mIntent, null, this, 0, null, null, null,
- AppOpsManager.OP_NONE, null, true, false, ActivityManagerService.MY_PID,
+ mService.broadcastIntentLocked(null, null, null, mIntent, null, this, 0, null, null,
+ null, AppOpsManager.OP_NONE, null, true, false, ActivityManagerService.MY_PID,
Process.SYSTEM_UID, Binder.getCallingUid(), Binder.getCallingPid(), mUserId);
}
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index c75ee04..e575e10 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2447,10 +2447,10 @@
int realCallingPid, @UserIdInt int userId) {
// TODO b/64165549 Verify that mLock is not held before calling AMS methods
synchronized (mService) {
- return mService.broadcastIntentLocked(null, null, intent, resolvedType, resultTo,
- resultCode, resultData, resultExtras, requiredPermissions, appOp, bOptions,
- ordered, sticky, callingPid, callingUid, realCallingUid, realCallingPid,
- userId);
+ return mService.broadcastIntentLocked(null, null, null, intent, resolvedType,
+ resultTo, resultCode, resultData, resultExtras, requiredPermissions, appOp,
+ bOptions, ordered, sticky, callingPid, callingUid, realCallingUid,
+ realCallingPid, userId);
}
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 60f420e..e17c1f8 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -24,7 +24,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.media.AudioDeviceAddress;
+import android.media.AudioDevice;
import android.media.AudioManager;
import android.media.AudioRoutesInfo;
import android.media.AudioSystem;
@@ -402,7 +402,7 @@
}
/*package*/ int setPreferredDeviceForStrategySync(int strategy,
- @NonNull AudioDeviceAddress device) {
+ @NonNull AudioDevice device) {
return mDeviceInventory.setPreferredDeviceForStrategySync(strategy, device);
}
@@ -543,7 +543,7 @@
sendLMsgNoDelay(MSG_L_SCOCLIENT_DIED, SENDMSG_QUEUE, obj);
}
- /*package*/ void postSaveSetPreferredDeviceForStrategy(int strategy, AudioDeviceAddress device)
+ /*package*/ void postSaveSetPreferredDeviceForStrategy(int strategy, AudioDevice device)
{
sendILMsgNoDelay(MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY, SENDMSG_QUEUE, strategy, device);
}
@@ -904,7 +904,7 @@
} break;
case MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY: {
final int strategy = msg.arg1;
- final AudioDeviceAddress device = (AudioDeviceAddress) msg.obj;
+ final AudioDevice device = (AudioDevice) msg.obj;
mDeviceInventory.onSaveSetPreferredDevice(strategy, device);
} break;
case MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY: {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 75d9dd8..1f998c3 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -23,7 +23,7 @@
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothProfile;
import android.content.Intent;
-import android.media.AudioDeviceAddress;
+import android.media.AudioDevice;
import android.media.AudioDevicePort;
import android.media.AudioFormat;
import android.media.AudioManager;
@@ -75,7 +75,7 @@
private final ArrayMap<Integer, String> mApmConnectedDevices = new ArrayMap<>();
// List of preferred devices for strategies
- private final ArrayMap<Integer, AudioDeviceAddress> mPreferredDevices = new ArrayMap<>();
+ private final ArrayMap<Integer, AudioDevice> mPreferredDevices = new ArrayMap<>();
// the wrapper for AudioSystem static methods, allows us to spy AudioSystem
private final @NonNull AudioSystemAdapter mAudioSystem;
@@ -468,7 +468,7 @@
}
}
- /*package*/ void onSaveSetPreferredDevice(int strategy, @NonNull AudioDeviceAddress device) {
+ /*package*/ void onSaveSetPreferredDevice(int strategy, @NonNull AudioDevice device) {
mPreferredDevices.put(strategy, device);
}
@@ -480,7 +480,7 @@
//
/*package*/ int setPreferredDeviceForStrategySync(int strategy,
- @NonNull AudioDeviceAddress device) {
+ @NonNull AudioDevice device) {
final long identity = Binder.clearCallingIdentity();
final int status = mAudioSystem.setPreferredDeviceForStrategy(strategy, device);
Binder.restoreCallingIdentity(identity);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 82a2f01..342ce22 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -65,7 +65,7 @@
import android.hidl.manager.V1_0.IServiceManager;
import android.media.AudioAttributes;
import android.media.AudioAttributes.AttributeSystemUsage;
-import android.media.AudioDeviceAddress;
+import android.media.AudioDevice;
import android.media.AudioDeviceInfo;
import android.media.AudioFocusInfo;
import android.media.AudioFocusRequest;
@@ -1712,7 +1712,7 @@
// IPC methods
///////////////////////////////////////////////////////////////////////////
/** @see AudioManager#setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceInfo) */
- public int setPreferredDeviceForStrategy(int strategy, AudioDeviceAddress device) {
+ public int setPreferredDeviceForStrategy(int strategy, AudioDevice device) {
if (device == null) {
return AudioSystem.ERROR;
}
@@ -1721,7 +1721,7 @@
"setPreferredDeviceForStrategy u/pid:%d/%d strat:%d dev:%s",
Binder.getCallingUid(), Binder.getCallingPid(), strategy, device.toString());
sDeviceLogger.log(new AudioEventLogger.StringEvent(logString).printLog(TAG));
- if (device.getRole() == AudioDeviceAddress.ROLE_INPUT) {
+ if (device.getRole() == AudioDevice.ROLE_INPUT) {
Log.e(TAG, "Unsupported input routing in " + logString);
return AudioSystem.ERROR;
}
@@ -1749,9 +1749,9 @@
}
/** @see AudioManager#getPreferredDeviceForStrategy(AudioProductStrategy) */
- public AudioDeviceAddress getPreferredDeviceForStrategy(int strategy) {
+ public AudioDevice getPreferredDeviceForStrategy(int strategy) {
enforceModifyAudioRoutingPermission();
- AudioDeviceAddress[] devices = new AudioDeviceAddress[1];
+ AudioDevice[] devices = new AudioDevice[1];
final long identity = Binder.clearCallingIdentity();
final int status = AudioSystem.getPreferredDeviceForStrategy(strategy, devices);
Binder.restoreCallingIdentity(identity);
@@ -1765,7 +1765,7 @@
}
/** @see AudioManager#getDevicesForAttributes(AudioAttributes) */
- public @NonNull ArrayList<AudioDeviceAddress> getDevicesForAttributes(
+ public @NonNull ArrayList<AudioDevice> getDevicesForAttributes(
@NonNull AudioAttributes attributes) {
Objects.requireNonNull(attributes);
enforceModifyAudioRoutingPermission();
diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
index 9d06b42..a3086c0 100644
--- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java
+++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
@@ -17,7 +17,7 @@
package com.android.server.audio;
import android.annotation.NonNull;
-import android.media.AudioDeviceAddress;
+import android.media.AudioDevice;
import android.media.AudioSystem;
import android.util.Log;
@@ -86,12 +86,12 @@
}
/**
- * Same as {@link AudioSystem#setPreferredDeviceForStrategy(int, AudioDeviceAddress)}
+ * Same as {@link AudioSystem#setPreferredDeviceForStrategy(int, AudioDevice)}
* @param strategy
* @param device
* @return
*/
- public int setPreferredDeviceForStrategy(int strategy, @NonNull AudioDeviceAddress device) {
+ public int setPreferredDeviceForStrategy(int strategy, @NonNull AudioDevice device) {
return AudioSystem.setPreferredDeviceForStrategy(strategy, device);
}
@@ -138,7 +138,7 @@
}
@Override
- public int setPreferredDeviceForStrategy(int strategy, @NonNull AudioDeviceAddress device) {
+ public int setPreferredDeviceForStrategy(int strategy, @NonNull AudioDevice device) {
return AudioSystem.AUDIO_STATUS_OK;
}
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index 0450647..68ced79 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -272,21 +272,15 @@
List<String> installerCertificates =
getInstallerCertificateFingerprint(installerPackageName);
- // TODO (b/148373316): Figure out what field contains which fields are populated for
- // rotated and the multiple signers. Until then, return the first certificate.
- String appCert = appCertificates.isEmpty() ? "" : appCertificates.get(0);
- String installerCert =
- installerCertificates.isEmpty() ? "" : installerCertificates.get(0);
-
Slog.w(TAG, appCertificates.toString());
AppInstallMetadata.Builder builder = new AppInstallMetadata.Builder();
builder.setPackageName(getPackageNameNormalized(packageName));
- builder.setAppCertificate(appCert);
+ builder.setAppCertificates(appCertificates);
builder.setVersionCode(intent.getLongExtra(EXTRA_LONG_VERSION_CODE, -1));
builder.setInstallerName(getPackageNameNormalized(installerPackageName));
- builder.setInstallerCertificate(installerCert);
+ builder.setInstallerCertificates(installerCertificates);
builder.setIsPreInstalled(isSystemApp(packageName));
AppInstallMetadata appInstallMetadata = builder.build();
@@ -307,7 +301,7 @@
FrameworkStatsLog.write(
FrameworkStatsLog.INTEGRITY_CHECK_RESULT_REPORTED,
packageName,
- appCert,
+ appCertificates.toString(),
appInstallMetadata.getVersionCode(),
installerPackageName,
result.getLoggingResponse(),
diff --git a/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java b/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
index 87eee4e..60e8cce 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
@@ -63,10 +63,12 @@
searchIndexingKeysRangeContainingKey(
sPackageNameBasedIndexes, appInstallMetadata.getPackageName()));
- // Add the range for app certificate indexes rules.
- indexRanges.add(
- searchIndexingKeysRangeContainingKey(
- sAppCertificateBasedIndexes, appInstallMetadata.getAppCertificate()));
+ // Add the range for app certificate indexes rules of all certificates.
+ for (String appCertificate : appInstallMetadata.getAppCertificates()) {
+ indexRanges.add(
+ searchIndexingKeysRangeContainingKey(
+ sAppCertificateBasedIndexes, appCertificate));
+ }
// Add the range for unindexed rules.
indexRanges.add(
diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
index 669f1ac..6474303 100644
--- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java
+++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
@@ -27,6 +27,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.media.AudioManager;
import android.media.MediaRoute2Info;
import android.text.TextUtils;
import android.util.Slog;
@@ -55,6 +56,7 @@
private final Context mContext;
private final BluetoothAdapter mBluetoothAdapter;
private final BluetoothRoutesUpdatedListener mListener;
+ private final AudioManager mAudioManager;
private final Map<String, BluetoothEventReceiver> mEventReceiverMap = new HashMap<>();
private final IntentFilter mIntentFilter = new IntentFilter();
private final BroadcastReceiver mBroadcastReceiver = new BluetoothBroadcastReceiver();
@@ -82,6 +84,7 @@
mContext = context;
mBluetoothAdapter = btAdapter;
mListener = listener;
+ mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
buildBluetoothRoutes();
mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP);
@@ -181,12 +184,15 @@
private BluetoothRouteInfo createBluetoothRoute(BluetoothDevice device) {
BluetoothRouteInfo newBtRoute = new BluetoothRouteInfo();
newBtRoute.btDevice = device;
+ // Current / Max 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())
.addFeature(MediaRoute2Info.FEATURE_LIVE_AUDIO)
.setConnectionState(MediaRoute2Info.CONNECTION_STATE_DISCONNECTED)
.setDescription(mContext.getResources().getText(
R.string.bluetooth_a2dp_audio_route_name).toString())
.setDeviceType(MediaRoute2Info.DEVICE_TYPE_BLUETOOTH)
+ .setVolumeHandling(MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
.build();
newBtRoute.connectedProfiles = new SparseBooleanArray();
return newBtRoute;
@@ -203,10 +209,20 @@
Slog.w(TAG, "setRouteConnectionStateForDevice: route shouldn't be null");
return;
}
- if (btRoute.route.getConnectionState() != state) {
- btRoute.route = new MediaRoute2Info.Builder(btRoute.route)
- .setConnectionState(state).build();
+ if (btRoute.route.getConnectionState() == state) {
+ return;
}
+
+ // Update volume when the connection state is changed.
+ MediaRoute2Info.Builder builder = new MediaRoute2Info.Builder(btRoute.route)
+ .setConnectionState(state);
+
+ 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);
+ }
+ btRoute.route = builder.build();
}
interface BluetoothRoutesUpdatedListener {
diff --git a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
new file mode 100644
index 0000000..58c2707
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
@@ -0,0 +1,360 @@
+/*
+ * 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 com.android.server.media;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ComponentInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
+/**
+ * Holds the media button receiver, and also provides helper methods around it.
+ */
+final class MediaButtonReceiverHolder {
+ public static final int COMPONENT_TYPE_INVALID = 0;
+ public static final int COMPONENT_TYPE_BROADCAST = 1;
+ public static final int COMPONENT_TYPE_ACTIVITY = 2;
+ public static final int COMPONENT_TYPE_SERVICE = 3;
+
+ @IntDef(value = {
+ COMPONENT_TYPE_INVALID,
+ COMPONENT_TYPE_BROADCAST,
+ COMPONENT_TYPE_ACTIVITY,
+ COMPONENT_TYPE_SERVICE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ComponentType {}
+
+ private static final String TAG = "PendingIntentHolder";
+ private static final boolean DEBUG_KEY_EVENT = MediaSessionService.DEBUG_KEY_EVENT;
+ private static final String COMPONENT_NAME_USER_ID_DELIM = ",";
+
+ private final int mUserId;
+ private final PendingIntent mPendingIntent;
+ private final ComponentName mComponentName;
+ private final String mPackageName;
+ @ComponentType
+ private final int mComponentType;
+
+ /**
+ * Unflatten from string which is previously flattened string via flattenToString().
+ * <p>
+ * It's used to store and restore media button receiver across the boot, by keeping the intent's
+ * component name to the persistent storage.
+ *
+ * @param mediaButtonReceiverInfo previously flattened string via flattenToString()
+ * @return new instance if the string was valid. {@code null} otherwise.
+ */
+ public static MediaButtonReceiverHolder unflattenFromString(
+ Context context, String mediaButtonReceiverInfo) {
+ if (TextUtils.isEmpty(mediaButtonReceiverInfo)) {
+ return null;
+ }
+ String[] tokens = mediaButtonReceiverInfo.split(COMPONENT_NAME_USER_ID_DELIM);
+ if (tokens == null || (tokens.length != 2 && tokens.length != 3)) {
+ return null;
+ }
+ ComponentName componentName = ComponentName.unflattenFromString(tokens[0]);
+ int userId = Integer.parseInt(tokens[1]);
+ // Guess component type if the OS version is updated from the older version.
+ int componentType = (tokens.length == 3)
+ ? Integer.parseInt(tokens[2])
+ : getComponentType(context, componentName);
+ return new MediaButtonReceiverHolder(userId, null, componentName, componentType);
+ }
+
+ /**
+ * Creates a new instance.
+ *
+ * @param context context
+ * @param userId userId
+ * @param pendingIntent pending intent
+ * @return Can be {@code null} if pending intent was null.
+ */
+ public static MediaButtonReceiverHolder create(Context context, int userId,
+ PendingIntent pendingIntent) {
+ if (pendingIntent == null) {
+ return null;
+ }
+ ComponentName componentName = (pendingIntent != null && pendingIntent.getIntent() != null)
+ ? pendingIntent.getIntent().getComponent() : null;
+ if (componentName != null) {
+ // Explicit intent, where component name is in the PendingIntent.
+ return new MediaButtonReceiverHolder(userId, pendingIntent, componentName,
+ getComponentType(context, componentName));
+ }
+
+ // Implicit intent, where component name isn't in the PendingIntent. Try resolve.
+ PackageManager pm = context.getPackageManager();
+ Intent intent = pendingIntent.getIntent();
+ if ((componentName = resolveImplicitServiceIntent(pm, intent)) != null) {
+ return new MediaButtonReceiverHolder(
+ userId, pendingIntent, componentName, COMPONENT_TYPE_SERVICE);
+ } else if ((componentName = resolveManifestDeclaredBroadcastReceiverIntent(pm, intent))
+ != null) {
+ return new MediaButtonReceiverHolder(
+ userId, pendingIntent, componentName, COMPONENT_TYPE_BROADCAST);
+ } else if ((componentName = resolveImplicitActivityIntent(pm, intent)) != null) {
+ return new MediaButtonReceiverHolder(
+ userId, pendingIntent, componentName, COMPONENT_TYPE_ACTIVITY);
+ }
+
+ // Failed to resolve target component for the pending intent. It's unlikely to be usable.
+ // However, the pending intent would be still used, just to follow the legacy behavior.
+ Log.w(TAG, "Unresolvable implicit intent is set, pi=" + pendingIntent);
+ String packageName = (pendingIntent != null && pendingIntent.getIntent() != null)
+ ? pendingIntent.getIntent().getPackage() : null;
+ return new MediaButtonReceiverHolder(userId, pendingIntent,
+ packageName != null ? packageName : "");
+ }
+
+ private MediaButtonReceiverHolder(int userId, PendingIntent pendingIntent,
+ ComponentName componentName, @ComponentType int componentType) {
+ mUserId = userId;
+ mPendingIntent = pendingIntent;
+ mComponentName = componentName;
+ mPackageName = componentName.getPackageName();
+ mComponentType = componentType;
+ }
+
+ private MediaButtonReceiverHolder(int userId, PendingIntent pendingIntent, String packageName) {
+ mUserId = userId;
+ mPendingIntent = pendingIntent;
+ mComponentName = null;
+ mPackageName = packageName;
+ mComponentType = COMPONENT_TYPE_INVALID;
+ }
+
+ /**
+ * @return the user id
+ */
+ public int getUserId() {
+ return mUserId;
+ }
+
+ /**
+ * @return package name that the media button receiver would be sent to.
+ */
+ @NonNull
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ /**
+ * Sends the media key event to the media button receiver.
+ * <p>
+ * This prioritizes using use pending intent for sending media key event.
+ *
+ * @param context context to be used to call PendingIntent#send
+ * @param keyEvent keyEvent to send
+ * @param resultCode result code to be used to call PendingIntent#send
+ * Ignored if there's no valid pending intent.
+ * @param onFinishedListener callback to be used to get result of PendingIntent#send.
+ * Ignored if there's no valid pending intent.
+ * @param handler handler to be used to call onFinishedListener
+ * Ignored if there's no valid pending intent.
+ * @see PendingIntent#send(Context, int, Intent, PendingIntent.OnFinished, Handler)
+ */
+ public boolean send(Context context, KeyEvent keyEvent, String callingPackageName,
+ int resultCode, PendingIntent.OnFinished onFinishedListener, Handler handler) {
+ Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+ mediaButtonIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+ // TODO: Find a way to also send PID/UID in secure way.
+ mediaButtonIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, callingPackageName);
+
+ if (mPendingIntent != null) {
+ if (DEBUG_KEY_EVENT) {
+ Log.d(TAG, "Sending " + keyEvent + " to the last known PendingIntent "
+ + mPendingIntent);
+ }
+ try {
+ mPendingIntent.send(
+ context, resultCode, mediaButtonIntent, onFinishedListener, handler);
+ } catch (PendingIntent.CanceledException e) {
+ Log.w(TAG, "Error sending key event to media button receiver " + mPendingIntent, e);
+ return false;
+ }
+ } else if (mComponentName != null) {
+ if (DEBUG_KEY_EVENT) {
+ Log.d(TAG, "Sending " + keyEvent + " to the restored intent "
+ + mComponentName + ", type=" + mComponentType);
+ }
+ mediaButtonIntent.setComponent(mComponentName);
+ UserHandle userHandle = UserHandle.of(mUserId);
+ try {
+ switch (mComponentType) {
+ case COMPONENT_TYPE_ACTIVITY:
+ context.startActivityAsUser(mediaButtonIntent, userHandle);
+ break;
+ case COMPONENT_TYPE_SERVICE:
+ context.startForegroundServiceAsUser(mediaButtonIntent,
+ userHandle);
+ break;
+ default:
+ // Legacy behavior for other cases.
+ context.sendBroadcastAsUser(mediaButtonIntent, userHandle);
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Error sending media button to the restored intent "
+ + mComponentName + ", type=" + mComponentType, e);
+ return false;
+ }
+ } else {
+ // Leave log, just in case.
+ Log.e(TAG, "Shouldn't be happen -- pending intent or component name must be set");
+ return false;
+ }
+ return true;
+ }
+
+
+ @Override
+ public String toString() {
+ if (mPendingIntent != null) {
+ return "MBR {pi=" + mPendingIntent + ", type=" + mComponentType + "}";
+ }
+ return "Restored MBR {component=" + mComponentName + ", type=" + mComponentType + "}";
+ }
+
+ /**
+ * @return flattened string. Can be empty string if the MBR is created with implicit intent.
+ */
+ public String flattenToString() {
+ if (mComponentName == null) {
+ // We don't know which component would receive the key event.
+ return "";
+ }
+ return String.join(COMPONENT_NAME_USER_ID_DELIM,
+ mComponentName.toString(),
+ String.valueOf(mUserId),
+ String.valueOf(mComponentType));
+ }
+
+ /**
+ * Gets the type of the component
+ *
+ * @param context context
+ * @param componentName component name
+ * @return A component type
+ */
+ @ComponentType
+ private static int getComponentType(Context context, ComponentName componentName) {
+ if (componentName == null) {
+ return COMPONENT_TYPE_INVALID;
+ }
+ PackageManager pm = context.getPackageManager();
+ try {
+ ActivityInfo activityInfo = pm.getActivityInfo(componentName,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.GET_ACTIVITIES);
+ if (activityInfo != null) {
+ return COMPONENT_TYPE_ACTIVITY;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+ try {
+ ServiceInfo serviceInfo = pm.getServiceInfo(componentName,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.GET_SERVICES);
+ if (serviceInfo != null) {
+ return COMPONENT_TYPE_SERVICE;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+ // Pick legacy behavior for BroadcastReceiver or unknown.
+ return COMPONENT_TYPE_BROADCAST;
+ }
+
+ private static ComponentName resolveImplicitServiceIntent(PackageManager pm, Intent intent) {
+ // Flag explanations.
+ // - MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE:
+ // filter apps regardless of the phone's locked/unlocked state.
+ // - GET_SERVICES: Return service
+ return createComponentName(pm.resolveService(intent,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.GET_SERVICES));
+ }
+
+ private static ComponentName resolveManifestDeclaredBroadcastReceiverIntent(
+ PackageManager pm, Intent intent) {
+ // Flag explanations.
+ // - MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE:
+ // filter apps regardless of the phone's locked/unlocked state.
+ List<ResolveInfo> resolveInfos = pm.queryBroadcastReceivers(intent,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
+ return (resolveInfos != null && !resolveInfos.isEmpty())
+ ? createComponentName(resolveInfos.get(0)) : null;
+ }
+
+ private static ComponentName resolveImplicitActivityIntent(PackageManager pm, Intent intent) {
+ // Flag explanations.
+ // - MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE:
+ // Filter apps regardless of the phone's locked/unlocked state.
+ // - MATCH_DEFAULT_ONLY:
+ // Implicit intent receiver should be set as default. Only needed for activity.
+ // - GET_ACTIVITIES: Return activity
+ return createComponentName(pm.resolveActivity(intent,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_DEFAULT_ONLY
+ | PackageManager.GET_ACTIVITIES));
+ }
+
+ private static ComponentName createComponentName(ResolveInfo resolveInfo) {
+ if (resolveInfo == null) {
+ return null;
+ }
+ ComponentInfo componentInfo;
+ // Code borrowed from ResolveInfo#getComponentInfo().
+ if (resolveInfo.activityInfo != null) {
+ componentInfo = resolveInfo.activityInfo;
+ } else if (resolveInfo.serviceInfo != null) {
+ componentInfo = resolveInfo.serviceInfo;
+ } else {
+ // We're not interested in content provider.
+ return null;
+ }
+ // Code borrowed from ComponentInfo#getComponentName().
+ try {
+ return new ComponentName(componentInfo.packageName, componentInfo.name);
+ } catch (IllegalArgumentException | NullPointerException e) {
+ // This may be happen if resolveActivity() end up with matching multiple activities.
+ // see PackageManager#resolveActivity().
+ return null;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 7bcbcd4..9f47b34 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -127,7 +127,7 @@
new ArrayList<>();
private long mFlags;
- private PendingIntent mMediaButtonReceiver;
+ private MediaButtonReceiverHolder mMediaButtonReceiverHolder;
private PendingIntent mLaunchIntent;
// TransportPerformer fields
@@ -220,8 +220,8 @@
*
* @return The pending intent set by the app or null.
*/
- public PendingIntent getMediaButtonReceiver() {
- return mMediaButtonReceiver;
+ public MediaButtonReceiverHolder getMediaButtonReceiver() {
+ return mMediaButtonReceiverHolder;
}
/**
@@ -471,7 +471,7 @@
+ ", userId=" + mUserId);
pw.println(indent + "package=" + mPackageName);
pw.println(indent + "launchIntent=" + mLaunchIntent);
- pw.println(indent + "mediaButtonReceiver=" + mMediaButtonReceiver);
+ pw.println(indent + "mediaButtonReceiver=" + mMediaButtonReceiverHolder);
pw.println(indent + "active=" + mIsActive);
pw.println(indent + "flags=" + mFlags);
pw.println(indent + "rating type=" + mRatingType);
@@ -833,12 +833,14 @@
@Override
public void setMediaButtonReceiver(PendingIntent pi) throws RemoteException {
- if ((mPolicies & SessionPolicyProvider.SESSION_POLICY_IGNORE_BUTTON_RECEIVER) == 1) {
- return;
- }
- mMediaButtonReceiver = pi;
final long token = Binder.clearCallingIdentity();
try {
+ if ((mPolicies & SessionPolicyProvider.SESSION_POLICY_IGNORE_BUTTON_RECEIVER)
+ != 0) {
+ return;
+ }
+ mMediaButtonReceiverHolder =
+ MediaButtonReceiverHolder.create(mContext, mUserId, pi);
mService.onMediaButtonReceiverChanged(MediaSessionRecord.this);
} finally {
Binder.restoreCallingIdentity(token);
@@ -1529,5 +1531,4 @@
msg.sendToTarget();
}
}
-
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 88b884e..7ffac06 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -18,22 +18,17 @@
import static android.os.UserHandle.USER_ALL;
-import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.INotificationManager;
import android.app.KeyguardManager;
import android.app.PendingIntent;
-import android.app.PendingIntent.CanceledException;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
-import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.media.AudioManager;
@@ -99,7 +94,7 @@
private static final String TAG = "MediaSessionService";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
// Leave log for key event always.
- private static final boolean DEBUG_KEY_EVENT = true;
+ static final boolean DEBUG_KEY_EVENT = true;
private static final int WAKELOCK_TIMEOUT = 5000;
private static final int MEDIA_KEY_LISTENER_TIMEOUT = 1000;
@@ -760,12 +755,6 @@
* <p>The contents of this object is guarded by {@link #mLock}.
*/
final class FullUserRecord implements MediaSessionStack.OnMediaButtonSessionChangedListener {
- public static final int COMPONENT_TYPE_INVALID = 0;
- public static final int COMPONENT_TYPE_BROADCAST = 1;
- public static final int COMPONENT_TYPE_ACTIVITY = 2;
- public static final int COMPONENT_TYPE_SERVICE = 3;
- private static final String COMPONENT_NAME_USER_ID_DELIM = ",";
-
private final int mFullUserId;
private final MediaSessionStack mPriorityStack;
private final HashMap<IBinder, OnMediaKeyEventDispatchedListenerRecord>
@@ -774,10 +763,7 @@
mOnMediaKeyEventSessionChangedListeners = new HashMap<>();
private final SparseIntArray mUidToSessionCount = new SparseIntArray();
- private PendingIntent mLastMediaButtonReceiver;
- private ComponentName mRestoredMediaButtonReceiver;
- private int mRestoredMediaButtonReceiverComponentType;
- private int mRestoredMediaButtonReceiverUserId;
+ private MediaButtonReceiverHolder mLastMediaButtonReceiverHolder;
private IOnVolumeKeyLongPressListener mOnVolumeKeyLongPressListener;
private int mOnVolumeKeyLongPressListenerUid;
@@ -794,21 +780,9 @@
// Restore the remembered media button receiver before the boot.
String mediaButtonReceiverInfo = Settings.Secure.getStringForUser(mContentResolver,
Settings.System.MEDIA_BUTTON_RECEIVER, mFullUserId);
- if (mediaButtonReceiverInfo == null) {
- return;
- }
- String[] tokens = mediaButtonReceiverInfo.split(COMPONENT_NAME_USER_ID_DELIM);
- if (tokens == null || (tokens.length != 2 && tokens.length != 3)) {
- return;
- }
- mRestoredMediaButtonReceiver = ComponentName.unflattenFromString(tokens[0]);
- mRestoredMediaButtonReceiverUserId = Integer.parseInt(tokens[1]);
- if (tokens.length == 3) {
- mRestoredMediaButtonReceiverComponentType = Integer.parseInt(tokens[2]);
- } else {
- mRestoredMediaButtonReceiverComponentType =
- getComponentType(mRestoredMediaButtonReceiver);
- }
+ mLastMediaButtonReceiverHolder =
+ MediaButtonReceiverHolder.unflattenFromString(
+ mContext, mediaButtonReceiverInfo);
}
public void destroySessionsForUserLocked(int userId) {
@@ -892,10 +866,7 @@
: mOnMediaKeyEventSessionChangedListeners.values()) {
pw.println(indent + " from " + getCallingPackageName(cr.uid));
}
- pw.println(indent + "Last MediaButtonReceiver: " + mLastMediaButtonReceiver);
- pw.println(indent + "Restored MediaButtonReceiver: " + mRestoredMediaButtonReceiver);
- pw.println(indent + "Restored MediaButtonReceiverComponentType: "
- + mRestoredMediaButtonReceiverComponentType);
+ pw.println(indent + "Last MediaButtonReceiver: " + mLastMediaButtonReceiverHolder);
mPriorityStack.dump(pw, indent);
}
@@ -924,25 +895,12 @@
return;
}
MediaSessionRecord sessionRecord = (MediaSessionRecord) record;
- PendingIntent receiver = sessionRecord.getMediaButtonReceiver();
- mLastMediaButtonReceiver = receiver;
- mRestoredMediaButtonReceiver = null;
- mRestoredMediaButtonReceiverComponentType = COMPONENT_TYPE_INVALID;
-
- String mediaButtonReceiverInfo = "";
- if (receiver != null) {
- ComponentName component = receiver.getIntent().getComponent();
- if (component != null
- && record.getPackageName().equals(component.getPackageName())) {
- String componentName = component.flattenToString();
- int componentType = getComponentType(component);
- mediaButtonReceiverInfo = String.join(COMPONENT_NAME_USER_ID_DELIM,
- componentName, String.valueOf(record.getUserId()),
- String.valueOf(componentType));
- }
- }
+ mLastMediaButtonReceiverHolder = sessionRecord.getMediaButtonReceiver();
+ String mediaButtonReceiverInfo = (mLastMediaButtonReceiverHolder == null)
+ ? "" : mLastMediaButtonReceiverHolder.flattenToString();
Settings.Secure.putStringForUser(mContentResolver,
- Settings.System.MEDIA_BUTTON_RECEIVER, mediaButtonReceiverInfo,
+ Settings.System.MEDIA_BUTTON_RECEIVER,
+ mediaButtonReceiverInfo,
mFullUserId);
}
@@ -958,15 +916,9 @@
} else {
// TODO(jaewan): Implement
}
- } else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) {
- callback.onMediaKeyEventSessionChanged(
- mCurrentFullUserRecord.mLastMediaButtonReceiver
- .getIntent().getComponent().getPackageName(),
- null);
- } else if (mCurrentFullUserRecord.mRestoredMediaButtonReceiver != null) {
- callback.onMediaKeyEventSessionChanged(
- mCurrentFullUserRecord.mRestoredMediaButtonReceiver.getPackageName(),
- null);
+ } else if (mCurrentFullUserRecord.mLastMediaButtonReceiverHolder != null) {
+ String packageName = mLastMediaButtonReceiverHolder.getPackageName();
+ callback.onMediaKeyEventSessionChanged(packageName, null);
}
} catch (RemoteException e) {
Log.w(TAG, "Failed to pushAddressedPlayerChangedLocked", e);
@@ -985,35 +937,6 @@
? mGlobalPrioritySession : mPriorityStack.getMediaButtonSession();
}
- private int getComponentType(@Nullable ComponentName componentName) {
- if (componentName == null) {
- return COMPONENT_TYPE_INVALID;
- }
- PackageManager pm = mContext.getPackageManager();
- try {
- ActivityInfo activityInfo = pm.getActivityInfo(componentName,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.GET_ACTIVITIES);
- if (activityInfo != null) {
- return COMPONENT_TYPE_ACTIVITY;
- }
- } catch (NameNotFoundException e) {
- }
- try {
- ServiceInfo serviceInfo = pm.getServiceInfo(componentName,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.GET_SERVICES);
- if (serviceInfo != null) {
- return COMPONENT_TYPE_SERVICE;
- }
- } catch (NameNotFoundException e) {
- }
- // Pick legacy behavior for BroadcastReceiver or unknown.
- return COMPONENT_TYPE_BROADCAST;
- }
-
final class OnMediaKeyEventDispatchedListenerRecord implements IBinder.DeathRecipient {
public final IOnMediaKeyEventDispatchedListener callback;
public final int uid;
@@ -2166,79 +2089,31 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed to send callback", e);
}
- } else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null
- || mCurrentFullUserRecord.mRestoredMediaButtonReceiver != null) {
+ } else if (mCurrentFullUserRecord.mLastMediaButtonReceiverHolder != null) {
if (needWakeLock) {
mKeyEventReceiver.acquireWakeLockLocked();
}
- Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
- mediaButtonIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
- // TODO: Find a way to also send PID/UID in secure way.
- String callerPackageName =
+ String callingPackageName =
(asSystemService) ? mContext.getPackageName() : packageName;
- mediaButtonIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, callerPackageName);
- try {
- if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) {
- PendingIntent receiver = mCurrentFullUserRecord.mLastMediaButtonReceiver;
- if (DEBUG_KEY_EVENT) {
- Log.d(TAG, "Sending " + keyEvent
- + " to the last known PendingIntent " + receiver);
- }
- receiver.send(mContext,
- needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
- mediaButtonIntent, mKeyEventReceiver, mHandler);
- ComponentName componentName = mCurrentFullUserRecord
- .mLastMediaButtonReceiver.getIntent().getComponent();
- if (componentName != null) {
- for (FullUserRecord.OnMediaKeyEventDispatchedListenerRecord cr
- : mCurrentFullUserRecord
- .mOnMediaKeyEventDispatchedListeners.values()) {
- cr.callback.onMediaKeyEventDispatched(keyEvent,
- componentName.getPackageName(), null);
- }
- }
- } else {
- ComponentName receiver =
- mCurrentFullUserRecord.mRestoredMediaButtonReceiver;
- int componentType = mCurrentFullUserRecord
- .mRestoredMediaButtonReceiverComponentType;
- UserHandle userHandle = UserHandle.of(mCurrentFullUserRecord
- .mRestoredMediaButtonReceiverUserId);
- if (DEBUG_KEY_EVENT) {
- Log.d(TAG, "Sending " + keyEvent + " to the restored intent "
- + receiver + ", type=" + componentType);
- }
- mediaButtonIntent.setComponent(receiver);
+
+ MediaButtonReceiverHolder mediaButtonReceiverHolder =
+ mCurrentFullUserRecord.mLastMediaButtonReceiverHolder;
+
+ boolean sent = mediaButtonReceiverHolder.send(
+ mContext, keyEvent, callingPackageName,
+ needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1, mKeyEventReceiver,
+ mHandler);
+ if (sent) {
+ String pkgName = mediaButtonReceiverHolder.getPackageName();
+ for (FullUserRecord.OnMediaKeyEventDispatchedListenerRecord cr
+ : mCurrentFullUserRecord
+ .mOnMediaKeyEventDispatchedListeners.values()) {
try {
- switch (componentType) {
- case FullUserRecord.COMPONENT_TYPE_ACTIVITY:
- mContext.startActivityAsUser(mediaButtonIntent, userHandle);
- break;
- case FullUserRecord.COMPONENT_TYPE_SERVICE:
- mContext.startForegroundServiceAsUser(mediaButtonIntent,
- userHandle);
- break;
- default:
- // Legacy behavior for other cases.
- mContext.sendBroadcastAsUser(mediaButtonIntent, userHandle);
- }
- } catch (Exception e) {
- Log.w(TAG, "Error sending media button to the restored intent "
- + receiver + ", type=" + componentType, e);
- }
- for (FullUserRecord.OnMediaKeyEventDispatchedListenerRecord cr
- : mCurrentFullUserRecord
- .mOnMediaKeyEventDispatchedListeners.values()) {
- cr.callback.onMediaKeyEventDispatched(keyEvent,
- receiver.getPackageName(), null);
+ cr.callback.onMediaKeyEventDispatched(keyEvent, pkgName, null);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed notify key event dispatch, uid=" + cr.uid, e);
}
}
- } catch (CanceledException e) {
- Log.i(TAG, "Error sending key event to media button receiver "
- + mCurrentFullUserRecord.mLastMediaButtonReceiver, e);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to send callback", e);
}
}
}
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index 888f7ce..b5dcea8 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -20,9 +20,11 @@
import static android.media.MediaRoute2Info.FEATURE_LIVE_VIDEO;
import android.annotation.NonNull;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.media.AudioManager;
import android.media.AudioRoutesInfo;
import android.media.IAudioRoutesObserver;
@@ -107,6 +109,9 @@
}
});
initializeSessionInfo();
+
+ mContext.registerReceiver(new VolumeChangeReceiver(),
+ new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION));
}
@Override
@@ -278,4 +283,44 @@
}
mCallback.onSessionUpdated(this, sessionInfo);
}
+
+ private class VolumeChangeReceiver 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)) {
+ return;
+ }
+
+ final 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) {
+ String activeBtDeviceAddress = mBtRouteProvider.getActiveDeviceAddress();
+ if (!TextUtils.isEmpty(activeBtDeviceAddress)) {
+ for (int i = mBluetoothRoutes.size() - 1; i >= 0; i--) {
+ MediaRoute2Info route = mBluetoothRoutes.get(i);
+ if (TextUtils.equals(activeBtDeviceAddress, route.getId())) {
+ mBluetoothRoutes.set(i,
+ new MediaRoute2Info.Builder(route)
+ .setVolume(newVolume)
+ .build());
+ break;
+ }
+ }
+ } else {
+ mDefaultRoute = new MediaRoute2Info.Builder(mDefaultRoute)
+ .setVolume(newVolume)
+ .build();
+ }
+ publishRoutes();
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
index e8cb163..061cbd8 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
@@ -170,6 +170,11 @@
mFileWriteHandler.post(rpr);
}
+ public void deleteNotificationHistoryItem(String pkg, long postedTime) {
+ RemoveNotificationRunnable rnr = new RemoveNotificationRunnable(pkg, postedTime);
+ mFileWriteHandler.post(rnr);
+ }
+
public void addNotification(final HistoricalNotification notification) {
synchronized (mLock) {
mBuffer.addNewNotificationToWrite(notification);
@@ -367,6 +372,49 @@
}
}
+ final class RemoveNotificationRunnable implements Runnable {
+ private String mPkg;
+ private long mPostedTime;
+ private NotificationHistory mNotificationHistory;
+
+ public RemoveNotificationRunnable(String pkg, long postedTime) {
+ mPkg = pkg;
+ mPostedTime = postedTime;
+ }
+
+ @VisibleForTesting
+ void setNotificationHistory(NotificationHistory nh) {
+ mNotificationHistory = nh;
+ }
+
+ @Override
+ public void run() {
+ if (DEBUG) Slog.d(TAG, "RemovePackageRunnable");
+ synchronized (mLock) {
+ // Remove from pending history
+ mBuffer.removeNotificationFromWrite(mPkg, mPostedTime);
+
+ Iterator<AtomicFile> historyFileItr = mHistoryFiles.iterator();
+ while (historyFileItr.hasNext()) {
+ final AtomicFile af = historyFileItr.next();
+ try {
+ NotificationHistory notificationHistory = mNotificationHistory != null
+ ? mNotificationHistory
+ : new NotificationHistory();
+ readLocked(af, notificationHistory,
+ new NotificationHistoryFilter.Builder().build());
+ if(notificationHistory.removeNotificationFromWrite(mPkg, mPostedTime)) {
+ writeLocked(af, notificationHistory);
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Cannot clean up file on notification removal "
+ + af.getBaseFile().getName(), e);
+ }
+ }
+ }
+ }
+ }
+
public static final class NotificationHistoryFileAttrProvider implements
NotificationHistoryDatabase.FileAttrProvider {
final static String TAG = "NotifHistoryFileDate";
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryManager.java b/services/core/java/com/android/server/notification/NotificationHistoryManager.java
index 41bc29f..9aab0fd 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryManager.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryManager.java
@@ -130,7 +130,7 @@
}
}
- public void onPackageRemoved(int userId, String packageName) {
+ public void onPackageRemoved(@UserIdInt int userId, String packageName) {
synchronized (mLock) {
if (!mUserUnlockedStates.get(userId, false)) {
if (mHistoryEnabled.get(userId, false)) {
@@ -150,6 +150,22 @@
}
}
+ public void deleteNotificationHistoryItem(String pkg, int uid, long postedTime) {
+ synchronized (mLock) {
+ int userId = UserHandle.getUserId(uid);
+ final NotificationHistoryDatabase userHistory =
+ getUserHistoryAndInitializeIfNeededLocked(userId);
+ // TODO: it shouldn't be possible to delete a notification entry while the user is
+ // locked but we should handle it
+ if (userHistory == null) {
+ Slog.w(TAG, "Attempted to remove notif for locked/gone/disabled user "
+ + userId);
+ return;
+ }
+ userHistory.deleteNotificationHistoryItem(pkg, postedTime);
+ }
+ }
+
// TODO: wire this up to AMS when power button is long pressed
public void triggerWriteToDisk() {
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f071135..7ffd899 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -193,6 +193,7 @@
import android.provider.Settings;
import android.service.notification.Adjustment;
import android.service.notification.Condition;
+import android.service.notification.ConversationChannelWrapper;
import android.service.notification.IConditionProvider;
import android.service.notification.INotificationListener;
import android.service.notification.IStatusBarNotificationHolder;
@@ -2780,7 +2781,7 @@
if (!isSystemToast) {
int count = 0;
final int N = mToastQueue.size();
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
final ToastRecord r = mToastQueue.get(i);
if (r.pkg.equals(pkg)) {
count++;
@@ -2820,7 +2821,7 @@
if (pkg == null || token == null) {
Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " token=" + token);
- return ;
+ return;
}
synchronized (mToastQueue) {
@@ -2933,14 +2934,14 @@
/**
* Updates the enabled state for notifications for the given package (and uid).
- * Additionally, this method marks the app importance as locked by the user, which means
+ * Additionally, this method marks the app importance as locked by the user, which
+ * means
* that notifications from the app will <b>not</b> be considered for showing a
* blocking helper.
*
- * @param pkg package that owns the notifications to update
- * @param uid uid of the app providing notifications
+ * @param pkg package that owns the notifications to update
+ * @param uid uid of the app providing notifications
* @param enabled whether notifications should be enabled for the app
- *
* @see #setNotificationsEnabledForPackage(String, int, boolean)
*/
@Override
@@ -3031,6 +3032,12 @@
}
@Override
+ public void deleteNotificationHistoryItem(String pkg, int uid, long postedTime) {
+ checkCallerIsSystem();
+ mHistoryManager.deleteNotificationHistoryItem(pkg, uid, postedTime);
+ }
+
+ @Override
public int getPackageImportance(String pkg) {
checkCallerIsSystemOrSameApp(pkg);
return mPreferencesHelper.getImportance(pkg, Binder.getCallingUid());
@@ -3215,9 +3222,10 @@
@Override
public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
- String channelId, boolean includeDeleted) {
+ String channelId, String conversationId, boolean includeDeleted) {
checkCallerIsSystem();
- return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
+ return mPreferencesHelper.getConversationNotificationChannel(
+ pkg, uid, channelId, conversationId, true, includeDeleted);
}
@Override
@@ -3354,6 +3362,27 @@
}
@Override
+ public ParceledListSlice<ConversationChannelWrapper> getConversationsForPackage(String pkg,
+ int uid) {
+ enforceSystemOrSystemUI("getConversationsForPackage");
+ ArrayList<ConversationChannelWrapper> conversations =
+ mPreferencesHelper.getConversations(pkg, uid);
+ for (ConversationChannelWrapper conversation : conversations) {
+ LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery()
+ .setPackage(pkg)
+ .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED)
+ .setShortcutIds(Arrays.asList(
+ conversation.getNotificationChannel().getConversationId()));
+ List<ShortcutInfo> shortcuts = mLauncherAppsService.getShortcuts(
+ query, UserHandle.of(UserHandle.getUserId(uid)));
+ if (shortcuts != null && !shortcuts.isEmpty()) {
+ conversation.setShortcutInfo(shortcuts.get(0));
+ }
+ }
+ return new ParceledListSlice<>(conversations);
+ }
+
+ @Override
public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(
String pkg, int uid, String groupId, boolean includeDeleted) {
enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage");
@@ -7434,13 +7463,15 @@
}
@GuardedBy("mNotificationLock")
- private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
+ private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete,
+ @NotificationListenerService.NotificationCancelReason int reason,
boolean wasPosted, String listenerName) {
cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName);
}
@GuardedBy("mNotificationLock")
- private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
+ private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete,
+ @NotificationListenerService.NotificationCancelReason int reason,
int rank, int count, boolean wasPosted, String listenerName) {
final String canceledKey = r.getKey();
@@ -7558,6 +7589,10 @@
EventLogTags.writeNotificationCanceled(canceledKey, reason,
r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
rank, count, listenerName);
+ if (wasPosted) {
+ mNotificationRecordLogger.logNotificationCancelled(r, reason,
+ r.getStats().getDismissalSurface());
+ }
}
@VisibleForTesting
@@ -9256,7 +9291,7 @@
}
BackgroundThread.getHandler().post(() -> {
- if (hasCompanionDevice(serviceInfo)) {
+ if (serviceInfo.isSystem || hasCompanionDevice(serviceInfo)) {
notifyNotificationChannelChanged(
serviceInfo, pkg, user, channel, modificationType);
}
@@ -9276,7 +9311,7 @@
}
BackgroundThread.getHandler().post(() -> {
- if (hasCompanionDevice(serviceInfo)) {
+ if (serviceInfo.isSystem || hasCompanionDevice(serviceInfo)) {
notifyNotificationChannelGroupChanged(
serviceInfo, pkg, user, group, modificationType);
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
index 8d8511f..fc2d9e7 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLogger.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
@@ -16,10 +16,16 @@
package com.android.server.notification;
+import static android.service.notification.NotificationListenerService.REASON_CANCEL;
+import static android.service.notification.NotificationListenerService.REASON_CLICK;
+import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
+
import android.annotation.Nullable;
import android.app.Notification;
import android.app.Person;
import android.os.Bundle;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationStats;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
@@ -44,22 +50,144 @@
int position, int buzzBeepBlink);
/**
+ * Logs a notification cancel / dismiss event using UiEventReported (event ids from the
+ * NotificationCancelledEvents enum).
+ * @param r The NotificationRecord. If null, no action is taken.
+ * @param reason The reason the notification was canceled.
+ * @param dismissalSurface The surface the notification was dismissed from.
+ */
+ void logNotificationCancelled(@Nullable NotificationRecord r,
+ @NotificationListenerService.NotificationCancelReason int reason,
+ @NotificationStats.DismissalSurface int dismissalSurface);
+
+ /**
* The UiEvent enums that this class can log.
*/
- enum NotificationReportedEvents implements UiEventLogger.UiEventEnum {
- INVALID(0),
+ enum NotificationReportedEvent implements UiEventLogger.UiEventEnum {
@UiEvent(doc = "New notification enqueued to post")
NOTIFICATION_POSTED(162),
- @UiEvent(doc = "Notification substantially updated")
+ @UiEvent(doc = "Notification substantially updated, or alerted again.")
NOTIFICATION_UPDATED(163);
private final int mId;
- NotificationReportedEvents(int id) {
+ NotificationReportedEvent(int id) {
mId = id;
}
@Override public int getId() {
return mId;
}
+
+ public static NotificationReportedEvent fromRecordPair(NotificationRecordPair p) {
+ return (p.old != null) ? NotificationReportedEvent.NOTIFICATION_UPDATED :
+ NotificationReportedEvent.NOTIFICATION_POSTED;
+ }
+ }
+
+ enum NotificationCancelledEvent implements UiEventLogger.UiEventEnum {
+ INVALID(0),
+ @UiEvent(doc = "Notification was canceled due to a notification click.")
+ NOTIFICATION_CANCEL_CLICK(164),
+ @UiEvent(doc = "Notification was canceled due to a user dismissal, surface not specified.")
+ NOTIFICATION_CANCEL_USER_OTHER(165),
+ @UiEvent(doc = "Notification was canceled due to a user dismiss-all (from the notification"
+ + " shade).")
+ NOTIFICATION_CANCEL_USER_CANCEL_ALL(166),
+ @UiEvent(doc = "Notification was canceled due to an inflation error.")
+ NOTIFICATION_CANCEL_ERROR(167),
+ @UiEvent(doc = "Notification was canceled by the package manager modifying the package.")
+ NOTIFICATION_CANCEL_PACKAGE_CHANGED(168),
+ @UiEvent(doc = "Notification was canceled by the owning user context being stopped.")
+ NOTIFICATION_CANCEL_USER_STOPPED(169),
+ @UiEvent(doc = "Notification was canceled by the user banning the package.")
+ NOTIFICATION_CANCEL_PACKAGE_BANNED(170),
+ @UiEvent(doc = "Notification was canceled by the app canceling this specific notification.")
+ NOTIFICATION_CANCEL_APP_CANCEL(171),
+ @UiEvent(doc = "Notification was canceled by the app cancelling all its notifications.")
+ NOTIFICATION_CANCEL_APP_CANCEL_ALL(172),
+ @UiEvent(doc = "Notification was canceled by a listener reporting a user dismissal.")
+ NOTIFICATION_CANCEL_LISTENER_CANCEL(173),
+ @UiEvent(doc = "Notification was canceled by a listener reporting a user dismiss all.")
+ NOTIFICATION_CANCEL_LISTENER_CANCEL_ALL(174),
+ @UiEvent(doc = "Notification was canceled because it was a member of a canceled group.")
+ NOTIFICATION_CANCEL_GROUP_SUMMARY_CANCELED(175),
+ @UiEvent(doc = "Notification was canceled because it was an invisible member of a group.")
+ NOTIFICATION_CANCEL_GROUP_OPTIMIZATION(176),
+ @UiEvent(doc = "Notification was canceled by the device administrator suspending the "
+ + "package.")
+ NOTIFICATION_CANCEL_PACKAGE_SUSPENDED(177),
+ @UiEvent(doc = "Notification was canceled by the owning managed profile being turned off.")
+ NOTIFICATION_CANCEL_PROFILE_TURNED_OFF(178),
+ @UiEvent(doc = "Autobundled summary notification was canceled because its group was "
+ + "unbundled")
+ NOTIFICATION_CANCEL_UNAUTOBUNDLED(179),
+ @UiEvent(doc = "Notification was canceled by the user banning the channel.")
+ NOTIFICATION_CANCEL_CHANNEL_BANNED(180),
+ @UiEvent(doc = "Notification was snoozed.")
+ NOTIFICATION_CANCEL_SNOOZED(181),
+ @UiEvent(doc = "Notification was canceled due to timeout")
+ NOTIFICATION_CANCEL_TIMEOUT(182),
+ // Values 183-189 reserved for future system dismissal reasons
+ @UiEvent(doc = "Notification was canceled due to user dismissal of a peeking notification.")
+ NOTIFICATION_CANCEL_USER_PEEK(190),
+ @UiEvent(doc = "Notification was canceled due to user dismissal from the always-on display")
+ NOTIFICATION_CANCEL_USER_AOD(191),
+ @UiEvent(doc = "Notification was canceled due to user dismissal from the notification"
+ + " shade.")
+ NOTIFICATION_CANCEL_USER_SHADE(192),
+ @UiEvent(doc = "Notification was canceled due to user dismissal from the lockscreen")
+ NOTIFICATION_CANCEL_USER_LOCKSCREEN(193);
+
+ private final int mId;
+ NotificationCancelledEvent(int id) {
+ mId = id;
+ }
+ @Override public int getId() {
+ return mId;
+ }
+ public static NotificationCancelledEvent fromCancelReason(
+ @NotificationListenerService.NotificationCancelReason int reason,
+ @NotificationStats.DismissalSurface int surface) {
+ // Shouldn't be possible to get a non-dismissed notification here.
+ if (surface == NotificationStats.DISMISSAL_NOT_DISMISSED) {
+ if (NotificationManagerService.DBG) {
+ throw new IllegalArgumentException("Unexpected surface " + surface);
+ }
+ return INVALID;
+ }
+ // Most cancel reasons do not have a meaningful surface. Reason codes map directly
+ // to NotificationCancelledEvent codes.
+ if (surface == NotificationStats.DISMISSAL_OTHER) {
+ if ((REASON_CLICK <= reason) && (reason <= REASON_TIMEOUT)) {
+ return NotificationCancelledEvent.values()[reason];
+ }
+ if (NotificationManagerService.DBG) {
+ throw new IllegalArgumentException("Unexpected cancel reason " + reason);
+ }
+ return INVALID;
+ }
+ // User cancels have a meaningful surface, which we differentiate by. See b/149038335
+ // for caveats.
+ if (reason != REASON_CANCEL) {
+ if (NotificationManagerService.DBG) {
+ throw new IllegalArgumentException("Unexpected cancel with surface " + reason);
+ }
+ return INVALID;
+ }
+ switch (surface) {
+ case NotificationStats.DISMISSAL_PEEK:
+ return NOTIFICATION_CANCEL_USER_PEEK;
+ case NotificationStats.DISMISSAL_AOD:
+ return NOTIFICATION_CANCEL_USER_AOD;
+ case NotificationStats.DISMISSAL_SHADE:
+ return NOTIFICATION_CANCEL_USER_SHADE;
+ default:
+ if (NotificationManagerService.DBG) {
+ throw new IllegalArgumentException("Unexpected surface for user-dismiss "
+ + reason);
+ }
+ return INVALID;
+ }
+ }
}
/**
@@ -88,7 +216,8 @@
return true;
}
- return !(Objects.equals(r.getSbn().getChannelIdLogTag(), old.getSbn().getChannelIdLogTag())
+ return !(Objects.equals(r.getSbn().getChannelIdLogTag(),
+ old.getSbn().getChannelIdLogTag())
&& Objects.equals(r.getSbn().getGroupLogTag(), old.getSbn().getGroupLogTag())
&& (r.getSbn().getNotification().isGroupSummary()
== old.getSbn().getNotification().isGroupSummary())
@@ -97,11 +226,6 @@
&& (r.getImportance() == old.getImportance()));
}
- NotificationReportedEvents getUiEvent() {
- return (old != null) ? NotificationReportedEvents.NOTIFICATION_UPDATED :
- NotificationReportedEvents.NOTIFICATION_POSTED;
- }
-
/**
* @return hash code for the notification style class, or 0 if none exists.
*/
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
index 4974c30..015d280 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
@@ -16,6 +16,8 @@
package com.android.server.notification;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.UiEventLoggerImpl;
import com.android.internal.util.FrameworkStatsLog;
/**
@@ -24,6 +26,8 @@
*/
public class NotificationRecordLoggerImpl implements NotificationRecordLogger {
+ UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
+
@Override
public void logNotificationReported(NotificationRecord r, NotificationRecord old,
int position, int buzzBeepBlink) {
@@ -32,7 +36,7 @@
return;
}
FrameworkStatsLog.write(FrameworkStatsLog.NOTIFICATION_REPORTED,
- /* int32 event_id = 1 */ p.getUiEvent().getId(),
+ /* int32 event_id = 1 */ NotificationReportedEvent.fromRecordPair(p).getId(),
/* int32 uid = 2 */ r.getUid(),
/* string package_name = 3 */ r.getSbn().getPackageName(),
/* int32 instance_id = 4 */ p.getInstanceId(),
@@ -61,9 +65,10 @@
);
}
-
-
-
-
-
+ @Override
+ public void logNotificationCancelled(NotificationRecord r, int reason, int dismissalSurface) {
+ mUiEventLogger.logWithInstanceId(
+ NotificationCancelledEvent.fromCancelReason(reason, dismissalSurface),
+ r.getUid(), r.getSbn().getPackageName(), r.getSbn().getInstanceId());
+ }
}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index fe39322..a244c48 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -36,6 +36,7 @@
import android.os.Build;
import android.os.UserHandle;
import android.provider.Settings;
+import android.service.notification.ConversationChannelWrapper;
import android.service.notification.NotificationListenerService;
import android.service.notification.RankingHelperProto;
import android.text.TextUtils;
@@ -1176,6 +1177,43 @@
return groups;
}
+ public ArrayList<ConversationChannelWrapper> getConversations(String pkg, int uid) {
+ Objects.requireNonNull(pkg);
+ synchronized (mPackagePreferences) {
+ PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+ if (r == null) {
+ return new ArrayList<>();
+ }
+ ArrayList<ConversationChannelWrapper> conversations = new ArrayList<>();
+ int N = r.channels.size();
+ for (int i = 0; i < N; i++) {
+ final NotificationChannel nc = r.channels.valueAt(i);
+ if (!TextUtils.isEmpty(nc.getConversationId()) && !nc.isDeleted()) {
+ ConversationChannelWrapper conversation = new ConversationChannelWrapper();
+ conversation.setNotificationChannel(nc);
+ conversation.setParentChannelLabel(
+ r.channels.get(nc.getParentChannelId()).getName());
+ boolean blockedByGroup = false;
+ if (nc.getGroup() != null) {
+ NotificationChannelGroup group = r.groups.get(nc.getGroup());
+ if (group != null) {
+ if (group.isBlocked()) {
+ blockedByGroup = true;
+ } else {
+ conversation.setGroupLabel(group.getName());
+ }
+ }
+ }
+ if (!blockedByGroup) {
+ conversations.add(conversation);
+ }
+ }
+ }
+
+ return conversations;
+ }
+ }
+
@Override
public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid,
boolean includeDeleted) {
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 3c31f6a..d75eb6d 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -913,9 +913,9 @@
}
try {
- ActivityManager.getService().broadcastIntent(null, intent, null, null, 0,
- null, null, null, android.app.AppOpsManager.OP_NONE, null, false, false,
- userId);
+ ActivityManager.getService().broadcastIntentWithFeature(null, null, intent,
+ null, null, 0, null, null, null, android.app.AppOpsManager.OP_NONE,
+ null, false, false, userId);
} catch (RemoteException e) {
// Intentionally left empty.
}
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 42bc464..a440c62 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -36,6 +36,7 @@
import android.os.Environment;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.Trace;
import android.sysprop.ApexProperties;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -46,6 +47,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.utils.TimingsTraceAndSlog;
import com.google.android.collect.Lists;
@@ -375,8 +377,11 @@
@Override
public List<ActiveApexInfo> getActiveApexInfos() {
+ final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
+ Trace.TRACE_TAG_APEX_MANAGER);
synchronized (mLock) {
if (mActiveApexInfosCache == null) {
+ t.traceBegin("getActiveApexInfos_noCache");
try {
mActiveApexInfosCache = new ArraySet<>();
final ApexInfo[] activePackages = mApexService.getActivePackages();
@@ -387,6 +392,7 @@
} catch (RemoteException e) {
Slog.e(TAG, "Unable to retrieve packages from apexservice", e);
}
+ t.traceEnd();
}
if (mActiveApexInfosCache != null) {
return new ArrayList<>(mActiveApexInfosCache);
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 3ad1207..8c13b5b 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -34,6 +34,7 @@
import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
import android.content.pm.parsing.ComponentParseUtils.ParsedService;
import android.net.Uri;
+import android.os.Binder;
import android.os.Process;
import android.os.Trace;
import android.os.UserHandle;
@@ -171,11 +172,13 @@
@Override
public boolean packageIsEnabled(AndroidPackage pkg) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "packageIsEnabled");
+ final long token = Binder.clearCallingIdentity();
try {
// TODO(b/135203078): Do not use toAppInfo
return mInjector.getCompatibility().isChangeEnabled(
PackageManager.FILTER_APPLICATION_QUERY, pkg.toAppInfoWithoutState());
} finally {
+ Binder.restoreCallingIdentity(token);
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 74d2efe..cd4485e 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -44,9 +44,7 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.os.Binder;
-import android.os.IBinder;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.stats.devicepolicy.DevicePolicyEnums;
@@ -54,10 +52,8 @@
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.IAppOpsService;
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
-import com.android.server.appop.AppOpsService;
import com.android.server.wm.ActivityTaskManagerInternal;
import java.util.ArrayList;
@@ -69,7 +65,7 @@
private Context mContext;
private Injector mInjector;
- private AppOpsService mAppOpsService;
+ private AppOpsManager mAppOpsManager;
public CrossProfileAppsServiceImpl(Context context) {
this(context, new InjectorImpl(context));
@@ -100,6 +96,7 @@
public void startActivityAsUser(
IApplicationThread caller,
String callingPackage,
+ String callingFeatureId,
ComponentName component,
@UserIdInt int userId,
boolean launchMainActivity) throws RemoteException {
@@ -165,7 +162,7 @@
launchIntent.setPackage(null);
launchIntent.setComponent(component);
mInjector.getActivityTaskManagerInternal().startActivityAsUser(
- caller, callingPackage, launchIntent,
+ caller, callingPackage, callingFeatureId, launchIntent,
launchMainActivity
? ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle()
: null,
@@ -176,6 +173,7 @@
public void startActivityAsUserByIntent(
IApplicationThread caller,
String callingPackage,
+ String callingFeatureId,
Intent intent,
@UserIdInt int userId) throws RemoteException {
Objects.requireNonNull(callingPackage);
@@ -212,8 +210,8 @@
verifyActivityCanHandleIntent(launchIntent, callingUid, userId);
- mInjector.getActivityTaskManagerInternal().startActivityAsUser(
- caller, callingPackage, launchIntent, /* options= */ null, userId);
+ mInjector.getActivityTaskManagerInternal().startActivityAsUser(caller, callingPackage,
+ callingFeatureId, launchIntent, /* options= */ null, userId);
}
@Override
@@ -545,12 +543,11 @@
permission, uid, /* owningUid= */-1, /* exported= */ true);
}
- private AppOpsService getAppOpsService() {
- if (mAppOpsService == null) {
- IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
- mAppOpsService = (AppOpsService) IAppOpsService.Stub.asInterface(b);
+ private AppOpsManager getAppOpsManager() {
+ if (mAppOpsManager == null) {
+ mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
}
- return mAppOpsService;
+ return mAppOpsManager;
}
private static class InjectorImpl implements Injector {
diff --git a/services/core/java/com/android/server/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java
index 8333ae5..0b0f139 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolver.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolver.java
@@ -222,6 +222,7 @@
sanitizedIntent,
failureIntent,
requestObj.callingPackage,
+ requestObj.callingFeatureId,
requestObj.verificationBundle,
requestObj.resolvedType,
requestObj.userId,
@@ -266,6 +267,7 @@
@NonNull Intent sanitizedIntent,
@Nullable Intent failureIntent,
@NonNull String callingPackage,
+ @Nullable String callingFeatureId,
@Nullable Bundle verificationBundle,
@NonNull String resolvedType,
int userId,
@@ -308,9 +310,10 @@
onFailureIntent = failureIntent;
}
final IIntentSender failureIntentTarget = ActivityManager.getService()
- .getIntentSender(
+ .getIntentSenderWithFeature(
ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
- null /*token*/, null /*resultWho*/, 1 /*requestCode*/,
+ callingFeatureId, null /*token*/, null /*resultWho*/,
+ 1 /*requestCode*/,
new Intent[] { onFailureIntent },
new String[] { resolvedType },
PendingIntent.FLAG_CANCEL_CURRENT
@@ -328,9 +331,10 @@
successIntent.setLaunchToken(token);
try {
final IIntentSender successIntentTarget = ActivityManager.getService()
- .getIntentSender(
+ .getIntentSenderWithFeature(
ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
- null /*token*/, null /*resultWho*/, 0 /*requestCode*/,
+ callingFeatureId, null /*token*/, null /*resultWho*/,
+ 0 /*requestCode*/,
new Intent[] { successIntent },
new String[] { resolvedType },
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 3e64e98..da07365 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -17,6 +17,7 @@
package com.android.server.pm;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
@@ -661,6 +662,23 @@
}
}
+ private void ensureStrictAccessShortcutsPermission(@NonNull String callingPackage) {
+ verifyCallingPackage(callingPackage);
+ if (!injectHasAccessShortcutsPermission(injectBinderCallingPid(),
+ injectBinderCallingUid())) {
+ throw new SecurityException("Caller can't access shortcut information");
+ }
+ }
+
+ /**
+ * Returns true if the caller has the "ACCESS_SHORTCUTS" permission.
+ */
+ @VisibleForTesting
+ boolean injectHasAccessShortcutsPermission(int callingPid, int callingUid) {
+ return mContext.checkPermission(android.Manifest.permission.ACCESS_SHORTCUTS,
+ callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
+ }
+
@Override
public ParceledListSlice getShortcuts(String callingPackage, long changedSince,
String packageName, List shortcutIds, List<LocusId> locusIds,
@@ -710,6 +728,30 @@
}
@Override
+ public void cacheShortcuts(String callingPackage, String packageName, List<String> ids,
+ UserHandle targetUser) {
+ ensureStrictAccessShortcutsPermission(callingPackage);
+ if (!canAccessProfile(targetUser.getIdentifier(), "Cannot cache shortcuts")) {
+ return;
+ }
+
+ mShortcutServiceInternal.cacheShortcuts(getCallingUserId(),
+ callingPackage, packageName, ids, targetUser.getIdentifier());
+ }
+
+ @Override
+ public void uncacheShortcuts(String callingPackage, String packageName, List<String> ids,
+ UserHandle targetUser) {
+ ensureStrictAccessShortcutsPermission(callingPackage);
+ if (!canAccessProfile(targetUser.getIdentifier(), "Cannot uncache shortcuts")) {
+ return;
+ }
+
+ mShortcutServiceInternal.uncacheShortcuts(getCallingUserId(),
+ callingPackage, packageName, ids, targetUser.getIdentifier());
+ }
+
+ @Override
public int getShortcutIconResId(String callingPackage, String packageName, String id,
int targetUserId) {
ensureShortcutPermission(callingPackage);
@@ -741,8 +783,9 @@
}
@Override
- public boolean startShortcut(String callingPackage, String packageName, String shortcutId,
- Rect sourceBounds, Bundle startActivityOptions, int targetUserId) {
+ public boolean startShortcut(String callingPackage, String packageName, String featureId,
+ String shortcutId, Rect sourceBounds, Bundle startActivityOptions,
+ int targetUserId) {
verifyCallingPackage(callingPackage);
if (!canAccessProfile(targetUserId, "Cannot start activity")) {
return false;
@@ -766,15 +809,16 @@
intents[0].setSourceBounds(sourceBounds);
return startShortcutIntentsAsPublisher(
- intents, packageName, startActivityOptions, targetUserId);
+ intents, packageName, featureId, startActivityOptions, targetUserId);
}
private boolean startShortcutIntentsAsPublisher(@NonNull Intent[] intents,
- @NonNull String publisherPackage, Bundle startActivityOptions, int userId) {
+ @NonNull String publisherPackage, @Nullable String publishedFeatureId,
+ Bundle startActivityOptions, int userId) {
final int code;
try {
code = mActivityTaskManagerInternal.startActivitiesAsPackage(publisherPackage,
- userId, intents, startActivityOptions);
+ publishedFeatureId, userId, intents, startActivityOptions);
if (ActivityManager.isStartResultSuccessful(code)) {
return true; // Success
} else {
@@ -829,8 +873,8 @@
@Override
public void startSessionDetailsActivityAsUser(IApplicationThread caller,
- String callingPackage, SessionInfo sessionInfo, Rect sourceBounds,
- Bundle opts, UserHandle userHandle) throws RemoteException {
+ String callingPackage, String callingFeatureId, SessionInfo sessionInfo,
+ Rect sourceBounds, Bundle opts, UserHandle userHandle) throws RemoteException {
int userId = userHandle.getIdentifier();
if (!canAccessProfile(userId, "Cannot start details activity")) {
return;
@@ -846,13 +890,13 @@
.authority(callingPackage).build());
i.setSourceBounds(sourceBounds);
- mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage, i, opts,
- userId);
+ mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage,
+ callingFeatureId, i, opts, userId);
}
@Override
public void startActivityAsUser(IApplicationThread caller, String callingPackage,
- ComponentName component, Rect sourceBounds,
+ String callingFeatureId, ComponentName component, Rect sourceBounds,
Bundle opts, UserHandle user) throws RemoteException {
if (!canAccessProfile(user.getIdentifier(), "Cannot start activity")) {
return;
@@ -906,12 +950,12 @@
Binder.restoreCallingIdentity(ident);
}
mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage,
- launchIntent, opts, user.getIdentifier());
+ callingFeatureId, launchIntent, opts, user.getIdentifier());
}
@Override
public void showAppDetailsAsUser(IApplicationThread caller,
- String callingPackage, ComponentName component,
+ String callingPackage, String callingFeatureId, ComponentName component,
Rect sourceBounds, Bundle opts, UserHandle user) throws RemoteException {
if (!canAccessProfile(user.getIdentifier(), "Cannot show app details")) {
return;
@@ -929,7 +973,7 @@
Binder.restoreCallingIdentity(ident);
}
mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage,
- intent, opts, user.getIdentifier());
+ callingFeatureId, intent, opts, user.getIdentifier());
}
/** Checks if user is a profile of or same as listeningUser.
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index e550bae..482fc49 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -344,18 +344,10 @@
int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
if (extractLibs) {
- if (onIncremental) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER,
- "incrementalNativeBinaries");
- abi32 = NativeLibraryHelper.configureNativeBinariesForSupportedAbi(pkg,
- handle, nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
- useIsaSpecificSubdirs);
- } else {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
- abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
- nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
- useIsaSpecificSubdirs);
- }
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+ abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+ nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
+ useIsaSpecificSubdirs, onIncremental);
} else {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
abi32 = NativeLibraryHelper.findSupportedAbi(
@@ -375,18 +367,10 @@
if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
if (extractLibs) {
- if (onIncremental) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER,
- "incrementalNativeBinaries");
- abi64 = NativeLibraryHelper.configureNativeBinariesForSupportedAbi(pkg,
- handle, nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
- useIsaSpecificSubdirs);
- } else {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
- abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
- nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
- useIsaSpecificSubdirs);
- }
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+ abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+ nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
+ useIsaSpecificSubdirs, onIncremental);
} else {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
abi64 = NativeLibraryHelper.findSupportedAbi(
@@ -437,15 +421,9 @@
final int copyRet;
if (extractLibs) {
- if (onIncremental) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "incrementalNativeBinaries");
- copyRet = NativeLibraryHelper.configureNativeBinariesForSupportedAbi(pkg,
- handle, nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
- } else {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
- copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
- nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
- }
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+ copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+ nativeLibraryRoot, abiList, useIsaSpecificSubdirs, onIncremental);
} else {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 0cf8b42..944280d 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1681,10 +1681,7 @@
mInternalProgress = 0.5f;
computeProgressLocked(true);
- // Unpack native libraries for non-incremental installation
- if (!isIncrementalInstallation()) {
- extractNativeLibraries(stageDir, params.abiOverride, mayInheritNativeLibs());
- }
+ extractNativeLibraries(stageDir, params.abiOverride, mayInheritNativeLibs());
}
// We've reached point of no return; call into PMS to install the stage.
@@ -2260,7 +2257,7 @@
Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
}
- private static void extractNativeLibraries(File packageDir, String abiOverride, boolean inherit)
+ private void extractNativeLibraries(File packageDir, String abiOverride, boolean inherit)
throws PackageManagerException {
final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
if (!inherit) {
@@ -2272,7 +2269,7 @@
try {
handle = NativeLibraryHelper.Handle.create(packageDir);
final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir,
- abiOverride);
+ abiOverride, isIncrementalInstallation());
if (res != PackageManager.INSTALL_SUCCEEDED) {
throw new PackageManagerException(res,
"Failed to extract native libraries, res=" + res);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 42b2483..2c85d06 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3627,7 +3627,7 @@
try {
handle = NativeLibraryHelper.Handle.create(dstCodePath);
ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
- null /*abiOverride*/);
+ null /*abiOverride*/, false /*isIncremental*/);
} catch (IOException e) {
logCriticalInfo(Log.ERROR, "Failed to extract native libraries"
+ "; pkg: " + packageName);
@@ -6298,10 +6298,11 @@
private void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
Intent origIntent, String resolvedType, String callingPackage,
- boolean isRequesterInstantApp, Bundle verificationBundle, int userId) {
+ @Nullable String callingFeatureId, boolean isRequesterInstantApp,
+ Bundle verificationBundle, int userId) {
final Message msg = mHandler.obtainMessage(INSTANT_APP_RESOLUTION_PHASE_TWO,
new InstantAppRequest(responseObj, origIntent, resolvedType,
- callingPackage, isRequesterInstantApp, userId, verificationBundle,
+ callingPackage, callingFeatureId, isRequesterInstantApp, userId, verificationBundle,
false /*resolveForStart*/, responseObj.hostDigestPrefixSecure,
responseObj.token));
mHandler.sendMessage(msg);
@@ -6987,10 +6988,10 @@
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
String token = UUID.randomUUID().toString();
InstantAppDigest digest = InstantAppResolver.parseDigest(intent);
- final InstantAppRequest requestObject = new InstantAppRequest(
- null /*responseObj*/, intent /*origIntent*/, resolvedType,
- null /*callingPackage*/, isRequesterInstantApp,
- userId, null /*verificationBundle*/, resolveForStart,
+ final InstantAppRequest requestObject = new InstantAppRequest(null /*responseObj*/,
+ intent /*origIntent*/, resolvedType, null /*callingPackage*/,
+ null /*callingFeatureId*/, isRequesterInstantApp, userId,
+ null /*verificationBundle*/, resolveForStart,
digest.getDigestPrefixSecure(), token);
auxiliaryResponse = InstantAppResolver.doInstantAppResolutionPhaseOne(
mInstantAppResolverConnection, requestObject);
@@ -12206,7 +12207,7 @@
+ intent.toShortString(false, true, false, false)
+ " " + intent.getExtras(), here);
}
- am.broadcastIntent(null, intent, null, finishedReceiver,
+ am.broadcastIntentWithFeature(null, null, intent, null, finishedReceiver,
0, null, null, requiredPermissions, android.app.AppOpsManager.OP_NONE,
null, finishedReceiver != null, false, id);
}
@@ -12368,8 +12369,9 @@
lockedBcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
}
final String[] requiredPermissions = {Manifest.permission.RECEIVE_BOOT_COMPLETED};
- am.broadcastIntent(null, lockedBcIntent, null, null, 0, null, null, requiredPermissions,
- android.app.AppOpsManager.OP_NONE, null, false, false, userId);
+ am.broadcastIntentWithFeature(null, null, lockedBcIntent, null, null, 0, null, null,
+ requiredPermissions, android.app.AppOpsManager.OP_NONE, null, false, false,
+ userId);
// Deliver BOOT_COMPLETED only if user is unlocked
if (mUserManager.isUserUnlockingOrUnlocked(userId)) {
@@ -12377,8 +12379,9 @@
if (includeStopped) {
bcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
}
- am.broadcastIntent(null, bcIntent, null, null, 0, null, null, requiredPermissions,
- android.app.AppOpsManager.OP_NONE, null, false, false, userId);
+ am.broadcastIntentWithFeature(null, null, bcIntent, null, null, 0, null, null,
+ requiredPermissions, android.app.AppOpsManager.OP_NONE, null, false, false,
+ userId);
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -14970,12 +14973,13 @@
return ret;
}
+ final boolean isIncremental = isIncrementalPath(codeFile.getAbsolutePath());
final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(codeFile);
ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
- abiOverride);
+ abiOverride, isIncremental);
} catch (IOException e) {
Slog.e(TAG, "Copying native libraries failed", e);
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
@@ -18780,7 +18784,7 @@
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
try {
- am.broadcastIntent(null, intent, null, null,
+ am.broadcastIntentWithFeature(null, null, intent, null, null,
0, null, null, null, android.app.AppOpsManager.OP_NONE,
null, false, false, userId);
} catch (RemoteException e) {
@@ -23424,9 +23428,10 @@
@Override
public void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
Intent origIntent, String resolvedType, String callingPackage,
- boolean isRequesterInstantApp, Bundle verificationBundle, int userId) {
- PackageManagerService.this.requestInstantAppResolutionPhaseTwo(
- responseObj, origIntent, resolvedType, callingPackage, isRequesterInstantApp,
+ @Nullable String callingFeatureId, boolean isRequesterInstantApp,
+ Bundle verificationBundle, int userId) {
+ PackageManagerService.this.requestInstantAppResolutionPhaseTwo(responseObj, origIntent,
+ resolvedType, callingPackage, callingFeatureId, isRequesterInstantApp,
verificationBundle, userId);
}
@@ -24336,8 +24341,9 @@
Manifest.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY,
};
try {
- am.broadcastIntent(null, intent, null, null, 0, null, null, requiredPermissions,
- android.app.AppOpsManager.OP_NONE, null, false, false, UserHandle.USER_ALL);
+ am.broadcastIntentWithFeature(null, null, intent, null, null, 0, null, null,
+ requiredPermissions, android.app.AppOpsManager.OP_NONE, null, false, false,
+ UserHandle.USER_ALL);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index d16c074..377fd16 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1704,7 +1704,7 @@
ShortcutInfo.validateIcon(shortcut.getIcon());
}
- shortcut.replaceFlags(0);
+ shortcut.replaceFlags(shortcut.getFlags() & ShortcutInfo.FLAG_LONG_LIVED);
}
private void fixUpIncomingShortcutInfo(@NonNull ShortcutInfo shortcut, boolean forUpdate) {
@@ -2758,6 +2758,68 @@
}
@Override
+ public void cacheShortcuts(int launcherUserId,
+ @NonNull String callingPackage, @NonNull String packageName,
+ @NonNull List<String> shortcutIds, int userId) {
+ updateCachedShortcutsInternal(launcherUserId, callingPackage, packageName, shortcutIds,
+ userId, /* doCache= */ true);
+ }
+
+ @Override
+ public void uncacheShortcuts(int launcherUserId,
+ @NonNull String callingPackage, @NonNull String packageName,
+ @NonNull List<String> shortcutIds, int userId) {
+ updateCachedShortcutsInternal(launcherUserId, callingPackage, packageName, shortcutIds,
+ userId, /* doCache= */ false);
+ }
+
+ private void updateCachedShortcutsInternal(int launcherUserId,
+ @NonNull String callingPackage, @NonNull String packageName,
+ @NonNull List<String> shortcutIds, int userId, boolean doCache) {
+ // Calling permission must be checked by LauncherAppsImpl.
+ Preconditions.checkStringNotEmpty(packageName, "packageName");
+ Objects.requireNonNull(shortcutIds, "shortcutIds");
+
+ synchronized (mLock) {
+ throwIfUserLockedL(userId);
+ throwIfUserLockedL(launcherUserId);
+
+ final int idSize = shortcutIds.size();
+ final ShortcutPackage sp = getUserShortcutsLocked(userId)
+ .getPackageShortcutsIfExists(packageName);
+ if (idSize == 0 || sp == null) {
+ return;
+ }
+
+ for (int i = 0; i < idSize; i++) {
+ final String id = Preconditions.checkStringNotEmpty(shortcutIds.get(i));
+ final ShortcutInfo si = sp.findShortcutById(id);
+ if (si == null || doCache == si.isCached()) {
+ continue;
+ }
+
+ if (doCache) {
+ if (si.isDynamic() && si.isLongLived()) {
+ si.addFlags(ShortcutInfo.FLAG_CACHED);
+ } else {
+ Log.w(TAG, "Only dynamic long lived shortcuts can get cached. Ignoring"
+ + "shortcut " + si.getId());
+ }
+ } else {
+ if (si.isDynamic()) {
+ si.clearFlags(ShortcutInfo.FLAG_CACHED);
+ } else {
+ sp.deleteLongLivedWithId(id, /*ignoreInvisible=*/ true);
+ }
+ }
+ }
+ }
+ packageShortcutsChanged(packageName, userId);
+
+ verifyStates();
+ }
+
+ @Override
public Intent[] createShortcutIntents(int launcherUserId,
@NonNull String callingPackage,
@NonNull String packageName, @NonNull String shortcutId, int userId,
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 8935453..614cc3f 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -57,6 +57,7 @@
import android.os.UserManagerInternal;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
+import android.text.TextUtils;
import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -67,6 +68,7 @@
import com.android.internal.content.PackageHelper;
import com.android.internal.os.BackgroundThread;
import com.android.server.LocalServices;
+import com.android.server.rollback.WatchdogRollbackLogger;
import java.io.File;
import java.io.IOException;
@@ -99,6 +101,10 @@
@GuardedBy("mStagedSessions")
private final SparseIntArray mSessionRollbackIds = new SparseIntArray();
+ @GuardedBy("mFailedPackageNames")
+ private final List<String> mFailedPackageNames = new ArrayList<>();
+ private String mNativeFailureReason;
+
StagingManager(PackageInstallerService pi, Context context) {
mPi = pi;
mContext = context;
@@ -441,6 +447,22 @@
}
}
+ /**
+ * Prepares for the logging of apexd reverts by storing the native failure reason if necessary,
+ * and adding the package name of the session which apexd reverted to the list of reverted
+ * session package names.
+ * Logging needs to wait until the ACTION_BOOT_COMPLETED broadcast is sent.
+ */
+ private void prepareForLoggingApexdRevert(@NonNull PackageInstallerSession session,
+ @NonNull String nativeFailureReason) {
+ synchronized (mFailedPackageNames) {
+ mNativeFailureReason = nativeFailureReason;
+ if (session.getPackageName() != null) {
+ mFailedPackageNames.add(session.getPackageName());
+ }
+ }
+ }
+
private void resumeSession(@NonNull PackageInstallerSession session) {
Slog.d(TAG, "Resuming session " + session.sessionId);
@@ -450,6 +472,12 @@
// Check with apexservice whether the apex packages have been activated.
apexSessionInfo = mApexManager.getStagedSessionInfo(session.sessionId);
+ // Prepare for logging a native crash during boot, if one occurred.
+ if (apexSessionInfo != null && !TextUtils.isEmpty(
+ apexSessionInfo.crashingNativeProcess)) {
+ prepareForLoggingApexdRevert(session, apexSessionInfo.crashingNativeProcess);
+ }
+
if (apexSessionInfo != null && apexSessionInfo.isVerified) {
// Session has been previously submitted to apexd, but didn't complete all the
// pre-reboot verification, perhaps because the device rebooted in the meantime.
@@ -955,12 +983,23 @@
}
}
+ private void logFailedApexSessionsIfNecessary() {
+ synchronized (mFailedPackageNames) {
+ if (!mFailedPackageNames.isEmpty()) {
+ WatchdogRollbackLogger.logApexdRevert(mContext,
+ mFailedPackageNames, mNativeFailureReason);
+ }
+ }
+ }
+
void systemReady() {
// Register the receiver of boot completed intent for staging manager.
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context ctx, Intent intent) {
mPreRebootVerificationHandler.readyToStart();
+ BackgroundThread.getExecutor().execute(
+ () -> logFailedApexSessionsIfNecessary());
ctx.unregisterReceiver(this);
}
}, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 0cb8f495..1c02161 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1901,7 +1901,7 @@
@Override
public boolean hasBaseUserRestriction(String restrictionKey, @UserIdInt int userId) {
- checkManageUsersPermission("hasBaseUserRestriction");
+ checkManageOrCreateUsersPermission("hasBaseUserRestriction");
if (!UserRestrictionsUtils.isValidRestriction(restrictionKey)) {
return false;
}
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 2c7795a..43d4596 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -39,9 +39,7 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManagerInternal.PackageListObserver;
import android.content.pm.PermissionInfo;
-import android.content.pm.parsing.AndroidPackage;
import android.os.Build;
-import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -52,14 +50,15 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LongSparseLongArray;
-import android.util.Pair;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
import com.android.internal.infra.AndroidFuture;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IntPair;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.FgThread;
@@ -70,6 +69,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.ExecutionException;
/**
@@ -100,7 +100,7 @@
* scheduled for a package/user.
*/
@GuardedBy("mLock")
- private final ArraySet<Pair<String, Integer>> mIsPackageSyncsScheduled = new ArraySet<>();
+ private final ArraySet<Integer> mIsPackageSyncsScheduled = new ArraySet<>();
public PermissionPolicyService(@NonNull Context context) {
super(context);
@@ -125,10 +125,8 @@
@Override
public void onPackageChanged(String packageName, int uid) {
- final int userId = UserHandle.getUserId(uid);
-
- if (isStarted(userId)) {
- synchronizePackagePermissionsAndAppOpsForUser(packageName, userId);
+ if (isStarted(UserHandle.getUserId(uid))) {
+ synchronizePackagePermissionsAndAppOpsForUser(uid);
}
}
@@ -139,12 +137,21 @@
});
permManagerInternal.addOnRuntimePermissionStateChangedListener(
- this::synchronizePackagePermissionsAndAppOpsAsyncForUser);
+ (packageName, userId) -> {
+ int uid;
+ try {
+ uid = getContext().getPackageManager().getPackageUidAsUser(packageName, 0,
+ userId);
+ } catch (NameNotFoundException e) {
+ Slog.e(LOG_TAG, "Cannot synchronize changed package " + packageName, e);
+ return;
+ }
+ synchronizeUidPermissionsAndAppOpsAsync(uid);
+ });
mAppOpsCallback = new IAppOpsCallback.Stub() {
public void opChanged(int op, int uid, String packageName) {
- synchronizePackagePermissionsAndAppOpsAsyncForUser(packageName,
- UserHandle.getUserId(uid));
+ synchronizeUidPermissionsAndAppOpsAsync(uid);
}
};
@@ -194,19 +201,17 @@
return AppOpsManager.opToSwitch(op);
}
- private void synchronizePackagePermissionsAndAppOpsAsyncForUser(@NonNull String packageName,
- @UserIdInt int changedUserId) {
- if (isStarted(changedUserId)) {
+ private void synchronizeUidPermissionsAndAppOpsAsync(int uid) {
+ if (isStarted(UserHandle.getUserId(uid))) {
synchronized (mLock) {
- if (mIsPackageSyncsScheduled.add(new Pair<>(packageName, changedUserId))) {
+ if (mIsPackageSyncsScheduled.add(uid)) {
FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
PermissionPolicyService
::synchronizePackagePermissionsAndAppOpsForUser,
- this, packageName, changedUserId));
+ this, uid));
} else {
if (DEBUG) {
- Slog.v(LOG_TAG, "sync for " + packageName + "/" + changedUserId
- + " already scheduled");
+ Slog.v(LOG_TAG, "sync for " + uid + " already scheduled");
}
}
}
@@ -335,39 +340,20 @@
/**
* Synchronize a single package.
*/
- private void synchronizePackagePermissionsAndAppOpsForUser(@NonNull String packageName,
- @UserIdInt int userId) {
+ private void synchronizePackagePermissionsAndAppOpsForUser(int uid) {
synchronized (mLock) {
- mIsPackageSyncsScheduled.remove(new Pair<>(packageName, userId));
+ mIsPackageSyncsScheduled.remove(uid);
}
if (DEBUG) {
Slog.v(LOG_TAG,
- "synchronizePackagePermissionsAndAppOpsForUser(" + packageName + ", "
- + userId + ")");
+ "synchronizePackagePermissionsAndAppOpsForUser(" + uid + ")");
}
- final PackageManagerInternal packageManagerInternal = LocalServices.getService(
- PackageManagerInternal.class);
- final PackageInfo pkg = packageManagerInternal.getPackageInfo(packageName, 0,
- Process.SYSTEM_UID, userId);
- if (pkg == null) {
- return;
- }
final PermissionToOpSynchroniser synchroniser = new PermissionToOpSynchroniser(
- getUserContext(getContext(), UserHandle.of(userId)));
- synchroniser.addPackage(pkg.packageName);
- final String[] sharedPkgNames = packageManagerInternal.getSharedUserPackagesForPackage(
- pkg.packageName, userId);
-
- for (String sharedPkgName : sharedPkgNames) {
- final AndroidPackage sharedPkg = packageManagerInternal
- .getPackage(sharedPkgName);
- if (sharedPkg != null) {
- synchroniser.addPackage(sharedPkg.getPackageName());
- }
- }
- synchroniser.syncPackages();
+ getUserContext(getContext(), UserHandle.getUserHandleForUid(uid)));
+ synchroniser.addUid(uid);
+ synchroniser.syncUids();
}
/**
@@ -381,8 +367,8 @@
final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser(
getUserContext(getContext(), UserHandle.of(userId)));
packageManagerInternal.forEachPackage(
- (pkg) -> synchronizer.addPackage(pkg.getPackageName()));
- synchronizer.syncPackages();
+ (pkg) -> synchronizer.addUid(pkg.getUid()));
+ synchronizer.syncUids();
}
/**
@@ -397,37 +383,51 @@
private final @NonNull ArrayMap<String, PermissionInfo> mRuntimePermissionInfos;
+ // Cache uid -> packageNames
+ private SparseArray<String[]> mUidToPkg = new SparseArray<>();
+
/**
* All ops that need to be flipped to allow.
*
- * @see #syncPackages
+ * @see #syncUids
*/
- private final @NonNull ArrayList<OpToChange> mOpsToAllow = new ArrayList<>();
+ private final @NonNull ArraySet<OpToChange> mOpsToAllow = new ArraySet<>();
/**
* All ops that need to be flipped to ignore.
*
- * @see #syncPackages
+ * @see #syncUids
*/
- private final @NonNull ArrayList<OpToChange> mOpsToIgnore = new ArrayList<>();
+ private final @NonNull ArraySet<OpToChange> mOpsToIgnore = new ArraySet<>();
/**
* All ops that need to be flipped to ignore if not allowed.
*
* Currently, only used by soft restricted permissions logic.
*
- * @see #syncPackages
+ * @see #syncUids
*/
- private final @NonNull ArrayList<OpToChange> mOpsToIgnoreIfNotAllowed = new ArrayList<>();
+ private final @NonNull ArraySet<OpToChange> mOpsToIgnoreIfNotAllowed = new ArraySet<>();
/**
* All ops that need to be flipped to foreground.
*
* Currently, only used by the foreground/background permissions logic.
*
- * @see #syncPackages
+ * @see #syncUids
*/
- private final @NonNull ArrayList<OpToChange> mOpsToForeground = new ArrayList<>();
+ private final @NonNull ArraySet<OpToChange> mOpsToForeground = new ArraySet<>();
+
+ private @Nullable String[] getPackageNamesForUid(int uid) {
+ String[] pkgs = mUidToPkg.get(uid);
+ if (pkgs != null) {
+ return pkgs;
+ }
+
+ pkgs = mPackageManager.getPackagesForUid(uid);
+ mUidToPkg.put(uid, pkgs);
+ return pkgs;
+ }
PermissionToOpSynchroniser(@NonNull Context context) {
mContext = context;
@@ -449,11 +449,11 @@
}
/**
- * Set app ops that were added in {@link #addPackage}.
+ * Set app ops that were added in {@link #addUid}.
*
* <p>This processes ops previously added by {@link #addAppOps(PackageInfo, String)}
*/
- private void syncPackages() {
+ private void syncUids() {
// Remember which ops were already set. This makes sure that we always set the most
// permissive mode if two OpChanges are scheduled. This can e.g. happen if two
// permissions change the same op. See {@link #getSwitchOp}.
@@ -461,42 +461,42 @@
final int allowCount = mOpsToAllow.size();
for (int i = 0; i < allowCount; i++) {
- final OpToChange op = mOpsToAllow.get(i);
+ final OpToChange op = mOpsToAllow.valueAt(i);
- setUidModeAllowed(op.code, op.uid, op.packageName);
+ setUidModeAllowed(op.code, op.uid);
alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
}
final int foregroundCount = mOpsToForeground.size();
for (int i = 0; i < foregroundCount; i++) {
- final OpToChange op = mOpsToForeground.get(i);
+ final OpToChange op = mOpsToForeground.valueAt(i);
if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
continue;
}
- setUidModeForeground(op.code, op.uid, op.packageName);
+ setUidModeForeground(op.code, op.uid);
alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
}
final int ignoreCount = mOpsToIgnore.size();
for (int i = 0; i < ignoreCount; i++) {
- final OpToChange op = mOpsToIgnore.get(i);
+ final OpToChange op = mOpsToIgnore.valueAt(i);
if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
continue;
}
- setUidModeIgnored(op.code, op.uid, op.packageName);
+ setUidModeIgnored(op.code, op.uid);
alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
}
final int ignoreIfNotAllowedCount = mOpsToIgnoreIfNotAllowed.size();
for (int i = 0; i < ignoreIfNotAllowedCount; i++) {
- final OpToChange op = mOpsToIgnoreIfNotAllowed.get(i);
+ final OpToChange op = mOpsToIgnoreIfNotAllowed.valueAt(i);
if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
continue;
}
- boolean wasSet = setUidModeIgnoredIfNotAllowed(op.code, op.uid, op.packageName);
+ boolean wasSet = setUidModeIgnoredIfNotAllowed(op.code, op.uid);
if (wasSet) {
alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
}
@@ -555,7 +555,7 @@
}
int uid = packageInfo.applicationInfo.uid;
- OpToChange opToChange = new OpToChange(uid, packageName, appOpCode);
+ OpToChange opToChange = new OpToChange(uid, appOpCode);
switch (appOpMode) {
case MODE_ALLOWED:
mOpsToAllow.add(opToChange);
@@ -618,8 +618,7 @@
}
int uid = packageInfo.applicationInfo.uid;
- String packageName = packageInfo.packageName;
- OpToChange extraOpToChange = new OpToChange(uid, packageName, extraOpCode);
+ OpToChange extraOpToChange = new OpToChange(uid, extraOpCode);
if (policy.mayAllowExtraAppOp()) {
mOpsToAllow.add(extraOpToChange);
} else {
@@ -632,45 +631,56 @@
}
/**
- * Add a package for {@link #syncPackages() processing} later.
+ * Add a Uid for {@link #syncUids() processing} later.
*
* <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager.
*
- * @param pkgName The package to add for later processing.
+ * @param uid The uid to add for later processing.
*/
- void addPackage(@NonNull String pkgName) {
- final PackageInfo pkg;
- try {
- pkg = mPackageManager.getPackageInfo(pkgName, GET_PERMISSIONS);
- } catch (NameNotFoundException e) {
+ void addUid(int uid) {
+ String[] pkgNames = getPackageNamesForUid(uid);
+ if (pkgNames == null) {
return;
}
- if (pkg.requestedPermissions == null) {
- return;
- }
+ for (String pkgName : pkgNames) {
+ final PackageInfo pkg;
+ try {
+ pkg = mPackageManager.getPackageInfo(pkgName, GET_PERMISSIONS);
+ } catch (NameNotFoundException e) {
+ continue;
+ }
- for (String permission : pkg.requestedPermissions) {
- addAppOps(pkg, permission);
+ if (pkg.requestedPermissions == null) {
+ continue;
+ }
+
+ for (String permission : pkg.requestedPermissions) {
+ addAppOps(pkg, permission);
+ }
}
}
- private void setUidModeAllowed(int opCode, int uid, @NonNull String packageName) {
- setUidMode(opCode, uid, MODE_ALLOWED, packageName);
+ private void setUidModeAllowed(int opCode, int uid) {
+ setUidMode(opCode, uid, MODE_ALLOWED);
}
- private void setUidModeForeground(int opCode, int uid, @NonNull String packageName) {
- setUidMode(opCode, uid, MODE_FOREGROUND, packageName);
+ private void setUidModeForeground(int opCode, int uid) {
+ setUidMode(opCode, uid, MODE_FOREGROUND);
}
- private void setUidModeIgnored(int opCode, int uid, @NonNull String packageName) {
- setUidMode(opCode, uid, MODE_IGNORED, packageName);
+ private void setUidModeIgnored(int opCode, int uid) {
+ setUidMode(opCode, uid, MODE_IGNORED);
}
- private boolean setUidModeIgnoredIfNotAllowed(int opCode, int uid,
- @NonNull String packageName) {
+ private boolean setUidModeIgnoredIfNotAllowed(int opCode, int uid) {
+ String[] pkgsOfUid = getPackageNamesForUid(uid);
+ if (ArrayUtils.isEmpty(pkgsOfUid)) {
+ return false;
+ }
+
final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName(
- opCode), uid, packageName);
+ opCode), uid, pkgsOfUid[0]);
if (currentMode != MODE_ALLOWED) {
if (currentMode != MODE_IGNORED) {
mAppOpsManagerInternal.setUidModeIgnoringCallback(opCode, uid, MODE_IGNORED,
@@ -681,20 +691,24 @@
return false;
}
- private void setUidMode(int opCode, int uid, int mode,
- @NonNull String packageName) {
+ private void setUidMode(int opCode, int uid, int mode) {
+ String[] pkgsOfUid = getPackageNamesForUid(uid);
+ if (ArrayUtils.isEmpty(pkgsOfUid)) {
+ return;
+ }
+
final int oldMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName(
- opCode), uid, packageName);
+ opCode), uid, pkgsOfUid[0]);
if (oldMode != mode) {
mAppOpsManagerInternal.setUidModeIgnoringCallback(opCode, uid, mode,
mAppOpsCallback);
final int newMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName(
- opCode), uid, packageName);
+ opCode), uid, pkgsOfUid[0]);
if (newMode != mode) {
// Work around incorrectly-set package mode. It never makes sense for app ops
// related to runtime permissions, but can get in the way and we have to reset
// it.
- mAppOpsManagerInternal.setModeIgnoringCallback(opCode, uid, packageName,
+ mAppOpsManagerInternal.setModeIgnoringCallback(opCode, uid, pkgsOfUid[0],
AppOpsManager.opToDefaultMode(opCode), mAppOpsCallback);
}
}
@@ -702,14 +716,30 @@
private class OpToChange {
final int uid;
- final @NonNull String packageName;
final int code;
- OpToChange(int uid, @NonNull String packageName, int code) {
+ OpToChange(int uid, int code) {
this.uid = uid;
- this.packageName = packageName;
this.code = code;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ OpToChange other = (OpToChange) o;
+ return uid == other.uid && code == other.code;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(uid, code);
+ }
}
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index ede04f3..4b2dc85 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -5195,7 +5195,8 @@
final Intent dock = createHomeDockIntent();
if (dock != null) {
int result = ActivityTaskManager.getService()
- .startActivityAsUser(null, mContext.getBasePackageName(), dock,
+ .startActivityAsUser(null, mContext.getBasePackageName(),
+ mContext.getFeatureId(), dock,
dock.resolveTypeIfNeeded(mContext.getContentResolver()),
null, null, 0,
ActivityManager.START_FLAG_ONLY_IF_NEEDED,
@@ -5206,7 +5207,8 @@
}
}
int result = ActivityTaskManager.getService()
- .startActivityAsUser(null, mContext.getBasePackageName(), mHomeIntent,
+ .startActivityAsUser(null, mContext.getBasePackageName(),
+ mContext.getFeatureId(), mHomeIntent,
mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
null, null, 0,
ActivityManager.START_FLAG_ONLY_IF_NEEDED,
diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
index 81ec466..d754380 100644
--- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
+++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
@@ -122,8 +122,9 @@
PackageManager pm = context.getPackageManager();
int flags = pm.getPermissionFlags(permission, appInfo.packageName, user);
isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
- shouldApplyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
targetSDK = getMinimumTargetSDK(context, appInfo, user);
+ shouldApplyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0
+ || targetSDK > Build.VERSION_CODES.Q;
hasRequestedLegacyExternalStorage = hasUidRequestedLegacyExternalStorage(
appInfo.uid, context);
hasWriteMediaStorageGrantedForUid = hasWriteMediaStorageGrantedForUid(
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index 4d7af9c..b5da1c2 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -182,6 +182,15 @@
private int mNumPackageSessionsWithSuccess;
/**
+ * A temp flag to facilitate merging of the 2 rollback collections managed by
+ * RollbackManagerServiceImpl. True if this rollback is in the process of enabling and was
+ * originally managed by RollbackManagerServiceImpl#mNewRollbacks.
+ * TODO: remove this flag when merge is completed.
+ */
+ @GuardedBy("mLock")
+ private boolean mIsNewRollback = false;
+
+ /**
* Constructs a new, empty Rollback instance.
*
* @param rollbackId the id of the rollback.
@@ -829,6 +838,18 @@
}
}
+ void setIsNewRollback(boolean newRollback) {
+ synchronized (mLock) {
+ mIsNewRollback = newRollback;
+ }
+ }
+
+ boolean isNewRollback() {
+ synchronized (mLock) {
+ return mIsNewRollback;
+ }
+ }
+
static String rollbackStateToString(@RollbackState int state) {
switch (state) {
case Rollback.ROLLBACK_STATE_ENABLING: return "enabling";
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 8bd9533..1421258 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -19,6 +19,7 @@
import android.Manifest;
import android.annotation.AnyThread;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.AppOpsManager;
@@ -50,7 +51,6 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.DeviceConfig;
-import android.util.ArraySet;
import android.util.IntArray;
import android.util.Log;
import android.util.LongArrayQueue;
@@ -121,10 +121,6 @@
@GuardedBy("mLock")
private final SparseBooleanArray mAllocatedRollbackIds = new SparseBooleanArray();
- // Rollbacks we are in the process of enabling.
- @GuardedBy("mLock")
- private final Set<Rollback> mNewRollbacks = new ArraySet<>();
-
// The list of all rollbacks, including available and committed rollbacks.
@GuardedBy("mLock")
private final List<Rollback> mRollbacks;
@@ -240,17 +236,14 @@
Slog.v(TAG, "broadcast=ACTION_CANCEL_ENABLE_ROLLBACK token=" + token);
}
synchronized (mLock) {
- Rollback found = null;
- for (Rollback newRollback : mNewRollbacks) {
- if (newRollback.hasToken(token)) {
- found = newRollback;
+ for (int i = 0; i < mRollbacks.size(); ++i) {
+ Rollback rollback = mRollbacks.get(i);
+ if (rollback.hasToken(token) && rollback.isEnabling()) {
+ mRollbacks.remove(i);
+ rollback.delete(mAppDataRollbackHelper);
break;
}
}
- if (found != null) {
- mNewRollbacks.remove(found);
- found.delete(mAppDataRollbackHelper);
- }
}
}
}
@@ -442,15 +435,6 @@
rollback.delete(mAppDataRollbackHelper);
}
}
- Iterator<Rollback> iter2 = mNewRollbacks.iterator();
- while (iter2.hasNext()) {
- Rollback newRollback = iter2.next();
- if (newRollback.includesPackage(packageName)) {
- iter2.remove();
- newRollback.delete(mAppDataRollbackHelper);
- }
-
- }
}
}
@@ -810,7 +794,8 @@
newRollback = getNewRollbackForPackageSessionLocked(packageSession.getSessionId());
if (newRollback == null) {
newRollback = createNewRollbackLocked(parentSession);
- mNewRollbacks.add(newRollback);
+ mRollbacks.add(newRollback);
+ newRollback.setIsNewRollback(true);
}
}
newRollback.addToken(token);
@@ -818,34 +803,6 @@
return enableRollbackForPackageSession(newRollback, packageSession);
}
- @WorkerThread
- private void removeRollbackForPackageSessionId(int sessionId) {
- if (LOCAL_LOGV) {
- Slog.v(TAG, "removeRollbackForPackageSessionId=" + sessionId);
- }
-
- synchronized (mLock) {
- Rollback newRollback = getNewRollbackForPackageSessionLocked(sessionId);
- if (newRollback != null) {
- Slog.w(TAG, "Delete new rollback id=" + newRollback.info.getRollbackId()
- + " for session id=" + sessionId);
- mNewRollbacks.remove(newRollback);
- newRollback.delete(mAppDataRollbackHelper);
- }
- Iterator<Rollback> iter = mRollbacks.iterator();
- while (iter.hasNext()) {
- Rollback rollback = iter.next();
- if (rollback.getStagedSessionId() == sessionId) {
- Slog.w(TAG, "Delete rollback id=" + rollback.info.getRollbackId()
- + " for session id=" + sessionId);
- iter.remove();
- rollback.delete(mAppDataRollbackHelper);
- break;
- }
- }
- }
- }
-
/**
* Do code and userdata backups to enable rollback of the given session.
* In case of multiPackage sessions, <code>session</code> should be one of
@@ -966,15 +923,10 @@
+ " users=" + Arrays.toString(userIds));
}
synchronized (mLock) {
- // staged installs
for (int i = 0; i < mRollbacks.size(); i++) {
Rollback rollback = mRollbacks.get(i);
rollback.snapshotUserData(packageName, userIds, mAppDataRollbackHelper);
}
- // non-staged installs
- for (Rollback rollback : mNewRollbacks) {
- rollback.snapshotUserData(packageName, userIds, mAppDataRollbackHelper);
- }
}
}
@@ -1200,7 +1152,8 @@
synchronized (mLock) {
newRollback = getNewRollbackForPackageSessionLocked(sessionId);
if (newRollback != null && newRollback.notifySessionWithSuccess()) {
- mNewRollbacks.remove(newRollback);
+ mRollbacks.remove(newRollback);
+ newRollback.setIsNewRollback(false);
} else {
// Not all child sessions finished with success.
// Don't enable the rollback yet.
@@ -1215,7 +1168,15 @@
}
}
} else {
- removeRollbackForPackageSessionId(sessionId);
+ synchronized (mLock) {
+ Rollback rollback = getRollbackForSessionLocked(sessionId);
+ if (rollback != null && rollback.isEnabling()) {
+ Slog.w(TAG, "Delete rollback id=" + rollback.info.getRollbackId()
+ + " for failed session id=" + sessionId);
+ mRollbacks.remove(rollback);
+ rollback.delete(mAppDataRollbackHelper);
+ }
+ }
}
}
}
@@ -1376,6 +1337,25 @@
}
/**
+ * Returns the Rollback associated with the given session if parent or child session id matches.
+ * Returns null if not found.
+ */
+ @WorkerThread
+ @GuardedBy("mLock")
+ @Nullable
+ private Rollback getRollbackForSessionLocked(int sessionId) {
+ // We expect mRollbacks to be a very small list; linear search should be plenty fast.
+ for (int i = 0; i < mRollbacks.size(); ++i) {
+ Rollback rollback = mRollbacks.get(i);
+ if (rollback.getStagedSessionId() == sessionId
+ || rollback.containsSessionId(sessionId)) {
+ return rollback;
+ }
+ }
+ return null;
+ }
+
+ /**
* Returns the NewRollback associated with the given package session.
* Returns null if no NewRollback is found for the given package
* session.
@@ -1383,11 +1363,11 @@
@WorkerThread
@GuardedBy("mLock")
Rollback getNewRollbackForPackageSessionLocked(int packageSessionId) {
- // We expect mNewRollbacks to be a very small list; linear search
+ // We expect mRollbacks to be a very small list; linear search
// should be plenty fast.
- for (Rollback newRollback: mNewRollbacks) {
- if (newRollback.containsSessionId(packageSessionId)) {
- return newRollback;
+ for (Rollback rollback: mRollbacks) {
+ if (rollback.isNewRollback() && rollback.containsSessionId(packageSessionId)) {
+ return rollback;
}
}
return null;
diff --git a/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java b/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java
index 46ec2f8..1be6f22 100644
--- a/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java
+++ b/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java
@@ -20,7 +20,12 @@
import static com.android.internal.util.FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_NOT_RESPONDING;
import static com.android.internal.util.FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_EXPLICIT_HEALTH_CHECK;
import static com.android.internal.util.FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH;
+import static com.android.internal.util.FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH_DURING_BOOT;
import static com.android.internal.util.FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN;
+import static com.android.internal.util.FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED;
+import static com.android.internal.util.FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE;
+import static com.android.internal.util.FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE;
+import static com.android.internal.util.FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -33,7 +38,6 @@
import android.content.rollback.RollbackInfo;
import android.util.ArraySet;
import android.util.Slog;
-import android.util.StatsLog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
@@ -58,8 +62,8 @@
private static String getLoggingParentName(Context context, @NonNull String packageName) {
PackageManager packageManager = context.getPackageManager();
try {
- ApplicationInfo ai = packageManager.getApplicationInfo(packageName,
- PackageManager.GET_META_DATA);
+ int flags = PackageManager.MATCH_APEX | PackageManager.GET_META_DATA;
+ ApplicationInfo ai = packageManager.getPackageInfo(packageName, flags).applicationInfo;
if (ai.metaData == null) {
return null;
}
@@ -95,6 +99,22 @@
return loggingParent;
}
+
+ /**
+ * Gets the set of parent packages for a given set of failed package names. In the case that
+ * multiple sessions have failed, we want to log failure for each of the parent packages.
+ * Even if multiple failed packages have the same parent, we only log the parent package once.
+ */
+ private static Set<VersionedPackage> getLogPackages(Context context,
+ @NonNull List<String> failedPackageNames) {
+ Set<VersionedPackage> parentPackages = new ArraySet<>();
+ for (String failedPackageName: failedPackageNames) {
+ parentPackages.add(getLogPackage(context, new VersionedPackage(failedPackageName, 0)));
+ }
+ return parentPackages;
+ }
+
+
static void logRollbackStatusOnBoot(Context context, int rollbackId,
List<RollbackInfo> recentlyCommittedRollbacks) {
PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
@@ -142,19 +162,36 @@
for (VersionedPackage oldLoggingPackage : oldLoggingPackages) {
if (sessionInfo.isStagedSessionApplied()) {
logEvent(oldLoggingPackage,
- FrameworkStatsLog
- .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
+ WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, "");
} else if (sessionInfo.isStagedSessionFailed()) {
logEvent(oldLoggingPackage,
- FrameworkStatsLog
- .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
+ WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, "");
}
}
}
/**
+ * Logs that one or more apexd reverts have occurred, along with the crashing native process
+ * that caused apexd to revert during boot.
+ *
+ * @param context the context to use when determining the log packages
+ * @param failedPackageNames a list of names of packages which were reverted
+ * @param failingNativeProcess the crashing native process which caused a revert
+ */
+ public static void logApexdRevert(Context context, @NonNull List<String> failedPackageNames,
+ @NonNull String failingNativeProcess) {
+ Set<VersionedPackage> logPackages = getLogPackages(context, failedPackageNames);
+ for (VersionedPackage logPackage: logPackages) {
+ logEvent(logPackage,
+ WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
+ WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH_DURING_BOOT,
+ failingNativeProcess);
+ }
+ }
+
+ /**
* Log a Watchdog rollback event to statsd.
*
* @param logPackage the package to associate the rollback with.
@@ -169,12 +206,25 @@
+ " rollbackReason: " + rollbackReasonToString(rollbackReason)
+ " failedPackageName: " + failingPackageName);
if (logPackage != null) {
- StatsLog.logWatchdogRollbackOccurred(type, logPackage.getPackageName(),
- logPackage.getVersionCode(), rollbackReason, failingPackageName);
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED,
+ type,
+ logPackage.getPackageName(),
+ logPackage.getVersionCode(),
+ rollbackReason,
+ failingPackageName,
+ new byte[]{});
} else {
// In the case that the log package is null, still log an empty string as an
// indication that retrieving the logging parent failed.
- StatsLog.logWatchdogRollbackOccurred(type, "", 0, rollbackReason, failingPackageName);
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED,
+ type,
+ "",
+ 0,
+ rollbackReason,
+ failingPackageName,
+ new byte[]{});
}
}
@@ -196,14 +246,13 @@
private static String rollbackTypeToString(int type) {
switch (type) {
- case FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE:
+ case WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE:
return "ROLLBACK_INITIATE";
- case FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS:
+ case WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS:
return "ROLLBACK_SUCCESS";
- case FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE:
+ case WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE:
return "ROLLBACK_FAILURE";
- case FrameworkStatsLog
- .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED:
+ case WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED:
return "ROLLBACK_BOOT_TRIGGERED";
default:
return "UNKNOWN";
@@ -212,16 +261,16 @@
private static String rollbackReasonToString(int reason) {
switch (reason) {
- case FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH:
+ case WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH:
return "REASON_NATIVE_CRASH";
- case FrameworkStatsLog
- .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_EXPLICIT_HEALTH_CHECK:
+ case WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_EXPLICIT_HEALTH_CHECK:
return "REASON_EXPLICIT_HEALTH_CHECK";
- case FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_CRASH:
+ case WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_CRASH:
return "REASON_APP_CRASH";
- case FrameworkStatsLog
- .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_NOT_RESPONDING:
+ case WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_NOT_RESPONDING:
return "REASON_APP_NOT_RESPONDING";
+ case WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH_DURING_BOOT:
+ return "REASON_NATIVE_CRASH_DURING_BOOT";
default:
return "UNKNOWN";
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index a54f5d4..ad57e1f 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -362,6 +362,7 @@
private static final String TAG_PERSISTABLEBUNDLE = "persistable_bundle";
private static final String ATTR_LAUNCHEDFROMUID = "launched_from_uid";
private static final String ATTR_LAUNCHEDFROMPACKAGE = "launched_from_package";
+ private static final String ATTR_LAUNCHEDFROMFEATURE = "launched_from_feature";
private static final String ATTR_RESOLVEDTYPE = "resolved_type";
private static final String ATTR_COMPONENTSPECIFIED = "component_specified";
static final String ACTIVITY_ICON_SUFFIX = "_activity_icon_";
@@ -422,6 +423,7 @@
final int launchedFromPid; // always the pid who started the activity.
final int launchedFromUid; // always the uid who started the activity.
final String launchedFromPackage; // always the package who started the activity.
+ final @Nullable String launchedFromFeatureId; // always the feature in launchedFromPackage
final Intent intent; // the original intent that generated us
final String shortComponentName; // the short component name of the intent
final String resolvedType; // as per original caller;
@@ -773,6 +775,7 @@
pw.print(" processName="); pw.println(processName);
pw.print(prefix); pw.print("launchedFromUid="); pw.print(launchedFromUid);
pw.print(" launchedFromPackage="); pw.print(launchedFromPackage);
+ pw.print(" launchedFromFeature="); pw.print(launchedFromFeatureId);
pw.print(" userId="); pw.println(mUserId);
pw.print(prefix); pw.print("app="); pw.println(app);
pw.print(prefix); pw.println(intent.toInsecureString());
@@ -1483,9 +1486,10 @@
}
ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller,
- int _launchedFromPid, int _launchedFromUid, String _launchedFromPackage, Intent _intent,
- String _resolvedType, ActivityInfo aInfo, Configuration _configuration,
- ActivityRecord _resultTo, String _resultWho, int _reqCode, boolean _componentSpecified,
+ int _launchedFromPid, int _launchedFromUid, String _launchedFromPackage,
+ @Nullable String _launchedFromFeature, Intent _intent, String _resolvedType,
+ ActivityInfo aInfo, Configuration _configuration, ActivityRecord _resultTo,
+ String _resultWho, int _reqCode, boolean _componentSpecified,
boolean _rootVoiceInteraction, ActivityStackSupervisor supervisor,
ActivityOptions options, ActivityRecord sourceRecord) {
super(_service.mWindowManager, new Token(_intent).asBinder(), TYPE_APPLICATION, true,
@@ -1564,6 +1568,7 @@
launchedFromPid = _launchedFromPid;
launchedFromUid = _launchedFromUid;
launchedFromPackage = _launchedFromPackage;
+ launchedFromFeatureId = _launchedFromFeature;
shortComponentName = _intent.getComponent().flattenToShortString();
resolvedType = _resolvedType;
componentSpecified = _componentSpecified;
@@ -2284,7 +2289,7 @@
* @return Whether AppOps allows this package to enter picture-in-picture.
*/
private boolean checkEnterPictureInPictureAppOpsState() {
- return mAtmService.getAppOpsService().checkOperation(
+ return mAtmService.getAppOpsManager().checkOpNoThrow(
OP_PICTURE_IN_PICTURE, info.applicationInfo.uid, packageName) == MODE_ALLOWED;
}
@@ -7282,6 +7287,9 @@
if (launchedFromPackage != null) {
out.attribute(null, ATTR_LAUNCHEDFROMPACKAGE, launchedFromPackage);
}
+ if (launchedFromFeatureId != null) {
+ out.attribute(null, ATTR_LAUNCHEDFROMFEATURE, launchedFromFeatureId);
+ }
if (resolvedType != null) {
out.attribute(null, ATTR_RESOLVEDTYPE, resolvedType);
}
@@ -7309,6 +7317,7 @@
PersistableBundle persistentState = null;
int launchedFromUid = 0;
String launchedFromPackage = null;
+ String launchedFromFeature = null;
String resolvedType = null;
boolean componentSpecified = false;
int userId = 0;
@@ -7327,6 +7336,8 @@
launchedFromUid = Integer.parseInt(attrValue);
} else if (ATTR_LAUNCHEDFROMPACKAGE.equals(attrName)) {
launchedFromPackage = attrValue;
+ } else if (ATTR_LAUNCHEDFROMFEATURE.equals(attrName)) {
+ launchedFromFeature = attrValue;
} else if (ATTR_RESOLVEDTYPE.equals(attrName)) {
resolvedType = attrValue;
} else if (ATTR_COMPONENTSPECIFIED.equals(attrName)) {
@@ -7374,10 +7385,11 @@
" resolvedType=" + resolvedType);
}
final ActivityRecord r = new ActivityRecord(service, null /* caller */,
- 0 /* launchedFromPid */, launchedFromUid, launchedFromPackage, intent, resolvedType,
- aInfo, service.getConfiguration(), null /* resultTo */, null /* resultWho */,
- 0 /* reqCode */, componentSpecified, false /* rootVoiceInteraction */,
- stackSupervisor, null /* options */, null /* sourceRecord */);
+ 0 /* launchedFromPid */, launchedFromUid, launchedFromPackage, launchedFromFeature,
+ intent, resolvedType, aInfo, service.getConfiguration(), null /* resultTo */,
+ null /* resultWho */, 0 /* reqCode */, componentSpecified,
+ false /* rootVoiceInteraction */, stackSupervisor, null /* options */,
+ null /* sourceRecord */);
r.mPersistentState = persistentState;
r.taskDescription = taskDescription;
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index d380f8c..9030fce 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -135,6 +135,7 @@
import static java.lang.Integer.MAX_VALUE;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
@@ -622,7 +623,7 @@
true /*neverRelinquishIdentity*/,
_taskDescription != null ? _taskDescription : new ActivityManager.TaskDescription(),
id, INVALID_TASK_ID, INVALID_TASK_ID, 0 /*taskAffiliationColor*/,
- info.applicationInfo.uid, info.packageName, info.resizeMode,
+ info.applicationInfo.uid, info.packageName, null, info.resizeMode,
info.supportsPictureInPicture(), false /*_realActivitySuspended*/,
false /*userSetupComplete*/, INVALID_MIN_SIZE, INVALID_MIN_SIZE, info,
_voiceSession, _voiceInteractor, stack);
@@ -635,15 +636,16 @@
String _lastDescription, long lastTimeMoved, boolean neverRelinquishIdentity,
ActivityManager.TaskDescription _lastTaskDescription, int taskAffiliation,
int prevTaskId, int nextTaskId, int taskAffiliationColor, int callingUid,
- String callingPackage, int resizeMode, boolean supportsPictureInPicture,
- boolean _realActivitySuspended, boolean userSetupComplete, int minWidth, int minHeight,
+ String callingPackage, @Nullable String callingFeatureId, int resizeMode,
+ boolean supportsPictureInPicture, boolean _realActivitySuspended,
+ boolean userSetupComplete, int minWidth, int minHeight,
ActivityInfo info, IVoiceInteractionSession _voiceSession,
IVoiceInteractor _voiceInteractor, ActivityStack stack) {
super(atmService, id, _intent, _affinityIntent, _affinity, _rootAffinity,
_realActivity, _origActivity, _rootWasReset, _autoRemoveRecents, _askedCompatMode,
_userId, _effectiveUid, _lastDescription, lastTimeMoved, neverRelinquishIdentity,
_lastTaskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor,
- callingUid, callingPackage, resizeMode, supportsPictureInPicture,
+ callingUid, callingPackage, callingFeatureId, resizeMode, supportsPictureInPicture,
_realActivitySuspended, userSetupComplete, minWidth, minHeight, info, _voiceSession,
_voiceInteractor, stack);
@@ -2924,6 +2926,7 @@
.setCallingPid(-1)
.setCallingUid(parent.launchedFromUid)
.setCallingPackage(parent.launchedFromPackage)
+ .setCallingFeatureId(parent.launchedFromFeatureId)
.setRealCallingPid(-1)
.setRealCallingUid(parent.launchedFromUid)
.setComponentSpecified(true)
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index a513ef8..a582f21 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -88,6 +88,7 @@
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import android.Manifest;
+import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
@@ -260,7 +261,9 @@
/** Short cut */
private WindowManagerService mWindowManager;
- /** Common synchronization logic used to save things to disks. */
+ private AppOpsManager mAppOpsManager;
+
+ /** Common synchronization logic used to save things to disks. */
PersisterQueue mPersisterQueue;
LaunchParamsPersister mLaunchParamsPersister;
private LaunchParamsController mLaunchParamsController;
@@ -1047,8 +1050,8 @@
boolean checkStartAnyActivityPermission(Intent intent, ActivityInfo aInfo, String resultWho,
int requestCode, int callingPid, int callingUid, String callingPackage,
- boolean ignoreTargetSecurity, boolean launchingInTask,
- WindowProcessController callerApp, ActivityRecord resultRecord,
+ @Nullable String callingFeatureId, boolean ignoreTargetSecurity,
+ boolean launchingInTask, WindowProcessController callerApp, ActivityRecord resultRecord,
ActivityStack resultStack) {
final boolean isCallerRecents = mService.getRecentTasks() != null
&& mService.getRecentTasks().isCallerRecents(callingUid);
@@ -1060,10 +1063,10 @@
// existing task, then also allow the activity to be fully relaunched.
return true;
}
- final int componentRestriction = getComponentRestrictionForCallingPackage(
- aInfo, callingPackage, callingPid, callingUid, ignoreTargetSecurity);
+ final int componentRestriction = getComponentRestrictionForCallingPackage(aInfo,
+ callingPackage, callingFeatureId, callingPid, callingUid, ignoreTargetSecurity);
final int actionRestriction = getActionRestrictionForCallingPackage(
- intent.getAction(), callingPackage, callingPid, callingUid);
+ intent.getAction(), callingPackage, callingFeatureId, callingPid, callingUid);
if (componentRestriction == ACTIVITY_RESTRICTION_PERMISSION
|| actionRestriction == ACTIVITY_RESTRICTION_PERMISSION) {
if (resultRecord != null) {
@@ -1194,8 +1197,16 @@
}
}
+ private AppOpsManager getAppOpsManager() {
+ if (mAppOpsManager == null) {
+ mAppOpsManager = mService.mContext.getSystemService(AppOpsManager.class);
+ }
+ return mAppOpsManager;
+ }
+
private int getComponentRestrictionForCallingPackage(ActivityInfo activityInfo,
- String callingPackage, int callingPid, int callingUid, boolean ignoreTargetSecurity) {
+ String callingPackage, @Nullable String callingFeatureId, int callingPid,
+ int callingUid, boolean ignoreTargetSecurity) {
if (!ignoreTargetSecurity && mService.checkComponentPermission(activityInfo.permission,
callingPid, callingUid, activityInfo.applicationInfo.uid, activityInfo.exported)
== PERMISSION_DENIED) {
@@ -1211,9 +1222,8 @@
return ACTIVITY_RESTRICTION_NONE;
}
- // TODO moltmann b/136595429: Set featureId from caller
- if (mService.getAppOpsService().noteOperation(opCode, callingUid,
- callingPackage, /* featureId */ null, false, "") != AppOpsManager.MODE_ALLOWED) {
+ if (getAppOpsManager().noteOpNoThrow(opCode, callingUid,
+ callingPackage, callingFeatureId, "") != AppOpsManager.MODE_ALLOWED) {
if (!ignoreTargetSecurity) {
return ACTIVITY_RESTRICTION_APPOP;
}
@@ -1222,8 +1232,8 @@
return ACTIVITY_RESTRICTION_NONE;
}
- private int getActionRestrictionForCallingPackage(String action,
- String callingPackage, int callingPid, int callingUid) {
+ private int getActionRestrictionForCallingPackage(String action, String callingPackage,
+ @Nullable String callingFeatureId, int callingPid, int callingUid) {
if (action == null) {
return ACTIVITY_RESTRICTION_NONE;
}
@@ -1256,9 +1266,8 @@
return ACTIVITY_RESTRICTION_NONE;
}
- // TODO moltmann b/136595429: Set featureId from caller
- if (mService.getAppOpsService().noteOperation(opCode, callingUid,
- callingPackage, /* featureId */ null, false, "") != AppOpsManager.MODE_ALLOWED) {
+ if (getAppOpsManager().noteOpNoThrow(opCode, callingUid,
+ callingPackage, callingFeatureId, "") != AppOpsManager.MODE_ALLOWED) {
return ACTIVITY_RESTRICTION_APPOP;
}
@@ -2701,6 +2710,7 @@
SafeActivityOptions options) {
Task task = null;
final String callingPackage;
+ final String callingFeatureId;
final Intent intent;
final int userId;
int activityType = ACTIVITY_TYPE_UNDEFINED;
@@ -2780,11 +2790,12 @@
return ActivityManager.START_TASK_TO_FRONT;
}
callingPackage = task.mCallingPackage;
+ callingFeatureId = task.mCallingFeatureId;
intent = task.intent;
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
userId = task.mUserId;
- return mService.getActivityStartController().startActivityInPackage(
- task.mCallingUid, callingPid, callingUid, callingPackage, intent, null, null,
+ return mService.getActivityStartController().startActivityInPackage(task.mCallingUid,
+ callingPid, callingUid, callingPackage, callingFeatureId, intent, null, null,
null, 0, 0, options, userId, task, "startActivityFromRecents",
false /* validateIncomingUser */, null /* originatingPendingIntent */,
false /* allowBackgroundActivityStart */);
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index f35ba9e..881dc81 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -26,6 +26,7 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.IApplicationThread;
import android.content.ComponentName;
@@ -278,10 +279,11 @@
}
final int startActivityInPackage(int uid, int realCallingPid, int realCallingUid,
- String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
- String resultWho, int requestCode, int startFlags, SafeActivityOptions options,
- int userId, Task inTask, String reason, boolean validateIncomingUser,
- PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
+ String callingPackage, @Nullable String callingFeatureId, Intent intent,
+ String resolvedType, IBinder resultTo, String resultWho, int requestCode,
+ int startFlags, SafeActivityOptions options, int userId, Task inTask, String reason,
+ boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
+ boolean allowBackgroundActivityStart) {
userId = checkTargetUser(userId, validateIncomingUser, realCallingPid, realCallingUid,
reason);
@@ -292,6 +294,7 @@
.setRealCallingPid(realCallingPid)
.setRealCallingUid(realCallingUid)
.setCallingPackage(callingPackage)
+ .setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
@@ -310,19 +313,20 @@
*
* @param uid Make a call as if this UID did.
* @param callingPackage Make a call as if this package did.
+ * @param callingFeatureId Make a call as if this feature in the package did.
* @param intents Intents to start.
* @param userId Start the intents on this user.
* @param validateIncomingUser Set true to skip checking {@code userId} with the calling UID.
* @param originatingPendingIntent PendingIntentRecord that originated this activity start or
* null if not originated by PendingIntent
*/
- final int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents,
- String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
- boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
- boolean allowBackgroundActivityStart) {
+ final int startActivitiesInPackage(int uid, String callingPackage,
+ @Nullable String callingFeatureId, Intent[] intents, String[] resolvedTypes,
+ IBinder resultTo, SafeActivityOptions options, int userId, boolean validateIncomingUser,
+ PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
return startActivitiesInPackage(uid, 0 /* realCallingPid */, -1 /* realCallingUid */,
- callingPackage, intents, resolvedTypes, resultTo, options, userId, validateIncomingUser,
- originatingPendingIntent, allowBackgroundActivityStart);
+ callingPackage, callingFeatureId, intents, resolvedTypes, resultTo, options, userId,
+ validateIncomingUser, originatingPendingIntent, allowBackgroundActivityStart);
}
/**
@@ -339,9 +343,9 @@
* null if not originated by PendingIntent
*/
final int startActivitiesInPackage(int uid, int realCallingPid, int realCallingUid,
- String callingPackage, Intent[] intents, String[] resolvedTypes, IBinder resultTo,
- SafeActivityOptions options, int userId, boolean validateIncomingUser,
- PendingIntentRecord originatingPendingIntent,
+ String callingPackage, @Nullable String callingFeatureId, Intent[] intents,
+ String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
+ boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
boolean allowBackgroundActivityStart) {
final String reason = "startActivityInPackage";
@@ -350,14 +354,14 @@
Binder.getCallingUid(), reason);
// TODO: Switch to user app stacks here.
- return startActivities(null, uid, realCallingPid, realCallingUid, callingPackage, intents,
- resolvedTypes, resultTo, options, userId, reason, originatingPendingIntent,
- allowBackgroundActivityStart);
+ return startActivities(null, uid, realCallingPid, realCallingUid, callingPackage,
+ callingFeatureId, intents, resolvedTypes, resultTo, options, userId, reason,
+ originatingPendingIntent, allowBackgroundActivityStart);
}
int startActivities(IApplicationThread caller, int callingUid, int incomingRealCallingPid,
- int incomingRealCallingUid, String callingPackage, Intent[] intents,
- String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options,
+ int incomingRealCallingUid, String callingPackage, @Nullable String callingFeatureId,
+ Intent[] intents, String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options,
int userId, String reason, PendingIntentRecord originatingPendingIntent,
boolean allowBackgroundActivityStart) {
if (intents == null) {
@@ -435,6 +439,7 @@
.setCallingPid(callingPid)
.setCallingUid(callingUid)
.setCallingPackage(callingPackage)
+ .setCallingFeatureId(callingFeatureId)
.setRealCallingPid(realCallingPid)
.setRealCallingUid(realCallingUid)
.setActivityOptions(checkedOptions)
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index 76aa1d1..1009771 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -34,6 +34,7 @@
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.KeyguardManager;
import android.app.admin.DevicePolicyManagerInternal;
@@ -85,6 +86,7 @@
private int mUserId;
private int mStartFlags;
private String mCallingPackage;
+ private @Nullable String mCallingFeatureId;
/*
* Per-intent states that were load from ActivityStarter and are subject to modifications
@@ -120,19 +122,20 @@
* method should not be changed during intercept.
*/
void setStates(int userId, int realCallingPid, int realCallingUid, int startFlags,
- String callingPackage) {
+ String callingPackage, @Nullable String callingFeatureId) {
mRealCallingPid = realCallingPid;
mRealCallingUid = realCallingUid;
mUserId = userId;
mStartFlags = startFlags;
mCallingPackage = callingPackage;
+ mCallingFeatureId = callingFeatureId;
}
private IntentSender createIntentSenderForOriginalIntent(int callingUid, int flags) {
Bundle activityOptions = deferCrossProfileAppsAnimationIfNecessary();
final IIntentSender target = mService.getIntentSenderLocked(
- INTENT_SENDER_ACTIVITY, mCallingPackage, callingUid, mUserId, null /*token*/,
- null /*resultCode*/, 0 /*requestCode*/,
+ INTENT_SENDER_ACTIVITY, mCallingPackage, mCallingFeatureId, callingUid, mUserId,
+ null /*token*/, null /*resultCode*/, 0 /*requestCode*/,
new Intent[] { mIntent }, new String[] { mResolvedType },
flags, activityOptions);
return new IntentSender(target);
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index c7270f2..8ed798c 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -318,6 +318,7 @@
int callingPid = DEFAULT_CALLING_PID;
int callingUid = DEFAULT_CALLING_UID;
String callingPackage;
+ @Nullable String callingFeatureId;
int realCallingPid = DEFAULT_REAL_CALLING_PID;
int realCallingUid = DEFAULT_REAL_CALLING_UID;
int startFlags;
@@ -367,6 +368,7 @@
callingPid = DEFAULT_CALLING_PID;
callingUid = DEFAULT_CALLING_UID;
callingPackage = null;
+ callingFeatureId = null;
realCallingPid = DEFAULT_REAL_CALLING_PID;
realCallingUid = DEFAULT_REAL_CALLING_UID;
startFlags = 0;
@@ -405,6 +407,7 @@
callingPid = request.callingPid;
callingUid = request.callingUid;
callingPackage = request.callingPackage;
+ callingFeatureId = request.callingFeatureId;
realCallingPid = request.realCallingPid;
realCallingUid = request.realCallingUid;
startFlags = request.startFlags;
@@ -693,9 +696,10 @@
}
final IIntentSender target = mService.getIntentSenderLocked(
- ActivityManager.INTENT_SENDER_ACTIVITY, "android" /* packageName */, appCallingUid,
- mRequest.userId, null /* token */, null /* resultWho*/, 0 /* requestCode*/,
- new Intent[] { mRequest.intent }, new String[] { mRequest.resolvedType },
+ ActivityManager.INTENT_SENDER_ACTIVITY, "android" /* packageName */,
+ null /* featureId */, appCallingUid, mRequest.userId, null /* token */,
+ null /* resultWho*/, 0 /* requestCode*/, new Intent[]{mRequest.intent},
+ new String[]{mRequest.resolvedType},
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT,
null /* bOptions */);
@@ -807,6 +811,7 @@
int callingPid = request.callingPid;
int callingUid = request.callingUid;
String callingPackage = request.callingPackage;
+ String callingFeatureId = request.callingFeatureId;
final int realCallingPid = request.realCallingPid;
final int realCallingUid = request.realCallingUid;
final int startFlags = request.startFlags;
@@ -882,6 +887,7 @@
// we want the final activity to consider it to have been launched by the
// previous app activity.
callingPackage = sourceRecord.launchedFromPackage;
+ callingFeatureId = sourceRecord.launchedFromFeatureId;
}
}
@@ -949,8 +955,8 @@
}
boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
- requestCode, callingPid, callingUid, callingPackage, request.ignoreTargetSecurity,
- inTask != null, callerApp, resultRecord, resultStack);
+ requestCode, callingPid, callingUid, callingPackage, callingFeatureId,
+ request.ignoreTargetSecurity, inTask != null, callerApp, resultRecord, resultStack);
abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
callingPid, resolvedType, aInfo.applicationInfo);
abort |= !mService.getPermissionPolicyInternal().checkStartActivity(intent, callingUid,
@@ -990,7 +996,8 @@
}
}
- mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage);
+ mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage,
+ callingFeatureId);
if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid,
callingUid, checkedOptions)) {
// activity start was intercepted, e.g. because the target user is currently in quiet
@@ -1023,7 +1030,7 @@
if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
aInfo.packageName, userId)) {
final IIntentSender target = mService.getIntentSenderLocked(
- ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
+ ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, callingFeatureId,
callingUid, userId, null, null, 0, new Intent[]{intent},
new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT
| PendingIntent.FLAG_ONE_SHOT, null);
@@ -1081,7 +1088,7 @@
// app [on install success].
if (rInfo != null && rInfo.auxiliaryInfo != null) {
intent = createLaunchIntent(rInfo.auxiliaryInfo, request.ephemeralIntent,
- callingPackage, verificationBundle, resolvedType, userId);
+ callingPackage, callingFeatureId, verificationBundle, resolvedType, userId);
resolvedType = null;
callingUid = realCallingUid;
callingPid = realCallingPid;
@@ -1090,9 +1097,10 @@
}
final ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
- callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
- resultRecord, resultWho, requestCode, request.componentSpecified,
- voiceSession != null, mSupervisor, checkedOptions, sourceRecord);
+ callingPackage, callingFeatureId, intent, resolvedType, aInfo,
+ mService.getGlobalConfiguration(), resultRecord, resultWho, requestCode,
+ request.componentSpecified, voiceSession != null, mSupervisor, checkedOptions,
+ sourceRecord);
mLastStartActivityRecord = r;
if (r.appTimeTracker == null && sourceRecord != null) {
@@ -1302,21 +1310,22 @@
* Creates a launch intent for the given auxiliary resolution data.
*/
private @NonNull Intent createLaunchIntent(@Nullable AuxiliaryResolveInfo auxiliaryResponse,
- Intent originalIntent, String callingPackage, Bundle verificationBundle,
- String resolvedType, int userId) {
+ Intent originalIntent, String callingPackage, @Nullable String callingFeatureId,
+ Bundle verificationBundle, String resolvedType, int userId) {
if (auxiliaryResponse != null && auxiliaryResponse.needsPhaseTwo) {
// request phase two resolution
PackageManagerInternal packageManager = mService.getPackageManagerInternalLocked();
boolean isRequesterInstantApp = packageManager.isInstantApp(callingPackage, userId);
packageManager.requestInstantAppResolutionPhaseTwo(
auxiliaryResponse, originalIntent, resolvedType, callingPackage,
- isRequesterInstantApp, verificationBundle, userId);
+ callingFeatureId, isRequesterInstantApp, verificationBundle, userId);
}
return InstantAppResolver.buildEphemeralInstallerIntent(
originalIntent,
InstantAppResolver.sanitizeIntent(originalIntent),
auxiliaryResponse == null ? null : auxiliaryResponse.failureIntent,
callingPackage,
+ callingFeatureId,
verificationBundle,
resolvedType,
userId,
@@ -2575,6 +2584,11 @@
return this;
}
+ ActivityStarter setCallingFeatureId(String callingFeatureId) {
+ mRequest.callingFeatureId = callingFeatureId;
+ return this;
+ }
+
/**
* Sets the pid of the caller who requested to launch the activity.
*
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 25f6d6f..7302e52 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -182,14 +182,15 @@
public abstract void notifySingleTaskDisplayDrawn(int displayId);
/**
- * Start activity {@code intents} as if {@code packageName} on user {@code userId} did it.
+ * Start activity {@code intents} as if {@code packageName/featureId} on user {@code userId} did
+ * it.
*
* - DO NOT call it with the calling UID cleared.
* - All the necessary caller permission checks must be done at callsites.
*
* @return error codes used by {@link IActivityManager#startActivity} and its siblings.
*/
- public abstract int startActivitiesAsPackage(String packageName,
+ public abstract int startActivitiesAsPackage(String packageName, String featureId,
int userId, Intent[] intents, Bundle bOptions);
/**
@@ -199,6 +200,7 @@
* @param realCallingPid PID of the real caller.
* @param realCallingUid UID of the real caller.
* @param callingPackage Make a call as if this package did.
+ * @param callingFeatureId Make a call as if this feature in the package did.
* @param intents Intents to start.
* @param userId Start the intents on this user.
* @param validateIncomingUser Set true to skip checking {@code userId} with the calling UID.
@@ -208,16 +210,17 @@
* from originatingPendingIntent
*/
public abstract int startActivitiesInPackage(int uid, int realCallingPid, int realCallingUid,
- String callingPackage, Intent[] intents, String[] resolvedTypes, IBinder resultTo,
- SafeActivityOptions options, int userId, boolean validateIncomingUser,
- PendingIntentRecord originatingPendingIntent,
+ String callingPackage, @Nullable String callingFeatureId, Intent[] intents,
+ String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
+ boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
boolean allowBackgroundActivityStart);
public abstract int startActivityInPackage(int uid, int realCallingPid, int realCallingUid,
- String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
- String resultWho, int requestCode, int startFlags, SafeActivityOptions options,
- int userId, Task inTask, String reason, boolean validateIncomingUser,
- PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart);
+ String callingPackage, @Nullable String callingFeaturId, Intent intent,
+ String resolvedType, IBinder resultTo, String resultWho, int requestCode,
+ int startFlags, SafeActivityOptions options, int userId, Task inTask, String reason,
+ boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
+ boolean allowBackgroundActivityStart);
/**
* Start activity {@code intent} without calling user-id check.
@@ -228,7 +231,7 @@
* @return error codes used by {@link IActivityManager#startActivity} and its siblings.
*/
public abstract int startActivityAsUser(IApplicationThread caller, String callingPackage,
- Intent intent, @Nullable Bundle options, int userId);
+ @Nullable String callingFeatureId, Intent intent, @Nullable Bundle options, int userId);
/**
* Called when Keyguard flags might have changed.
@@ -388,7 +391,7 @@
public abstract ActivityTokens getTopActivityForTask(int taskId);
public abstract IIntentSender getIntentSender(int type, String packageName,
- int callingUid, int userId, IBinder token, String resultWho,
+ @Nullable String featureId, int callingUid, int userId, IBinder token, String resultWho,
int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
Bundle bOptions);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 5f3e3a3..ea5a71a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -234,7 +234,6 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.AssistUtils;
-import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.ProcessMap;
import com.android.internal.logging.MetricsLogger;
@@ -264,7 +263,6 @@
import com.android.server.am.PendingIntentController;
import com.android.server.am.PendingIntentRecord;
import com.android.server.am.UserState;
-import com.android.server.appop.AppOpsService;
import com.android.server.firewall.IntentFirewall;
import com.android.server.inputmethod.InputMethodSystemProperty;
import com.android.server.pm.UserManagerService;
@@ -378,7 +376,7 @@
RootWindowContainer mRootWindowContainer;
WindowManagerService mWindowManager;
private UserManagerService mUserManager;
- private AppOpsService mAppOpsService;
+ private AppOpsManager mAppOpsManager;
/** All active uids in the system. */
private final MirrorActiveUids mActiveUids = new MirrorActiveUids();
private final SparseArray<String> mPendingTempWhitelist = new SparseArray<>();
@@ -891,12 +889,11 @@
return mUserManager;
}
- AppOpsService getAppOpsService() {
- if (mAppOpsService == null) {
- IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
- mAppOpsService = (AppOpsService) IAppOpsService.Stub.asInterface(b);
+ AppOpsManager getAppOpsManager() {
+ if (mAppOpsManager == null) {
+ mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
}
- return mAppOpsService;
+ return mAppOpsManager;
}
boolean hasUserRestriction(String restriction, int userId) {
@@ -904,8 +901,8 @@
}
boolean hasSystemAlertWindowPermission(int callingUid, int callingPid, String callingPackage) {
- final int mode = getAppOpsService().noteOperation(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
- callingUid, callingPackage, /* featureId */ null, false, "");
+ final int mode = getAppOpsManager().noteOpNoThrow(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
+ callingUid, callingPackage, /* featureId */ null, "");
if (mode == AppOpsManager.MODE_DEFAULT) {
return checkPermission(Manifest.permission.SYSTEM_ALERT_WINDOW, callingPid, callingUid)
== PERMISSION_GRANTED;
@@ -1025,41 +1022,43 @@
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
- Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
- int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
- return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
- resultWho, requestCode, startFlags, profilerInfo, bOptions,
+ String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
+ String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
+ Bundle bOptions) {
+ return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
+ resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
@Override
public final int startActivities(IApplicationThread caller, String callingPackage,
- Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle bOptions,
- int userId) {
+ String callingFeatureId, Intent[] intents, String[] resolvedTypes, IBinder resultTo,
+ Bundle bOptions, int userId) {
assertPackageMatchesCallingUid(callingPackage);
final String reason = "startActivities";
enforceNotIsolatedCaller(reason);
userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, reason);
// TODO: Switch to user app stacks here.
return getActivityStartController().startActivities(caller, -1, 0, -1, callingPackage,
- intents, resolvedTypes, resultTo, SafeActivityOptions.fromBundle(bOptions), userId,
- reason, null /* originatingPendingIntent */,
- false /* allowBackgroundActivityStart */);
+ callingFeatureId, intents, resolvedTypes, resultTo,
+ SafeActivityOptions.fromBundle(bOptions), userId, reason,
+ null /* originatingPendingIntent */, false /* allowBackgroundActivityStart */);
}
@Override
public int startActivityAsUser(IApplicationThread caller, String callingPackage,
- Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
- int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
- return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
- resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
+ String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
+ String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
+ Bundle bOptions, int userId) {
+ return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
+ resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
true /*validateIncomingUser*/);
}
private int startActivityAsUser(IApplicationThread caller, String callingPackage,
- Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
- int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
- boolean validateIncomingUser) {
+ @Nullable String callingFeatureId, Intent intent, String resolvedType,
+ IBinder resultTo, String resultWho, int requestCode, int startFlags,
+ ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
assertPackageMatchesCallingUid(callingPackage);
enforceNotIsolatedCaller("startActivityAsUser");
@@ -1070,6 +1069,7 @@
return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
+ .setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
@@ -1215,6 +1215,7 @@
.setCallingPid(-1)
.setCallingUid(r.launchedFromUid)
.setCallingPackage(r.launchedFromPackage)
+ .setCallingFeatureId(r.launchedFromFeatureId)
.setRealCallingPid(-1)
.setRealCallingUid(r.launchedFromUid)
.setActivityOptions(options)
@@ -1231,8 +1232,9 @@
@Override
public final WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
- Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
- int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
+ String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
+ String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
+ Bundle bOptions, int userId) {
assertPackageMatchesCallingUid(callingPackage);
final WaitResult res = new WaitResult();
enforceNotIsolatedCaller("startActivityAndWait");
@@ -1242,6 +1244,7 @@
getActivityStartController().obtainStarter(intent, "startActivityAndWait")
.setCaller(caller)
.setCallingPackage(callingPackage)
+ .setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
@@ -1257,8 +1260,9 @@
@Override
public final int startActivityWithConfig(IApplicationThread caller, String callingPackage,
- Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
- int startFlags, Configuration config, Bundle bOptions, int userId) {
+ String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
+ String resultWho, int requestCode, int startFlags, Configuration config,
+ Bundle bOptions, int userId) {
assertPackageMatchesCallingUid(callingPackage);
enforceNotIsolatedCaller("startActivityWithConfig");
userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
@@ -1267,6 +1271,7 @@
return getActivityStartController().obtainStarter(intent, "startActivityWithConfig")
.setCaller(caller)
.setCallingPackage(callingPackage)
+ .setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
@@ -1317,6 +1322,7 @@
final ActivityRecord sourceRecord;
final int targetUid;
final String targetPackage;
+ final String targetFeatureId;
final boolean isResolver;
synchronized (mGlobalLock) {
if (resultTo == null) {
@@ -1384,6 +1390,7 @@
}
targetUid = sourceRecord.launchedFromUid;
targetPackage = sourceRecord.launchedFromPackage;
+ targetFeatureId = sourceRecord.launchedFromFeatureId;
isResolver = sourceRecord.isResolverOrChildActivity();
}
@@ -1396,6 +1403,7 @@
return getActivityStartController().obtainStarter(intent, "startActivityAsCaller")
.setCallingUid(targetUid)
.setCallingPackage(targetPackage)
+ .setCallingFeatureId(targetFeatureId)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
@@ -1431,8 +1439,8 @@
}
@Override
- public int startVoiceActivity(String callingPackage, int callingPid, int callingUid,
- Intent intent, String resolvedType, IVoiceInteractionSession session,
+ public int startVoiceActivity(String callingPackage, String callingFeatureId, int callingPid,
+ int callingUid, Intent intent, String resolvedType, IVoiceInteractionSession session,
IVoiceInteractor interactor, int startFlags, ProfilerInfo profilerInfo,
Bundle bOptions, int userId) {
assertPackageMatchesCallingUid(callingPackage);
@@ -1445,6 +1453,7 @@
return getActivityStartController().obtainStarter(intent, "startVoiceActivity")
.setCallingUid(callingUid)
.setCallingPackage(callingPackage)
+ .setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setVoiceSession(session)
.setVoiceInteractor(interactor)
@@ -1457,8 +1466,9 @@
}
@Override
- public int startAssistantActivity(String callingPackage, int callingPid, int callingUid,
- Intent intent, String resolvedType, Bundle bOptions, int userId) {
+ public int startAssistantActivity(String callingPackage, @NonNull String callingFeatureId,
+ int callingPid, int callingUid, Intent intent, String resolvedType, Bundle bOptions,
+ int userId) {
assertPackageMatchesCallingUid(callingPackage);
mAmInternal.enforceCallingPermission(BIND_VOICE_INTERACTION, "startAssistantActivity()");
userId = handleIncomingUser(callingPid, callingUid, userId, "startAssistantActivity");
@@ -1466,6 +1476,7 @@
return getActivityStartController().obtainStarter(intent, "startAssistantActivity")
.setCallingUid(callingUid)
.setCallingPackage(callingPackage)
+ .setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setActivityOptions(bOptions)
.setUserId(userId)
@@ -1489,13 +1500,14 @@
try {
synchronized (mGlobalLock) {
final ComponentName recentsComponent = mRecentTasks.getRecentsComponent();
+ final String recentsFeatureId = mRecentTasks.getRecentsComponentFeatureId();
final int recentsUid = mRecentTasks.getRecentsComponentUid();
final WindowProcessController caller = getProcessController(callingPid, callingUid);
// Start a new recents animation
final RecentsAnimation anim = new RecentsAnimation(this, mStackSupervisor,
getActivityStartController(), mWindowManager, intent, recentsComponent,
- recentsUid, caller);
+ recentsFeatureId, recentsUid, caller);
if (recentsAnimationRunner == null) {
anim.preloadRecentsActivity();
} else {
@@ -5773,9 +5785,9 @@
}
- IIntentSender getIntentSenderLocked(int type, String packageName, int callingUid, int userId,
- IBinder token, String resultWho, int requestCode, Intent[] intents,
- String[] resolvedTypes, int flags, Bundle bOptions) {
+ IIntentSender getIntentSenderLocked(int type, String packageName, String featureId,
+ int callingUid, int userId, IBinder token, String resultWho, int requestCode,
+ Intent[] intents, String[] resolvedTypes, int flags, Bundle bOptions) {
ActivityRecord activity = null;
if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {
@@ -5791,8 +5803,8 @@
}
final PendingIntentRecord rec = mPendingIntentController.getIntentSender(type, packageName,
- callingUid, userId, token, resultWho, requestCode, intents, resolvedTypes, flags,
- bOptions);
+ featureId, callingUid, userId, token, resultWho, requestCode, intents,
+ resolvedTypes, flags, bOptions);
final boolean noCreate = (flags & PendingIntent.FLAG_NO_CREATE) != 0;
if (noCreate) {
return rec;
@@ -6180,8 +6192,8 @@
}
@Override
- public int startActivitiesAsPackage(String packageName, int userId, Intent[] intents,
- Bundle bOptions) {
+ public int startActivitiesAsPackage(String packageName, @Nullable String featureId,
+ int userId, Intent[] intents, Bundle bOptions) {
Objects.requireNonNull(intents, "intents");
final String[] resolvedTypes = new String[intents.length];
@@ -6206,7 +6218,7 @@
}
return getActivityStartController().startActivitiesInPackage(
- packageUid, packageName,
+ packageUid, packageName, featureId,
intents, resolvedTypes, null /* resultTo */,
SafeActivityOptions.fromBundle(bOptions), userId,
false /* validateIncomingUser */, null /* originatingPendingIntent */,
@@ -6215,41 +6227,41 @@
@Override
public int startActivitiesInPackage(int uid, int realCallingPid, int realCallingUid,
- String callingPackage, Intent[] intents, String[] resolvedTypes, IBinder resultTo,
- SafeActivityOptions options, int userId, boolean validateIncomingUser,
- PendingIntentRecord originatingPendingIntent,
+ String callingPackage, @Nullable String callingFeatureId, Intent[] intents,
+ String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
+ boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
boolean allowBackgroundActivityStart) {
assertPackageMatchesCallingUid(callingPackage);
synchronized (mGlobalLock) {
return getActivityStartController().startActivitiesInPackage(uid, realCallingPid,
- realCallingUid, callingPackage, intents, resolvedTypes, resultTo, options,
- userId, validateIncomingUser, originatingPendingIntent,
+ realCallingUid, callingPackage, callingFeatureId, intents, resolvedTypes,
+ resultTo, options, userId, validateIncomingUser, originatingPendingIntent,
allowBackgroundActivityStart);
}
}
@Override
public int startActivityInPackage(int uid, int realCallingPid, int realCallingUid,
- String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
- String resultWho, int requestCode, int startFlags, SafeActivityOptions options,
- int userId, Task inTask, String reason, boolean validateIncomingUser,
- PendingIntentRecord originatingPendingIntent,
+ String callingPackage, @Nullable String callingFeatureId, Intent intent,
+ String resolvedType, IBinder resultTo, String resultWho, int requestCode,
+ int startFlags, SafeActivityOptions options, int userId, Task inTask, String reason,
+ boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
boolean allowBackgroundActivityStart) {
assertPackageMatchesCallingUid(callingPackage);
synchronized (mGlobalLock) {
return getActivityStartController().startActivityInPackage(uid, realCallingPid,
- realCallingUid, callingPackage, intent, resolvedType, resultTo, resultWho,
- requestCode, startFlags, options, userId, inTask, reason,
- validateIncomingUser, originatingPendingIntent,
+ realCallingUid, callingPackage, callingFeatureId, intent, resolvedType,
+ resultTo, resultWho, requestCode, startFlags, options, userId, inTask,
+ reason, validateIncomingUser, originatingPendingIntent,
allowBackgroundActivityStart);
}
}
@Override
- public int startActivityAsUser(IApplicationThread caller, String callerPacakge,
- Intent intent, Bundle options, int userId) {
+ public int startActivityAsUser(IApplicationThread caller, String callerPackage,
+ @Nullable String callerFeatureId, Intent intent, Bundle options, int userId) {
return ActivityTaskManagerService.this.startActivityAsUser(
- caller, callerPacakge, intent,
+ caller, callerPackage, callerFeatureId, intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, options, userId,
false /*validateIncomingUser*/);
@@ -6685,12 +6697,12 @@
@Override
public IIntentSender getIntentSender(int type, String packageName,
- int callingUid, int userId, IBinder token, String resultWho,
- int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
- Bundle bOptions) {
+ @Nullable String featureId, int callingUid, int userId, IBinder token,
+ String resultWho, int requestCode, Intent[] intents, String[] resolvedTypes,
+ int flags, Bundle bOptions) {
synchronized (mGlobalLock) {
- return getIntentSenderLocked(type, packageName, callingUid, userId, token,
- resultWho, requestCode, intents, resolvedTypes, flags, bOptions);
+ return getIntentSenderLocked(type, packageName, featureId, callingUid, userId,
+ token, resultWho, requestCode, intents, resolvedTypes, flags, bOptions);
}
}
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 16a7564..8fa8119 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -125,7 +125,7 @@
}
@Override
- public int startActivity(IBinder whoThread, String callingPackage,
+ public int startActivity(IBinder whoThread, String callingPackage, String callingFeatureId,
Intent intent, String resolvedType, Bundle bOptions) {
checkCaller();
mService.assertPackageMatchesCallingUid(callingPackage);
@@ -148,6 +148,7 @@
return mService.getActivityStartController().obtainStarter(intent, "AppTaskImpl")
.setCaller(appThread)
.setCallingPackage(callingPackage)
+ .setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setActivityOptions(bOptions)
.setUserId(callingUser)
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 0418afaf..7986659 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -240,6 +240,10 @@
target = target.getWindow().getImeControlTarget();
}
+ if (mWin != null && mWin.getSurfaceControl() == null) {
+ // if window doesn't have a surface, set it null and return.
+ setWindow(null, null, null);
+ }
if (mWin == null) {
mControlTarget = target;
return;
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index a9dc36d..3771b3e 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -42,6 +42,7 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.AppGlobals;
@@ -155,6 +156,7 @@
*/
private int mRecentsUid = -1;
private ComponentName mRecentsComponent = null;
+ private @Nullable String mFeatureId;
/**
* Mapping of user id -> whether recent tasks have been loaded for that user.
@@ -418,6 +420,13 @@
}
/**
+ * @return the featureId for the recents component.
+ */
+ @Nullable String getRecentsComponentFeatureId() {
+ return mFeatureId;
+ }
+
+ /**
* @return the uid for the recents component.
*/
int getRecentsComponentUid() {
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 9770947..b0492be 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -63,6 +63,7 @@
private final DisplayContent mDefaultDisplay;
private final Intent mTargetIntent;
private final ComponentName mRecentsComponent;
+ private final @Nullable String mRecentsFeatureId;
private final int mRecentsUid;
private final @Nullable WindowProcessController mCaller;
private final int mUserId;
@@ -80,8 +81,8 @@
RecentsAnimation(ActivityTaskManagerService atm, ActivityStackSupervisor stackSupervisor,
ActivityStartController activityStartController, WindowManagerService wm,
- Intent targetIntent, ComponentName recentsComponent, int recentsUid,
- @Nullable WindowProcessController caller) {
+ Intent targetIntent, ComponentName recentsComponent, @Nullable String recentsFeatureId,
+ int recentsUid, @Nullable WindowProcessController caller) {
mService = atm;
mStackSupervisor = stackSupervisor;
mDefaultDisplay = mService.mRootWindowContainer.getDefaultDisplay();
@@ -89,6 +90,7 @@
mWindowManager = wm;
mTargetIntent = targetIntent;
mRecentsComponent = recentsComponent;
+ mRecentsFeatureId = recentsFeatureId;
mRecentsUid = recentsUid;
mCaller = caller;
mUserId = atm.getCurrentUserId();
@@ -456,6 +458,7 @@
.obtainStarter(mTargetIntent, reason)
.setCallingUid(mRecentsUid)
.setCallingPackage(mRecentsComponent.getPackageName())
+ .setCallingFeatureId(mRecentsFeatureId)
.setActivityOptions(new SafeActivityOptions(options))
.setUserId(mUserId)
.execute();
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 87c91ef..0e500f9 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -79,11 +79,6 @@
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.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
-import static com.android.server.wm.TaskProto.DISPLAYED_BOUNDS;
-import static com.android.server.wm.TaskProto.FILLS_PARENT;
-import static com.android.server.wm.TaskProto.SURFACE_HEIGHT;
-import static com.android.server.wm.TaskProto.SURFACE_WIDTH;
-import static com.android.server.wm.TaskProto.WINDOW_CONTAINER;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
@@ -125,7 +120,6 @@
import android.service.voice.IVoiceInteractionSession;
import android.util.DisplayMetrics;
import android.util.Slog;
-import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
import android.view.ITaskOrganizer;
import android.view.RemoteAnimationTarget;
@@ -189,6 +183,7 @@
private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
private static final String ATTR_CALLING_UID = "calling_uid";
private static final String ATTR_CALLING_PACKAGE = "calling_package";
+ private static final String ATTR_CALLING_FEATURE_ID = "calling_feature_id";
private static final String ATTR_SUPPORTS_PICTURE_IN_PICTURE = "supports_picture_in_picture";
private static final String ATTR_RESIZE_MODE = "resize_mode";
private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";
@@ -302,6 +297,7 @@
// For relaunching the task from recents as though it was launched by the original launcher.
int mCallingUid;
String mCallingPackage;
+ String mCallingFeatureId;
private final Rect mTmpStableBounds = new Rect();
private final Rect mTmpNonDecorBounds = new Rect();
@@ -483,8 +479,8 @@
true /*neverRelinquishIdentity*/,
_taskDescription != null ? _taskDescription : new TaskDescription(),
_taskId, INVALID_TASK_ID, INVALID_TASK_ID, 0 /*taskAffiliationColor*/,
- info.applicationInfo.uid, info.packageName, info.resizeMode,
- info.supportsPictureInPicture(), false /*_realActivitySuspended*/,
+ info.applicationInfo.uid, info.packageName, null /* default featureId */,
+ info.resizeMode, info.supportsPictureInPicture(), false /*_realActivitySuspended*/,
false /*userSetupComplete*/, INVALID_MIN_SIZE, INVALID_MIN_SIZE, info,
_voiceSession, _voiceInteractor, stack);
}
@@ -506,18 +502,17 @@
}
/** Don't use constructor directly. This is only used by XML parser. */
- Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
- Intent _affinityIntent, String _affinity, String _rootAffinity,
- ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
- boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId,
- int _effectiveUid, String _lastDescription,
+ Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent, Intent _affinityIntent,
+ String _affinity, String _rootAffinity, ComponentName _realActivity,
+ ComponentName _origActivity, boolean _rootWasReset, boolean _autoRemoveRecents,
+ boolean _askedCompatMode, int _userId, int _effectiveUid, String _lastDescription,
long lastTimeMoved, boolean neverRelinquishIdentity,
TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId,
int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
- int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended,
- boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info,
- IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
- ActivityStack stack) {
+ @Nullable String callingFeatureId, int resizeMode, boolean supportsPictureInPicture,
+ boolean _realActivitySuspended, boolean userSetupComplete, int minWidth, int minHeight,
+ ActivityInfo info, IVoiceInteractionSession _voiceSession,
+ IVoiceInteractor _voiceInteractor, ActivityStack stack) {
super(atmService.mWindowManager);
EventLogTags.writeWmTaskCreated(_taskId, stack != null ? getRootTaskId() : INVALID_TASK_ID);
@@ -556,6 +551,7 @@
mNextAffiliateTaskId = nextTaskId;
mCallingUid = callingUid;
mCallingPackage = callingPackage;
+ mCallingFeatureId = callingFeatureId;
mResizeMode = resizeMode;
if (info != null) {
setIntent(_intent, info);
@@ -902,6 +898,7 @@
void setIntent(ActivityRecord r) {
mCallingUid = r.launchedFromUid;
mCallingPackage = r.launchedFromPackage;
+ mCallingFeatureId = r.launchedFromFeatureId;
setIntent(r.intent, r.info);
setLockTaskAuth(r);
@@ -1357,6 +1354,7 @@
isPersistable = r.isPersistable();
mCallingUid = r.launchedFromUid;
mCallingPackage = r.launchedFromPackage;
+ mCallingFeatureId = r.launchedFromFeatureId;
// Clamp to [1, max].
maxRecents = Math.min(Math.max(r.info.maxRecents, 1),
ActivityTaskManager.getMaxAppRecentsLimitStatic());
@@ -3195,12 +3193,16 @@
info.lastActiveTime = lastActiveTime;
info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription());
info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
- info.resizeMode = mResizeMode;
info.configuration.setTo(getConfiguration());
info.token = mRemoteToken;
// Get's the first non-undefined activity type among this and children. Can't use
// configuration.windowConfiguration because that would only be this level.
info.topActivityType = getActivityType();
+
+ //TODO (AM refactor): Just use local once updateEffectiveIntent is run during all child
+ // order changes.
+ final Task top = getTopMostTask();
+ info.resizeMode = top != null ? top.mResizeMode : mResizeMode;
}
/**
@@ -3233,6 +3235,7 @@
pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid);
pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete);
pw.print(" mCallingPackage="); pw.println(mCallingPackage);
+ pw.print(" mCallingFeatureId="); pw.println(mCallingFeatureId);
if (affinity != null || rootAffinity != null) {
pw.print(prefix); pw.print("affinity="); pw.print(affinity);
if (affinity == null || !affinity.equals(rootAffinity)) {
@@ -3442,6 +3445,8 @@
out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
+ out.attribute(null, ATTR_CALLING_FEATURE_ID,
+ mCallingFeatureId == null ? "" : mCallingFeatureId);
out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE,
String.valueOf(mSupportsPictureInPicture));
@@ -3555,16 +3560,17 @@
long lastTimeMoved, boolean neverRelinquishIdentity,
TaskDescription lastTaskDescription, int taskAffiliation, int prevTaskId,
int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
- int resizeMode, boolean supportsPictureInPicture, boolean realActivitySuspended,
+ @Nullable String callingFeatureId, int resizeMode,
+ boolean supportsPictureInPicture, boolean realActivitySuspended,
boolean userSetupComplete, int minWidth, int minHeight, ActivityStack stack) {
return new ActivityStack(service, taskId, intent, affinityIntent, affinity,
rootAffinity, realActivity, origActivity, rootWasReset, autoRemoveRecents,
askedCompatMode, userId, effectiveUid, lastDescription,
lastTimeMoved, neverRelinquishIdentity, lastTaskDescription, taskAffiliation,
prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage,
- resizeMode, supportsPictureInPicture, realActivitySuspended, userSetupComplete,
- minWidth, minHeight, null /*ActivityInfo*/, null /*_voiceSession*/,
- null /*_voiceInteractor*/, stack);
+ callingFeatureId, resizeMode, supportsPictureInPicture, realActivitySuspended,
+ userSetupComplete, minWidth, minHeight, null /*ActivityInfo*/,
+ null /*_voiceSession*/, null /*_voiceInteractor*/, stack);
}
Task restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
@@ -3597,6 +3603,7 @@
int nextTaskId = INVALID_TASK_ID;
int callingUid = -1;
String callingPackage = "";
+ String callingFeatureId = null;
int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
boolean supportsPictureInPicture = false;
Rect lastNonFullscreenBounds = null;
@@ -3677,6 +3684,9 @@
case ATTR_CALLING_PACKAGE:
callingPackage = attrValue;
break;
+ case ATTR_CALLING_FEATURE_ID:
+ callingFeatureId = attrValue;
+ break;
case ATTR_RESIZE_MODE:
resizeMode = Integer.parseInt(attrValue);
break;
@@ -3778,8 +3788,8 @@
autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription,
lastTimeOnTop, neverRelinquishIdentity, taskDescription,
taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid,
- callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended,
- userSetupComplete, minWidth, minHeight, null /*stack*/);
+ callingPackage, callingFeatureId, resizeMode, supportsPictureInPicture,
+ realActivitySuspended, userSetupComplete, minWidth, minHeight, null /*stack*/);
task.mLastNonFullscreenBounds = lastNonFullscreenBounds;
task.setBounds(lastNonFullscreenBounds);
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 096541f..0a0530c9 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -23,6 +23,8 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
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;
import android.annotation.Nullable;
import android.app.ActivityManager.RunningTaskInfo;
@@ -47,6 +49,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
@@ -375,6 +378,45 @@
}
}
+ @Override
+ public List<RunningTaskInfo> getChildTasks(IWindowContainer parent) {
+ enforceStackPermission("getChildTasks()");
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ if (parent == null) {
+ throw new IllegalArgumentException("Can't get children of null parent");
+ }
+ final WindowContainer container = WindowContainer.fromBinder(parent.asBinder());
+ if (container == null) {
+ Slog.e(TAG, "Can't get children of " + parent + " because it is not valid.");
+ return null;
+ }
+ // For now, only support returning children of persistent root tasks (of which the
+ // only current implementation is TaskTile).
+ if (!(container instanceof TaskTile)) {
+ Slog.w(TAG, "Can only get children of root tasks created via createRootTask");
+ return null;
+ }
+ ArrayList<RunningTaskInfo> out = new ArrayList<>();
+ // Tiles aren't real parents, so we need to go through stacks on the display to
+ // ensure correct ordering.
+ final DisplayContent dc = container.getDisplayContent();
+ for (int i = dc.getStackCount() - 1; i >= 0; --i) {
+ final ActivityStack as = dc.getStackAt(i);
+ if (as.getTile() == container) {
+ final RunningTaskInfo info = new RunningTaskInfo();
+ as.fillTaskInfo(info);
+ out.add(info);
+ }
+ }
+ return out;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
private int sanitizeAndApplyChange(WindowContainer container,
WindowContainerTransaction.Change change) {
if (!(container instanceof Task)) {
@@ -405,6 +447,54 @@
return effects;
}
+ private int sanitizeAndApplyHierarchyOp(WindowContainer container,
+ WindowContainerTransaction.HierarchyOp hop) {
+ if (!(container instanceof Task)) {
+ throw new IllegalArgumentException("Invalid container in hierarchy op");
+ }
+ if (hop.isReparent()) {
+ // special case for tiles since they are "virtual" parents
+ if (container instanceof ActivityStack && ((ActivityStack) container).isRootTask()) {
+ ActivityStack as = (ActivityStack) container;
+ TaskTile newParent = hop.getNewParent() == null ? null
+ : (TaskTile) WindowContainer.fromBinder(hop.getNewParent());
+ if (as.getTile() != newParent) {
+ if (as.getTile() != null) {
+ as.getTile().removeChild(as);
+ }
+ if (newParent != null) {
+ if (!as.affectedBySplitScreenResize()) {
+ return 0;
+ }
+ newParent.addChild(as, POSITION_TOP);
+ }
+ }
+ if (hop.getToTop()) {
+ as.getDisplay().positionStackAtTop(as, false /* includingParents */);
+ } else {
+ as.getDisplay().positionStackAtBottom(as);
+ }
+ } else if (container instanceof Task) {
+ throw new RuntimeException("Reparenting leaf Tasks is not supported now.");
+ }
+ } else {
+ // Ugh, of course ActivityStack has its own special reorder logic...
+ if (container instanceof ActivityStack && ((ActivityStack) container).isRootTask()) {
+ ActivityStack as = (ActivityStack) container;
+ if (hop.getToTop()) {
+ as.getDisplay().positionStackAtTop(as, false /* includingParents */);
+ } else {
+ as.getDisplay().positionStackAtBottom(as);
+ }
+ } else {
+ container.getParent().positionChildAt(
+ hop.getToTop() ? POSITION_TOP : POSITION_BOTTOM,
+ container, false /* includingParents */);
+ }
+ }
+ return TRANSACT_EFFECTS_LIFECYCLE;
+ }
+
private void resizePinnedStackIfNeeded(ConfigurationContainer container, int configMask,
int windowMask, Configuration config) {
if ((container instanceof ActivityStack)
@@ -470,8 +560,7 @@
while (entries.hasNext()) {
final Map.Entry<IBinder, WindowContainerTransaction.Change> entry =
entries.next();
- final WindowContainer wc = WindowContainer.RemoteToken.fromBinder(
- entry.getKey()).getContainer();
+ final WindowContainer wc = WindowContainer.fromBinder(entry.getKey());
int containerEffect = applyWindowContainerChange(wc, entry.getValue());
effects |= containerEffect;
@@ -484,6 +573,13 @@
mBLASTSyncEngine.addToSyncSet(syncId, wc);
}
}
+ // Hierarchy changes
+ final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps();
+ for (int i = 0, n = hops.size(); i < n; ++i) {
+ final WindowContainerTransaction.HierarchyOp hop = hops.get(i);
+ final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
+ effects |= sanitizeAndApplyHierarchyOp(wc, hop);
+ }
if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) {
// Already calls ensureActivityConfig
mService.mRootWindowContainer.ensureActivitiesVisible(
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 8bbb0d7..b5892b9 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -20,6 +20,11 @@
import static android.app.ActivityTaskManager.RESIZE_MODE_USER_FORCED;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_BOTTOM;
+import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_LEFT;
+import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_NONE;
+import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_RIGHT;
+import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_TOP;
import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
@@ -29,7 +34,6 @@
import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP;
import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.app.IActivityTaskManager;
import android.graphics.Point;
@@ -55,11 +59,10 @@
import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.policy.TaskResizingAlgorithm;
+import com.android.internal.policy.TaskResizingAlgorithm.CtrlType;
import com.android.server.protolog.common.ProtoLog;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
class TaskPositioner implements IBinder.DeathRecipient {
private static final boolean DEBUG_ORIENTATION_VIOLATIONS = false;
private static final String TAG_LOCAL = "TaskPositioner";
@@ -67,33 +70,10 @@
private static Factory sFactory;
- @IntDef(flag = true,
- value = {
- CTRL_NONE,
- CTRL_LEFT,
- CTRL_RIGHT,
- CTRL_TOP,
- CTRL_BOTTOM
- })
- @Retention(RetentionPolicy.SOURCE)
- @interface CtrlType {}
-
- private static final int CTRL_NONE = 0x0;
- private static final int CTRL_LEFT = 0x1;
- private static final int CTRL_RIGHT = 0x2;
- private static final int CTRL_TOP = 0x4;
- private static final int CTRL_BOTTOM = 0x8;
-
public static final float RESIZING_HINT_ALPHA = 0.5f;
public static final int RESIZING_HINT_DURATION_MS = 0;
- // The minimal aspect ratio which needs to be met to count as landscape (or 1/.. for portrait).
- // Note: We do not use the 1.33 from the CDD here since the user is allowed to use what ever
- // aspect he desires.
- @VisibleForTesting
- static final float MIN_ASPECT = 1.2f;
-
private final WindowManagerService mService;
private final IActivityTaskManager mActivityManager;
private WindowPositionerEventReceiver mInputEventReceiver;
@@ -477,122 +457,13 @@
*/
@VisibleForTesting
void resizeDrag(float x, float y) {
- // This is a resizing operation.
- // We need to keep various constraints:
- // 1. mMinVisible[Width/Height] <= [width/height] <= mMaxVisibleSize.[x/y]
- // 2. The orientation is kept - if required.
- final int deltaX = Math.round(x - mStartDragX);
- final int deltaY = Math.round(y - mStartDragY);
- int left = mWindowOriginalBounds.left;
- int top = mWindowOriginalBounds.top;
- int right = mWindowOriginalBounds.right;
- int bottom = mWindowOriginalBounds.bottom;
-
- // Calculate the resulting width and height of the drag operation.
- int width = right - left;
- int height = bottom - top;
- if ((mCtrlType & CTRL_LEFT) != 0) {
- width = Math.max(mMinVisibleWidth, width - deltaX);
- } else if ((mCtrlType & CTRL_RIGHT) != 0) {
- width = Math.max(mMinVisibleWidth, width + deltaX);
- }
- if ((mCtrlType & CTRL_TOP) != 0) {
- height = Math.max(mMinVisibleHeight, height - deltaY);
- } else if ((mCtrlType & CTRL_BOTTOM) != 0) {
- height = Math.max(mMinVisibleHeight, height + deltaY);
- }
-
- // If we have to preserve the orientation - check that we are doing so.
- final float aspect = (float) width / (float) height;
- if (mPreserveOrientation && ((mStartOrientationWasLandscape && aspect < MIN_ASPECT)
- || (!mStartOrientationWasLandscape && aspect > (1.0 / MIN_ASPECT)))) {
- // Calculate 2 rectangles fulfilling all requirements for either X or Y being the major
- // drag axis. What ever is producing the bigger rectangle will be chosen.
- int width1;
- int width2;
- int height1;
- int height2;
- if (mStartOrientationWasLandscape) {
- // Assuming that the width is our target we calculate the height.
- width1 = Math.max(mMinVisibleWidth, Math.min(mMaxVisibleSize.x, width));
- height1 = Math.min(height, Math.round((float)width1 / MIN_ASPECT));
- if (height1 < mMinVisibleHeight) {
- // If the resulting height is too small we adjust to the minimal size.
- height1 = mMinVisibleHeight;
- width1 = Math.max(mMinVisibleWidth,
- Math.min(mMaxVisibleSize.x, Math.round((float)height1 * MIN_ASPECT)));
- }
- // Assuming that the height is our target we calculate the width.
- height2 = Math.max(mMinVisibleHeight, Math.min(mMaxVisibleSize.y, height));
- width2 = Math.max(width, Math.round((float)height2 * MIN_ASPECT));
- if (width2 < mMinVisibleWidth) {
- // If the resulting width is too small we adjust to the minimal size.
- width2 = mMinVisibleWidth;
- height2 = Math.max(mMinVisibleHeight,
- Math.min(mMaxVisibleSize.y, Math.round((float)width2 / MIN_ASPECT)));
- }
- } else {
- // Assuming that the width is our target we calculate the height.
- width1 = Math.max(mMinVisibleWidth, Math.min(mMaxVisibleSize.x, width));
- height1 = Math.max(height, Math.round((float)width1 * MIN_ASPECT));
- if (height1 < mMinVisibleHeight) {
- // If the resulting height is too small we adjust to the minimal size.
- height1 = mMinVisibleHeight;
- width1 = Math.max(mMinVisibleWidth,
- Math.min(mMaxVisibleSize.x, Math.round((float)height1 / MIN_ASPECT)));
- }
- // Assuming that the height is our target we calculate the width.
- height2 = Math.max(mMinVisibleHeight, Math.min(mMaxVisibleSize.y, height));
- width2 = Math.min(width, Math.round((float)height2 / MIN_ASPECT));
- if (width2 < mMinVisibleWidth) {
- // If the resulting width is too small we adjust to the minimal size.
- width2 = mMinVisibleWidth;
- height2 = Math.max(mMinVisibleHeight,
- Math.min(mMaxVisibleSize.y, Math.round((float)width2 * MIN_ASPECT)));
- }
- }
-
- // Use the bigger of the two rectangles if the major change was positive, otherwise
- // do the opposite.
- final boolean grows = width > (right - left) || height > (bottom - top);
- if (grows == (width1 * height1 > width2 * height2)) {
- width = width1;
- height = height1;
- } else {
- width = width2;
- height = height2;
- }
- }
-
- // Update mWindowDragBounds to the new drag size.
- updateDraggedBounds(left, top, right, bottom, width, height);
+ updateDraggedBounds(TaskResizingAlgorithm.resizeDrag(x, y, mStartDragX, mStartDragY,
+ mWindowOriginalBounds, mCtrlType, mMinVisibleWidth, mMinVisibleHeight,
+ mMaxVisibleSize, mPreserveOrientation, mStartOrientationWasLandscape));
}
- /**
- * Given the old coordinates and the new width and height, update the mWindowDragBounds.
- *
- * @param left The original left bound before the user started dragging.
- * @param top The original top bound before the user started dragging.
- * @param right The original right bound before the user started dragging.
- * @param bottom The original bottom bound before the user started dragging.
- * @param newWidth The new dragged width.
- * @param newHeight The new dragged height.
- */
- void updateDraggedBounds(int left, int top, int right, int bottom, int newWidth,
- int newHeight) {
- // Generate the final bounds by keeping the opposite drag edge constant.
- if ((mCtrlType & CTRL_LEFT) != 0) {
- left = right - newWidth;
- } else { // Note: The right might have changed - if we pulled at the right or not.
- right = left + newWidth;
- }
- if ((mCtrlType & CTRL_TOP) != 0) {
- top = bottom - newHeight;
- } else { // Note: The height might have changed - if we pulled at the bottom or not.
- bottom = top + newHeight;
- }
-
- mWindowDragBounds.set(left, top, right, bottom);
+ private void updateDraggedBounds(Rect newBounds) {
+ mWindowDragBounds.set(newBounds);
checkBoundsForOrientationViolations(mWindowDragBounds);
}
diff --git a/services/core/java/com/android/server/wm/TaskTile.java b/services/core/java/com/android/server/wm/TaskTile.java
index add11d6..369db05 100644
--- a/services/core/java/com/android/server/wm/TaskTile.java
+++ b/services/core/java/com/android/server/wm/TaskTile.java
@@ -60,10 +60,11 @@
System.currentTimeMillis(), true /*neverRelinquishIdentity*/,
new ActivityManager.TaskDescription(), id, INVALID_TASK_ID, INVALID_TASK_ID,
0 /*taskAffiliationColor*/, 0 /*callingUid*/, "" /*callingPackage*/,
- RESIZE_MODE_RESIZEABLE, false /*supportsPictureInPicture*/,
- false /*_realActivitySuspended*/, false /*userSetupComplete*/, INVALID_MIN_SIZE,
- INVALID_MIN_SIZE, createEmptyActivityInfo(), null /*voiceSession*/,
- null /*voiceInteractor*/, null /*stack*/);
+ null /*callingFeatureId*/, RESIZE_MODE_RESIZEABLE,
+ false /*supportsPictureInPicture*/, false /*_realActivitySuspended*/,
+ false /*userSetupComplete*/, INVALID_MIN_SIZE, INVALID_MIN_SIZE,
+ createEmptyActivityInfo(), null /*voiceSession*/, null /*voiceInteractor*/,
+ null /*stack*/);
getRequestedOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode);
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 9acb660..504aa2d 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -2296,6 +2296,10 @@
return mRemoteToken;
}
+ static WindowContainer fromBinder(IBinder binder) {
+ return RemoteToken.fromBinder(binder).getContainer();
+ }
+
static class RemoteToken extends IWindowContainer.Stub {
final WeakReference<WindowContainer> mWeakRef;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6330985..a370093 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -8021,7 +8021,11 @@
int displayId, Rect outContentInsets, Rect outStableInsets,
DisplayCutout.ParcelableWrapper displayCutout) {
synchronized (mGlobalLock) {
- final DisplayContent dc = mRoot.getDisplayContent(displayId);
+ final DisplayContent dc = mRoot.getDisplayContentOrCreate(displayId);
+ if (dc == null) {
+ throw new WindowManager.InvalidDisplayException("Display#" + displayId
+ + "could not be found!");
+ }
final WindowToken windowToken = dc.getWindowToken(attrs.token);
final ActivityRecord activity;
if (windowToken != null && windowToken.asActivityRecord() != null) {
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 812bc43..49c7e0a 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -13,7 +13,6 @@
],
srcs: [
- ":graphicsstats_proto",
":lib_alarmManagerService_native",
"BroadcastRadio/JavaRef.cpp",
"BroadcastRadio/NativeCallbackThread.cpp",
@@ -53,7 +52,6 @@
"com_android_server_UsbHostManager.cpp",
"com_android_server_VibratorService.cpp",
"com_android_server_PersistentDataBlockService.cpp",
- "com_android_server_GraphicsStatsService.cpp",
"com_android_server_am_CachedAppOptimizer.cpp",
"com_android_server_am_LowMemDetector.cpp",
"com_android_server_incremental_IncrementalManagerService.cpp",
@@ -107,8 +105,6 @@
"libinputflinger",
"libinputflinger_base",
"libinputservice",
- "libprotobuf-cpp-lite",
- "libprotoutil",
"libstatshidl",
"libstatspull",
"libstatssocket",
diff --git a/services/core/jni/com_android_server_GraphicsStatsService.cpp b/services/core/jni/com_android_server_GraphicsStatsService.cpp
deleted file mode 100644
index aa7067e..0000000
--- a/services/core/jni/com_android_server_GraphicsStatsService.cpp
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "GraphicsStatsService"
-
-#include <jni.h>
-#include <log/log.h>
-#include <nativehelper/JNIHelp.h>
-#include <nativehelper/ScopedPrimitiveArray.h>
-#include <nativehelper/ScopedUtfChars.h>
-#include <JankTracker.h>
-#include <service/GraphicsStatsService.h>
-#include <stats_pull_atom_callback.h>
-#include <stats_event.h>
-#include <statslog.h>
-#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
-#include <android/util/ProtoOutputStream.h>
-#include "android/graphics/Utils.h"
-#include "core_jni_helpers.h"
-#include "protos/graphicsstats.pb.h"
-#include <cstring>
-#include <memory>
-
-namespace android {
-
-using namespace android::uirenderer;
-
-static jint getAshmemSize(JNIEnv*, jobject) {
- return sizeof(ProfileData);
-}
-
-static jlong createDump(JNIEnv*, jobject, jint fd, jboolean isProto) {
- GraphicsStatsService::Dump* dump = GraphicsStatsService::createDump(fd, isProto
- ? GraphicsStatsService::DumpType::Protobuf : GraphicsStatsService::DumpType::Text);
- return reinterpret_cast<jlong>(dump);
-}
-
-static void addToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath, jstring jpackage,
- jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) {
- std::string path;
- const ProfileData* data = nullptr;
- LOG_ALWAYS_FATAL_IF(jdata == nullptr && jpath == nullptr, "Path and data can't both be null");
- ScopedByteArrayRO buffer{env};
- if (jdata != nullptr) {
- buffer.reset(jdata);
- LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData),
- "Buffer size %zu doesn't match expected %zu!", buffer.size(), sizeof(ProfileData));
- data = reinterpret_cast<const ProfileData*>(buffer.get());
- }
- if (jpath != nullptr) {
- ScopedUtfChars pathChars(env, jpath);
- LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), "Failed to get path chars");
- path.assign(pathChars.c_str(), pathChars.size());
- }
- ScopedUtfChars packageChars(env, jpackage);
- LOG_ALWAYS_FATAL_IF(packageChars.size() <= 0 || !packageChars.c_str(), "Failed to get path chars");
- GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
- LOG_ALWAYS_FATAL_IF(!dump, "null passed for dump pointer");
-
- const std::string package(packageChars.c_str(), packageChars.size());
- GraphicsStatsService::addToDump(dump, path, package, versionCode, startTime, endTime, data);
-}
-
-static void addFileToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath) {
- ScopedUtfChars pathChars(env, jpath);
- LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), "Failed to get path chars");
- const std::string path(pathChars.c_str(), pathChars.size());
- GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
- GraphicsStatsService::addToDump(dump, path);
-}
-
-static void finishDump(JNIEnv*, jobject, jlong dumpPtr) {
- GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
- GraphicsStatsService::finishDump(dump);
-}
-
-static jlong finishDumpInMemory(JNIEnv* env, jobject, jlong dumpPtr) {
- GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
- std::vector<uint8_t>* result = new std::vector<uint8_t>();
- GraphicsStatsService::finishDumpInMemory(dump,
- [](void* buffer, int bufferOffset, int bufferSize, int totalSize, void* param1, void* param2) {
- std::vector<uint8_t>* outBuffer = reinterpret_cast<std::vector<uint8_t>*>(param2);
- if (outBuffer->size() < totalSize) {
- outBuffer->resize(totalSize);
- }
- std::memcpy(outBuffer->data() + bufferOffset, buffer, bufferSize);
- }, env, result);
- return reinterpret_cast<jlong>(result);
-}
-
-static void saveBuffer(JNIEnv* env, jobject clazz, jstring jpath, jstring jpackage,
- jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) {
- ScopedByteArrayRO buffer(env, jdata);
- LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData),
- "Buffer size %zu doesn't match expected %zu!", buffer.size(), sizeof(ProfileData));
- ScopedUtfChars pathChars(env, jpath);
- LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), "Failed to get path chars");
- ScopedUtfChars packageChars(env, jpackage);
- LOG_ALWAYS_FATAL_IF(packageChars.size() <= 0 || !packageChars.c_str(), "Failed to get path chars");
-
- const std::string path(pathChars.c_str(), pathChars.size());
- const std::string package(packageChars.c_str(), packageChars.size());
- const ProfileData* data = reinterpret_cast<const ProfileData*>(buffer.get());
- GraphicsStatsService::saveBuffer(path, package, versionCode, startTime, endTime, data);
-}
-
-static jobject gGraphicsStatsServiceObject = nullptr;
-static jmethodID gGraphicsStatsService_pullGraphicsStatsMethodID;
-
-static JNIEnv* getJNIEnv() {
- JavaVM* vm = AndroidRuntime::getJavaVM();
- JNIEnv* env = nullptr;
- if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
- if (vm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
- LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!");
- }
- }
- return env;
-}
-
-using namespace google::protobuf;
-
-// Field ids taken from FrameTimingHistogram message in atoms.proto
-#define TIME_MILLIS_BUCKETS_FIELD_NUMBER 1
-#define FRAME_COUNTS_FIELD_NUMBER 2
-
-static void writeCpuHistogram(AStatsEvent* event,
- const uirenderer::protos::GraphicsStatsProto& stat) {
- util::ProtoOutputStream proto;
- for (int bucketIndex = 0; bucketIndex < stat.histogram_size(); bucketIndex++) {
- auto& bucket = stat.histogram(bucketIndex);
- proto.write(android::util::FIELD_TYPE_INT32 | android::util::FIELD_COUNT_REPEATED |
- TIME_MILLIS_BUCKETS_FIELD_NUMBER /* field id */,
- (int)bucket.render_millis());
- }
- for (int bucketIndex = 0; bucketIndex < stat.histogram_size(); bucketIndex++) {
- auto& bucket = stat.histogram(bucketIndex);
- proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED |
- FRAME_COUNTS_FIELD_NUMBER /* field id */,
- (long long)bucket.frame_count());
- }
- std::vector<uint8_t> outVector;
- proto.serializeToVector(&outVector);
- AStatsEvent_writeByteArray(event, outVector.data(), outVector.size());
-}
-
-static void writeGpuHistogram(AStatsEvent* event,
- const uirenderer::protos::GraphicsStatsProto& stat) {
- util::ProtoOutputStream proto;
- for (int bucketIndex = 0; bucketIndex < stat.gpu_histogram_size(); bucketIndex++) {
- auto& bucket = stat.gpu_histogram(bucketIndex);
- proto.write(android::util::FIELD_TYPE_INT32 | android::util::FIELD_COUNT_REPEATED |
- TIME_MILLIS_BUCKETS_FIELD_NUMBER /* field id */,
- (int)bucket.render_millis());
- }
- for (int bucketIndex = 0; bucketIndex < stat.gpu_histogram_size(); bucketIndex++) {
- auto& bucket = stat.gpu_histogram(bucketIndex);
- proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED |
- FRAME_COUNTS_FIELD_NUMBER /* field id */,
- (long long)bucket.frame_count());
- }
- std::vector<uint8_t> outVector;
- proto.serializeToVector(&outVector);
- AStatsEvent_writeByteArray(event, outVector.data(), outVector.size());
-}
-
-// graphicsStatsPullCallback is invoked by statsd service to pull GRAPHICS_STATS atom.
-static AStatsManager_PullAtomCallbackReturn graphicsStatsPullCallback(int32_t atom_tag,
- AStatsEventList* data,
- void* cookie) {
- JNIEnv* env = getJNIEnv();
- if (!env) {
- return false;
- }
- if (gGraphicsStatsServiceObject == nullptr) {
- ALOGE("Failed to get graphicsstats service");
- return AStatsManager_PULL_SKIP;
- }
-
- for (bool lastFullDay : {true, false}) {
- jlong jdata = (jlong) env->CallLongMethod(
- gGraphicsStatsServiceObject,
- gGraphicsStatsService_pullGraphicsStatsMethodID,
- (jboolean)(lastFullDay ? JNI_TRUE : JNI_FALSE));
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- ALOGE("Failed to invoke graphicsstats service");
- return AStatsManager_PULL_SKIP;
- }
- if (!jdata) {
- // null means data is not available for that day.
- continue;
- }
- android::uirenderer::protos::GraphicsStatsServiceDumpProto serviceDump;
- std::vector<uint8_t>* buffer = reinterpret_cast<std::vector<uint8_t>*>(jdata);
- std::unique_ptr<std::vector<uint8_t>> bufferRelease(buffer);
- int dataSize = buffer->size();
- if (!dataSize) {
- // Data is not available for that day.
- continue;
- }
- io::ArrayInputStream input{buffer->data(), dataSize};
- bool success = serviceDump.ParseFromZeroCopyStream(&input);
- if (!success) {
- ALOGW("Parse failed on GraphicsStatsPuller error='%s' dataSize='%d'",
- serviceDump.InitializationErrorString().c_str(), dataSize);
- return AStatsManager_PULL_SKIP;
- }
-
- for (int stat_index = 0; stat_index < serviceDump.stats_size(); stat_index++) {
- auto& stat = serviceDump.stats(stat_index);
- AStatsEvent* event = AStatsEventList_addStatsEvent(data);
- AStatsEvent_setAtomId(event, android::util::GRAPHICS_STATS);
- AStatsEvent_writeString(event, stat.package_name().c_str());
- AStatsEvent_writeInt64(event, (int64_t)stat.version_code());
- AStatsEvent_writeInt64(event, (int64_t)stat.stats_start());
- AStatsEvent_writeInt64(event, (int64_t)stat.stats_end());
- AStatsEvent_writeInt32(event, (int32_t)stat.pipeline());
- AStatsEvent_writeInt32(event, (int32_t)stat.summary().total_frames());
- AStatsEvent_writeInt32(event, (int32_t)stat.summary().missed_vsync_count());
- AStatsEvent_writeInt32(event, (int32_t)stat.summary().high_input_latency_count());
- AStatsEvent_writeInt32(event, (int32_t)stat.summary().slow_ui_thread_count());
- AStatsEvent_writeInt32(event, (int32_t)stat.summary().slow_bitmap_upload_count());
- AStatsEvent_writeInt32(event, (int32_t)stat.summary().slow_draw_count());
- AStatsEvent_writeInt32(event, (int32_t)stat.summary().missed_deadline_count());
- writeCpuHistogram(event, stat);
- writeGpuHistogram(event, stat);
- // TODO: fill in UI mainline module version, when the feature is available.
- AStatsEvent_writeInt64(event, (int64_t)0);
- AStatsEvent_writeBool(event, !lastFullDay);
- AStatsEvent_build(event);
- }
- }
- return AStatsManager_PULL_SUCCESS;
-}
-
-// Register a puller for GRAPHICS_STATS atom with the statsd service.
-static void nativeInit(JNIEnv* env, jobject javaObject) {
- gGraphicsStatsServiceObject = env->NewGlobalRef(javaObject);
- AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
- AStatsManager_PullAtomMetadata_setCoolDownNs(metadata, 10 * 1000000); // 10 milliseconds
- AStatsManager_PullAtomMetadata_setTimeoutNs(metadata, 2 * NS_PER_SEC); // 2 seconds
-
- AStatsManager_registerPullAtomCallback(android::util::GRAPHICS_STATS,
- &graphicsStatsPullCallback, metadata, nullptr);
-
- AStatsManager_PullAtomMetadata_release(metadata);
-}
-
-static void nativeDestructor(JNIEnv* env, jobject javaObject) {
- AStatsManager_unregisterPullAtomCallback(android::util::GRAPHICS_STATS);
- env->DeleteGlobalRef(gGraphicsStatsServiceObject);
- gGraphicsStatsServiceObject = nullptr;
-}
-
-static const JNINativeMethod sMethods[] = {
- { "nGetAshmemSize", "()I", (void*) getAshmemSize },
- { "nCreateDump", "(IZ)J", (void*) createDump },
- { "nAddToDump", "(JLjava/lang/String;Ljava/lang/String;JJJ[B)V", (void*) addToDump },
- { "nAddToDump", "(JLjava/lang/String;)V", (void*) addFileToDump },
- { "nFinishDump", "(J)V", (void*) finishDump },
- { "nFinishDumpInMemory", "(J)J", (void*) finishDumpInMemory },
- { "nSaveBuffer", "(Ljava/lang/String;Ljava/lang/String;JJJ[B)V", (void*) saveBuffer },
- { "nativeInit", "()V", (void*) nativeInit },
- { "nativeDestructor", "()V", (void*)nativeDestructor }
-};
-
-int register_android_server_GraphicsStatsService(JNIEnv* env)
-{
- jclass graphicsStatsService_class = FindClassOrDie(env,
- "com/android/server/GraphicsStatsService");
- gGraphicsStatsService_pullGraphicsStatsMethodID = GetMethodIDOrDie(env,
- graphicsStatsService_class, "pullGraphicsStats", "(Z)J");
- return jniRegisterNativeMethods(env, "com/android/server/GraphicsStatsService",
- sMethods, NELEM(sMethods));
-}
-
-} // namespace android
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 1202ad3..c186494 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -49,7 +49,7 @@
int register_android_server_Watchdog(JNIEnv* env);
int register_android_server_HardwarePropertiesManagerService(JNIEnv* env);
int register_android_server_SyntheticPasswordManager(JNIEnv* env);
-int register_android_server_GraphicsStatsService(JNIEnv* env);
+int register_android_graphics_GraphicsStatsService(JNIEnv* env);
int register_android_hardware_display_DisplayViewport(JNIEnv* env);
int register_android_server_net_NetworkStatsFactory(JNIEnv* env);
int register_android_server_net_NetworkStatsService(JNIEnv* env);
@@ -102,7 +102,7 @@
register_android_server_HardwarePropertiesManagerService(env);
register_android_server_storage_AppFuse(env);
register_android_server_SyntheticPasswordManager(env);
- register_android_server_GraphicsStatsService(env);
+ register_android_graphics_GraphicsStatsService(env);
register_android_hardware_display_DisplayViewport(env);
register_android_server_net_NetworkStatsFactory(env);
register_android_server_net_NetworkStatsService(env);
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index 0941831..b2c316a 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -16,6 +16,7 @@
#include "BinderIncrementalService.h"
+#include <android-base/logging.h>
#include <binder/IResultReceiver.h>
#include <binder/PermissionCache.h>
#include <incfs.h>
@@ -24,7 +25,6 @@
#include "jni.h"
#include "nativehelper/JNIHelp.h"
#include "path.h"
-#include <android-base/logging.h>
using namespace std::literals;
using namespace android::incremental;
@@ -277,6 +277,13 @@
return ok();
}
+binder::Status BinderIncrementalService::configureNativeBinaries(
+ int32_t storageId, const std::string& apkFullPath, const std::string& libDirRelativePath,
+ const std::string& abi, bool* _aidl_return) {
+ *_aidl_return = mImpl.configureNativeBinaries(storageId, apkFullPath, libDirRelativePath, abi);
+ return ok();
+}
+
} // namespace android::os::incremental
jlong Incremental_IncrementalService_Start() {
diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h
index 8a09977..51d7de3 100644
--- a/services/incremental/BinderIncrementalService.h
+++ b/services/incremental/BinderIncrementalService.h
@@ -28,11 +28,11 @@
class BinderIncrementalService : public BnIncrementalService,
public BinderService<BinderIncrementalService> {
public:
- BinderIncrementalService(const sp<IServiceManager> &sm);
+ BinderIncrementalService(const sp<IServiceManager>& sm);
- static BinderIncrementalService *start();
- static const char16_t *getServiceName() { return u"incremental_service"; }
- status_t dump(int fd, const Vector<String16> &args) final;
+ static BinderIncrementalService* start();
+ static const char16_t* getServiceName() { return u"incremental_service"; }
+ status_t dump(int fd, const Vector<String16>& args) final;
void onSystemReady();
void onInvalidStorage(int mountId);
@@ -70,6 +70,9 @@
std::vector<uint8_t>* _aidl_return) final;
binder::Status startLoading(int32_t storageId, bool* _aidl_return) final;
binder::Status deleteStorage(int32_t storageId) final;
+ binder::Status configureNativeBinaries(int32_t storageId, const std::string& apkFullPath,
+ const std::string& libDirRelativePath,
+ const std::string& abi, bool* _aidl_return) final;
private:
android::incremental::IncrementalService mImpl;
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index dbd97cf..3b51377 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -60,6 +60,9 @@
static constexpr auto storagePrefix = "st"sv;
static constexpr auto mountpointMdPrefix = ".mountpoint."sv;
static constexpr auto infoMdName = ".info"sv;
+ static constexpr auto libDir = "lib"sv;
+ static constexpr auto libSuffix = ".so"sv;
+ static constexpr auto blockSize = 4096;
};
static const Constants& constants() {
@@ -259,16 +262,18 @@
inline const char* toString(TimePoint t) {
using SystemClock = std::chrono::system_clock;
- time_t time = SystemClock::to_time_t(SystemClock::now() + std::chrono::duration_cast<SystemClock::duration>(t - Clock::now()));
+ time_t time = SystemClock::to_time_t(
+ SystemClock::now() +
+ std::chrono::duration_cast<SystemClock::duration>(t - Clock::now()));
return std::ctime(&time);
}
inline const char* toString(IncrementalService::BindKind kind) {
switch (kind) {
- case IncrementalService::BindKind::Temporary:
- return "Temporary";
- case IncrementalService::BindKind::Permanent:
- return "Permanent";
+ case IncrementalService::BindKind::Temporary:
+ return "Temporary";
+ case IncrementalService::BindKind::Permanent:
+ return "Permanent";
}
}
@@ -1124,6 +1129,122 @@
return true;
}
+// Extract lib filse from zip, create new files in incfs and write data to them
+bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_view apkFullPath,
+ std::string_view libDirRelativePath,
+ std::string_view abi) {
+ const auto ifs = getIfs(storage);
+ // First prepare target directories if they don't exist yet
+ if (auto res = makeDirs(storage, libDirRelativePath, 0755)) {
+ LOG(ERROR) << "Failed to prepare target lib directory " << libDirRelativePath
+ << " errno: " << res;
+ return false;
+ }
+
+ std::unique_ptr<ZipFileRO> zipFile(ZipFileRO::open(apkFullPath.data()));
+ if (!zipFile) {
+ LOG(ERROR) << "Failed to open zip file at " << apkFullPath;
+ return false;
+ }
+ void* cookie = nullptr;
+ const auto libFilePrefix = path::join(constants().libDir, abi);
+ if (!zipFile.get()->startIteration(&cookie, libFilePrefix.c_str() /* prefix */,
+ constants().libSuffix.data() /* suffix */)) {
+ LOG(ERROR) << "Failed to start zip iteration for " << apkFullPath;
+ return false;
+ }
+ ZipEntryRO entry = nullptr;
+ bool success = true;
+ while ((entry = zipFile.get()->nextEntry(cookie)) != nullptr) {
+ char fileName[PATH_MAX];
+ if (zipFile.get()->getEntryFileName(entry, fileName, sizeof(fileName))) {
+ continue;
+ }
+ const auto libName = path::basename(fileName);
+ const auto targetLibPath = path::join(libDirRelativePath, libName);
+ const auto targetLibPathAbsolute = normalizePathToStorage(ifs, storage, targetLibPath);
+ // If the extract file already exists, skip
+ struct stat st;
+ if (stat(targetLibPathAbsolute.c_str(), &st) == 0) {
+ LOG(INFO) << "Native lib file already exists: " << targetLibPath
+ << "; skipping extraction";
+ continue;
+ }
+
+ uint32_t uncompressedLen;
+ if (!zipFile.get()->getEntryInfo(entry, nullptr, &uncompressedLen, nullptr, nullptr,
+ nullptr, nullptr)) {
+ LOG(ERROR) << "Failed to read native lib entry: " << fileName;
+ success = false;
+ break;
+ }
+
+ // Create new lib file without signature info
+ incfs::NewFileParams libFileParams;
+ libFileParams.size = uncompressedLen;
+ libFileParams.verification.hashAlgorithm = INCFS_HASH_NONE;
+ // Metadata of the new lib file is its relative path
+ IncFsSpan libFileMetadata;
+ libFileMetadata.data = targetLibPath.c_str();
+ libFileMetadata.size = targetLibPath.size();
+ libFileParams.metadata = libFileMetadata;
+ incfs::FileId libFileId = idFromMetadata(targetLibPath);
+ if (auto res = makeFile(storage, targetLibPath, 0777, libFileId, libFileParams)) {
+ LOG(ERROR) << "Failed to make file for: " << targetLibPath << " errno: " << res;
+ success = false;
+ // If one lib file fails to be created, abort others as well
+ break;
+ }
+
+ // Write extracted data to new file
+ std::vector<uint8_t> libData(uncompressedLen);
+ if (!zipFile.get()->uncompressEntry(entry, &libData[0], uncompressedLen)) {
+ LOG(ERROR) << "Failed to extract native lib zip entry: " << fileName;
+ success = false;
+ break;
+ }
+ android::base::unique_fd writeFd(mIncFs->openWrite(ifs->control, libFileId));
+ if (writeFd < 0) {
+ LOG(ERROR) << "Failed to open write fd for: " << targetLibPath << " errno: " << writeFd;
+ success = false;
+ break;
+ }
+ const int numBlocks = uncompressedLen / constants().blockSize + 1;
+ std::vector<IncFsDataBlock> instructions;
+ auto remainingData = std::span(libData);
+ for (int i = 0; i < numBlocks - 1; i++) {
+ auto inst = IncFsDataBlock{
+ .fileFd = writeFd,
+ .pageIndex = static_cast<IncFsBlockIndex>(i),
+ .compression = INCFS_COMPRESSION_KIND_NONE,
+ .kind = INCFS_BLOCK_KIND_DATA,
+ .dataSize = static_cast<uint16_t>(constants().blockSize),
+ .data = reinterpret_cast<const char*>(remainingData.data()),
+ };
+ instructions.push_back(inst);
+ remainingData = remainingData.subspan(constants().blockSize);
+ }
+ // Last block
+ auto inst = IncFsDataBlock{
+ .fileFd = writeFd,
+ .pageIndex = static_cast<IncFsBlockIndex>(numBlocks - 1),
+ .compression = INCFS_COMPRESSION_KIND_NONE,
+ .kind = INCFS_BLOCK_KIND_DATA,
+ .dataSize = static_cast<uint16_t>(remainingData.size()),
+ .data = reinterpret_cast<const char*>(remainingData.data()),
+ };
+ instructions.push_back(inst);
+ size_t res = mIncFs->writeBlocks(instructions);
+ if (res != instructions.size()) {
+ LOG(ERROR) << "Failed to write data into: " << targetLibPath;
+ success = false;
+ }
+ instructions.clear();
+ }
+ zipFile.get()->endIteration(cookie);
+ return success;
+}
+
binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChanged(MountId mountId,
int newStatus) {
std::unique_lock l(incrementalService.mLock);
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index dec9f64..2444dde 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -126,7 +126,8 @@
std::vector<std::string> listFiles(StorageId storage) const;
bool startLoading(StorageId storage) const;
-
+ bool configureNativeBinaries(StorageId storage, std::string_view apkFullPath,
+ std::string_view libDirRelativePath, std::string_view abi);
class IncrementalDataLoaderListener : public android::content::pm::BnDataLoaderStatusListener {
public:
IncrementalDataLoaderListener(IncrementalService& incrementalService)
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 036335c..eef6c63 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -41,6 +41,7 @@
import android.content.res.Resources.Theme;
import android.database.sqlite.SQLiteCompatibilityWalFlags;
import android.database.sqlite.SQLiteGlobal;
+import android.graphics.GraphicsStatsService;
import android.hardware.display.DisplayManagerInternal;
import android.net.ConnectivityModuleConnector;
import android.net.ITetheringConnector;
diff --git a/services/people/java/com/android/server/people/data/ConversationInfo.java b/services/people/java/com/android/server/people/data/ConversationInfo.java
index bb97533..b60ed3e 100644
--- a/services/people/java/com/android/server/people/data/ConversationInfo.java
+++ b/services/people/java/com/android/server/people/data/ConversationInfo.java
@@ -35,7 +35,7 @@
*/
public class ConversationInfo {
- private static final int FLAG_VIP = 1;
+ private static final int FLAG_IMPORTANT = 1;
private static final int FLAG_NOTIFICATION_SILENCED = 1 << 1;
@@ -50,7 +50,7 @@
private static final int FLAG_DEMOTED = 1 << 6;
@IntDef(flag = true, prefix = {"FLAG_"}, value = {
- FLAG_VIP,
+ FLAG_IMPORTANT,
FLAG_NOTIFICATION_SILENCED,
FLAG_BUBBLED,
FLAG_PERSON_IMPORTANT,
@@ -129,9 +129,9 @@
return hasShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED);
}
- /** Whether this conversation is marked as VIP by the user. */
- public boolean isVip() {
- return hasConversationFlags(FLAG_VIP);
+ /** Whether this conversation is marked as important by the user. */
+ public boolean isImportant() {
+ return hasConversationFlags(FLAG_IMPORTANT);
}
/** Whether the notifications for this conversation should be silenced. */
@@ -208,8 +208,8 @@
sb.append("]");
sb.append(", conversationFlags=0x").append(Integer.toHexString(mConversationFlags));
sb.append(" [");
- if (isVip()) {
- sb.append("Vip");
+ if (isImportant()) {
+ sb.append("Imp");
}
if (isNotificationSilenced()) {
sb.append("Sil");
@@ -221,7 +221,7 @@
sb.append("Dem");
}
if (isPersonImportant()) {
- sb.append("Imp");
+ sb.append("PIm");
}
if (isPersonBot()) {
sb.append("Bot");
@@ -318,8 +318,8 @@
return this;
}
- Builder setVip(boolean value) {
- return setConversationFlag(FLAG_VIP, value);
+ Builder setImportant(boolean value) {
+ return setConversationFlag(FLAG_IMPORTANT, value);
}
Builder setNotificationSilenced(boolean value) {
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index 7fdcf42..7a3ed53 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -21,6 +21,8 @@
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
import android.app.Person;
import android.app.prediction.AppTarget;
import android.app.prediction.AppTargetEvent;
@@ -157,8 +159,8 @@
mNotificationListeners.put(userId, notificationListener);
try {
notificationListener.registerAsSystemService(mContext,
- new ComponentName(PLATFORM_PACKAGE_NAME, getClass().getSimpleName()),
- UserHandle.myUserId());
+ new ComponentName(PLATFORM_PACKAGE_NAME, getClass().getCanonicalName()),
+ userId);
} catch (RemoteException e) {
// Should never occur for local calls.
}
@@ -571,6 +573,44 @@
long currentTime = System.currentTimeMillis();
eventHistory.addEvent(new Event(currentTime, Event.TYPE_NOTIFICATION_OPENED));
}
+
+ @Override
+ public void onNotificationChannelModified(String pkg, UserHandle user,
+ NotificationChannel channel, int modificationType) {
+ PackageData packageData = getPackage(pkg, user.getIdentifier());
+ String shortcutId = channel.getConversationId();
+ if (packageData == null || shortcutId == null) {
+ return;
+ }
+ ConversationStore conversationStore = packageData.getConversationStore();
+ ConversationInfo conversationInfo = conversationStore.getConversation(shortcutId);
+ if (conversationInfo == null) {
+ return;
+ }
+ ConversationInfo.Builder builder = new ConversationInfo.Builder(conversationInfo);
+ switch (modificationType) {
+ case NOTIFICATION_CHANNEL_OR_GROUP_ADDED:
+ case NOTIFICATION_CHANNEL_OR_GROUP_UPDATED:
+ builder.setNotificationChannelId(channel.getId());
+ builder.setImportant(channel.isImportantConversation());
+ builder.setDemoted(channel.isDemoted());
+ builder.setNotificationSilenced(
+ channel.getImportance() <= NotificationManager.IMPORTANCE_LOW);
+ builder.setBubbled(channel.canBubble());
+ break;
+ case NOTIFICATION_CHANNEL_OR_GROUP_DELETED:
+ // If the notification channel is deleted, revert all the notification settings
+ // to the default value.
+ builder.setNotificationChannelId(null);
+ builder.setImportant(false);
+ builder.setDemoted(false);
+ builder.setNotificationSilenced(false);
+ builder.setBubbled(false);
+ break;
+ }
+ conversationStore.addOrUpdate(builder.build());
+ // TODO: Cache the shortcut when a conversation's notification setting is changed.
+ }
}
/**
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
index 8d2a152..6083ce34 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
@@ -174,12 +174,12 @@
final int app1ConnectiongGroup = 10;
final int app1UidUser2 = 1010123;
final int app1PidUser2 = 12347;
- final int app1Pss1 = 34567;
- final int app1Rss1 = 45678;
- final int app1Pss2 = 34568;
- final int app1Rss2 = 45679;
- final int app1Pss3 = 34569;
- final int app1Rss3 = 45680;
+ final long app1Pss1 = 34567;
+ final long app1Rss1 = 45678;
+ final long app1Pss2 = 34568;
+ final long app1Rss2 = 45679;
+ final long app1Pss3 = 34569;
+ final long app1Rss3 = 45680;
final String app1ProcessName = "com.android.test.stub1:process";
final String app1PackageName = "com.android.test.stub1";
@@ -344,8 +344,8 @@
// Case 4: Create a process from another package with kill from lmkd
final int app2UidUser2 = 1010234;
final int app2PidUser2 = 12348;
- final int app2Pss1 = 54321;
- final int app2Rss1 = 65432;
+ final long app2Pss1 = 54321;
+ final long app2Rss1 = 65432;
final String app2ProcessName = "com.android.test.stub2:process";
final String app2PackageName = "com.android.test.stub2";
@@ -402,8 +402,8 @@
final int app3UidUser2 = 1010345;
final int app3PidUser2 = 12349;
final int app3ConnectiongGroup = 4;
- final int app3Pss1 = 54320;
- final int app3Rss1 = 65430;
+ final long app3Pss1 = 54320;
+ final long app3Rss1 = 65430;
final String app3ProcessName = "com.android.test.stub3:process";
final String app3PackageName = "com.android.test.stub3";
final String app3Description = "native crash";
@@ -529,8 +529,8 @@
final int app3Uid = 10345;
final int app3IsolatedUid = 99001; // it's an isolated process
final int app3Pid = 12350;
- final int app3Pss2 = 23232;
- final int app3Rss2 = 32323;
+ final long app3Pss2 = 23232;
+ final long app3Rss2 = 32323;
final String app3Description2 = "force close";
sleep(1);
@@ -618,8 +618,8 @@
sleep(1);
final int app1IsolatedUidUser2 = 1099002; // isolated uid
- final int app1Pss4 = 34343;
- final int app1Rss4 = 43434;
+ final long app1Pss4 = 34343;
+ final long app1Rss4 = 43434;
final long now8 = System.currentTimeMillis();
sigNum = OsConstants.SIGKILL;
doReturn(new Pair<Long, Object>(now8, makeSignalStatus(sigNum)))
@@ -673,8 +673,8 @@
sleep(1);
final int app1Pid2User2 = 56565;
final int app1IsolatedUid2User2 = 1099003; // isolated uid
- final int app1Pss5 = 34344;
- final int app1Rss5 = 43435;
+ final long app1Pss5 = 34344;
+ final long app1Rss5 = 43435;
final long now9 = System.currentTimeMillis();
sigNum = OsConstants.SIGKILL;
doReturn(new Pair<Long, Object>(now9, makeSignalStatus(sigNum)))
@@ -831,7 +831,7 @@
}
private ProcessRecord makeProcessRecord(int pid, int uid, int packageUid, Integer definingUid,
- int connectionGroup, int procState, int pss, int rss,
+ int connectionGroup, int procState, long pss, long rss,
String processName, String packageName) {
ApplicationInfo ai = new ApplicationInfo();
ai.packageName = packageName;
@@ -847,8 +847,8 @@
app.connectionGroup = connectionGroup;
app.setProcState = procState;
app.lastMemInfo = spy(new Debug.MemoryInfo());
- doReturn(pss).when(app.lastMemInfo).getTotalPss();
- doReturn(rss).when(app.lastMemInfo).getTotalRss();
+ doReturn((int) pss).when(app.lastMemInfo).getTotalPss();
+ doReturn((int) rss).when(app.lastMemInfo).getTotalRss();
return app;
}
@@ -856,7 +856,7 @@
Long timestamp, Integer pid, Integer uid, Integer packageUid,
Integer definingUid, String processName, Integer connectionGroup,
Integer reason, Integer subReason, Integer status,
- Integer pss, Integer rss, Integer importance, String description) {
+ Long pss, Long rss, Integer importance, String description) {
assertNotNull(info);
if (timestamp != null) {
@@ -892,10 +892,10 @@
assertEquals(status.intValue(), info.getStatus());
}
if (pss != null) {
- assertEquals(pss.intValue(), info.getPss());
+ assertEquals(pss.longValue(), info.getPss());
}
if (rss != null) {
- assertEquals(rss.intValue(), info.getRss());
+ assertEquals(rss.longValue(), info.getRss());
}
if (importance != null) {
assertEquals(importance.intValue(), info.getImportance());
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java
index 3975f0b..e3453a0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java
@@ -50,6 +50,7 @@
@RunWith(AndroidJUnit4.class)
public class PendingIntentControllerTest {
private static final String TEST_PACKAGE_NAME = "test-package-1";
+ private static final String TEST_FEATURE_ID = "test-feature-1";
private static final int TEST_CALLING_UID = android.os.Process.myUid();
private static final Intent[] TEST_INTENTS = new Intent[]{new Intent("com.test.intent")};
@@ -87,8 +88,8 @@
private PendingIntentRecord createPendingIntentRecord(int flags) {
return mPendingIntentController.getIntentSender(ActivityManager.INTENT_SENDER_BROADCAST,
- TEST_PACKAGE_NAME, TEST_CALLING_UID, 0, null, null, 0, TEST_INTENTS, null, flags,
- null);
+ TEST_PACKAGE_NAME, TEST_FEATURE_ID, TEST_CALLING_UID, 0, null, null, 0,
+ TEST_INTENTS, null, flags, null);
}
@Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
index 16dde42..3778e17 100644
--- a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
@@ -216,8 +216,8 @@
doReturn(System.currentTimeMillis() - SESSION_EXPIRY_TIMEOUT_MILLIS + 1000)
.when(sessionFile1).lastModified();
final long sessionId1 = 342;
- final BlobHandle blobHandle1 = mock(BlobHandle.class);
- doReturn(System.currentTimeMillis() - 1000).when(blobHandle1).getExpiryTimeMillis();
+ final BlobHandle blobHandle1 = BlobHandle.createWithSha256("digest1".getBytes(),
+ "label1", System.currentTimeMillis() - 1000, "tag1");
final BlobStoreSession session1 = createBlobStoreSessionMock(TEST_PKG1, TEST_UID1,
sessionId1, sessionFile1, blobHandle1);
mUserSessions.append(sessionId1, session1);
@@ -226,8 +226,8 @@
doReturn(System.currentTimeMillis() - 20000)
.when(sessionFile2).lastModified();
final long sessionId2 = 4597;
- final BlobHandle blobHandle2 = mock(BlobHandle.class);
- doReturn(System.currentTimeMillis() + 20000).when(blobHandle2).getExpiryTimeMillis();
+ final BlobHandle blobHandle2 = BlobHandle.createWithSha256("digest2".getBytes(),
+ "label2", System.currentTimeMillis() + 20000, "tag2");
final BlobStoreSession session2 = createBlobStoreSessionMock(TEST_PKG2, TEST_UID2,
sessionId2, sessionFile2, blobHandle2);
mUserSessions.append(sessionId2, session2);
@@ -236,8 +236,8 @@
doReturn(System.currentTimeMillis() - SESSION_EXPIRY_TIMEOUT_MILLIS - 2000)
.when(sessionFile3).lastModified();
final long sessionId3 = 9484;
- final BlobHandle blobHandle3 = mock(BlobHandle.class);
- doReturn(System.currentTimeMillis() + 30000).when(blobHandle3).getExpiryTimeMillis();
+ final BlobHandle blobHandle3 = BlobHandle.createWithSha256("digest3".getBytes(),
+ "label3", System.currentTimeMillis() + 30000, "tag3");
final BlobStoreSession session3 = createBlobStoreSessionMock(TEST_PKG3, TEST_UID3,
sessionId3, sessionFile3, blobHandle3);
mUserSessions.append(sessionId3, session3);
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index f990810..bf2b9be 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -74,7 +74,6 @@
"libbacktrace",
"libbase",
"libbinder",
- "libbinderthreadstate",
"libc++",
"libcutils",
"liblog",
diff --git a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
index 089a79b..a871ec6 100644
--- a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
@@ -178,6 +178,7 @@
new Intent(),
null /* callerApp */,
null /* callerPackage */,
+ null /* callerFeatureId */,
0 /* callingPid */,
0 /* callingUid */,
false /* callerInstantApp */,
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
index c9ec874..d40130a 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -281,9 +281,9 @@
AppInstallMetadata appInstallMetadata = metadataCaptor.getValue();
allowedInstallers = allowedInstallersCaptor.getValue();
assertEquals(PACKAGE_NAME, appInstallMetadata.getPackageName());
- assertEquals(APP_CERT, appInstallMetadata.getAppCertificate());
+ assertThat(appInstallMetadata.getAppCertificates()).containsExactly(APP_CERT);
assertEquals(INSTALLER_SHA256, appInstallMetadata.getInstallerName());
- assertEquals(INSTALLER_CERT, appInstallMetadata.getInstallerCertificate());
+ assertThat(appInstallMetadata.getInstallerCertificates()).containsExactly(INSTALLER_CERT);
assertEquals(VERSION_CODE, appInstallMetadata.getVersionCode());
assertFalse(appInstallMetadata.isPreInstalled());
// These are hardcoded in the test apk android manifest
diff --git a/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java b/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java
index 86daf69..41be54a 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java
@@ -141,10 +141,10 @@
AppInstallMetadata appInstallMetadata =
new AppInstallMetadata.Builder()
.setPackageName(packageName)
- .setAppCertificate(packageCert)
+ .setAppCertificates(Collections.singletonList(packageCert))
.setVersionCode(version)
.setInstallerName("abc")
- .setInstallerCertificate("abc")
+ .setInstallerCertificates(Collections.singletonList("abc"))
.setIsPreInstalled(true)
.build();
List<Rule> rulesFetched = mIntegrityFileManager.readRules(appInstallMetadata);
@@ -182,10 +182,10 @@
AppInstallMetadata appInstallMetadata =
new AppInstallMetadata.Builder()
.setPackageName(installedPackageName)
- .setAppCertificate(installedAppCertificate)
+ .setAppCertificates(Collections.singletonList(installedAppCertificate))
.setVersionCode(250)
.setInstallerName("abc")
- .setInstallerCertificate("abc")
+ .setInstallerCertificates(Collections.singletonList("abc"))
.setIsPreInstalled(true)
.build();
List<Rule> rulesFetched = mIntegrityFileManager.readRules(appInstallMetadata);
diff --git a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java
index 26b2096..b0b9596 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java
@@ -70,17 +70,17 @@
AppInstallMetadata appInstallMetadata1 =
getAppInstallMetadataBuilder()
.setInstallerName(INSTALLER_1)
- .setInstallerCertificate(INSTALLER_1_CERT)
+ .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
.build();
AppInstallMetadata appInstallMetadata2 =
getAppInstallMetadataBuilder()
.setInstallerName(INSTALLER_2)
- .setInstallerCertificate(INSTALLER_2_CERT)
+ .setInstallerCertificates(Collections.singletonList(INSTALLER_2_CERT))
.build();
AppInstallMetadata appInstallMetadata3 =
getAppInstallMetadataBuilder()
.setInstallerName(RANDOM_INSTALLER)
- .setInstallerCertificate(RANDOM_INSTALLER_CERT)
+ .setInstallerCertificates(Collections.singletonList(RANDOM_INSTALLER_CERT))
.build();
assertThat(mEngine.evaluate(appInstallMetadata1, allowedInstallers).getEffect())
@@ -99,7 +99,7 @@
AppInstallMetadata appInstallMetadata1 =
getAppInstallMetadataBuilder()
.setInstallerName(INSTALLER_1)
- .setInstallerCertificate(INSTALLER_1_CERT)
+ .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
.build();
assertThat(mEngine.evaluate(appInstallMetadata1, allowedInstallers).getEffect())
.isEqualTo(IntegrityCheckResult.Effect.ALLOW);
@@ -107,7 +107,7 @@
AppInstallMetadata appInstallMetadata2 =
getAppInstallMetadataBuilder()
.setInstallerName(RANDOM_INSTALLER)
- .setInstallerCertificate(INSTALLER_1_CERT)
+ .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
.build();
assertThat(mEngine.evaluate(appInstallMetadata2, allowedInstallers).getEffect())
.isEqualTo(IntegrityCheckResult.Effect.DENY);
@@ -115,7 +115,7 @@
AppInstallMetadata appInstallMetadata3 =
getAppInstallMetadataBuilder()
.setInstallerName(INSTALLER_1)
- .setInstallerCertificate(RANDOM_INSTALLER_CERT)
+ .setInstallerCertificates(Collections.singletonList(RANDOM_INSTALLER_CERT))
.build();
assertThat(mEngine.evaluate(appInstallMetadata3, allowedInstallers).getEffect())
.isEqualTo(IntegrityCheckResult.Effect.DENY);
@@ -123,7 +123,7 @@
AppInstallMetadata appInstallMetadata4 =
getAppInstallMetadataBuilder()
.setInstallerName(INSTALLER_1)
- .setInstallerCertificate(RANDOM_INSTALLER_CERT)
+ .setInstallerCertificates(Collections.singletonList(RANDOM_INSTALLER_CERT))
.build();
assertThat(mEngine.evaluate(appInstallMetadata4, allowedInstallers).getEffect())
.isEqualTo(IntegrityCheckResult.Effect.DENY);
@@ -138,7 +138,7 @@
AppInstallMetadata appInstallMetadata1 =
getAppInstallMetadataBuilder()
.setInstallerName(INSTALLER_1)
- .setInstallerCertificate(INSTALLER_1_CERT)
+ .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
.build();
assertThat(mEngine.evaluate(appInstallMetadata1, allowedInstallers).getEffect())
.isEqualTo(IntegrityCheckResult.Effect.ALLOW);
@@ -146,7 +146,7 @@
AppInstallMetadata appInstallMetadata2 =
getAppInstallMetadataBuilder()
.setInstallerName(INSTALLER_2)
- .setInstallerCertificate(INSTALLER_2_CERT)
+ .setInstallerCertificates(Collections.singletonList(INSTALLER_2_CERT))
.build();
assertThat(mEngine.evaluate(appInstallMetadata2, allowedInstallers).getEffect())
.isEqualTo(IntegrityCheckResult.Effect.ALLOW);
@@ -154,7 +154,7 @@
AppInstallMetadata appInstallMetadata3 =
getAppInstallMetadataBuilder()
.setInstallerName(INSTALLER_1)
- .setInstallerCertificate(INSTALLER_2_CERT)
+ .setInstallerCertificates(Collections.singletonList(INSTALLER_2_CERT))
.build();
assertThat(mEngine.evaluate(appInstallMetadata3, allowedInstallers).getEffect())
.isEqualTo(IntegrityCheckResult.Effect.DENY);
@@ -162,7 +162,7 @@
AppInstallMetadata appInstallMetadata4 =
getAppInstallMetadataBuilder()
.setInstallerName(INSTALLER_2)
- .setInstallerCertificate(INSTALLER_1_CERT)
+ .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
.build();
assertThat(mEngine.evaluate(appInstallMetadata4, allowedInstallers).getEffect())
.isEqualTo(IntegrityCheckResult.Effect.DENY);
@@ -178,7 +178,7 @@
AppInstallMetadata appInstallMetadata1 =
getAppInstallMetadataBuilder()
.setInstallerName(INSTALLER_1)
- .setInstallerCertificate(INSTALLER_1_CERT)
+ .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
.build();
assertThat(mEngine.evaluate(appInstallMetadata1, allowedInstallers).getEffect())
.isEqualTo(IntegrityCheckResult.Effect.ALLOW);
@@ -186,7 +186,7 @@
AppInstallMetadata appInstallMetadata2 =
getAppInstallMetadataBuilder()
.setInstallerName(RANDOM_INSTALLER)
- .setInstallerCertificate(INSTALLER_1_CERT)
+ .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
.build();
assertThat(mEngine.evaluate(appInstallMetadata2, allowedInstallers).getEffect())
.isEqualTo(IntegrityCheckResult.Effect.DENY);
@@ -196,8 +196,8 @@
private AppInstallMetadata.Builder getAppInstallMetadataBuilder() {
return new AppInstallMetadata.Builder()
.setPackageName("abc")
- .setAppCertificate("abc")
- .setInstallerCertificate("abc")
+ .setAppCertificates(Collections.singletonList("abc"))
+ .setInstallerCertificates(Collections.singletonList("abc"))
.setInstallerName("abc")
.setVersionCode(-1)
.setIsPreInstalled(true);
diff --git a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java
index 7b53e5e..b271a77 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java
@@ -48,7 +48,7 @@
private static final AppInstallMetadata APP_INSTALL_METADATA =
new AppInstallMetadata.Builder()
.setPackageName(PACKAGE_NAME_1)
- .setAppCertificate(APP_CERTIFICATE)
+ .setAppCertificates(Collections.singletonList(APP_CERTIFICATE))
.setVersionCode(2)
.build();
diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java
index 742952e..0784b7a 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java
@@ -35,6 +35,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
@RunWith(JUnit4.class)
@@ -49,7 +51,7 @@
AppInstallMetadata appInstallMetadata =
new AppInstallMetadata.Builder()
.setPackageName("ddd")
- .setAppCertificate("777")
+ .setAppCertificates(Collections.singletonList("777"))
.build();
List<RuleIndexRange> resultingIndexes =
@@ -63,6 +65,29 @@
}
@Test
+ public void verifyIndexRangeSearchIsCorrect_multipleAppCertificates() throws IOException {
+ InputStream inputStream = obtainDefaultIndexingMapForTest();
+
+ RuleIndexingController indexingController = new RuleIndexingController(inputStream);
+
+ AppInstallMetadata appInstallMetadata =
+ new AppInstallMetadata.Builder()
+ .setPackageName("ddd")
+ .setAppCertificates(Arrays.asList("777", "999"))
+ .build();
+
+ List<RuleIndexRange> resultingIndexes =
+ indexingController.identifyRulesToEvaluate(appInstallMetadata);
+
+ assertThat(resultingIndexes)
+ .containsExactly(
+ new RuleIndexRange(200, 300),
+ new RuleIndexRange(700, 800),
+ new RuleIndexRange(800, 900),
+ new RuleIndexRange(900, 945));
+ }
+
+ @Test
public void verifyIndexRangeSearchIsCorrect_keysInFirstAndLastBlock() throws IOException {
InputStream inputStream = obtainDefaultIndexingMapForTest();
@@ -71,7 +96,7 @@
AppInstallMetadata appInstallMetadata =
new AppInstallMetadata.Builder()
.setPackageName("bbb")
- .setAppCertificate("999")
+ .setAppCertificates(Collections.singletonList("999"))
.build();
List<RuleIndexRange> resultingIndexes =
@@ -93,7 +118,7 @@
AppInstallMetadata appInstallMetadata =
new AppInstallMetadata.Builder()
.setPackageName("ccc")
- .setAppCertificate("444")
+ .setAppCertificates(Collections.singletonList("444"))
.build();
List<RuleIndexRange> resultingIndexes =
@@ -125,7 +150,7 @@
AppInstallMetadata appInstallMetadata =
new AppInstallMetadata.Builder()
.setPackageName("ccc")
- .setAppCertificate("444")
+ .setAppCertificates(Collections.singletonList("444"))
.build();
List<RuleIndexRange> resultingIndexes =
diff --git a/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java b/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java
index 05a9a80..c0e7927 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java
@@ -47,7 +47,7 @@
.setContactPhoneNumber(PHONE_NUMBER)
.setNotificationChannelId(NOTIFICATION_CHANNEL_ID)
.setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED)
- .setVip(true)
+ .setImportant(true)
.setNotificationSilenced(true)
.setBubbled(true)
.setDemoted(true)
@@ -62,7 +62,7 @@
assertEquals(PHONE_NUMBER, conversationInfo.getContactPhoneNumber());
assertEquals(NOTIFICATION_CHANNEL_ID, conversationInfo.getNotificationChannelId());
assertTrue(conversationInfo.isShortcutLongLived());
- assertTrue(conversationInfo.isVip());
+ assertTrue(conversationInfo.isImportant());
assertTrue(conversationInfo.isNotificationSilenced());
assertTrue(conversationInfo.isBubbled());
assertTrue(conversationInfo.isDemoted());
@@ -83,7 +83,7 @@
assertNull(conversationInfo.getContactPhoneNumber());
assertNull(conversationInfo.getNotificationChannelId());
assertFalse(conversationInfo.isShortcutLongLived());
- assertFalse(conversationInfo.isVip());
+ assertFalse(conversationInfo.isImportant());
assertFalse(conversationInfo.isNotificationSilenced());
assertFalse(conversationInfo.isBubbled());
assertFalse(conversationInfo.isDemoted());
@@ -101,7 +101,7 @@
.setContactPhoneNumber(PHONE_NUMBER)
.setNotificationChannelId(NOTIFICATION_CHANNEL_ID)
.setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED)
- .setVip(true)
+ .setImportant(true)
.setNotificationSilenced(true)
.setBubbled(true)
.setPersonImportant(true)
@@ -110,7 +110,7 @@
.build();
ConversationInfo destination = new ConversationInfo.Builder(source)
- .setVip(false)
+ .setImportant(false)
.setContactStarred(false)
.build();
@@ -120,7 +120,7 @@
assertEquals(PHONE_NUMBER, destination.getContactPhoneNumber());
assertEquals(NOTIFICATION_CHANNEL_ID, destination.getNotificationChannelId());
assertTrue(destination.isShortcutLongLived());
- assertFalse(destination.isVip());
+ assertFalse(destination.isImportant());
assertTrue(destination.isNotificationSilenced());
assertTrue(destination.isBubbled());
assertTrue(destination.isPersonImportant());
diff --git a/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java b/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
index bbcb54e..331ad59 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
@@ -167,7 +167,7 @@
.setContactPhoneNumber(phoneNumber)
.setNotificationChannelId(notificationChannelId)
.setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED)
- .setVip(true)
+ .setImportant(true)
.setBubbled(true)
.build();
}
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index ad5c57d..498d888 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -16,10 +16,15 @@
package com.android.server.people.data;
+import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
+import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
+import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
+
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -33,6 +38,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
import android.app.Person;
import android.app.prediction.AppTarget;
import android.app.prediction.AppTargetEvent;
@@ -88,6 +95,7 @@
private static final String TEST_SHORTCUT_ID = "sc";
private static final String CONTACT_URI = "content://com.android.contacts/contacts/lookup/123";
private static final String PHONE_NUMBER = "+1234567890";
+ private static final String NOTIFICATION_CHANNEL_ID = "test : sc";
private static final long MILLIS_PER_MINUTE = 1000L * 60L;
@Mock private Context mContext;
@@ -103,6 +111,7 @@
@Mock private StatusBarNotification mStatusBarNotification;
@Mock private Notification mNotification;
+ private NotificationChannel mNotificationChannel;
private DataManager mDataManager;
private int mCallingUserId;
private TestInjector mInjector;
@@ -152,6 +161,10 @@
when(mStatusBarNotification.getUser()).thenReturn(UserHandle.of(USER_ID_PRIMARY));
when(mNotification.getShortcutId()).thenReturn(TEST_SHORTCUT_ID);
+ mNotificationChannel = new NotificationChannel(
+ NOTIFICATION_CHANNEL_ID, "test channel", NotificationManager.IMPORTANCE_DEFAULT);
+ mNotificationChannel.setConversationId("test", TEST_SHORTCUT_ID);
+
mCallingUserId = USER_ID_PRIMARY;
mInjector = new TestInjector();
@@ -284,9 +297,8 @@
}
@Test
- public void testNotificationListener() {
+ public void testNotificationOpened() {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
- mDataManager.onUserUnlocked(USER_ID_SECONDARY);
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
buildPerson());
@@ -308,6 +320,83 @@
}
@Test
+ public void testNotificationChannelCreated() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+ mDataManager.onUserUnlocked(USER_ID_SECONDARY);
+
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ mDataManager.onShortcutAddedOrUpdated(shortcut);
+
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+ listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
+ mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
+
+ ConversationInfo conversationInfo = mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
+ .getConversationStore()
+ .getConversation(TEST_SHORTCUT_ID);
+ assertEquals(NOTIFICATION_CHANNEL_ID, conversationInfo.getNotificationChannelId());
+ assertFalse(conversationInfo.isImportant());
+ assertFalse(conversationInfo.isNotificationSilenced());
+ assertFalse(conversationInfo.isDemoted());
+ }
+
+ @Test
+ public void testNotificationChannelModified() {
+ mNotificationChannel.setImportantConversation(true);
+
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+ mDataManager.onUserUnlocked(USER_ID_SECONDARY);
+
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ mDataManager.onShortcutAddedOrUpdated(shortcut);
+
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+ listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
+ mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
+
+ ConversationInfo conversationInfo = mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
+ .getConversationStore()
+ .getConversation(TEST_SHORTCUT_ID);
+ assertEquals(NOTIFICATION_CHANNEL_ID, conversationInfo.getNotificationChannelId());
+ assertTrue(conversationInfo.isImportant());
+ assertFalse(conversationInfo.isNotificationSilenced());
+ assertFalse(conversationInfo.isDemoted());
+ }
+
+ @Test
+ public void testNotificationChannelDeleted() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+ mDataManager.onUserUnlocked(USER_ID_SECONDARY);
+
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ mDataManager.onShortcutAddedOrUpdated(shortcut);
+
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+ listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
+ mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
+ ConversationInfo conversationInfo = mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
+ .getConversationStore()
+ .getConversation(TEST_SHORTCUT_ID);
+ assertEquals(NOTIFICATION_CHANNEL_ID, conversationInfo.getNotificationChannelId());
+
+ listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
+ mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
+ conversationInfo = mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
+ .getConversationStore()
+ .getConversation(TEST_SHORTCUT_ID);
+ assertNull(conversationInfo.getNotificationChannelId());
+ assertFalse(conversationInfo.isImportant());
+ assertFalse(conversationInfo.isNotificationSilenced());
+ assertFalse(conversationInfo.isDemoted());
+ }
+
+ @Test
public void testCallLogContentObserver() {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
mDataManager.onUserUnlocked(USER_ID_SECONDARY);
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 3d190be..df2b3ef 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -24,6 +24,7 @@
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.set;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
@@ -556,6 +557,11 @@
void injectRestoreCallingIdentity(long token) {
mInjectedCallingUid = (int) token;
}
+
+ @Override
+ boolean injectHasAccessShortcutsPermission(int callingPid, int callingUid) {
+ return true;
+ }
}
protected class LauncherAppsTestable extends LauncherApps {
@@ -1617,6 +1623,22 @@
}
/**
+ * Make a long lived shortcut with an ID.
+ */
+ protected ShortcutInfo makeLongLivedShortcut(String id) {
+ final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mClientContext, id)
+ .setActivity(new ComponentName(mClientContext.getPackageName(), "main"))
+ .setShortLabel("title-" + id)
+ .setIntent(makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class))
+ .setLongLived(true);
+ final ShortcutInfo s = b.build();
+
+ s.setTimestamp(mInjectedCurrentTimeMillis); // HACK
+
+ return s;
+ }
+
+ /**
* Make an intent.
*/
protected Intent makeIntent(String action, Class<?> clazz, Object... bundleKeysAndValues) {
@@ -1707,6 +1729,7 @@
final ArgumentCaptor<Intent[]> intentsCaptor = ArgumentCaptor.forClass(Intent[].class);
verify(mMockActivityTaskManagerInternal).startActivitiesAsPackage(
eq(packageName),
+ isNull(),
eq(userId),
intentsCaptor.capture(),
anyOrNull(Bundle.class));
@@ -1765,6 +1788,7 @@
// This shouldn't have been called.
verify(mMockActivityTaskManagerInternal, times(0)).startActivitiesAsPackage(
anyString(),
+ isNull(),
anyInt(),
any(Intent[].class),
anyOrNull(Bundle.class));
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 91cc9f3..fea1b82 100644
--- a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
@@ -55,6 +55,7 @@
@RunWith(MockitoJUnitRunner.class)
public class CrossProfileAppsServiceImplTest {
private static final String PACKAGE_ONE = "com.one";
+ private static final String FEATURE_ID = "feature.one";
private static final int PACKAGE_ONE_UID = 1111;
private static final ComponentName ACTIVITY_COMPONENT =
new ComponentName("com.one", "test");
@@ -220,6 +221,7 @@
mCrossProfileAppsServiceImpl.startActivityAsUser(
mIApplicationThread,
PACKAGE_ONE,
+ FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PRIMARY_USER).getIdentifier(),
true));
@@ -228,6 +230,7 @@
.startActivityAsUser(
nullable(IApplicationThread.class),
anyString(),
+ nullable(String.class),
any(Intent.class),
nullable(Bundle.class),
anyInt());
@@ -241,6 +244,7 @@
mCrossProfileAppsServiceImpl.startActivityAsUser(
mIApplicationThread,
PACKAGE_ONE,
+ FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PRIMARY_USER).getIdentifier(),
false));
@@ -249,6 +253,7 @@
.startActivityAsUser(
nullable(IApplicationThread.class),
anyString(),
+ nullable(String.class),
any(Intent.class),
nullable(Bundle.class),
anyInt());
@@ -264,6 +269,7 @@
mCrossProfileAppsServiceImpl.startActivityAsUser(
mIApplicationThread,
PACKAGE_ONE,
+ FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
true));
@@ -272,6 +278,7 @@
.startActivityAsUser(
nullable(IApplicationThread.class),
anyString(),
+ nullable(String.class),
any(Intent.class),
nullable(Bundle.class),
anyInt());
@@ -287,6 +294,7 @@
mCrossProfileAppsServiceImpl.startActivityAsUser(
mIApplicationThread,
PACKAGE_ONE,
+ FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
false));
@@ -295,6 +303,7 @@
.startActivityAsUser(
nullable(IApplicationThread.class),
anyString(),
+ nullable(String.class),
any(Intent.class),
nullable(Bundle.class),
anyInt());
@@ -308,6 +317,7 @@
mCrossProfileAppsServiceImpl.startActivityAsUser(
mIApplicationThread,
PACKAGE_TWO,
+ FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
true));
@@ -316,6 +326,7 @@
.startActivityAsUser(
nullable(IApplicationThread.class),
anyString(),
+ nullable(String.class),
any(Intent.class),
nullable(Bundle.class),
anyInt());
@@ -329,6 +340,7 @@
mCrossProfileAppsServiceImpl.startActivityAsUser(
mIApplicationThread,
PACKAGE_TWO,
+ FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
false));
@@ -337,6 +349,7 @@
.startActivityAsUser(
nullable(IApplicationThread.class),
anyString(),
+ nullable(String.class),
any(Intent.class),
nullable(Bundle.class),
anyInt());
@@ -352,6 +365,7 @@
mCrossProfileAppsServiceImpl.startActivityAsUser(
mIApplicationThread,
PACKAGE_ONE,
+ FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
true));
@@ -360,6 +374,7 @@
.startActivityAsUser(
nullable(IApplicationThread.class),
anyString(),
+ nullable(String.class),
any(Intent.class),
nullable(Bundle.class),
anyInt());
@@ -380,6 +395,7 @@
mCrossProfileAppsServiceImpl.startActivityAsUser(
mIApplicationThread,
PACKAGE_ONE,
+ FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
false));
@@ -388,6 +404,7 @@
.startActivityAsUser(
nullable(IApplicationThread.class),
anyString(),
+ nullable(String.class),
any(Intent.class),
nullable(Bundle.class),
anyInt());
@@ -401,6 +418,7 @@
mCrossProfileAppsServiceImpl.startActivityAsUser(
mIApplicationThread,
PACKAGE_ONE,
+ FEATURE_ID,
new ComponentName(PACKAGE_TWO, "test"),
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
true));
@@ -409,6 +427,7 @@
.startActivityAsUser(
nullable(IApplicationThread.class),
anyString(),
+ nullable(String.class),
any(Intent.class),
nullable(Bundle.class),
anyInt());
@@ -422,6 +441,7 @@
mCrossProfileAppsServiceImpl.startActivityAsUser(
mIApplicationThread,
PACKAGE_ONE,
+ FEATURE_ID,
new ComponentName(PACKAGE_TWO, "test"),
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
false));
@@ -430,6 +450,7 @@
.startActivityAsUser(
nullable(IApplicationThread.class),
anyString(),
+ nullable(String.class),
any(Intent.class),
nullable(Bundle.class),
anyInt());
@@ -443,6 +464,7 @@
mCrossProfileAppsServiceImpl.startActivityAsUser(
mIApplicationThread,
PACKAGE_ONE,
+ FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(SECONDARY_USER).getIdentifier(),
true));
@@ -451,6 +473,7 @@
.startActivityAsUser(
nullable(IApplicationThread.class),
anyString(),
+ nullable(String.class),
any(Intent.class),
nullable(Bundle.class),
anyInt());
@@ -464,6 +487,7 @@
mCrossProfileAppsServiceImpl.startActivityAsUser(
mIApplicationThread,
PACKAGE_ONE,
+ FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(SECONDARY_USER).getIdentifier(),
false));
@@ -472,6 +496,7 @@
.startActivityAsUser(
nullable(IApplicationThread.class),
anyString(),
+ nullable(String.class),
any(Intent.class),
nullable(Bundle.class),
anyInt());
@@ -484,6 +509,7 @@
mCrossProfileAppsServiceImpl.startActivityAsUser(
mIApplicationThread,
PACKAGE_ONE,
+ FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PRIMARY_USER).getIdentifier(),
true);
@@ -492,6 +518,7 @@
.startActivityAsUser(
nullable(IApplicationThread.class),
eq(PACKAGE_ONE),
+ eq(FEATURE_ID),
any(Intent.class),
nullable(Bundle.class),
eq(PRIMARY_USER));
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 63da5fb..2936bdd 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -1240,7 +1240,7 @@
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertTrue(mManager.setDynamicShortcuts(list(
- makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ makeLongLivedShortcut("s1"), makeLongLivedShortcut("s2"), makeShortcut("s3"))));
});
// Pin 2 and 3
@@ -1250,9 +1250,12 @@
});
// Cache 1 and 2
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2"),
+ HANDLE_USER_0);
+ });
+
setCaller(CALLING_PACKAGE_1);
- getCallerShortcut("s1").setCached();
- getCallerShortcut("s2").setCached();
// Get manifest shortcuts
assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_MANIFEST),
@@ -1315,8 +1318,9 @@
public void testCachedShortcuts() {
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"), makeShortcut("s2"),
- makeShortcut("s3"), makeShortcut("s4"))));
+ assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"),
+ makeLongLivedShortcut("s2"), makeLongLivedShortcut("s3"),
+ makeLongLivedShortcut("s4"))));
});
// Pin s2
@@ -1325,11 +1329,13 @@
HANDLE_USER_0);
});
- // Cache 2, 3 and 4
+ // Cache some, but non long lived shortcuts will be ignored.
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s4"),
+ HANDLE_USER_0);
+ });
+
setCaller(CALLING_PACKAGE_1);
- getCallerShortcut("s2").setCached();
- getCallerShortcut("s3").setCached();
- getCallerShortcut("s4").setCached();
// Get dynamic shortcuts
assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_DYNAMIC),
@@ -1339,27 +1345,37 @@
"s2");
// Get cached shortcuts
assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED),
- "s2", "s3", "s4");
+ "s2", "s4");
// Remove a dynamic cached shortcut
- mManager.removeDynamicShortcuts(list("s3"));
+ mManager.removeDynamicShortcuts(list("s4"));
assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_DYNAMIC),
- "s1", "s2", "s4");
+ "s1", "s2", "s3");
assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED),
- "s2", "s3", "s4");
+ "s2", "s4");
- // Remove dynamic cached long lived shortcuts
- mManager.removeLongLivedShortcuts(list("s3", "s4"));
- assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_DYNAMIC),
- "s1", "s2");
+ // uncache a non-dynamic shortcut. Should be removed.
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s4"),
+ HANDLE_USER_0);
+ });
assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED),
"s2");
+ // Cache another shortcut
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s3"),
+ HANDLE_USER_0);
+ });
+ assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED),
+ "s2", "s3");
+
// Remove a dynamic cached pinned long lived shortcut
mManager.removeLongLivedShortcuts(list("s2"));
assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_DYNAMIC),
- "s1");
- assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED));
+ "s1", "s3");
+ assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED),
+ "s3");
assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_PINNED),
"s2");
}
@@ -1371,7 +1387,7 @@
// Set up shortcuts.
setCaller(CALLING_PACKAGE_1);
- final ShortcutInfo s1_1 = makeShortcut("s1");
+ final ShortcutInfo s1_1 = makeLongLivedShortcut("s1");
final ShortcutInfo s1_2 = makeShortcutWithLocusId("s2", makeLocusId("l1"));
assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
@@ -1395,6 +1411,8 @@
setCaller(CALLING_PACKAGE_3);
final ShortcutInfo s3_2 = makeShortcutWithLocusId("s3", makeLocusId("l2"));
+ s3_2.setLongLived();
+
assertTrue(mManager.setDynamicShortcuts(list(s3_2)));
getCallerShortcut("s3").setTimestamp(START_TIME + 5000);
@@ -1535,26 +1553,20 @@
// TODO More tests: pinned but dynamic.
- // Cache some shortcuts
- setCaller(CALLING_PACKAGE_1);
- getCallerShortcut("s1").setCached();
-
- setCaller(CALLING_PACKAGE_2);
- getCallerShortcut("s4").setCached();
-
- setCaller(CALLING_PACKAGE_3);
- getCallerShortcut("s3").setCached();
-
setCaller(LAUNCHER_1);
+ // Cache some shortcuts. Only long lived shortcuts can get cached.
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1"), getCallingUser());
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_3, list("s3"), getCallingUser());
+
// Cached ones only
assertShortcutIds(assertAllNotKeyFieldsOnly(
mLauncherApps.getShortcuts(buildQuery(
- /* time =*/ 0, CALLING_PACKAGE_2,
+ /* time =*/ 0, CALLING_PACKAGE_3,
/* activity =*/ null,
ShortcutQuery.FLAG_MATCH_CACHED),
getCallingUser())),
- "s4");
+ "s3");
// All packages.
assertShortcutIds(assertAllNotKeyFieldsOnly(
@@ -1563,7 +1575,7 @@
/* activity =*/ null,
ShortcutQuery.FLAG_MATCH_CACHED),
getCallingUser())),
- "s1", "s4", "s3");
+ "s1", "s3");
assertExpectException(
IllegalArgumentException.class, "package name must also be set", () -> {
@@ -1581,7 +1593,7 @@
/* activity =*/ null,
ShortcutQuery.FLAG_MATCH_CACHED),
getCallingUser())),
- "s1", "s4", "s3");
+ "s1", "s3");
}
public void testGetShortcuts_shortcutKinds() throws Exception {
@@ -3132,7 +3144,7 @@
// Not launchable.
doReturn(ActivityManager.START_CLASS_NOT_FOUND)
.when(mMockActivityTaskManagerInternal).startActivitiesAsPackage(
- anyStringOrNull(), anyInt(),
+ anyStringOrNull(), anyStringOrNull(), anyInt(),
anyOrNull(Intent[].class), anyOrNull(Bundle.class));
assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_0,
ActivityNotFoundException.class);
@@ -3141,7 +3153,7 @@
doReturn(ActivityManager.START_CLASS_NOT_FOUND)
.when(mMockActivityTaskManagerInternal)
.startActivitiesAsPackage(
- anyStringOrNull(), anyInt(),
+ anyStringOrNull(), anyStringOrNull(), anyInt(),
anyOrNull(Intent[].class), anyOrNull(Bundle.class));
assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_0,
ActivityNotFoundException.class);
diff --git a/services/tests/servicestests/src/com/android/server/rollback/WatchdogRollbackLoggerTest.java b/services/tests/servicestests/src/com/android/server/rollback/WatchdogRollbackLoggerTest.java
index ba493d4..d1c9643 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/WatchdogRollbackLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/WatchdogRollbackLoggerTest.java
@@ -20,7 +20,11 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -36,6 +40,8 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import java.util.List;
+
@RunWith(JUnit4.class)
public class WatchdogRollbackLoggerTest {
@@ -46,6 +52,11 @@
private PackageInfo mPackageInfo;
private static final String LOGGING_PARENT_KEY = "android.content.pm.LOGGING_PARENT";
+ private static final String LOGGING_PARENT_VALUE = "logging.parent";
+ private static final int PACKAGE_INFO_FLAGS = PackageManager.MATCH_APEX
+ | PackageManager.GET_META_DATA;
+ private static final List<String> sFailingPackages =
+ List.of("package1", "package2", "package3");
@Before
public void setUp() {
@@ -64,10 +75,12 @@
*/
@Test
public void testLogPackageHasNoMetadata() throws Exception {
- when(mMockPm.getApplicationInfo(anyString(), anyInt())).thenReturn(mApplicationInfo);
+ when(mMockPm.getPackageInfo(anyString(), anyInt())).thenReturn(mPackageInfo);
VersionedPackage logPackage = WatchdogRollbackLogger.getLogPackage(mMockContext,
sTestPackageV1);
assertThat(logPackage).isNull();
+ verify(mMockPm, times(1)).getPackageInfo(
+ sTestPackageV1.getPackageName(), PACKAGE_INFO_FLAGS);
}
/**
@@ -76,12 +89,16 @@
*/
@Test
public void testLogPackageParentKeyIsNull() throws Exception {
- when(mMockPm.getApplicationInfo(anyString(), anyInt())).thenReturn(mApplicationInfo);
+ when(mMockPm.getPackageInfo(anyString(), anyInt())).thenReturn(mPackageInfo);
Bundle bundle = new Bundle();
bundle.putString(LOGGING_PARENT_KEY, null);
+ mApplicationInfo.metaData = bundle;
+ mPackageInfo.applicationInfo = mApplicationInfo;
VersionedPackage logPackage = WatchdogRollbackLogger.getLogPackage(mMockContext,
sTestPackageV1);
assertThat(logPackage).isNull();
+ verify(mMockPm, times(1)).getPackageInfo(
+ sTestPackageV1.getPackageName(), PACKAGE_INFO_FLAGS);
}
/**
@@ -90,15 +107,18 @@
@Test
public void testLogPackageHasParentKey() throws Exception {
Bundle bundle = new Bundle();
- bundle.putString(LOGGING_PARENT_KEY, "logging.parent");
+ bundle.putString(LOGGING_PARENT_KEY, LOGGING_PARENT_VALUE);
mApplicationInfo.metaData = bundle;
+ mPackageInfo.applicationInfo = mApplicationInfo;
mPackageInfo.setLongVersionCode(12345L);
- when(mMockPm.getApplicationInfo(anyString(), anyInt())).thenReturn(mApplicationInfo);
when(mMockPm.getPackageInfo(anyString(), anyInt())).thenReturn(mPackageInfo);
VersionedPackage logPackage = WatchdogRollbackLogger.getLogPackage(mMockContext,
sTestPackageV1);
- VersionedPackage expectedLogPackage = new VersionedPackage("logging.parent", 12345);
+ VersionedPackage expectedLogPackage = new VersionedPackage(LOGGING_PARENT_VALUE, 12345);
assertThat(logPackage).isEqualTo(expectedLogPackage);
+ verify(mMockPm, times(1)).getPackageInfo(
+ sTestPackageV1.getPackageName(), PACKAGE_INFO_FLAGS);
+
}
/**
@@ -107,12 +127,64 @@
@Test
public void testLogPackageNameNotFound() throws Exception {
Bundle bundle = new Bundle();
- bundle.putString("android.content.pm.LOGGING_PARENT", "logging.parent");
+ bundle.putString(LOGGING_PARENT_KEY, LOGGING_PARENT_VALUE);
mApplicationInfo.metaData = bundle;
- when(mMockPm.getPackageInfo(anyString(), anyInt())).thenThrow(
+ mPackageInfo.applicationInfo = mApplicationInfo;
+ when(mMockPm.getPackageInfo(anyString(), anyInt())).thenReturn(mPackageInfo);
+ when(mMockPm.getPackageInfo(same(LOGGING_PARENT_VALUE), anyInt())).thenThrow(
new PackageManager.NameNotFoundException());
VersionedPackage logPackage = WatchdogRollbackLogger.getLogPackage(mMockContext,
sTestPackageV1);
assertThat(logPackage).isNull();
+ verify(mMockPm, times(1)).getPackageInfo(
+ sTestPackageV1.getPackageName(), PACKAGE_INFO_FLAGS);
+ }
+
+ /**
+ * Ensures that we make the correct Package Manager calls in the case that the failing packages
+ * are correctly configured with parent packages.
+ */
+ @Test
+ public void testApexdLoggingCallsWithParents() throws Exception {
+ for (String failingPackage: sFailingPackages) {
+ PackageInfo packageInfo = new PackageInfo();
+ ApplicationInfo applicationInfo = new ApplicationInfo();
+ Bundle bundle = new Bundle();
+ bundle.putString(LOGGING_PARENT_KEY, getParent(failingPackage));
+ applicationInfo.metaData = bundle;
+ packageInfo.applicationInfo = applicationInfo;
+ when(mMockPm.getPackageInfo(same(failingPackage), anyInt())).thenReturn(packageInfo);
+ }
+
+ when(mMockPm.getPackageInfo(anyString(), eq(0))).thenReturn(mPackageInfo);
+ WatchdogRollbackLogger.logApexdRevert(mMockContext, sFailingPackages, "test_process");
+ for (String failingPackage: sFailingPackages) {
+ verify(mMockPm, times(1)).getPackageInfo(failingPackage, PACKAGE_INFO_FLAGS);
+ verify(mMockPm, times(1)).getPackageInfo(getParent(failingPackage), 0);
+ }
+ }
+
+ /**
+ * Ensures that we don't make any calls to parent packages in the case that packages are not
+ * correctly configured with parent packages.
+ */
+ @Test
+ public void testApexdLoggingCallsWithNoParents() throws Exception {
+ for (String failingPackage: sFailingPackages) {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.applicationInfo = new ApplicationInfo();
+ when(mMockPm.getPackageInfo(same(failingPackage), anyInt())).thenReturn(packageInfo);
+ }
+ when(mMockPm.getPackageInfo(anyString(), eq(0))).thenReturn(mPackageInfo);
+
+ WatchdogRollbackLogger.logApexdRevert(mMockContext, sFailingPackages, "test_process");
+ verify(mMockPm, times(sFailingPackages.size())).getPackageInfo(anyString(), anyInt());
+ for (String failingPackage: sFailingPackages) {
+ verify(mMockPm, times(1)).getPackageInfo(failingPackage, PACKAGE_INFO_FLAGS);
+ }
+ }
+
+ private String getParent(String packageName) {
+ return packageName + "-parent";
}
}
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index fde0ddf..4d0481be 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -144,6 +144,40 @@
assertEquals("Incorrect blacklist", expectedBlack, actualBlack);
}
+ @Test
+ public void testComponentOverride() throws Exception {
+ final String contents =
+ "<permissions>"
+ + " <component-override package=\"com.android.package1\">\n"
+ + " <component class=\"com.android.package1.Full\" enabled=\"true\"/>"
+ + " <component class=\".Relative\" enabled=\"false\" />\n"
+ + " </component-override>"
+ + " <component-override package=\"com.android.package2\" >\n"
+ + " <component class=\"com.android.package3.Relative2\" enabled=\"yes\" />\n"
+ + " </component-override>\n"
+ + "</permissions>";
+
+ final File folder = createTempSubfolder("folder");
+ createTempFile(folder, "component-override.xml", contents);
+
+ mSysConfig.readPermissions(folder, /* No permission needed anyway */ 0);
+
+ final ArrayMap<String, Boolean> packageOneExpected = new ArrayMap<>();
+ packageOneExpected.put("com.android.package1.Full", true);
+ packageOneExpected.put("com.android.package1.Relative", false);
+
+ final ArrayMap<String, Boolean> packageTwoExpected = new ArrayMap<>();
+ packageTwoExpected.put("com.android.package3.Relative2", true);
+
+ final Map<String, Boolean> packageOne = mSysConfig.getComponentsEnabledStates(
+ "com.android.package1");
+ assertEquals(packageOneExpected, packageOne);
+
+ final Map<String, Boolean> packageTwo = mSysConfig.getComponentsEnabledStates(
+ "com.android.package2");
+ assertEquals(packageTwoExpected, packageTwo);
+ }
+
/**
* Creates folderName/fileName in the mTemporaryFolder and fills it with the contents.
* @param folderName subdirectory of mTemporaryFolder to put the file, creating if needed
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index f608bab..3f0cda3 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -47,7 +47,6 @@
"libbacktrace",
"libbase",
"libbinder",
- "libbinderthreadstate",
"libc++",
"libcutils",
"liblog",
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
index 5b5ad87..cbb760a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
@@ -44,6 +44,7 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.internal.matchers.Not;
import java.io.File;
import java.util.ArrayList;
@@ -239,6 +240,52 @@
verify(af2, never()).openRead();
}
+ @Test
+ public void testRemoveNotificationRunnable() throws Exception {
+ NotificationHistory nh = mock(NotificationHistory.class);
+ NotificationHistoryDatabase.RemoveNotificationRunnable rnr =
+ mDataBase.new RemoveNotificationRunnable("pkg", 123);
+ rnr.setNotificationHistory(nh);
+
+ AtomicFile af = mock(AtomicFile.class);
+ when(af.getBaseFile()).thenReturn(new File(mRootDir, "af"));
+ mDataBase.mHistoryFiles.addLast(af);
+
+ when(nh.removeNotificationFromWrite("pkg", 123)).thenReturn(true);
+
+ mDataBase.mBuffer = mock(NotificationHistory.class);
+
+ rnr.run();
+
+ verify(mDataBase.mBuffer).removeNotificationFromWrite("pkg", 123);
+ verify(af).openRead();
+ verify(nh).removeNotificationFromWrite("pkg", 123);
+ verify(af).startWrite();
+ }
+
+ @Test
+ public void testRemoveNotificationRunnable_noChanges() throws Exception {
+ NotificationHistory nh = mock(NotificationHistory.class);
+ NotificationHistoryDatabase.RemoveNotificationRunnable rnr =
+ mDataBase.new RemoveNotificationRunnable("pkg", 123);
+ rnr.setNotificationHistory(nh);
+
+ AtomicFile af = mock(AtomicFile.class);
+ when(af.getBaseFile()).thenReturn(new File(mRootDir, "af"));
+ mDataBase.mHistoryFiles.addLast(af);
+
+ when(nh.removeNotificationFromWrite("pkg", 123)).thenReturn(false);
+
+ mDataBase.mBuffer = mock(NotificationHistory.class);
+
+ rnr.run();
+
+ verify(mDataBase.mBuffer).removeNotificationFromWrite("pkg", 123);
+ verify(af).openRead();
+ verify(nh).removeNotificationFromWrite("pkg", 123);
+ verify(af, never()).startWrite();
+ }
+
private class TestFileAttrProvider implements NotificationHistoryDatabase.FileAttrProvider {
public Map<File, Long> creationDates = new HashMap<>();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java
index b5eb1bf..2c548be 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java
@@ -289,6 +289,20 @@
}
@Test
+ public void testDeleteNotificationHistoryItem_userUnlocked() {
+ String pkg = "pkg";
+ long time = 235;
+ NotificationHistoryDatabase userHistory = mock(NotificationHistoryDatabase.class);
+
+ mHistoryManager.onUserUnlocked(USER_SYSTEM);
+ mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistory);
+
+ mHistoryManager.deleteNotificationHistoryItem(pkg, 1, time);
+
+ verify(userHistory, times(1)).deleteNotificationHistoryItem(pkg, time);
+ }
+
+ @Test
public void testTriggerWriteToDisk() {
NotificationHistoryDatabase userHistorySystem = mock(NotificationHistoryDatabase.class);
NotificationHistoryDatabase userHistoryAll = mock(NotificationHistoryDatabase.class);
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 e0ee3ce..57428dc 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -32,7 +32,6 @@
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS;
import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS;
-import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
@@ -42,6 +41,8 @@
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC;
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED;
import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -50,6 +51,8 @@
import static android.os.UserHandle.USER_SYSTEM;
import static android.service.notification.Adjustment.KEY_IMPORTANCE;
import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
+import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
+import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
@@ -128,6 +131,7 @@
import android.provider.MediaStore;
import android.provider.Settings;
import android.service.notification.Adjustment;
+import android.service.notification.ConversationChannelWrapper;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationStats;
import android.service.notification.StatusBarNotification;
@@ -1144,7 +1148,9 @@
waitForIdle();
assertEquals(1, mNotificationRecordLogger.getCalls().size());
NotificationRecordLoggerFake.CallRecord call = mNotificationRecordLogger.get(0);
- assertTrue(call.shouldLog());
+ assertTrue(call.shouldLog);
+ assertEquals(NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED,
+ call.event);
assertNotNull(call.r);
assertNull(call.old);
assertEquals(0, call.position);
@@ -1153,7 +1159,7 @@
assertEquals(0, call.r.getSbn().getId());
assertEquals(tag, call.r.getSbn().getTag());
assertNotNull(call.r.getSbn().getInstanceId());
- assertEquals(0, call.r.getSbn().getInstanceId().getId());
+ assertEquals(0, call.getInstanceId()); // Fake instance IDs are assigned in order
}
@Test
@@ -1171,18 +1177,18 @@
waitForIdle();
assertEquals(2, mNotificationRecordLogger.getCalls().size());
- assertTrue(mNotificationRecordLogger.get(0).shouldLog());
+ assertTrue(mNotificationRecordLogger.get(0).shouldLog);
assertEquals(
- NotificationRecordLogger.NotificationReportedEvents.NOTIFICATION_POSTED,
- mNotificationRecordLogger.get(0).getUiEvent());
- assertEquals(0, mNotificationRecordLogger.get(0).r.getSbn().getInstanceId().getId());
+ NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED,
+ mNotificationRecordLogger.get(0).event);
+ assertEquals(0, mNotificationRecordLogger.get(0).getInstanceId());
- assertTrue(mNotificationRecordLogger.get(1).shouldLog());
+ assertTrue(mNotificationRecordLogger.get(1).shouldLog);
assertEquals(
- NotificationRecordLogger.NotificationReportedEvents.NOTIFICATION_UPDATED,
- mNotificationRecordLogger.get(1).getUiEvent());
+ NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_UPDATED,
+ mNotificationRecordLogger.get(1).event);
// Instance ID doesn't change on update of an active notification
- assertEquals(0, mNotificationRecordLogger.get(1).r.getSbn().getInstanceId().getId());
+ assertEquals(0, mNotificationRecordLogger.get(1).getInstanceId());
}
@Test
@@ -1194,8 +1200,8 @@
generateNotificationRecord(null).getNotification(), 0);
waitForIdle();
assertEquals(2, mNotificationRecordLogger.getCalls().size());
- assertTrue(mNotificationRecordLogger.get(0).shouldLog());
- assertFalse(mNotificationRecordLogger.get(1).shouldLog());
+ assertTrue(mNotificationRecordLogger.get(0).shouldLog);
+ assertFalse(mNotificationRecordLogger.get(1).shouldLog);
}
@Test
@@ -1210,20 +1216,37 @@
waitForIdle();
mBinderService.enqueueNotificationWithTag(PKG, PKG, tag, 0, notification, 0);
waitForIdle();
- assertEquals(2, mNotificationRecordLogger.getCalls().size());
+ assertEquals(3, mNotificationRecordLogger.getCalls().size());
- assertTrue(mNotificationRecordLogger.get(0).shouldLog());
assertEquals(
- NotificationRecordLogger.NotificationReportedEvents.NOTIFICATION_POSTED,
- mNotificationRecordLogger.get(0).getUiEvent());
- assertEquals(0, mNotificationRecordLogger.get(0).r.getSbn().getInstanceId().getId());
+ NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED,
+ mNotificationRecordLogger.get(0).event);
+ assertTrue(mNotificationRecordLogger.get(0).shouldLog);
+ assertEquals(0, mNotificationRecordLogger.get(0).getInstanceId());
- assertTrue(mNotificationRecordLogger.get(1).shouldLog());
+ assertEquals(REASON_APP_CANCEL, mNotificationRecordLogger.get(1).reason);
assertEquals(
- NotificationRecordLogger.NotificationReportedEvents.NOTIFICATION_POSTED,
- mNotificationRecordLogger.get(1).getUiEvent());
+ NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_APP_CANCEL,
+ mNotificationRecordLogger.get(1).event);
+ assertTrue(mNotificationRecordLogger.get(1).shouldLog);
+ assertEquals(0, mNotificationRecordLogger.get(1).getInstanceId());
+
+ assertEquals(
+ NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED,
+ mNotificationRecordLogger.get(2).event);
+ assertTrue(mNotificationRecordLogger.get(2).shouldLog);
// New instance ID because notification was canceled before re-post
- assertEquals(1, mNotificationRecordLogger.get(1).r.getSbn().getInstanceId().getId());
+ assertEquals(1, mNotificationRecordLogger.get(2).getInstanceId());
+ }
+
+ @Test
+ public void testCancelNonexistentNotification() throws Exception {
+ mBinderService.cancelNotificationWithTag(PKG, PKG,
+ "testCancelNonexistentNotification", 0, 0);
+ waitForIdle();
+ // The notification record logger doesn't even get called when a nonexistent notification
+ // is cancelled, because that happens very frequently and is not interesting.
+ assertEquals(0, mNotificationRecordLogger.getCalls().size());
}
@Test
@@ -3365,6 +3388,17 @@
waitForIdle();
assertEquals(NotificationStats.DISMISSAL_AOD, r.getStats().getDismissalSurface());
+
+ // Using mService.addNotification() does not generate a NotificationRecordLogger log,
+ // so we only get the cancel notification.
+ assertEquals(1, mNotificationRecordLogger.getCalls().size());
+
+ assertEquals(REASON_CANCEL, mNotificationRecordLogger.get(0).reason);
+ assertEquals(
+ NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_USER_AOD,
+ mNotificationRecordLogger.get(0).event);
+ assertTrue(mNotificationRecordLogger.get(0).shouldLog);
+ assertEquals(0, mNotificationRecordLogger.get(0).getInstanceId());
}
@Test
@@ -6273,4 +6307,60 @@
assertEquals(PRIORITY_CATEGORY_CALLS, actual);
}
+
+ @Test
+ public void testGetConversationsForPackage_hasShortcut() throws Exception {
+ mService.setPreferencesHelper(mPreferencesHelper);
+ ArrayList<ConversationChannelWrapper> convos = new ArrayList<>();
+ ConversationChannelWrapper convo1 = new ConversationChannelWrapper();
+ NotificationChannel channel1 = new NotificationChannel("a", "a", 1);
+ channel1.setConversationId("parent1", "convo 1");
+ convo1.setNotificationChannel(channel1);
+ convos.add(convo1);
+
+ ConversationChannelWrapper convo2 = new ConversationChannelWrapper();
+ NotificationChannel channel2 = new NotificationChannel("b", "b", 1);
+ channel2.setConversationId("parent1", "convo 2");
+ convo2.setNotificationChannel(channel2);
+ convos.add(convo2);
+ when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos);
+
+ // only one valid shortcut
+ LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery()
+ .setPackage(PKG_P)
+ .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED)
+ .setShortcutIds(Arrays.asList(channel1.getConversationId()));
+ ShortcutInfo si = mock(ShortcutInfo.class);
+ when(si.getShortLabel()).thenReturn("Hello");
+ when(mLauncherApps.getShortcuts(any(), any())).thenReturn(Arrays.asList(si));
+
+ List<ConversationChannelWrapper> conversations =
+ mBinderService.getConversationsForPackage(PKG_P, mUid).getList();
+ assertEquals(si, conversations.get(0).getShortcutInfo());
+ assertEquals(si, conversations.get(1).getShortcutInfo());
+
+ }
+
+ @Test
+ public void testGetConversationsForPackage_doesNotHaveShortcut() throws Exception {
+ mService.setPreferencesHelper(mPreferencesHelper);
+ ArrayList<ConversationChannelWrapper> convos = new ArrayList<>();
+ ConversationChannelWrapper convo1 = new ConversationChannelWrapper();
+ NotificationChannel channel1 = new NotificationChannel("a", "a", 1);
+ channel1.setConversationId("parent1", "convo 1");
+ convo1.setNotificationChannel(channel1);
+ convos.add(convo1);
+
+ ConversationChannelWrapper convo2 = new ConversationChannelWrapper();
+ NotificationChannel channel2 = new NotificationChannel("b", "b", 1);
+ channel2.setConversationId("parent1", "convo 2");
+ convo2.setNotificationChannel(channel2);
+ convos.add(convo2);
+ when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos);
+
+ List<ConversationChannelWrapper> conversations =
+ mBinderService.getConversationsForPackage(PKG_P, mUid).getList();
+ assertNull(conversations.get(0).getShortcutInfo());
+ assertNull(conversations.get(1).getShortcutInfo());
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java
index 5c1487f..b120dbe 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java
@@ -16,6 +16,8 @@
package com.android.server.notification;
+import com.android.internal.logging.UiEventLogger;
+
import java.util.ArrayList;
import java.util.List;
@@ -24,18 +26,27 @@
*/
class NotificationRecordLoggerFake implements NotificationRecordLogger {
static class CallRecord extends NotificationRecordPair {
- public int position, buzzBeepBlink;
+ static final int INVALID = -1;
+ public int position = INVALID, buzzBeepBlink = INVALID, reason = INVALID;
+ public boolean shouldLog;
+ public UiEventLogger.UiEventEnum event;
CallRecord(NotificationRecord r, NotificationRecord old, int position,
int buzzBeepBlink) {
super(r, old);
+
this.position = position;
this.buzzBeepBlink = buzzBeepBlink;
+ shouldLog = shouldLog(buzzBeepBlink);
+ event = NotificationReportedEvent.fromRecordPair(this);
}
- boolean shouldLog() {
- return shouldLog(buzzBeepBlink);
+ CallRecord(NotificationRecord r, int reason, int dismissalSurface) {
+ super(r, null);
+ this.reason = reason;
+ shouldLog = true;
+ event = NotificationCancelledEvent.fromCancelReason(reason, dismissalSurface);
}
}
- private List<CallRecord> mCalls = new ArrayList<CallRecord>();
+ private List<CallRecord> mCalls = new ArrayList<>();
List<CallRecord> getCalls() {
return mCalls;
@@ -50,4 +61,10 @@
int position, int buzzBeepBlink) {
mCalls.add(new CallRecord(r, old, position, buzzBeepBlink));
}
+
+ @Override
+ public void logNotificationCancelled(NotificationRecord r, int reason, int dismissalSurface) {
+ mCalls.add(new CallRecord(r, reason, dismissalSurface));
+ }
+
}
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 bb84b04..3f690b1 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -26,6 +26,8 @@
import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_COUNT_LIMIT;
+import static com.google.common.truth.Truth.assertThat;
+
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.fail;
@@ -64,6 +66,7 @@
import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
+import android.service.notification.ConversationChannelWrapper;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.TestableContentResolver;
import android.util.ArrayMap;
@@ -91,6 +94,7 @@
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -2939,4 +2943,97 @@
assertNotNull(mHelper.getNotificationChannel(PKG_O, UID_O, "id", true));
}
+
+ @Test
+ public void testGetConversations_invalidPkg() {
+ assertThat(mHelper.getConversations("bad", 1)).isEmpty();
+ }
+
+ @Test
+ public void testGetConversations_noConversations() {
+ NotificationChannel channel =
+ new NotificationChannel("not_convo", "not_convo", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
+
+ assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty();
+ }
+
+ @Test
+ public void testGetConversations_noDisabledGroups() {
+ NotificationChannelGroup group = new NotificationChannelGroup("a", "a");
+ group.setBlocked(true);
+ mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true);
+ NotificationChannel parent = new NotificationChannel("parent", "p", 1);
+ mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false);
+
+ NotificationChannel channel =
+ new NotificationChannel("convo", "convo", IMPORTANCE_DEFAULT);
+ channel.setConversationId("parent", "convo");
+ channel.setGroup(group.getId());
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
+
+ assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty();
+ }
+
+ @Test
+ public void testGetConversations_noDeleted() {
+ NotificationChannel parent = new NotificationChannel("parent", "p", 1);
+ mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false);
+ NotificationChannel channel =
+ new NotificationChannel("convo", "convo", IMPORTANCE_DEFAULT);
+ channel.setConversationId("parent", "convo");
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
+ mHelper.deleteNotificationChannel(PKG_O, UID_O, channel.getId());
+
+ assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty();
+ }
+
+ @Test
+ public void testGetConversations() {
+ NotificationChannelGroup group = new NotificationChannelGroup("acct", "account_name");
+ mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true);
+
+ NotificationChannel messages =
+ new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
+ messages.setGroup(group.getId());
+ mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false);
+ NotificationChannel calls =
+ new NotificationChannel("calls", "Calls", IMPORTANCE_HIGH);
+ mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false);
+
+ NotificationChannel channel =
+ new NotificationChannel("A person", "A lovely person", IMPORTANCE_DEFAULT);
+ channel.setGroup(group.getId());
+ channel.setConversationId(messages.getId(), channel.getName().toString());
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
+
+ NotificationChannel channel2 =
+ new NotificationChannel("B person", "B fabulous person", IMPORTANCE_DEFAULT);
+ channel2.setConversationId(calls.getId(), channel.getName().toString());
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false);
+
+ Map<String, NotificationChannel> expected = new HashMap<>();
+ expected.put(channel.getId(), channel);
+ expected.put(channel2.getId(), channel2);
+
+ Map<String, CharSequence> expectedGroup = new HashMap<>();
+ expectedGroup.put(channel.getId(), group.getName());
+ expectedGroup.put(channel2.getId(), null);
+
+ Map<String, CharSequence> expectedParentLabel= new HashMap<>();
+ expectedParentLabel.put(channel.getId(), messages.getName());
+ expectedParentLabel.put(channel2.getId(), calls.getName());
+
+ ArrayList<ConversationChannelWrapper> convos = mHelper.getConversations(PKG_O, UID_O);
+ assertThat(convos).hasSize(2);
+
+ for (ConversationChannelWrapper convo : convos) {
+ assertThat(convo.getNotificationChannel())
+ .isEqualTo(expected.get(convo.getNotificationChannel().getId()));
+ assertThat(convo.getParentChannelLabel())
+ .isEqualTo(expectedParentLabel.get(convo.getNotificationChannel().getId()));
+ assertThat(convo.getGroupLabel())
+ .isEqualTo(expectedGroup.get(convo.getNotificationChannel().getId()));
+ }
+ }
}
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 135d005..af04f76 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
@@ -120,7 +120,7 @@
mInterceptor = new ActivityStartInterceptor(
mService, mSupervisor, mRootWindowContainer, mContext);
mInterceptor.setStates(TEST_USER_ID, TEST_REAL_CALLING_PID, TEST_REAL_CALLING_UID,
- TEST_START_FLAGS, TEST_CALLING_PACKAGE);
+ TEST_START_FLAGS, TEST_CALLING_PACKAGE, null);
// Mock ActivityManagerInternal
LocalServices.removeServiceForTest(ActivityManagerInternal.class);
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 bab877e..fa182d6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -275,7 +275,7 @@
if (containsConditions(preconditions, PRECONDITION_CANNOT_START_ANY_ACTIVITY)) {
doReturn(false).when(service.mStackSupervisor).checkStartAnyActivityPermission(
- any(), any(), any(), anyInt(), anyInt(), anyInt(), any(),
+ any(), any(), any(), anyInt(), anyInt(), anyInt(), any(), any(),
anyBoolean(), anyBoolean(), any(), any(), any());
}
@@ -349,7 +349,7 @@
boolean mockGetLaunchStack) {
// always allow test to start activity.
doReturn(true).when(mSupervisor).checkStartAnyActivityPermission(
- any(), any(), any(), anyInt(), anyInt(), anyInt(), any(),
+ any(), any(), any(), anyInt(), anyInt(), anyInt(), any(), any(),
anyBoolean(), anyBoolean(), any(), any(), any());
if (mockGetLaunchStack) {
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 eb84d0a..c93dc97 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -255,10 +255,10 @@
final ActivityRecord activity = new ActivityRecord(mService, null /* caller */,
mLaunchedFromPid /* launchedFromPid */, mLaunchedFromUid /* launchedFromUid */,
- null, intent, null, aInfo /*aInfo*/, new Configuration(), null /* resultTo */,
- null /* resultWho */, 0 /* reqCode */, false /*componentSpecified*/,
- false /* rootVoiceInteraction */, mService.mStackSupervisor, options,
- null /* sourceRecord */);
+ null, null, intent, null, aInfo /*aInfo*/, new Configuration(),
+ null /* resultTo */, null /* resultWho */, 0 /* reqCode */,
+ false /*componentSpecified*/, false /* rootVoiceInteraction */,
+ mService.mStackSupervisor, options, null /* sourceRecord */);
spyOn(activity);
if (mTask != null) {
// fullscreen value is normally read from resources in ctor, so for testing we need
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 9dbaa4c..e6291a4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -95,8 +95,6 @@
@Before
public void setUp() throws Exception {
- updateDisplayFrames();
-
mWindow = spy(createWindow(null, TYPE_APPLICATION, "window"));
// We only test window frames set by DisplayPolicy, so here prevents computeFrameLw from
// changing those frames.
@@ -106,6 +104,8 @@
attrs.width = MATCH_PARENT;
attrs.height = MATCH_PARENT;
attrs.format = PixelFormat.TRANSLUCENT;
+
+ updateDisplayFrames();
}
@After
@@ -126,6 +126,7 @@
private void updateDisplayFrames() {
mFrames = createDisplayFrames();
+ mDisplayContent.mDisplayFrames = mFrames;
}
private DisplayFrames createDisplayFrames() {
@@ -180,63 +181,6 @@
}
@Test
- public void layoutWindowLw_appDrawsBars() {
- assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
-
- mWindow.mAttrs.flags = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitInsetsTypes(Type.systemBars());
- addWindow(mWindow);
-
- mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
- assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
- }
-
- @Test
- public void layoutWindowLw_forceAppDrawBars() {
- assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
-
- mWindow.mAttrs.privateFlags = PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitInsetsTypes(Type.systemBars());
- addWindow(mWindow);
-
- mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
- assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
- }
-
- @Test
- public void layoutWindowLw_onlyDrawBottomBar() {
- assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
-
- mWindow.mAttrs.flags = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitInsetsTypes(Type.systemBars());
- addWindow(mWindow);
-
- mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
- assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
- }
-
- @Test
public void layoutWindowLw_fitAllSides() {
assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
@@ -273,7 +217,7 @@
}
@Test
- public void layoutWindowLw_fitMax() {
+ public void layoutWindowLw_fitInsetsIgnoringVisibility() {
assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
final InsetsState state =
@@ -295,7 +239,7 @@
}
@Test
- public void layoutWindowLw_fitNonMax() {
+ public void layoutWindowLw_fitInsetsNotIgnoringVisibility() {
assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
final InsetsState state =
@@ -398,6 +342,7 @@
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
addWindow(mWindow);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -416,6 +361,7 @@
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
addWindow(mWindow);
@@ -435,6 +381,7 @@
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
mWindow.mAttrs.setFitInsetsTypes(
mWindow.mAttrs.getFitInsetsTypes() & ~Type.statusBars());
@@ -456,6 +403,7 @@
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
mDisplayContent.getInsetsPolicy().getInsetsForDispatch(mWindow)
.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
@@ -477,6 +425,7 @@
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
mDisplayContent.getInsetsPolicy().getInsetsForDispatch(mWindow)
.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
@@ -501,6 +450,7 @@
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
addWindow(mWindow);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -521,6 +471,7 @@
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
addWindow(mWindow);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -541,6 +492,7 @@
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
mWindow.mAttrs.setFitInsetsTypes(
mWindow.mAttrs.getFitInsetsTypes() & ~Type.statusBars());
@@ -581,6 +533,7 @@
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
mWindow.mAttrs.setFitInsetsTypes(
mWindow.mAttrs.getFitInsetsTypes() & ~Type.statusBars());
@@ -603,6 +556,7 @@
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);
@@ -625,6 +579,7 @@
public void layoutWindowLw_withForwardInset_SoftInputAdjustNothing() {
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_NOTHING;
addWindow(mWindow);
@@ -849,7 +804,6 @@
final String prefix = "";
final InsetsState simulatedInsetsState = new InsetsState();
final DisplayFrames simulatedDisplayFrames = createDisplayFrames();
- mDisplayContent.mDisplayFrames = mFrames;
mDisplayPolicy.beginLayoutLw(mFrames, uiMode);
mDisplayContent.getInsetsStateController().onPostLayout();
mDisplayPolicy.simulateLayoutDisplay(simulatedDisplayFrames, simulatedInsetsState, uiMode);
@@ -867,6 +821,7 @@
// Exclude comparing IME insets because currently the simulated layout only focuses on the
// insets from status bar and navigation bar.
realInsetsState.removeSource(InsetsState.ITYPE_IME);
+ realInsetsState.removeSource(InsetsState.ITYPE_CAPTION_BAR);
realInsetsState.dump(prefix, new PrintWriter(realInsetsDump));
final StringWriter simulatedInsetsDump = new StringWriter();
simulatedInsetsState.dump(prefix, new PrintWriter(simulatedInsetsDump));
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 e507508..f517881 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -439,11 +439,11 @@
doNothing().when(this).updateCpuStats();
// AppOpsService
- final AppOpsService aos = mock(AppOpsService.class);
- doReturn(aos).when(this).getAppOpsService();
+ final AppOpsManager aos = mock(AppOpsManager.class);
+ doReturn(aos).when(this).getAppOpsManager();
// Make sure permission checks aren't overridden.
- doReturn(AppOpsManager.MODE_DEFAULT).when(aos).noteOperation(anyInt(), anyInt(),
- anyString(), nullable(String.class), anyBoolean(), nullable(String.class));
+ doReturn(AppOpsManager.MODE_DEFAULT).when(aos).noteOpNoThrow(anyInt(), anyInt(),
+ anyString(), nullable(String.class), nullable(String.class));
// UserManagerService
final UserManagerService ums = mock(UserManagerService.class);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
index 7172a1b..f7aa3cc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -29,10 +29,10 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -45,8 +45,10 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
+import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.util.ArrayMap;
import android.view.Display;
import android.view.ITaskOrganizer;
import android.view.IWindowContainer;
@@ -357,6 +359,78 @@
assertEquals(ACTIVITY_TYPE_UNDEFINED, lastReportedTiles.get(0).topActivityType);
}
+ @Test
+ public void testHierarchyTransaction() {
+ final ArrayMap<IBinder, RunningTaskInfo> lastReportedTiles = new ArrayMap<>();
+ ITaskOrganizer listener = new ITaskOrganizer.Stub() {
+ @Override
+ public void taskAppeared(RunningTaskInfo taskInfo) { }
+
+ @Override
+ public void taskVanished(IWindowContainer container) { }
+
+ @Override
+ public void transactionReady(int id, SurfaceControl.Transaction t) { }
+
+ @Override
+ public void onTaskInfoChanged(RunningTaskInfo info) {
+ lastReportedTiles.put(info.token.asBinder(), info);
+ }
+ };
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(
+ listener, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
+ mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ RunningTaskInfo info2 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
+ mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+
+ final ActivityStack stack = createTaskStackOnDisplay(
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ final ActivityStack stack2 = createTaskStackOnDisplay(
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mDisplayContent);
+
+ lastReportedTiles.clear();
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.reparent(stack.mRemoteToken, info1.token, true /* onTop */);
+ wct.reparent(stack2.mRemoteToken, info2.token, true /* onTop */);
+ mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(wct,
+ null /* organizer */);
+ assertFalse(lastReportedTiles.isEmpty());
+ assertEquals(ACTIVITY_TYPE_STANDARD,
+ lastReportedTiles.get(info1.token.asBinder()).topActivityType);
+ assertEquals(ACTIVITY_TYPE_HOME,
+ lastReportedTiles.get(info2.token.asBinder()).topActivityType);
+
+ lastReportedTiles.clear();
+ wct = new WindowContainerTransaction();
+ wct.reparent(stack2.mRemoteToken, info1.token, false /* onTop */);
+ mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(wct,
+ null /* organizer */);
+ assertFalse(lastReportedTiles.isEmpty());
+ // Standard should still be on top of tile 1, so no change there
+ assertFalse(lastReportedTiles.containsKey(info1.token.asBinder()));
+ // But tile 2 has no children, so should become undefined
+ assertEquals(ACTIVITY_TYPE_UNDEFINED,
+ lastReportedTiles.get(info2.token.asBinder()).topActivityType);
+
+ // Check the getChildren call
+ List<RunningTaskInfo> children =
+ mWm.mAtmService.mTaskOrganizerController.getChildTasks(info1.token);
+ assertEquals(2, children.size());
+ children = mWm.mAtmService.mTaskOrganizerController.getChildTasks(info2.token);
+ assertEquals(0, children.size());
+
+ lastReportedTiles.clear();
+ wct = new WindowContainerTransaction();
+ wct.reorder(stack2.mRemoteToken, true /* onTop */);
+ mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(wct,
+ null /* organizer */);
+ // Home should now be on top. No change occurs in second tile, so not reported
+ assertEquals(1, lastReportedTiles.size());
+ assertEquals(ACTIVITY_TYPE_HOME,
+ lastReportedTiles.get(info1.token.asBinder()).topActivityType);
+ }
+
private List<TaskTile> getTaskTiles(DisplayContent dc) {
ArrayList<TaskTile> out = new ArrayList<>();
for (int i = dc.getStackCount() - 1; i >= 0; --i) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
index 7aaf3fb..52b465f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
@@ -20,7 +20,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.server.wm.TaskPositioner.MIN_ASPECT;
+import static com.android.internal.policy.TaskResizingAlgorithm.MIN_ASPECT;
import static com.android.server.wm.WindowManagerService.dipToPixel;
import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP;
import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index ebf14d2..feadd0a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -988,7 +988,7 @@
private Task createTask(int taskId) {
return new ActivityStack(mService, taskId, new Intent(), null, null, null,
ActivityBuilder.getDefaultComponent(), null, false, false, false, 0, 10050, null,
- 0, false, null, 0, 0, 0, 0, 0, null, 0, false, false, false, 0,
+ 0, false, null, 0, 0, 0, 0, 0, null, null, 0, false, false, false, 0,
0, null /*ActivityInfo*/, null /*_voiceSession*/, null /*_voiceInteractor*/,
null /*stack*/);
}
@@ -1022,7 +1022,7 @@
boolean neverRelinquishIdentity,
ActivityManager.TaskDescription lastTaskDescription,
int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor,
- int callingUid, String callingPackage, int resizeMode,
+ int callingUid, String callingPackage, String callingFeatureId, int resizeMode,
boolean supportsPictureInPicture,
boolean realActivitySuspended, boolean userSetupComplete, int minWidth,
int minHeight, ActivityStack stack) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index d5eec33..8378d8e 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -747,7 +747,8 @@
}
@Override
- public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) {
+ public int startVoiceActivity(IBinder token, Intent intent, String resolvedType,
+ String callingFeatureId) {
synchronized (this) {
if (mImpl == null) {
Slog.w(TAG, "startVoiceActivity without running voice interaction service");
@@ -757,8 +758,8 @@
final int callingUid = Binder.getCallingUid();
final long caller = Binder.clearCallingIdentity();
try {
- return mImpl.startVoiceActivityLocked(callingPid, callingUid, token,
- intent, resolvedType);
+ return mImpl.startVoiceActivityLocked(callingFeatureId, callingPid, callingUid,
+ token, intent, resolvedType);
} finally {
Binder.restoreCallingIdentity(caller);
}
@@ -766,7 +767,8 @@
}
@Override
- public int startAssistantActivity(IBinder token, Intent intent, String resolvedType) {
+ public int startAssistantActivity(IBinder token, Intent intent, String resolvedType,
+ String callingFeatureId) {
synchronized (this) {
if (mImpl == null) {
Slog.w(TAG, "startAssistantActivity without running voice interaction service");
@@ -776,8 +778,8 @@
final int callingUid = Binder.getCallingUid();
final long caller = Binder.clearCallingIdentity();
try {
- return mImpl.startAssistantActivityLocked(callingPid, callingUid, token,
- intent, resolvedType);
+ return mImpl.startAssistantActivityLocked(callingFeatureId, callingPid,
+ callingUid, token, intent, resolvedType);
} finally {
Binder.restoreCallingIdentity(caller);
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index a1210cf..a62b03c 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -216,8 +216,8 @@
return true;
}
- public int startVoiceActivityLocked(int callingPid, int callingUid, IBinder token,
- Intent intent, String resolvedType) {
+ public int startVoiceActivityLocked(@Nullable String callingFeatureId, int callingPid,
+ int callingUid, IBinder token, Intent intent, String resolvedType) {
try {
if (mActiveSession == null || token != mActiveSession.mToken) {
Slog.w(TAG, "startVoiceActivity does not match active session");
@@ -230,16 +230,16 @@
intent = new Intent(intent);
intent.addCategory(Intent.CATEGORY_VOICE);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- return mAtm.startVoiceActivity(mComponent.getPackageName(), callingPid, callingUid,
- intent, resolvedType, mActiveSession.mSession, mActiveSession.mInteractor,
- 0, null, null, mUser);
+ return mAtm.startVoiceActivity(mComponent.getPackageName(), callingFeatureId,
+ callingPid, callingUid, intent, resolvedType, mActiveSession.mSession,
+ mActiveSession.mInteractor, 0, null, null, mUser);
} catch (RemoteException e) {
throw new IllegalStateException("Unexpected remote error", e);
}
}
- public int startAssistantActivityLocked(int callingPid, int callingUid, IBinder token,
- Intent intent, String resolvedType) {
+ public int startAssistantActivityLocked(@Nullable String callingFeatureId, int callingPid,
+ int callingUid, IBinder token, Intent intent, String resolvedType) {
try {
if (mActiveSession == null || token != mActiveSession.mToken) {
Slog.w(TAG, "startAssistantActivity does not match active session");
@@ -253,8 +253,8 @@
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchActivityType(ACTIVITY_TYPE_ASSISTANT);
- return mAtm.startAssistantActivity(mComponent.getPackageName(), callingPid, callingUid,
- intent, resolvedType, options.toBundle(), mUser);
+ return mAtm.startAssistantActivity(mComponent.getPackageName(), callingFeatureId,
+ callingPid, callingUid, intent, resolvedType, options.toBundle(), mUser);
} catch (RemoteException e) {
throw new IllegalStateException("Unexpected remote error", e);
}
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index e16fffa..e1aec0a 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Context;
+import android.os.Binder;
import android.os.RemoteException;
import android.service.euicc.EuiccProfileInfo;
import android.telephony.TelephonyFrameworkInitializer;
@@ -168,7 +169,12 @@
new IGetAllProfilesCallback.Stub() {
@Override
public void onComplete(int resultCode, EuiccProfileInfo[] profiles) {
- executor.execute(() -> callback.onComplete(resultCode, profiles));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(resultCode, profiles));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
@@ -192,7 +198,12 @@
new IGetProfileCallback.Stub() {
@Override
public void onComplete(int resultCode, EuiccProfileInfo profile) {
- executor.execute(() -> callback.onComplete(resultCode, profile));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(resultCode, profile));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
@@ -217,7 +228,12 @@
refresh, new IDisableProfileCallback.Stub() {
@Override
public void onComplete(int resultCode) {
- executor.execute(() -> callback.onComplete(resultCode, null));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(resultCode, null));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
@@ -243,7 +259,12 @@
refresh, new ISwitchToProfileCallback.Stub() {
@Override
public void onComplete(int resultCode, EuiccProfileInfo profile) {
- executor.execute(() -> callback.onComplete(resultCode, profile));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(resultCode, profile));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
@@ -268,7 +289,12 @@
nickname, new ISetNicknameCallback.Stub() {
@Override
public void onComplete(int resultCode) {
- executor.execute(() -> callback.onComplete(resultCode, null));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(resultCode, null));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
@@ -292,7 +318,12 @@
new IDeleteProfileCallback.Stub() {
@Override
public void onComplete(int resultCode) {
- executor.execute(() -> callback.onComplete(resultCode, null));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(resultCode, null));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
@@ -317,7 +348,12 @@
new IResetMemoryCallback.Stub() {
@Override
public void onComplete(int resultCode) {
- executor.execute(() -> callback.onComplete(resultCode, null));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(resultCode, null));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
@@ -340,7 +376,12 @@
new IGetDefaultSmdpAddressCallback.Stub() {
@Override
public void onComplete(int resultCode, String address) {
- executor.execute(() -> callback.onComplete(resultCode, address));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(resultCode, address));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
@@ -363,7 +404,12 @@
new IGetSmdsAddressCallback.Stub() {
@Override
public void onComplete(int resultCode, String address) {
- executor.execute(() -> callback.onComplete(resultCode, address));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(resultCode, address));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
@@ -388,7 +434,12 @@
new ISetDefaultSmdpAddressCallback.Stub() {
@Override
public void onComplete(int resultCode) {
- executor.execute(() -> callback.onComplete(resultCode, null));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(resultCode, null));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
@@ -411,7 +462,12 @@
new IGetRulesAuthTableCallback.Stub() {
@Override
public void onComplete(int resultCode, EuiccRulesAuthTable rat) {
- executor.execute(() -> callback.onComplete(resultCode, rat));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(resultCode, rat));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
@@ -434,7 +490,12 @@
new IGetEuiccChallengeCallback.Stub() {
@Override
public void onComplete(int resultCode, byte[] challenge) {
- executor.execute(() -> callback.onComplete(resultCode, challenge));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(resultCode, challenge));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
@@ -457,7 +518,12 @@
new IGetEuiccInfo1Callback.Stub() {
@Override
public void onComplete(int resultCode, byte[] info) {
- executor.execute(() -> callback.onComplete(resultCode, info));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(resultCode, info));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
@@ -480,7 +546,12 @@
new IGetEuiccInfo2Callback.Stub() {
@Override
public void onComplete(int resultCode, byte[] info) {
- executor.execute(() -> callback.onComplete(resultCode, info));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(resultCode, info));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
@@ -522,7 +593,12 @@
new IAuthenticateServerCallback.Stub() {
@Override
public void onComplete(int resultCode, byte[] response) {
- executor.execute(() -> callback.onComplete(resultCode, response));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(resultCode, response));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
@@ -561,7 +637,12 @@
new IPrepareDownloadCallback.Stub() {
@Override
public void onComplete(int resultCode, byte[] response) {
- executor.execute(() -> callback.onComplete(resultCode, response));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(resultCode, response));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
@@ -589,7 +670,12 @@
new ILoadBoundProfilePackageCallback.Stub() {
@Override
public void onComplete(int resultCode, byte[] response) {
- executor.execute(() -> callback.onComplete(resultCode, response));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(resultCode, response));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
@@ -619,7 +705,12 @@
new ICancelSessionCallback.Stub() {
@Override
public void onComplete(int resultCode, byte[] response) {
- executor.execute(() -> callback.onComplete(resultCode, response));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(resultCode, response));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
@@ -643,7 +734,13 @@
new IListNotificationsCallback.Stub() {
@Override
public void onComplete(int resultCode, EuiccNotification[] notifications) {
- executor.execute(() -> callback.onComplete(resultCode, notifications));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(
+ resultCode, notifications));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
@@ -667,7 +764,13 @@
events, new IRetrieveNotificationListCallback.Stub() {
@Override
public void onComplete(int resultCode, EuiccNotification[] notifications) {
- executor.execute(() -> callback.onComplete(resultCode, notifications));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(
+ resultCode, notifications));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
@@ -691,7 +794,13 @@
seqNumber, new IRetrieveNotificationCallback.Stub() {
@Override
public void onComplete(int resultCode, EuiccNotification notification) {
- executor.execute(() -> callback.onComplete(resultCode, notification));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(
+ resultCode, notification));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
@@ -718,7 +827,12 @@
new IRemoveNotificationFromListCallback.Stub() {
@Override
public void onComplete(int resultCode) {
- executor.execute(() -> callback.onComplete(resultCode, null));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(resultCode, null));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
} catch (RemoteException e) {
diff --git a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
index 1361df3..5904916 100644
--- a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
+++ b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
@@ -321,7 +321,8 @@
}
mAtm.startActivityAndWait(null,
- getInstrumentation().getContext().getBasePackageName(), mLaunchIntent,
+ getInstrumentation().getContext().getBasePackageName(),
+ getInstrumentation().getContext().getFeatureId(), mLaunchIntent,
mimeType, null, null, 0, mLaunchIntent.getFlags(), null, null,
UserHandle.USER_CURRENT_OR_SELF);
} catch (RemoteException e) {
diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp
index 98e7b4e..89005da 100644
--- a/tests/RollbackTest/Android.bp
+++ b/tests/RollbackTest/Android.bp
@@ -36,6 +36,15 @@
}
java_test_host {
+ name: "NetworkStagedRollbackTest",
+ srcs: ["NetworkStagedRollbackTest/src/**/*.java"],
+ libs: ["tradefed"],
+ static_libs: ["testng"],
+ test_suites: ["general-tests"],
+ test_config: "NetworkStagedRollbackTest.xml",
+}
+
+java_test_host {
name: "MultiUserRollbackTest",
srcs: ["MultiUserRollbackTest/src/**/*.java"],
libs: ["tradefed"],
diff --git a/tests/RollbackTest/NetworkStagedRollbackTest.xml b/tests/RollbackTest/NetworkStagedRollbackTest.xml
new file mode 100644
index 0000000..a465a4f
--- /dev/null
+++ b/tests/RollbackTest/NetworkStagedRollbackTest.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.
+-->
+<configuration description="Runs the network staged rollback tests">
+ <option name="test-suite-tag" value="NetworkStagedRollbackTest" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="RollbackTest.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.HostTest" >
+ <option name="class" value="com.android.tests.rollback.host.NetworkStagedRollbackTest" />
+ </test>
+</configuration>
diff --git a/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java b/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
new file mode 100644
index 0000000..2c2e828
--- /dev/null
+++ b/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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.tests.rollback.host;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Runs the network rollback tests.
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class NetworkStagedRollbackTest extends BaseHostJUnit4Test {
+ /**
+ * Tests failed network health check triggers watchdog staged rollbacks.
+ */
+ @Test
+ public void testNetworkFailedRollback() throws Exception {
+ }
+
+ /**
+ * Tests passed network health check does not trigger watchdog staged rollbacks.
+ */
+ @Test
+ public void testNetworkPassedDoesNotRollback() throws Exception {
+ }
+}
diff --git a/tests/RollbackTest/RollbackTest.xml b/tests/RollbackTest/RollbackTest.xml
index a14b01c..f2c0f86 100644
--- a/tests/RollbackTest/RollbackTest.xml
+++ b/tests/RollbackTest/RollbackTest.xml
@@ -22,9 +22,9 @@
<option name="package" value="com.android.tests.rollback" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
- <!-- Exclude the StagedRollbackTest and MultiUserRollbackTest tests, which need to be
- specially driven from the StagedRollbackTest and MultiUserRollbackTest host test -->
+ <!-- Exclude the device tests which need to be specially driven from the host tests -->
<option name="exclude-filter" value="com.android.tests.rollback.StagedRollbackTest" />
+ <option name="exclude-filter" value="com.android.tests.rollback.NetworkStagedRollbackTest" />
<option name="exclude-filter" value="com.android.tests.rollback.MultiUserRollbackTest" />
</test>
</configuration>
diff --git a/core/java/android/os/StatsDimensionsValue.aidl b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java
similarity index 64%
copy from core/java/android/os/StatsDimensionsValue.aidl
copy to tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java
index 81a14a4..04004d6 100644
--- a/core/java/android/os/StatsDimensionsValue.aidl
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2018, The Android Open Source Project
+/*
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -14,7 +14,11 @@
* limitations under the License.
*/
-package android.os;
+package com.android.tests.rollback;
-/** @hide */
-parcelable StatsDimensionsValue cpp_header "android/os/StatsDimensionsValue.h";
\ No newline at end of file
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class NetworkStagedRollbackTest {
+}
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index b2f384a..124b660 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -8,7 +8,6 @@
"libbacktrace",
"libbase",
"libbinder",
- "libbinderthreadstate",
"libbpf",
"libbpf_android",
"libc++",
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 6a29b1c..1763975 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -47,7 +47,7 @@
// framework-wifi.jar. This is not a good idea, should move WifiNetworkScoreCache
// to a separate package.
"java/android/net/wifi/WifiNetworkScoreCache.java",
- "java/android/net/wifi/WifiOemConfigStoreMigrationHook.java",
+ "java/android/net/wifi/WifiOemMigrationHook.java",
"java/android/net/wifi/wificond/*.java",
":libwificond_ipc_aidl",
],
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 1f1c0c1..d4e024d 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -266,4 +266,10 @@
* Return the Map of {@link WifiNetworkSuggestion} and the list of <ScanResult>
*/
Map getMatchingScanResults(in List<WifiNetworkSuggestion> networkSuggestions, in List<ScanResult> scanResults, String callingPackage, String callingFeatureId);
+
+ void setScanThrottleEnabled(boolean enable);
+
+ boolean isScanThrottleEnabled();
+
+ Map getAllMatchingPasspointProfilesForScanResults(in List<ScanResult> scanResult);
}
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index c8fd243..0db3313 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -519,6 +519,9 @@
case BAND_5GHZ:
wifiConfig.apBand = WifiConfiguration.AP_BAND_5GHZ;
break;
+ case BAND_2GHZ | BAND_5GHZ:
+ wifiConfig.apBand = WifiConfiguration.AP_BAND_ANY;
+ break;
case BAND_ANY:
wifiConfig.apBand = WifiConfiguration.AP_BAND_ANY;
break;
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 7c3d0b9..a720236 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -2112,7 +2112,8 @@
return !TextUtils.isEmpty(FQDN)
&& !TextUtils.isEmpty(providerFriendlyName)
&& enterpriseConfig != null
- && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
+ && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE
+ && !TextUtils.isEmpty(mPasspointUniqueId);
}
/**
@@ -2494,12 +2495,17 @@
*/
@NonNull
public String getKey() {
- String key = providerFriendlyName == null
- ? getSsidAndSecurityTypeString()
- : FQDN + KeyMgmt.strings[KeyMgmt.WPA_EAP];
+ // Passpoint ephemeral networks have their unique identifier set. Return it as is to be
+ // able to match internally.
+ if (mPasspointUniqueId != null) {
+ return mPasspointUniqueId;
+ }
+
+ String key = getSsidAndSecurityTypeString();
if (!shared) {
key += "-" + UserHandle.getUserHandleForUid(creatorUid).getIdentifier();
}
+
return key;
}
@@ -2754,6 +2760,7 @@
requirePMF = source.requirePMF;
updateIdentifier = source.updateIdentifier;
carrierId = source.carrierId;
+ mPasspointUniqueId = source.mPasspointUniqueId;
}
}
@@ -2826,6 +2833,7 @@
dest.writeInt(osu ? 1 : 0);
dest.writeLong(randomizedMacExpirationTimeMs);
dest.writeInt(carrierId);
+ dest.writeString(mPasspointUniqueId);
}
/** Implement the Parcelable interface {@hide} */
@@ -2900,6 +2908,7 @@
config.osu = in.readInt() != 0;
config.randomizedMacExpirationTimeMs = in.readLong();
config.carrierId = in.readInt();
+ config.mPasspointUniqueId = in.readString();
return config;
}
@@ -2907,4 +2916,28 @@
return new WifiConfiguration[size];
}
};
+
+ /**
+ * Passpoint Unique identifier
+ * @hide
+ */
+ private String mPasspointUniqueId = null;
+
+ /**
+ * Set the Passpoint unique identifier
+ * @param uniqueId Passpoint unique identifier to be set
+ * @hide
+ */
+ public void setPasspointUniqueId(String uniqueId) {
+ mPasspointUniqueId = uniqueId;
+ }
+
+ /**
+ * Set the Passpoint unique identifier
+ * @hide
+ */
+ public String getPasspointUniqueId() {
+ return mPasspointUniqueId;
+ }
+
}
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 24b2a8e..0c306b4 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -291,6 +291,11 @@
*/
private boolean mMeteredHint;
+ /**
+ * Passpoint unique key
+ */
+ private String mPasspointUniqueId;
+
/** @hide */
@UnsupportedAppUsage
public WifiInfo() {
@@ -322,6 +327,7 @@
setRequestingPackageName(null);
setFQDN(null);
setProviderFriendlyName(null);
+ setPasspointUniqueId(null);
txBad = 0;
txSuccess = 0;
rxSuccess = 0;
@@ -370,6 +376,7 @@
mWifiStandard = source.mWifiStandard;
mMaxSupportedTxLinkSpeed = source.mMaxSupportedTxLinkSpeed;
mMaxSupportedRxLinkSpeed = source.mMaxSupportedRxLinkSpeed;
+ mPasspointUniqueId = source.mPasspointUniqueId;
}
}
@@ -977,6 +984,7 @@
dest.writeInt(mWifiStandard);
dest.writeInt(mMaxSupportedTxLinkSpeed);
dest.writeInt(mMaxSupportedRxLinkSpeed);
+ dest.writeString(mPasspointUniqueId);
}
/** Implement the Parcelable interface {@hide} */
@@ -1021,6 +1029,7 @@
info.mWifiStandard = in.readInt();
info.mMaxSupportedTxLinkSpeed = in.readInt();
info.mMaxSupportedRxLinkSpeed = in.readInt();
+ info.mPasspointUniqueId = in.readString();
return info;
}
@@ -1028,4 +1037,24 @@
return new WifiInfo[size];
}
};
+
+ /**
+ * Set the Passpoint unique identifier for the current connection
+ *
+ * @param passpointUniqueId Unique identifier
+ * @hide
+ */
+ public void setPasspointUniqueId(@Nullable String passpointUniqueId) {
+ mPasspointUniqueId = passpointUniqueId;
+ }
+
+ /**
+ * Get the Passpoint unique identifier for the current connection
+ *
+ * @return Passpoint unique identifier
+ * @hide
+ */
+ public @Nullable String getPasspointUniqueId() {
+ return mPasspointUniqueId;
+ }
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index a3cce7c..fb30910c 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1400,8 +1400,7 @@
List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> configs = new ArrayList<>();
try {
Map<String, Map<Integer, List<ScanResult>>> results =
- mService.getAllMatchingFqdnsForScanResults(
- scanResults);
+ mService.getAllMatchingPasspointProfilesForScanResults(scanResults);
if (results.isEmpty()) {
return configs;
}
@@ -1409,8 +1408,8 @@
mService.getWifiConfigsForPasspointProfiles(
new ArrayList<>(results.keySet()));
for (WifiConfiguration configuration : wifiConfigurations) {
- Map<Integer, List<ScanResult>> scanResultsPerNetworkType = results.get(
- configuration.FQDN);
+ Map<Integer, List<ScanResult>> scanResultsPerNetworkType =
+ results.get(configuration.getKey());
if (scanResultsPerNetworkType != null) {
configs.add(Pair.create(configuration, scanResultsPerNetworkType));
}
@@ -1962,9 +1961,11 @@
* for connecting to Passpoint networks that are operated by the Passpoint
* service provider specified in the configuration.
*
- * Each configuration is uniquely identified by its FQDN (Fully Qualified Domain
- * Name). In the case when there is an existing configuration with the same
- * FQDN, the new configuration will replace the existing configuration.
+ * Each configuration is uniquely identified by a unique key which depends on the contents of
+ * the configuration. This allows the caller to install multiple profiles with the same FQDN
+ * (Fully qualified domain name). Therefore, in order to update an existing profile, it is
+ * first required to remove it using {@link WifiManager#removePasspointConfiguration(String)}.
+ * Otherwise, a new profile will be added with both configuration.
*
* @param config The Passpoint configuration to be added
* @throws IllegalArgumentException if configuration is invalid or Passpoint is not enabled on
@@ -2982,7 +2983,7 @@
}
/**
- * Start Soft AP (hotspot) mode with the specified configuration.
+ * Start Soft AP (hotspot) mode for tethering purposes with the specified configuration.
* Note that starting Soft AP mode may disable station mode operation if the device does not
* support concurrency.
* @param wifiConfig SSID, security and channel details as part of WifiConfiguration, or null to
@@ -3278,7 +3279,7 @@
}
/**
- * Gets the Wi-Fi enabled state.
+ * Gets the tethered Wi-Fi hotspot enabled state.
* @return One of {@link #WIFI_AP_STATE_DISABLED},
* {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
* {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
@@ -3297,8 +3298,8 @@
}
/**
- * Return whether Wi-Fi AP is enabled or disabled.
- * @return {@code true} if Wi-Fi AP is enabled
+ * Return whether tethered Wi-Fi AP is enabled or disabled.
+ * @return {@code true} if tethered Wi-Fi AP is enabled
* @see #getWifiApState()
*
* @hide
@@ -3310,7 +3311,7 @@
}
/**
- * Gets the Wi-Fi AP Configuration.
+ * Gets the tethered Wi-Fi AP Configuration.
* @return AP details in WifiConfiguration
*
* Note that AP detail may contain configuration which is cannot be represented
@@ -3332,7 +3333,7 @@
}
/**
- * Gets the Wi-Fi AP Configuration.
+ * Gets the Wi-Fi tethered AP Configuration.
* @return AP details in {@link SoftApConfiguration}
*
* @hide
@@ -3349,7 +3350,7 @@
}
/**
- * Sets the Wi-Fi AP Configuration.
+ * Sets the tethered Wi-Fi AP Configuration.
* @return {@code true} if the operation succeeded, {@code false} otherwise
*
* @deprecated This API is deprecated. Use {@link #setSoftApConfiguration(SoftApConfiguration)}
@@ -3368,9 +3369,9 @@
}
/**
- * Sets the Wi-Fi AP Configuration.
+ * Sets the tethered Wi-Fi AP Configuration.
*
- * If the API is called while the soft AP is enabled, the configuration will apply to
+ * If the API is called while the tethered soft AP is enabled, the configuration will apply to
* the current soft AP if the new configuration only includes
* {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)}
* or {@link SoftApConfiguration.Builder#setShutdownTimeoutMillis(int)}
@@ -6118,4 +6119,48 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Enable/disable wifi scan throttling from 3rd party apps.
+ *
+ * <p>
+ * The throttling limits for apps are described in
+ * <a href="Wi-Fi Scan Throttling">
+ * https://developer.android.com/guide/topics/connectivity/wifi-scan#wifi-scan-throttling</a>
+ * </p>
+ *
+ * @param enable true to allow scan throttling, false to disallow scan throttling.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void setScanThrottleEnabled(boolean enable) {
+ try {
+ mService.setScanThrottleEnabled(enable);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get the persisted Wi-Fi scan throttle state. Defaults to true, unless changed by the user via
+ * Developer options.
+ *
+ * <p>
+ * The throttling limits for apps are described in
+ * <a href="Wi-Fi Scan Throttling">
+ * https://developer.android.com/guide/topics/connectivity/wifi-scan#wifi-scan-throttling</a>
+ * </p>
+ *
+ * @return true to indicate that scan throttling is enabled, false to indicate that scan
+ * throttling is disabled.
+ */
+ @RequiresPermission(ACCESS_WIFI_STATE)
+ public boolean isScanThrottleEnabled() {
+ try {
+ return mService.isScanThrottleEnabled();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 7201496..a854a4b 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -569,6 +569,7 @@
private WifiConfiguration buildWifiConfigurationForPasspoint() {
WifiConfiguration wifiConfiguration = new WifiConfiguration();
wifiConfiguration.FQDN = mPasspointConfiguration.getHomeSp().getFqdn();
+ wifiConfiguration.setPasspointUniqueId(mPasspointConfiguration.getUniqueId());
wifiConfiguration.priority = mPriority;
wifiConfiguration.meteredOverride =
mIsMetered ? WifiConfiguration.METERED_OVERRIDE_METERED
@@ -804,7 +805,7 @@
@Override
public int hashCode() {
return Objects.hash(wifiConfiguration.SSID, wifiConfiguration.BSSID,
- wifiConfiguration.allowedKeyManagement, wifiConfiguration.FQDN);
+ wifiConfiguration.allowedKeyManagement, wifiConfiguration.getKey());
}
/**
@@ -827,7 +828,8 @@
&& TextUtils.equals(this.wifiConfiguration.BSSID, lhs.wifiConfiguration.BSSID)
&& Objects.equals(this.wifiConfiguration.allowedKeyManagement,
lhs.wifiConfiguration.allowedKeyManagement)
- && TextUtils.equals(this.wifiConfiguration.FQDN, lhs.wifiConfiguration.FQDN);
+ && TextUtils.equals(this.wifiConfiguration.getKey(),
+ lhs.wifiConfiguration.getKey());
}
@Override
diff --git a/wifi/java/android/net/wifi/WifiOemConfigStoreMigrationHook.java b/wifi/java/android/net/wifi/WifiOemMigrationHook.java
similarity index 71%
rename from wifi/java/android/net/wifi/WifiOemConfigStoreMigrationHook.java
rename to wifi/java/android/net/wifi/WifiOemMigrationHook.java
index 642dcb9..22d7786 100755
--- a/wifi/java/android/net/wifi/WifiOemConfigStoreMigrationHook.java
+++ b/wifi/java/android/net/wifi/WifiOemMigrationHook.java
@@ -28,30 +28,17 @@
/**
* Class used to provide one time hooks for existing OEM devices to migrate their config store
- * data to the wifi mainline module.
- * <p>
- * Note:
- * <li> OEM's need to implement {@link #load()} only if their
- * existing config store format or file locations differs from the vanilla AOSP implementation (
- * which is what the wifi mainline module understands).
- * </li>
- * <li> The wifi mainline module will invoke {@link #load()} method on every bootup, its
- * the responsibility of the OEM implementation to ensure that this method returns non-null data
- * only on the first bootup. Once the migration is done, the OEM can safely delete their config
- * store files and then return null on any subsequent reboots. The first & only relevant invocation
- * of {@link #load()} occurs when a previously released device upgrades to the wifi
- * mainline module from an OEM implementation of the wifi stack.
- * </li>
+ * data and other settings to the wifi mainline module.
* @hide
*/
@SystemApi
-public final class WifiOemConfigStoreMigrationHook {
+public final class WifiOemMigrationHook {
/**
* Container for all the wifi config data to migrate.
*/
- public static final class MigrationData implements Parcelable {
+ public static final class ConfigStoreMigrationData implements Parcelable {
/**
- * Builder to create instance of {@link MigrationData}.
+ * Builder to create instance of {@link ConfigStoreMigrationData}.
*/
public static final class Builder {
private List<WifiConfiguration> mUserSavedNetworkConfigurations;
@@ -92,39 +79,40 @@
}
/**
- * Build an instance of {@link MigrationData}.
+ * Build an instance of {@link ConfigStoreMigrationData}.
*
- * @return Instance of {@link MigrationData}.
+ * @return Instance of {@link ConfigStoreMigrationData}.
*/
- public @NonNull MigrationData build() {
- return new MigrationData(mUserSavedNetworkConfigurations, mUserSoftApConfiguration);
+ public @NonNull ConfigStoreMigrationData build() {
+ return new ConfigStoreMigrationData(
+ mUserSavedNetworkConfigurations, mUserSoftApConfiguration);
}
}
private final List<WifiConfiguration> mUserSavedNetworkConfigurations;
private final SoftApConfiguration mUserSoftApConfiguration;
- private MigrationData(
+ private ConfigStoreMigrationData(
@Nullable List<WifiConfiguration> userSavedNetworkConfigurations,
@Nullable SoftApConfiguration userSoftApConfiguration) {
mUserSavedNetworkConfigurations = userSavedNetworkConfigurations;
mUserSoftApConfiguration = userSoftApConfiguration;
}
- public static final @NonNull Parcelable.Creator<MigrationData> CREATOR =
- new Parcelable.Creator<MigrationData>() {
+ public static final @NonNull Parcelable.Creator<ConfigStoreMigrationData> CREATOR =
+ new Parcelable.Creator<ConfigStoreMigrationData>() {
@Override
- public MigrationData createFromParcel(Parcel in) {
+ public ConfigStoreMigrationData createFromParcel(Parcel in) {
List<WifiConfiguration> userSavedNetworkConfigurations =
in.readArrayList(null);
SoftApConfiguration userSoftApConfiguration = in.readParcelable(null);
- return new MigrationData(
+ return new ConfigStoreMigrationData(
userSavedNetworkConfigurations, userSoftApConfiguration);
}
@Override
- public MigrationData[] newArray(int size) {
- return new MigrationData[size];
+ public ConfigStoreMigrationData[] newArray(int size) {
+ return new ConfigStoreMigrationData[size];
}
};
@@ -164,16 +152,29 @@
}
}
- private WifiOemConfigStoreMigrationHook() { }
+ private WifiOemMigrationHook() { }
/**
* Load data from OEM's config store.
+ * <p>
+ * Note:
+ * <li> OEM's need to implement {@link #loadFromConfigStore()} ()} only if their
+ * existing config store format or file locations differs from the vanilla AOSP implementation (
+ * which is what the wifi mainline module understands).
+ * </li>
+ * <li> The wifi mainline module will invoke {@link #loadFromConfigStore()} method on every
+ * bootup, its the responsibility of the OEM implementation to ensure that this method returns
+ * non-null data only on the first bootup. Once the migration is done, the OEM can safely delete
+ * their config store files and then return null on any subsequent reboots. The first & only
+ * relevant invocation of {@link #loadFromConfigStore()} occurs when a previously released
+ * device upgrades to the wifi mainline module from an OEM implementation of the wifi stack.
+ * </li>
*
- * @return Instance of {@link MigrationData} for migrating data, null if no
+ * @return Instance of {@link ConfigStoreMigrationData} for migrating data, null if no
* migration is necessary.
*/
@Nullable
- public static MigrationData load() {
+ public static ConfigStoreMigrationData loadFromConfigStore() {
// Note: OEM's should add code to parse data from their config store format here!
return null;
}
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 615331f..9f58184 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -908,6 +908,9 @@
throw new IllegalStateException("Credential or HomeSP are not initialized");
}
- return mHomeSp.getFqdn();
+ StringBuilder sb = new StringBuilder();
+ sb.append(String.format("%s_%x%x", mHomeSp.getFqdn(), mHomeSp.hashCode(),
+ mCredential.hashCode()));
+ return sb.toString();
}
}
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
index 49a76c3..a5de331 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
@@ -16,8 +16,8 @@
package android.net.wifi.hotspot2.pps;
-import android.os.Parcelable;
import android.os.Parcel;
+import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
@@ -299,8 +299,10 @@
@Override
public int hashCode() {
- return Objects.hash(mFqdn, mFriendlyName, mIconUrl, mHomeNetworkIds, mMatchAllOis,
- mMatchAnyOis, mOtherHomePartners, mRoamingConsortiumOis);
+ return Objects.hash(mFqdn, mFriendlyName, mIconUrl,
+ mHomeNetworkIds, Arrays.hashCode(mMatchAllOis),
+ Arrays.hashCode(mMatchAnyOis), Arrays.hashCode(mOtherHomePartners),
+ Arrays.hashCode(mRoamingConsortiumOis));
}
@Override
diff --git a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
index 2efdd97..d958488 100644
--- a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
@@ -287,17 +287,43 @@
@Test
public void testToWifiConfigurationWithSupportedParameter() {
- SoftApConfiguration softApConfig = new SoftApConfiguration.Builder()
+ SoftApConfiguration softApConfig_2g = new SoftApConfiguration.Builder()
+ .setPassphrase("secretsecret",
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
+ .setChannel(11, SoftApConfiguration.BAND_2GHZ)
+ .setHiddenSsid(true)
+ .build();
+ WifiConfiguration wifiConfig_2g = softApConfig_2g.toWifiConfiguration();
+ assertThat(wifiConfig_2g.getAuthType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK);
+ assertThat(wifiConfig_2g.preSharedKey).isEqualTo("secretsecret");
+ assertThat(wifiConfig_2g.apBand).isEqualTo(WifiConfiguration.AP_BAND_2GHZ);
+ assertThat(wifiConfig_2g.apChannel).isEqualTo(11);
+ assertThat(wifiConfig_2g.hiddenSSID).isEqualTo(true);
+
+ SoftApConfiguration softApConfig_5g = new SoftApConfiguration.Builder()
.setPassphrase("secretsecret",
SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
.setChannel(149, SoftApConfiguration.BAND_5GHZ)
.setHiddenSsid(true)
.build();
- WifiConfiguration wifiConfig = softApConfig.toWifiConfiguration();
- assertThat(wifiConfig.getAuthType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK);
- assertThat(wifiConfig.preSharedKey).isEqualTo("secretsecret");
- assertThat(wifiConfig.apBand).isEqualTo(WifiConfiguration.AP_BAND_5GHZ);
- assertThat(wifiConfig.apChannel).isEqualTo(149);
- assertThat(wifiConfig.hiddenSSID).isEqualTo(true);
+ WifiConfiguration wifiConfig_5g = softApConfig_5g.toWifiConfiguration();
+ assertThat(wifiConfig_5g.getAuthType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK);
+ assertThat(wifiConfig_5g.preSharedKey).isEqualTo("secretsecret");
+ assertThat(wifiConfig_5g.apBand).isEqualTo(WifiConfiguration.AP_BAND_5GHZ);
+ assertThat(wifiConfig_5g.apChannel).isEqualTo(149);
+ assertThat(wifiConfig_5g.hiddenSSID).isEqualTo(true);
+
+ SoftApConfiguration softApConfig_2g5g = new SoftApConfiguration.Builder()
+ .setPassphrase("secretsecret",
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
+ .setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ)
+ .setHiddenSsid(true)
+ .build();
+ WifiConfiguration wifiConfig_2g5g = softApConfig_2g5g.toWifiConfiguration();
+ assertThat(wifiConfig_2g5g.getAuthType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK);
+ assertThat(wifiConfig_2g5g.preSharedKey).isEqualTo("secretsecret");
+ assertThat(wifiConfig_2g5g.apBand).isEqualTo(WifiConfiguration.AP_BAND_ANY);
+ assertThat(wifiConfig_2g5g.apChannel).isEqualTo(0);
+ assertThat(wifiConfig_2g5g.hiddenSSID).isEqualTo(true);
}
}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 6320f85..847040c 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -1551,14 +1551,15 @@
*/
@Test
public void testGetAllMatchingWifiConfigs() throws Exception {
- Map<String, List<ScanResult>> fqdns = new HashMap<>();
- fqdns.put("www.test.com", new ArrayList<>());
- when(mWifiService.getAllMatchingFqdnsForScanResults(any(List.class))).thenReturn(fqdns);
+ Map<String, List<ScanResult>> passpointProfiles = new HashMap<>();
+ passpointProfiles.put("www.test.com_987a69bca26", new ArrayList<>());
+ when(mWifiService.getAllMatchingPasspointProfilesForScanResults(
+ any(List.class))).thenReturn(passpointProfiles);
InOrder inOrder = inOrder(mWifiService);
mWifiManager.getAllMatchingWifiConfigs(new ArrayList<>());
- inOrder.verify(mWifiService).getAllMatchingFqdnsForScanResults(any(List.class));
+ inOrder.verify(mWifiService).getAllMatchingPasspointProfilesForScanResults(any(List.class));
inOrder.verify(mWifiService).getWifiConfigsForPasspointProfiles(any(List.class));
}
@@ -2380,4 +2381,14 @@
verify(mWifiConnectedNetworkScorer).start(0);
verify(mWifiConnectedNetworkScorer).stop(10);
}
+
+ @Test
+ public void testScanThrottle() throws Exception {
+ mWifiManager.setScanThrottleEnabled(true);
+ verify(mWifiService).setScanThrottleEnabled(true);
+
+ when(mWifiService.isScanThrottleEnabled()).thenReturn(false);
+ assertFalse(mWifiManager.isScanThrottleEnabled());
+ verify(mWifiService).isScanThrottleEnabled();
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index ce542c2..8f6beb1 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -20,8 +20,11 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
+import android.net.wifi.hotspot2.pps.Credential;
+import android.net.wifi.hotspot2.pps.HomeSp;
import android.os.Parcel;
import androidx.test.filters.SmallTest;
@@ -367,16 +370,55 @@
}
/**
- * Verify that the unique identifier generated is correct.
+ * Verify that the unique identifier generated is identical for two instances
*
* @throws Exception
*/
@Test
public void validateUniqueId() throws Exception {
- PasspointConfiguration config = PasspointTestUtils.createConfig();
- String uniqueId;
- uniqueId = config.getUniqueId();
- assertEquals(uniqueId, config.getHomeSp().getFqdn());
+ PasspointConfiguration config1 = PasspointTestUtils.createConfig();
+ PasspointConfiguration config2 = PasspointTestUtils.createConfig();
+
+ assertEquals(config1.getUniqueId(), config2.getUniqueId());
+ }
+
+ /**
+ * Verify that the unique identifier generated is different for two instances with different
+ * HomeSp node
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUniqueIdDifferentHomeSp() throws Exception {
+ PasspointConfiguration config1 = PasspointTestUtils.createConfig();
+
+ // Modify config2's RCOIs to a different set of values
+ PasspointConfiguration config2 = PasspointTestUtils.createConfig();
+ HomeSp homeSp = config2.getHomeSp();
+ homeSp.setRoamingConsortiumOis(new long[] {0xaa, 0xbb});
+ config2.setHomeSp(homeSp);
+
+ assertNotEquals(config1.getUniqueId(), config2.getUniqueId());
+ }
+
+ /**
+ * Verify that the unique identifier generated is different for two instances with different
+ * Credential node
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUniqueIdDifferentCredential() throws Exception {
+ PasspointConfiguration config1 = PasspointTestUtils.createConfig();
+
+ // Modify config2's RCOIs to a different set of values
+ PasspointConfiguration config2 = PasspointTestUtils.createConfig();
+ Credential credential = config2.getCredential();
+ credential.setRealm("realm2.example.com");
+ credential.getSimCredential().setImsi("350460*");
+ config2.setCredential(credential);
+
+ assertNotEquals(config1.getUniqueId(), config2.getUniqueId());
}
/**