diff options
652 files changed, 14604 insertions, 9250 deletions
diff --git a/StubLibraries.bp b/StubLibraries.bp index 2bd5aee0cd24..0fe34fb650eb 100644 --- a/StubLibraries.bp +++ b/StubLibraries.bp @@ -311,6 +311,15 @@ java_defaults { compile_dex: true, } +java_defaults { + name: "android_stubs_dists_default", + dist: { + targets: ["sdk", "win_sdk"], + tag: ".jar", + dest: "android.jar", + }, +} + java_library_static { name: "android_monolith_stubs_current", srcs: [ ":api-stubs-docs" ], @@ -346,7 +355,21 @@ java_library_static { name: "android_system_monolith_stubs_current", srcs: [ ":system-api-stubs-docs" ], static_libs: [ "private-stub-annotations-jar" ], - defaults: ["android_defaults_stubs_current"], + defaults: [ + "android_defaults_stubs_current", + "android_stubs_dists_default", + ], + dist: { + dir: "apistubs/android/system", + }, + dists: [ + { + // Legacy dist path + targets: ["sdk", "win_sdk"], + tag: ".jar", + dest: "android_system.jar", + }, + ], } java_library_static { @@ -378,14 +401,34 @@ java_library_static { name: "android_test_stubs_current", srcs: [ ":test-api-stubs-docs" ], static_libs: [ "private-stub-annotations-jar" ], - defaults: ["android_defaults_stubs_current"], + defaults: [ + "android_defaults_stubs_current", + "android_stubs_dists_default", + ], + dist: { + dir: "apistubs/android/test", + }, + dists: [ + { + // Legacy dist path + targets: ["sdk", "win_sdk"], + tag: ".jar", + dest: "android_test.jar", + }, + ], } java_library_static { name: "android_module_lib_stubs_current", srcs: [ ":module-lib-api-stubs-docs-non-updatable" ], - defaults: ["android_defaults_stubs_current"], + defaults: [ + "android_defaults_stubs_current", + "android_stubs_dists_default", + ], libs: ["sdk_system_29_android"], + dist: { + dir: "apistubs/android/module-lib", + }, } java_library_static { diff --git a/apct-tests/perftests/core/Android.bp b/apct-tests/perftests/core/Android.bp index 984893a25605..03ab5b6f2c8c 100644 --- a/apct-tests/perftests/core/Android.bp +++ b/apct-tests/perftests/core/Android.bp @@ -12,6 +12,8 @@ android_test { "androidx.appcompat_appcompat", "androidx.test.rules", "androidx.annotation_annotation", + "androidx.benchmark_benchmark-common", + "androidx.benchmark_benchmark-junit4", "apct-perftests-overlay-apps", "apct-perftests-resources-manager-apps", "apct-perftests-utils", diff --git a/apct-tests/perftests/core/AndroidManifest.xml b/apct-tests/perftests/core/AndroidManifest.xml index e9f4747b4545..833ae63e1125 100644 --- a/apct-tests/perftests/core/AndroidManifest.xml +++ b/apct-tests/perftests/core/AndroidManifest.xml @@ -34,7 +34,7 @@ </application> - <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + <instrumentation android:name="androidx.benchmark.junit4.AndroidBenchmarkRunner" android:targetPackage="com.android.perftests.core"/> </manifest> diff --git a/apct-tests/perftests/core/src/android/view/CutoutSpecificationBenchmark.java b/apct-tests/perftests/core/src/android/view/CutoutSpecificationBenchmark.java index 14282bfbd24e..abd39f880a26 100644 --- a/apct-tests/perftests/core/src/android/view/CutoutSpecificationBenchmark.java +++ b/apct-tests/perftests/core/src/android/view/CutoutSpecificationBenchmark.java @@ -22,13 +22,13 @@ 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.benchmark.BenchmarkState; +import androidx.benchmark.junit4.BenchmarkRule; import androidx.test.filters.LargeTest; import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; @@ -67,7 +67,7 @@ public class CutoutSpecificationBenchmark { + "Z\n" + "@dp"; @Rule - public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + public BenchmarkRule mBenchmarkRule = new BenchmarkRule(); private Context mContext; private DisplayMetrics mDisplayMetrics; @@ -168,7 +168,7 @@ public class CutoutSpecificationBenchmark { @Test public void parseByOldMethodForDoubleCutout() { - final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + final BenchmarkState state = mBenchmarkRule.getState(); while (state.keepRunning()) { oldMethodParsingSpec(DOUBLE_CUTOUT_SPEC, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels, mDisplayMetrics.density); @@ -177,7 +177,7 @@ public class CutoutSpecificationBenchmark { @Test public void parseByNewMethodForDoubleCutout() { - final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + final BenchmarkState state = mBenchmarkRule.getState(); while (state.keepRunning()) { new CutoutSpecification.Parser(mDisplayMetrics.density, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels) @@ -209,7 +209,7 @@ public class CutoutSpecificationBenchmark { + "@right\n" + "@dp"; - final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + final BenchmarkState state = mBenchmarkRule.getState(); while (state.keepRunning()) { new CutoutSpecification.Parser(mDisplayMetrics.density, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels).parse(spec); @@ -231,7 +231,7 @@ public class CutoutSpecificationBenchmark { + "Z\n" + "@dp"; - final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + final BenchmarkState state = mBenchmarkRule.getState(); while (state.keepRunning()) { new CutoutSpecification.Parser(mDisplayMetrics.density, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels).parse(spec); diff --git a/apct-tests/perftests/core/src/android/view/ViewPerfTest.java b/apct-tests/perftests/core/src/android/view/ViewPerfTest.java index 72f02c488dbd..a2aeb313cbde 100644 --- a/apct-tests/perftests/core/src/android/view/ViewPerfTest.java +++ b/apct-tests/perftests/core/src/android/view/ViewPerfTest.java @@ -19,11 +19,11 @@ package android.view; import static junit.framework.Assert.assertTrue; import android.content.Context; -import android.perftests.utils.BenchmarkState; -import android.perftests.utils.PerfStatusReporter; import android.perftests.utils.PerfTestActivity; import android.widget.FrameLayout; +import androidx.benchmark.BenchmarkState; +import androidx.benchmark.junit4.BenchmarkRule; import androidx.test.InstrumentationRegistry; import androidx.test.filters.LargeTest; import androidx.test.rule.ActivityTestRule; @@ -37,7 +37,7 @@ import org.junit.Test; @LargeTest public class ViewPerfTest { @Rule - public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + public final BenchmarkRule mBenchmarkRule = new BenchmarkRule(); @Rule public final ActivityTestRule<PerfTestActivity> mActivityRule = @@ -52,7 +52,7 @@ public class ViewPerfTest { @Test public void testSimpleViewInflate() { - final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + final BenchmarkState state = mBenchmarkRule.getState(); LayoutInflater inflater = LayoutInflater.from(mContext); FrameLayout root = new FrameLayout(mContext); while (state.keepRunning()) { @@ -62,7 +62,7 @@ public class ViewPerfTest { @Test public void testTwelveKeyInflate() { - final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + final BenchmarkState state = mBenchmarkRule.getState(); LayoutInflater inflater = LayoutInflater.from(mContext); FrameLayout root = new FrameLayout(mContext); while (state.keepRunning()) { @@ -72,7 +72,7 @@ public class ViewPerfTest { @Test public void testPerformHapticFeedback() throws Throwable { - final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + final BenchmarkState state = mBenchmarkRule.getState(); mActivityRule.runOnUiThread(() -> { state.pauseTiming(); View view = new View(mContext); diff --git a/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java b/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java index b0edb117a00b..a69d3ffa46fa 100644 --- a/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java +++ b/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java @@ -21,14 +21,14 @@ import static org.junit.Assert.assertTrue; import android.content.Context; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; -import android.perftests.utils.BenchmarkState; -import android.perftests.utils.PerfStatusReporter; import android.perftests.utils.PerfTestActivity; import android.view.View.MeasureSpec; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; +import androidx.benchmark.BenchmarkState; +import androidx.benchmark.junit4.BenchmarkRule; import androidx.test.InstrumentationRegistry; import androidx.test.filters.LargeTest; import androidx.test.rule.ActivityTestRule; @@ -50,7 +50,7 @@ public class ViewShowHidePerfTest { new ActivityTestRule<>(PerfTestActivity.class); @Rule - public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + public final BenchmarkRule mBenchmarkRule = new BenchmarkRule(); public Context getContext() { return InstrumentationRegistry.getInstrumentation().getTargetContext(); @@ -143,7 +143,7 @@ public class ViewShowHidePerfTest { private void testParentWithChild(TestCallback callback) throws Throwable { mActivityRule.runOnUiThread(() -> { - final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + final BenchmarkState state = mBenchmarkRule.getState(); FrameLayout parent = new FrameLayout(getContext()); mActivityRule.getActivity().setContentView(parent); diff --git a/apct-tests/perftests/windowmanager/Android.bp b/apct-tests/perftests/windowmanager/Android.bp index f02cbcfc4daf..9e95a104af81 100644 --- a/apct-tests/perftests/windowmanager/Android.bp +++ b/apct-tests/perftests/windowmanager/Android.bp @@ -19,6 +19,7 @@ android_test { "androidx.test.rules", "androidx.annotation_annotation", "apct-perftests-utils", + "platform-test-annotations", ], test_suites: ["device-tests"], platform_apis: true, diff --git a/apct-tests/perftests/windowmanager/AndroidTest.xml b/apct-tests/perftests/windowmanager/AndroidTest.xml index 69d187f9419a..0a80cf96fba3 100644 --- a/apct-tests/perftests/windowmanager/AndroidTest.xml +++ b/apct-tests/perftests/windowmanager/AndroidTest.xml @@ -21,9 +21,17 @@ <option name="test-file-name" value="WmPerfTests.apk" /> </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.DeviceSetup"> + <option name="force-skip-system-props" value="true" /> + <option name="run-command" value="input keyevent KEYCODE_WAKEUP" /> + <option name="run-command" value="cmd window dismiss-keyguard" /> + <option name="run-command" value="cmd package compile -m speed com.android.perftests.wm" /> + </target_preparer> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="com.android.perftests.wm" /> <option name="hidden-api-checks" value="false"/> + <option name="device-listeners" value="android.wm.WmPerfRunListener" /> </test> <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector"> diff --git a/apct-tests/perftests/windowmanager/README.md b/apct-tests/perftests/windowmanager/README.md new file mode 100644 index 000000000000..05fa6279a949 --- /dev/null +++ b/apct-tests/perftests/windowmanager/README.md @@ -0,0 +1,27 @@ +## Window manager performance tests + +### Precondition +To reduce the variance of the test, if `perf-setup.sh` (platform_testing/scripts/perf-setup) +is available, it is better to use the following instructions to lock CPU and GPU frequencies. +``` +m perf-setup.sh +PERF_SETUP_PATH=/data/local/tmp/perf-setup.sh +adb push $OUT/$PERF_SETUP_PATH $PERF_SETUP_PATH +adb shell chmod +x $PERF_SETUP_PATH +adb shell $PERF_SETUP_PATH +``` + +### Example to run +Use `atest` +``` +atest WmPerfTests:RelayoutPerfTest -- \ + --module-arg WmPerfTests:instrumentation-arg:kill-bg:=true +``` +Use `am instrument` +``` +adb shell am instrument -w -r -e class android.wm.RelayoutPerfTest \ + -e listener android.wm.WmPerfRunListener \ + -e kill-bg true \ + com.android.perftests.wm/androidx.test.runner.AndroidJUnitRunner +``` +* `kill-bg` is optional. diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java index f04e55567520..cff5663e9d9e 100644 --- a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java +++ b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java @@ -26,6 +26,7 @@ import android.os.RemoteException; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.perftests.utils.PerfTestActivity; +import android.platform.test.annotations.Presubmit; import android.util.MergedConfiguration; import android.view.DisplayCutout; import android.view.IWindow; @@ -52,6 +53,7 @@ import java.util.function.IntSupplier; @RunWith(Parameterized.class) @LargeTest +@Presubmit public class RelayoutPerfTest extends WindowManagerPerfTestBase { private int mIteration; diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java index 655d2f7f8aa7..dc6245bf2c09 100644 --- a/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java +++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java @@ -23,18 +23,15 @@ import android.app.KeyguardManager; import android.app.UiAutomation; import android.content.Context; import android.content.Intent; -import android.os.BatteryManager; import android.os.ParcelFileDescriptor; import android.os.PowerManager; 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; @@ -43,7 +40,9 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.util.Objects; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; public class WindowManagerPerfTestBase { static final UiAutomation sUiAutomation = getInstrumentation().getUiAutomation(); @@ -56,21 +55,11 @@ public class WindowManagerPerfTestBase { * is in /data because while enabling method profling of system server, it cannot write the * trace to external storage. */ - static final File BASE_OUT_PATH = new File("/data/local/CorePerfTests"); - - private static int sOriginalStayOnWhilePluggedIn; + static final File BASE_OUT_PATH = new File("/data/local/WmPerfTests"); @BeforeClass public static void setUpOnce() { final Context context = getInstrumentation().getContext(); - final int stayOnWhilePluggedIn = Settings.Global.getInt(context.getContentResolver(), - Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0); - sOriginalStayOnWhilePluggedIn = -1; - if (stayOnWhilePluggedIn != BatteryManager.BATTERY_PLUGGED_ANY) { - sOriginalStayOnWhilePluggedIn = stayOnWhilePluggedIn; - // Keep the device awake during testing. - setStayOnWhilePluggedIn(BatteryManager.BATTERY_PLUGGED_ANY); - } if (!BASE_OUT_PATH.exists()) { executeShellCommand("mkdir -p " + BASE_OUT_PATH); @@ -84,18 +73,6 @@ public class WindowManagerPerfTestBase { .addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); } - @AfterClass - public static void tearDownOnce() { - if (sOriginalStayOnWhilePluggedIn != -1) { - 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. @@ -124,6 +101,42 @@ public class WindowManagerPerfTestBase { executeShellCommand("am profile stop system"); } + static void runWithShellPermissionIdentity(Runnable runnable) { + sUiAutomation.adoptShellPermissionIdentity(); + try { + runnable.run(); + } finally { + sUiAutomation.dropShellPermissionIdentity(); + } + } + + static class SettingsSession<T> implements AutoCloseable { + private final Consumer<T> mSetter; + private final T mOriginalValue; + private boolean mChanged; + + SettingsSession(T originalValue, Consumer<T> setter) { + mOriginalValue = originalValue; + mSetter = setter; + } + + void set(T value) { + if (Objects.equals(value, mOriginalValue)) { + mChanged = false; + return; + } + mSetter.accept(value); + mChanged = true; + } + + @Override + public void close() { + if (mChanged) { + mSetter.accept(mOriginalValue); + } + } + } + /** * Provides an activity that keeps screen on and is able to wait for a stable lifecycle stage. */ diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java b/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java new file mode 100644 index 000000000000..6eb85aacb4e8 --- /dev/null +++ b/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.wm; + +import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.wm.WindowManagerPerfTestBase.executeShellCommand; +import static android.wm.WindowManagerPerfTestBase.runWithShellPermissionIdentity; + +import android.app.ActivityManager; +import android.app.ActivityManager.RunningAppProcessInfo; +import android.app.ActivityTaskManager; +import android.content.Context; +import android.os.BatteryManager; +import android.os.Bundle; +import android.os.SystemClock; +import android.provider.Settings; +import android.view.WindowManagerPolicyConstants; +import android.wm.WindowManagerPerfTestBase.SettingsSession; + +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.internal.policy.PhoneWindow; + +import org.junit.runner.Description; +import org.junit.runner.Result; +import org.junit.runner.notification.RunListener; + +import java.util.List; + +/** Prepare the preconditions before running performance test. */ +public class WmPerfRunListener extends RunListener { + + private static final String OPTION_KILL_BACKGROUND = "kill-bg"; + private static final long KILL_BACKGROUND_WAIT_MS = 3000; + + private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); + private long mWaitPreconditionDoneMs = 500; + + private final SettingsSession<Integer> mStayOnWhilePluggedInSetting = new SettingsSession<>( + Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0), + value -> executeShellCommand(String.format("settings put global %s %d", + Settings.Global.STAY_ON_WHILE_PLUGGED_IN, value))); + + private final SettingsSession<Integer> mNavigationModeSetting = new SettingsSession<>( + mContext.getResources().getInteger( + com.android.internal.R.integer.config_navBarInteractionMode), + value -> { + final String navOverlay; + switch (value) { + case WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON: + navOverlay = WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY; + break; + case WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON: + navOverlay = WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY; + break; + case WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL: + default: + navOverlay = WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY; + break; + } + executeShellCommand("cmd overlay enable-exclusive " + navOverlay); + }); + + /** It only executes once before all tests. */ + @Override + public void testRunStarted(Description description) { + final Bundle arguments = InstrumentationRegistry.getArguments(); + + // Use gesture navigation for consistency. + mNavigationModeSetting.set(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL); + // Keep the device awake during testing. + mStayOnWhilePluggedInSetting.set(BatteryManager.BATTERY_PLUGGED_ANY); + + runWithShellPermissionIdentity(() -> { + final ActivityTaskManager atm = mContext.getSystemService(ActivityTaskManager.class); + atm.removeAllVisibleRecentTasks(); + atm.removeStacksWithActivityTypes(new int[] { ACTIVITY_TYPE_STANDARD, + ACTIVITY_TYPE_ASSISTANT, ACTIVITY_TYPE_RECENTS, ACTIVITY_TYPE_UNDEFINED }); + }); + PhoneWindow.sendCloseSystemWindows(mContext, "WmPerfTests"); + + if (Boolean.parseBoolean(arguments.getString(OPTION_KILL_BACKGROUND))) { + runWithShellPermissionIdentity(this::killBackgroundProcesses); + mWaitPreconditionDoneMs = KILL_BACKGROUND_WAIT_MS; + } + // Wait a while for the precondition setup to complete. + SystemClock.sleep(mWaitPreconditionDoneMs); + } + + private void killBackgroundProcesses() { + final ActivityManager am = mContext.getSystemService(ActivityManager.class); + final List<RunningAppProcessInfo> processes = am.getRunningAppProcesses(); + if (processes == null) { + return; + } + for (RunningAppProcessInfo processInfo : processes) { + if (processInfo.importanceReasonCode == RunningAppProcessInfo.REASON_UNKNOWN + && processInfo.importance > RunningAppProcessInfo.IMPORTANCE_SERVICE) { + for (String pkg : processInfo.pkgList) { + am.forceStopPackage(pkg); + } + } + } + } + + /** It only executes once after all tests. */ + @Override + public void testRunFinished(Result result) { + mNavigationModeSetting.close(); + mStayOnWhilePluggedInSetting.close(); + } +} diff --git a/apct-tests/perftests/windowmanager/src/com/android/server/wm/test/filters/FrameworksTestsFilter.java b/apct-tests/perftests/windowmanager/src/com/android/server/wm/test/filters/FrameworksTestsFilter.java new file mode 100644 index 000000000000..d018287986f2 --- /dev/null +++ b/apct-tests/perftests/windowmanager/src/com/android/server/wm/test/filters/FrameworksTestsFilter.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm.test.filters; + +import android.wm.RelayoutPerfTest; + +import org.junit.runner.Description; +import org.junit.runner.manipulation.Filter; + +/** + * A static filter to have the same signature as the one in frameworks/base/tests/utils/testutils/. + * This doesn't share the existing library because it doesn't support parameterized test. + */ +public class FrameworksTestsFilter extends Filter { + + private boolean mShouldRun; + + @Override + public boolean shouldRun(Description description) { + final Class<?> testClass = description.getTestClass(); + // Parameterized test methods don't have the original information. So keep the last status + // that matches the target class. + mShouldRun = (mShouldRun && testClass == null) || testClass == RelayoutPerfTest.class; + return mShouldRun; + } + + @Override + public String describe() { + return "Default filter"; + } +} diff --git a/apex/jobscheduler/framework/java/com/android/server/AppStateTracker.java b/apex/jobscheduler/framework/java/com/android/server/AppStateTracker.java new file mode 100644 index 000000000000..b0b9abccd229 --- /dev/null +++ b/apex/jobscheduler/framework/java/com/android/server/AppStateTracker.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.server; + +import android.annotation.NonNull; + +/** + * Tracks the forced-app-standby state for apps. + */ +public interface AppStateTracker { + String TAG = "AppStateTracker"; + + /** + * Register a {@link ServiceStateListener} to listen for forced-app-standby changes that should + * affect services. + */ + void addServiceStateListener(@NonNull ServiceStateListener listener); + + /** + * A listener to listen to forced-app-standby changes that should affect services. + */ + interface ServiceStateListener { + /** + * Called when an app goes into forced app standby and its foreground + * services need to be removed from that state. + */ + void stopForegroundServicesForUidPackage(int uid, String packageName); + } +} diff --git a/services/core/java/com/android/server/AppStateTracker.java b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java index 7343352e0c71..6d2363549604 100644 --- a/services/core/java/com/android/server/AppStateTracker.java +++ b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java @@ -73,8 +73,7 @@ import java.util.Objects; * * Test: atest com.android.server.AppStateTrackerTest */ -public class AppStateTracker { - private static final String TAG = "AppStateTracker"; +public class AppStateTrackerImpl implements AppStateTracker { private static final boolean DEBUG = false; private final Object mLock = new Object(); @@ -164,6 +163,16 @@ public class AppStateTracker { @GuardedBy("mLock") boolean mForcedAppStandbyEnabled; + @Override + public void addServiceStateListener(@NonNull ServiceStateListener listener) { + addListener(new Listener() { + @Override + public void stopForegroundServicesForUidPackage(int uid, String packageName) { + listener.stopForegroundServicesForUidPackage(uid, packageName); + } + }); + } + interface Stats { int UID_FG_STATE_CHANGED = 0; int UID_ACTIVE_STATE_CHANGED = 1; @@ -228,7 +237,7 @@ public class AppStateTracker { } mForcedAppStandbyEnabled = enabled; if (DEBUG) { - Slog.d(TAG,"Forced app standby feature flag changed: " + Slog.d(TAG, "Forced app standby feature flag changed: " + mForcedAppStandbyEnabled); } } @@ -253,17 +262,20 @@ public class AppStateTracker { } } - public static abstract class Listener { + /** + * Listener for any state changes that affect any app's eligibility to run. + */ + public abstract static class Listener { /** * This is called when the OP_RUN_ANY_IN_BACKGROUND appops changed for a package. */ - private void onRunAnyAppOpsChanged(AppStateTracker sender, + private void onRunAnyAppOpsChanged(AppStateTrackerImpl sender, int uid, @NonNull String packageName) { updateJobsForUidPackage(uid, packageName, sender.isUidActive(uid)); if (!sender.areAlarmsRestricted(uid, packageName, /*allowWhileIdle=*/ false)) { unblockAlarmsForUidPackage(uid, packageName); - } else if (!sender.areAlarmsRestricted(uid, packageName, /*allowWhileIdle=*/ true)){ + } else if (!sender.areAlarmsRestricted(uid, packageName, /*allowWhileIdle=*/ true)) { // we need to deliver the allow-while-idle alarms for this uid, package unblockAllUnrestrictedAlarms(); } @@ -278,14 +290,14 @@ public class AppStateTracker { /** * This is called when the foreground state changed for a UID. */ - private void onUidForegroundStateChanged(AppStateTracker sender, int uid) { + private void onUidForegroundStateChanged(AppStateTrackerImpl sender, int uid) { onUidForeground(uid, sender.isUidInForeground(uid)); } /** * This is called when the active/idle state changed for a UID. */ - private void onUidActiveStateChanged(AppStateTracker sender, int uid) { + private void onUidActiveStateChanged(AppStateTrackerImpl sender, int uid) { final boolean isActive = sender.isUidActive(uid); updateJobsForUid(uid, isActive); @@ -298,7 +310,7 @@ public class AppStateTracker { /** * This is called when an app-id(s) is removed from the power save whitelist. */ - private void onPowerSaveUnwhitelisted(AppStateTracker sender) { + private void onPowerSaveUnwhitelisted(AppStateTrackerImpl sender) { updateAllJobs(); unblockAllUnrestrictedAlarms(); } @@ -307,14 +319,14 @@ public class AppStateTracker { * This is called when the power save whitelist changes, excluding the * {@link #onPowerSaveUnwhitelisted} case. */ - private void onPowerSaveWhitelistedChanged(AppStateTracker sender) { + private void onPowerSaveWhitelistedChanged(AppStateTrackerImpl sender) { updateAllJobs(); } /** * This is called when the temp whitelist changes. */ - private void onTempPowerSaveWhitelistChanged(AppStateTracker sender) { + private void onTempPowerSaveWhitelistChanged(AppStateTrackerImpl sender) { // TODO This case happens rather frequently; consider optimizing and update jobs // only for affected app-ids. @@ -327,7 +339,7 @@ public class AppStateTracker { /** * This is called when the EXEMPT bucket is updated. */ - private void onExemptChanged(AppStateTracker sender) { + private void onExemptChanged(AppStateTrackerImpl sender) { // This doesn't happen very often, so just re-evaluate all jobs / alarms. updateAllJobs(); unblockAllUnrestrictedAlarms(); @@ -336,7 +348,7 @@ public class AppStateTracker { /** * This is called when the global "force all apps standby" flag changes. */ - private void onForceAllAppsStandbyChanged(AppStateTracker sender) { + private void onForceAllAppsStandbyChanged(AppStateTrackerImpl sender) { updateAllJobs(); if (!sender.isForceAllAppsStandbyEnabled()) { @@ -401,14 +413,12 @@ public class AppStateTracker { /** * Called when an ephemeral uid goes to the background, so its alarms need to be removed. - * - * @param uid */ public void removeAlarmsForUid(int uid) { } } - public AppStateTracker(Context context, Looper looper) { + public AppStateTrackerImpl(Context context, Looper looper) { mContext = context; mHandler = new MyHandler(looper); } @@ -711,7 +721,7 @@ public class AppStateTracker { public void onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket, int reason) { if (DEBUG) { - Slog.d(TAG,"onAppIdleStateChanged: " + packageName + " u" + userId + Slog.d(TAG, "onAppIdleStateChanged: " + packageName + " u" + userId + (idle ? " idle" : " active") + " " + bucket); } synchronized (mLock) { @@ -751,7 +761,7 @@ public class AppStateTracker { private static final int MSG_ON_UID_GONE = 13; private static final int MSG_ON_UID_IDLE = 14; - public MyHandler(Looper looper) { + MyHandler(Looper looper) { super(looper); } @@ -831,7 +841,7 @@ public class AppStateTracker { return; } } - final AppStateTracker sender = AppStateTracker.this; + final AppStateTrackerImpl sender = AppStateTrackerImpl.this; long start = mStatLogger.getTime(); switch (msg.what) { @@ -1077,7 +1087,7 @@ public class AppStateTracker { // Public interface. /** - * Register a new listener. + * Register a listener to get callbacks when any state changes. */ public void addListener(@NonNull Listener listener) { synchronized (mLock) { @@ -1127,8 +1137,7 @@ public class AppStateTracker { if (ArrayUtils.contains(mPowerWhitelistedAllAppIds, appId)) { return false; } - if (useTempWhitelistToo && - ArrayUtils.contains(mTempWhitelistedAppIds, appId)) { + if (useTempWhitelistToo && ArrayUtils.contains(mTempWhitelistedAppIds, appId)) { return false; } if (mForcedAppStandbyEnabled && isRunAnyRestrictedLocked(uid, packageName)) { @@ -1197,7 +1206,6 @@ public class AppStateTracker { /** * @return whether force all apps standby is enabled or not. - * */ public boolean isForceAllAppsStandbyEnabled() { synchronized (mLock) { @@ -1248,11 +1256,18 @@ public class AppStateTracker { } } + /** + * @deprecated use {@link #dump(IndentingPrintWriter)} instead. + */ @Deprecated public void dump(PrintWriter pw, String prefix) { dump(new IndentingPrintWriter(pw, " ").setIndent(prefix)); } + /** + * Dump the internal state to the given PrintWriter. Can be included in the dump + * of a binder service to be output on the shell command "dumpsys". + */ public void dump(IndentingPrintWriter pw) { synchronized (mLock) { pw.println("Forced App Standby Feature enabled: " + mForcedAppStandbyEnabled); @@ -1329,6 +1344,9 @@ public class AppStateTracker { pw.println("]"); } + /** + * Proto version of {@link #dump(IndentingPrintWriter)} + */ public void dumpProto(ProtoOutputStream proto, long fieldId) { synchronized (mLock) { final long token = proto.start(fieldId); diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java index 7b681fb8d1f8..f26549c24787 100644 --- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java @@ -286,7 +286,7 @@ public class DeviceIdleController extends SystemService private Intent mIdleIntent; private Intent mLightIdleIntent; private AnyMotionDetector mAnyMotionDetector; - private final AppStateTracker mAppStateTracker; + private final AppStateTrackerImpl mAppStateTracker; private boolean mLightEnabled; private boolean mDeepEnabled; private boolean mQuickDozeActivated; @@ -1859,8 +1859,8 @@ public class DeviceIdleController extends SystemService return new AnyMotionDetector(getPowerManager(), handler, sm, callback, angleThreshold); } - AppStateTracker getAppStateTracker(Context ctx, Looper looper) { - return new AppStateTracker(ctx, looper); + AppStateTrackerImpl getAppStateTracker(Context ctx, Looper looper) { + return new AppStateTrackerImpl(ctx, looper); } ConnectivityManager getConnectivityManager() { diff --git a/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING index d99830dc47c9..b8fef63fa008 100644 --- a/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING +++ b/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING @@ -10,6 +10,15 @@ {"exclude-annotation": "android.platform.test.annotations.FlakyTest"}, {"exclude-annotation": "androidx.test.filters.FlakyTest"} ] + }, + { + "name": "FrameworksMockingServicesTests", + "file_patterns": ["AppStateTrackerImpl\\.java"], + "options": [ + {"include-filter": "com.android.server.AppStateTrackerTest"}, + {"include-annotation": "android.platform.test.annotations.Presubmit"}, + {"exclude-annotation": "androidx.test.filters.FlakyTest"} + ] } ], "postsubmit": [ diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java index 5ca3b336e5be..6529503808b3 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java @@ -99,7 +99,8 @@ import com.android.internal.util.LocalLog; import com.android.internal.util.StatLogger; import com.android.server.AlarmManagerInternal; import com.android.server.AppStateTracker; -import com.android.server.AppStateTracker.Listener; +import com.android.server.AppStateTrackerImpl; +import com.android.server.AppStateTrackerImpl.Listener; import com.android.server.DeviceIdleInternal; import com.android.server.EventLogTags; import com.android.server.LocalServices; @@ -286,7 +287,7 @@ public class AlarmManagerService extends SystemService { private final SparseArray<AlarmManager.AlarmClockInfo> mHandlerSparseAlarmClockArray = new SparseArray<>(); - private AppStateTracker mAppStateTracker; + private AppStateTrackerImpl mAppStateTracker; private boolean mAppStandbyParole; /** @@ -1593,7 +1594,8 @@ public class AlarmManagerService extends SystemService { LocalServices.getService(AppStandbyInternal.class); appStandbyInternal.addListener(new AppStandbyTracker()); - mAppStateTracker = LocalServices.getService(AppStateTracker.class); + mAppStateTracker = + (AppStateTrackerImpl) LocalServices.getService(AppStateTracker.class); mAppStateTracker.addListener(mForceAppStandbyListener); mClockReceiver.scheduleTimeTickEvent(); @@ -4393,8 +4395,7 @@ public class AlarmManagerService extends SystemService { /** * Tracking of app assignments to standby buckets */ - private final class AppStandbyTracker extends - AppIdleStateChangeListener { + private final class AppStandbyTracker extends AppIdleStateChangeListener { @Override public void onAppIdleStateChanged(final String packageName, final @UserIdInt int userId, boolean idle, int bucket, int reason) { 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 a67e928c8cbe..06c469a5cc82 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -86,6 +86,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.server.AppStateTracker; +import com.android.server.AppStateTrackerImpl; import com.android.server.DeviceIdleInternal; import com.android.server.LocalServices; import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob; @@ -283,7 +284,7 @@ public class JobSchedulerService extends com.android.server.SystemService IBatteryStats mBatteryStats; DeviceIdleInternal mLocalDeviceIdleController; @VisibleForTesting - AppStateTracker mAppStateTracker; + AppStateTrackerImpl mAppStateTracker; final UsageStatsManagerInternal mUsageStats; private final AppStandbyInternal mAppStandbyInternal; @@ -1524,7 +1525,7 @@ public class JobSchedulerService extends com.android.server.SystemService controller.onSystemServicesReady(); } - mAppStateTracker = Objects.requireNonNull( + mAppStateTracker = (AppStateTrackerImpl) Objects.requireNonNull( LocalServices.getService(AppStateTracker.class)); // Register br for package removals and user removals. diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java index fd26b72ef9d9..b6324358ec33 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java @@ -26,7 +26,8 @@ import android.util.Slog; import android.util.proto.ProtoOutputStream; import com.android.server.AppStateTracker; -import com.android.server.AppStateTracker.Listener; +import com.android.server.AppStateTrackerImpl; +import com.android.server.AppStateTrackerImpl.Listener; import com.android.server.LocalServices; import com.android.server.job.JobSchedulerService; import com.android.server.job.JobStore; @@ -56,12 +57,12 @@ public final class BackgroundJobsController extends StateController { static final int KNOWN_ACTIVE = 1; static final int KNOWN_INACTIVE = 2; - private final AppStateTracker mAppStateTracker; + private final AppStateTrackerImpl mAppStateTracker; public BackgroundJobsController(JobSchedulerService service) { super(service); - mAppStateTracker = Objects.requireNonNull( + mAppStateTracker = (AppStateTrackerImpl) Objects.requireNonNull( LocalServices.getService(AppStateTracker.class)); mAppStateTracker.addListener(mForceAppStandbyListener); } diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java index 361ebe55ccd8..227b8276abe1 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java @@ -18,28 +18,20 @@ package com.android.server.job.controllers; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; -import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AlarmManager; import android.app.AlarmManager.OnAlarmListener; -import android.content.ContentResolver; import android.content.Context; -import android.database.ContentObserver; -import android.net.Uri; -import android.os.Handler; import android.os.Process; import android.os.UserHandle; import android.os.WorkSource; -import android.provider.Settings; import android.util.IndentingPrintWriter; -import android.util.KeyValueListParser; import android.util.Log; import android.util.Slog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.job.ConstantsProto; import com.android.server.job.JobSchedulerService; import com.android.server.job.StateControllerProto; @@ -63,9 +55,6 @@ public final class TimeController extends StateController { /** Delay alarm tag for logging purposes */ private final String DELAY_TAG = "*job.delay*"; - private final Handler mHandler; - private final TcConstants mTcConstants; - private long mNextJobExpiredElapsedMillis; private long mNextDelayExpiredElapsedMillis; @@ -81,14 +70,6 @@ public final class TimeController extends StateController { mNextJobExpiredElapsedMillis = Long.MAX_VALUE; mNextDelayExpiredElapsedMillis = Long.MAX_VALUE; mChainedAttributionEnabled = mService.isChainedAttributionEnabled(); - - mHandler = new Handler(mContext.getMainLooper()); - mTcConstants = new TcConstants(mHandler); - } - - @Override - public void onSystemServicesReady() { - mTcConstants.start(mContext.getContentResolver()); } /** @@ -372,8 +353,7 @@ public final class TimeController extends StateController { /** * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a job's * delay will expire. - * This alarm <b>will not</b> wake up the phone if - * {@link TcConstants#USE_NON_WAKEUP_ALARM_FOR_DELAY} is true. + * This alarm <b>will not</b> wake up the phone. */ private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) { alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis); @@ -381,10 +361,7 @@ public final class TimeController extends StateController { return; } mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis; - final int alarmType = - mTcConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY - ? AlarmManager.ELAPSED_REALTIME : AlarmManager.ELAPSED_REALTIME_WAKEUP; - updateAlarmWithListenerLocked(DELAY_TAG, alarmType, + updateAlarmWithListenerLocked(DELAY_TAG, AlarmManager.ELAPSED_REALTIME, mNextDelayExpiredListener, mNextDelayExpiredElapsedMillis, ws); } @@ -443,80 +420,6 @@ public final class TimeController extends StateController { } }; - @VisibleForTesting - class TcConstants extends ContentObserver { - private ContentResolver mResolver; - private final KeyValueListParser mParser = new KeyValueListParser(','); - - private static final String KEY_USE_NON_WAKEUP_ALARM_FOR_DELAY = - "use_non_wakeup_delay_alarm"; - - private static final boolean DEFAULT_USE_NON_WAKEUP_ALARM_FOR_DELAY = true; - - /** - * Whether or not TimeController should skip setting wakeup alarms for jobs that aren't - * ready now. - */ - public boolean USE_NON_WAKEUP_ALARM_FOR_DELAY = DEFAULT_USE_NON_WAKEUP_ALARM_FOR_DELAY; - - /** - * Creates a content observer. - * - * @param handler The handler to run {@link #onChange} on, or null if none. - */ - TcConstants(Handler handler) { - super(handler); - } - - private void start(ContentResolver resolver) { - mResolver = resolver; - mResolver.registerContentObserver(Settings.Global.getUriFor( - Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS), false, this); - onChange(true, null); - } - - @Override - public void onChange(boolean selfChange, Uri uri) { - final String constants = Settings.Global.getString( - mResolver, Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS); - - try { - mParser.setString(constants); - } catch (Exception e) { - // Failed to parse the settings string, log this and move on with defaults. - Slog.e(TAG, "Bad jobscheduler time controller settings", e); - } - - USE_NON_WAKEUP_ALARM_FOR_DELAY = mParser.getBoolean( - KEY_USE_NON_WAKEUP_ALARM_FOR_DELAY, DEFAULT_USE_NON_WAKEUP_ALARM_FOR_DELAY); - // Intentionally not calling checkExpiredDelaysAndResetAlarm() here. There's no need to - // iterate through the entire list again for this constant change. The next delay alarm - // that is set will make use of the new constant value. - } - - private void dump(IndentingPrintWriter pw) { - pw.println(); - pw.println("TimeController:"); - pw.increaseIndent(); - pw.print(KEY_USE_NON_WAKEUP_ALARM_FOR_DELAY, - USE_NON_WAKEUP_ALARM_FOR_DELAY).println(); - pw.decreaseIndent(); - } - - private void dump(ProtoOutputStream proto) { - final long tcToken = proto.start(ConstantsProto.TIME_CONTROLLER); - proto.write(ConstantsProto.TimeController.USE_NON_WAKEUP_ALARM_FOR_DELAY, - USE_NON_WAKEUP_ALARM_FOR_DELAY); - proto.end(tcToken); - } - } - - @VisibleForTesting - @NonNull - TcConstants getTcConstants() { - return mTcConstants; - } - @Override public void dumpControllerStateLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate) { @@ -591,14 +494,4 @@ public final class TimeController extends StateController { proto.end(mToken); proto.end(token); } - - @Override - public void dumpConstants(IndentingPrintWriter pw) { - mTcConstants.dump(pw); - } - - @Override - public void dumpConstants(ProtoOutputStream proto) { - mTcConstants.dump(proto); - } } diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java index f40f244e69e5..2f993dad51c7 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -487,9 +487,6 @@ public class AppStandbyController implements AppStandbyInternal { mSystemServicesReady = true; - // Offload to handler thread to avoid boot time impact. - mHandler.post(AppStandbyController.this::updatePowerWhitelistCache); - boolean userFileExists; synchronized (mAppIdleLock) { userFileExists = mAppIdleHistory.userFileExists(UserHandle.USER_SYSTEM); @@ -506,7 +503,9 @@ public class AppStandbyController implements AppStandbyInternal { setChargingState(mInjector.isCharging()); // Offload to handler thread after boot completed to avoid boot time impact. This means - // that headless system apps may be put in a lower bucket until boot has completed. + // that app standby buckets may be slightly out of date and headless system apps may be + // put in a lower bucket until boot has completed. + mHandler.post(AppStandbyController.this::updatePowerWhitelistCache); mHandler.post(this::loadHeadlessSystemAppCache); } } diff --git a/api/current.txt b/api/current.txt index 651cda564ee9..1d2286b333bb 100644 --- a/api/current.txt +++ b/api/current.txt @@ -24079,6 +24079,7 @@ package android.media { field public static final int TYPE_IP = 20; // 0x14 field public static final int TYPE_LINE_ANALOG = 5; // 0x5 field public static final int TYPE_LINE_DIGITAL = 6; // 0x6 + field public static final int TYPE_REMOTE_SUBMIX = 25; // 0x19 field public static final int TYPE_TELEPHONY = 18; // 0x12 field public static final int TYPE_TV_TUNER = 17; // 0x11 field public static final int TYPE_UNKNOWN = 0; // 0x0 @@ -27905,6 +27906,7 @@ package android.media.audiofx { field public static final java.util.UUID EFFECT_TYPE_DYNAMICS_PROCESSING; field public static final java.util.UUID EFFECT_TYPE_ENV_REVERB; field public static final java.util.UUID EFFECT_TYPE_EQUALIZER; + field @NonNull public static final java.util.UUID EFFECT_TYPE_HAPTIC_GENERATOR; field public static final java.util.UUID EFFECT_TYPE_LOUDNESS_ENHANCER; field public static final java.util.UUID EFFECT_TYPE_NS; field public static final java.util.UUID EFFECT_TYPE_PRESET_REVERB; @@ -28257,6 +28259,13 @@ package android.media.audiofx { field public short numBands; } + public class HapticGenerator extends android.media.audiofx.AudioEffect implements java.lang.AutoCloseable { + method public void close(); + method @NonNull public static android.media.audiofx.HapticGenerator create(int); + method public static boolean isAvailable(); + method public int setEnabled(boolean); + } + public class LoudnessEnhancer extends android.media.audiofx.AudioEffect { ctor public LoudnessEnhancer(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.RuntimeException, java.lang.UnsupportedOperationException; method public float getTargetGain() throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException; diff --git a/api/system-current.txt b/api/system-current.txt index fa4543001f90..11db781dd42f 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4172,10 +4172,6 @@ package android.media { field public static final int ROLE_OUTPUT = 2; // 0x2 } - public final class AudioDeviceInfo { - field public static final int TYPE_REMOTE_SUBMIX = 25; // 0x19 - } - public final class AudioFocusInfo implements android.os.Parcelable { method public int describeContents(); method @NonNull public android.media.AudioAttributes getAttributes(); diff --git a/api/test-current.txt b/api/test-current.txt index dc6626586efa..f1a3566f7b45 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -20,6 +20,7 @@ package android { field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS"; field public static final String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE"; field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS"; + field public static final String RESET_APP_ERRORS = "android.permission.RESET_APP_ERRORS"; field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS"; field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS"; field public static final String UPGRADE_RUNTIME_PERMISSIONS = "android.permission.UPGRADE_RUNTIME_PERMISSIONS"; @@ -83,6 +84,7 @@ package android.app { method public static boolean isHighEndGfx(); method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void killProcessesWhenImperceptible(@NonNull int[], @NonNull String); method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener); + method @RequiresPermission(android.Manifest.permission.RESET_APP_ERRORS) public void resetAppErrors(); method public static void resumeAppSwitches() throws android.os.RemoteException; method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int); method @RequiresPermission("android.permission.MANAGE_USERS") public boolean switchUser(@NonNull android.os.UserHandle); @@ -3292,6 +3294,7 @@ package android.provider { field public static final String LOW_POWER_MODE_STICKY = "low_power_sticky"; field public static final String NOTIFICATION_BUBBLES = "notification_bubbles"; field public static final String OVERLAY_DISPLAY_DEVICES = "overlay_display_devices"; + field public static final String SHOW_FIRST_CRASH_DIALOG = "show_first_crash_dialog"; field public static final String TETHER_OFFLOAD_DISABLED = "tether_offload_disabled"; field public static final String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package"; } @@ -3300,6 +3303,7 @@ package android.provider { method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static void resetToDefaults(@NonNull android.content.ContentResolver, @Nullable String); field public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED = "accessibility_display_magnification_enabled"; field public static final String ACCESSIBILITY_SHORTCUT_TARGET_SERVICE = "accessibility_shortcut_target_service"; + field public static final String ANR_SHOW_BACKGROUND = "anr_show_background"; field public static final String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = "autofill_field_classification"; field public static final String AUTOFILL_SERVICE = "autofill_service"; field public static final String AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT = "autofill_user_data_max_category_count"; @@ -3320,6 +3324,7 @@ package android.provider { field public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component"; field public static final String NOTIFICATION_BADGING = "notification_badging"; field public static final String POWER_MENU_LOCKED_SHOW_CONTENT = "power_menu_locked_show_content"; + field public static final String SHOW_FIRST_CRASH_DIALOG_DEV_OPTION = "show_first_crash_dialog_dev_option"; field public static final String SHOW_IME_WITH_HARD_KEYBOARD = "show_ime_with_hard_keyboard"; field @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static final String SYNC_PARENT_SOUNDS = "sync_parent_sounds"; field public static final String USER_SETUP_COMPLETE = "user_setup_complete"; diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp index 878cef94b674..e21a6b288fb3 100644 --- a/cmds/idmap2/Android.bp +++ b/cmds/idmap2/Android.bp @@ -181,7 +181,6 @@ cc_binary { "idmap2/Dump.cpp", "idmap2/Lookup.cpp", "idmap2/Main.cpp", - "idmap2/Scan.cpp", ], target: { android: { diff --git a/cmds/idmap2/idmap2/Commands.h b/cmds/idmap2/idmap2/Commands.h index 69eea8d262d2..4099671066a2 100644 --- a/cmds/idmap2/idmap2/Commands.h +++ b/cmds/idmap2/idmap2/Commands.h @@ -26,6 +26,5 @@ android::idmap2::Result<android::idmap2::Unit> Create(const std::vector<std::str android::idmap2::Result<android::idmap2::Unit> CreateMultiple(const std::vector<std::string>& args); android::idmap2::Result<android::idmap2::Unit> Dump(const std::vector<std::string>& args); android::idmap2::Result<android::idmap2::Unit> Lookup(const std::vector<std::string>& args); -android::idmap2::Result<android::idmap2::Unit> Scan(const std::vector<std::string>& args); #endif // IDMAP2_IDMAP2_COMMANDS_H_ diff --git a/cmds/idmap2/idmap2/Main.cpp b/cmds/idmap2/idmap2/Main.cpp index fb093f0f22a4..aa6d0e76698f 100644 --- a/cmds/idmap2/idmap2/Main.cpp +++ b/cmds/idmap2/idmap2/Main.cpp @@ -53,8 +53,10 @@ void PrintUsage(const NameToFunctionMap& commands, std::ostream& out) { int main(int argc, char** argv) { SYSTRACE << "main"; const NameToFunctionMap commands = { - {"create", Create}, {"create-multiple", CreateMultiple}, {"dump", Dump}, {"lookup", Lookup}, - {"scan", Scan}, + {"create", Create}, + {"create-multiple", CreateMultiple}, + {"dump", Dump}, + {"lookup", Lookup}, }; if (argc <= 1) { PrintUsage(commands, std::cerr); diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp deleted file mode 100644 index 36250450cc74..000000000000 --- a/cmds/idmap2/idmap2/Scan.cpp +++ /dev/null @@ -1,257 +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. - */ - -#include <dirent.h> - -#include <fstream> -#include <memory> -#include <ostream> -#include <set> -#include <string> -#include <utility> -#include <vector> - -#include "Commands.h" -#include "android-base/properties.h" -#include "idmap2/CommandLineOptions.h" -#include "idmap2/CommandUtils.h" -#include "idmap2/FileUtils.h" -#include "idmap2/Idmap.h" -#include "idmap2/Policies.h" -#include "idmap2/PolicyUtils.h" -#include "idmap2/ResourceUtils.h" -#include "idmap2/Result.h" -#include "idmap2/SysTrace.h" -#include "idmap2/XmlParser.h" - -using android::idmap2::CommandLineOptions; -using android::idmap2::Error; -using android::idmap2::Idmap; -using android::idmap2::Result; -using android::idmap2::Unit; -using android::idmap2::policy::kPolicyOdm; -using android::idmap2::policy::kPolicyOem; -using android::idmap2::policy::kPolicyProduct; -using android::idmap2::policy::kPolicyPublic; -using android::idmap2::policy::kPolicySystem; -using android::idmap2::policy::kPolicyVendor; -using android::idmap2::utils::ExtractOverlayManifestInfo; -using android::idmap2::utils::FindFiles; -using android::idmap2::utils::OverlayManifestInfo; -using android::idmap2::utils::PoliciesToBitmaskResult; - -using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask; - -namespace { - -struct InputOverlay { - bool operator<(InputOverlay const& rhs) const { - return priority < rhs.priority || (priority == rhs.priority && apk_path < rhs.apk_path); - } - - std::string apk_path; // NOLINT(misc-non-private-member-variables-in-classes) - std::string idmap_path; // NOLINT(misc-non-private-member-variables-in-classes) - int priority; // NOLINT(misc-non-private-member-variables-in-classes) - std::vector<std::string> policies; // NOLINT(misc-non-private-member-variables-in-classes) - bool ignore_overlayable; // NOLINT(misc-non-private-member-variables-in-classes) -}; - -bool VendorIsQOrLater() { - constexpr int kQSdkVersion = 29; - constexpr int kBase = 10; - std::string version_prop = android::base::GetProperty("ro.vndk.version", "29"); - int version = strtol(version_prop.data(), nullptr, kBase); - - // If the string cannot be parsed, it is a development sdk codename. - return version >= kQSdkVersion || version == 0; -} - -Result<std::unique_ptr<std::vector<std::string>>> FindApkFiles(const std::vector<std::string>& dirs, - bool recursive) { - SYSTRACE << "FindApkFiles " << dirs << " " << recursive; - const auto predicate = [](unsigned char type, const std::string& path) -> bool { - static constexpr size_t kExtLen = 4; // strlen(".apk") - return type == DT_REG && path.size() > kExtLen && - path.compare(path.size() - kExtLen, kExtLen, ".apk") == 0; - }; - // pass apk paths through a set to filter out duplicates - std::set<std::string> paths; - for (const auto& dir : dirs) { - const auto apk_paths = FindFiles(dir, recursive, predicate); - if (!apk_paths) { - return Error("failed to open directory %s", dir.c_str()); - } - paths.insert(apk_paths->cbegin(), apk_paths->cend()); - } - return std::make_unique<std::vector<std::string>>(paths.cbegin(), paths.cend()); -} - -std::vector<std::string> PoliciesForPath(const std::string& apk_path) { - // clang-format off - static const std::vector<std::pair<std::string, std::string>> values = { - {"/odm/", kPolicyOdm}, - {"/oem/", kPolicyOem}, - {"/product/", kPolicyProduct}, - {"/system/", kPolicySystem}, - {"/system_ext/", kPolicySystem}, - {"/vendor/", kPolicyVendor}, - }; - // clang-format on - - std::vector<std::string> fulfilled_policies = {kPolicyPublic}; - for (auto const& pair : values) { - if (apk_path.compare(0, pair.first.size(), pair.first) == 0) { - fulfilled_policies.emplace_back(pair.second); - break; - } - } - - return fulfilled_policies; -} - -} // namespace - -Result<Unit> Scan(const std::vector<std::string>& args) { - SYSTRACE << "Scan " << args; - std::vector<std::string> input_directories; - std::string target_package_name; - std::string target_apk_path; - std::string output_directory; - std::vector<std::string> override_policies; - bool recursive = false; - - const CommandLineOptions opts = - CommandLineOptions("idmap2 scan") - .MandatoryOption("--input-directory", "directory containing overlay apks to scan", - &input_directories) - .OptionalFlag("--recursive", "also scan subfolders of overlay-directory", &recursive) - .MandatoryOption("--target-package-name", "package name of target package", - &target_package_name) - .MandatoryOption("--target-apk-path", "path to target apk", &target_apk_path) - .MandatoryOption("--output-directory", - "directory in which to write artifacts (idmap files and overlays.list)", - &output_directory) - .OptionalOption( - "--override-policy", - "input: an overlayable policy this overlay fulfills " - "(if none or supplied, the overlays will not have their policies overriden", - &override_policies); - const auto opts_ok = opts.Parse(args); - if (!opts_ok) { - return opts_ok.GetError(); - } - - const auto apk_paths = FindApkFiles(input_directories, recursive); - if (!apk_paths) { - return Error(apk_paths.GetError(), "failed to find apk files"); - } - - std::vector<InputOverlay> interesting_apks; - for (const std::string& path : **apk_paths) { - Result<OverlayManifestInfo> overlay_info = - ExtractOverlayManifestInfo(path, /* assert_overlay */ false); - if (!overlay_info) { - return overlay_info.GetError(); - } - - if (!overlay_info->is_static) { - continue; - } - - if (overlay_info->target_package.empty() || - overlay_info->target_package != target_package_name) { - continue; - } - - if (overlay_info->priority < 0) { - continue; - } - - // Note that conditional property enablement/exclusion only applies if - // the attribute is present. In its absence, all overlays are presumed enabled. - if (!overlay_info->requiredSystemPropertyName.empty() && - !overlay_info->requiredSystemPropertyValue.empty()) { - // if property set & equal to value, then include overlay - otherwise skip - if (android::base::GetProperty(overlay_info->requiredSystemPropertyName, "") != - overlay_info->requiredSystemPropertyValue) { - continue; - } - } - - std::vector<std::string> fulfilled_policies; - if (!override_policies.empty()) { - fulfilled_policies = override_policies; - } else { - fulfilled_policies = PoliciesForPath(path); - } - - bool ignore_overlayable = false; - if (std::find(fulfilled_policies.begin(), fulfilled_policies.end(), kPolicyVendor) != - fulfilled_policies.end() && - !VendorIsQOrLater()) { - // If the overlay is on a pre-Q vendor partition, do not enforce overlayable - // restrictions on this overlay because the pre-Q platform has no understanding of - // overlayable. - ignore_overlayable = true; - } - - std::string idmap_path = Idmap::CanonicalIdmapPathFor(output_directory, path); - - // Sort the static overlays in ascending priority order - InputOverlay input{path, idmap_path, overlay_info->priority, fulfilled_policies, - ignore_overlayable}; - interesting_apks.insert( - std::lower_bound(interesting_apks.begin(), interesting_apks.end(), input), input); - } - - std::stringstream stream; - for (const auto& overlay : interesting_apks) { - const auto policy_bitmask = PoliciesToBitmaskResult(overlay.policies); - if (!policy_bitmask) { - LOG(WARNING) << "failed to create idmap for overlay apk path \"" << overlay.apk_path - << "\": " << policy_bitmask.GetErrorMessage(); - continue; - } - - if (!Verify(overlay.idmap_path, target_apk_path, overlay.apk_path, *policy_bitmask, - !overlay.ignore_overlayable)) { - std::vector<std::string> create_args = {"--target-apk-path", target_apk_path, - "--overlay-apk-path", overlay.apk_path, - "--idmap-path", overlay.idmap_path}; - if (overlay.ignore_overlayable) { - create_args.emplace_back("--ignore-overlayable"); - } - - for (const std::string& policy : overlay.policies) { - create_args.emplace_back("--policy"); - create_args.emplace_back(policy); - } - - const auto create_ok = Create(create_args); - if (!create_ok) { - LOG(WARNING) << "failed to create idmap for overlay apk path \"" << overlay.apk_path - << "\": " << create_ok.GetError().GetMessage(); - continue; - } - } - - stream << overlay.idmap_path << std::endl; - } - - std::cout << stream.str(); - - return Unit{}; -} diff --git a/cmds/idmap2/include/idmap2/FileUtils.h b/cmds/idmap2/include/idmap2/FileUtils.h index 3f03236d5e1a..c4e0e1fd8ef0 100644 --- a/cmds/idmap2/include/idmap2/FileUtils.h +++ b/cmds/idmap2/include/idmap2/FileUtils.h @@ -17,27 +17,13 @@ #ifndef IDMAP2_INCLUDE_IDMAP2_FILEUTILS_H_ #define IDMAP2_INCLUDE_IDMAP2_FILEUTILS_H_ -#include <sys/types.h> - -#include <functional> -#include <memory> #include <string> -#include <vector> namespace android::idmap2::utils { constexpr const char* kIdmapCacheDir = "/data/resource-cache"; constexpr const mode_t kIdmapFilePermissionMask = 0133; // u=rw,g=r,o=r -typedef std::function<bool(unsigned char type /* DT_* from dirent.h */, const std::string& path)> - FindFilesPredicate; -std::unique_ptr<std::vector<std::string>> FindFiles(const std::string& root, bool recurse, - const FindFilesPredicate& predicate); - -std::unique_ptr<std::string> ReadFile(int fd); - -std::unique_ptr<std::string> ReadFile(const std::string& path); - bool UidHasWriteAccessToPath(uid_t uid, const std::string& path); } // namespace android::idmap2::utils diff --git a/cmds/idmap2/libidmap2/FileUtils.cpp b/cmds/idmap2/libidmap2/FileUtils.cpp index 3e8e32989a09..3af1f70ebe39 100644 --- a/cmds/idmap2/libidmap2/FileUtils.cpp +++ b/cmds/idmap2/libidmap2/FileUtils.cpp @@ -16,19 +16,7 @@ #include "idmap2/FileUtils.h" -#include <dirent.h> -#include <sys/types.h> -#include <unistd.h> - -#include <cerrno> -#include <climits> -#include <cstdlib> -#include <cstring> -#include <fstream> -#include <memory> #include <string> -#include <utility> -#include <vector> #include "android-base/file.h" #include "android-base/macros.h" @@ -37,54 +25,6 @@ namespace android::idmap2::utils { -std::unique_ptr<std::vector<std::string>> FindFiles(const std::string& root, bool recurse, - const FindFilesPredicate& predicate) { - DIR* dir = opendir(root.c_str()); - if (dir == nullptr) { - return nullptr; - } - std::unique_ptr<std::vector<std::string>> vector(new std::vector<std::string>()); - struct dirent* dirent; - while ((dirent = readdir(dir)) != nullptr) { - const std::string path = root + "/" + dirent->d_name; - if (predicate(dirent->d_type, path)) { - vector->push_back(path); - } - if (recurse && dirent->d_type == DT_DIR && strcmp(dirent->d_name, ".") != 0 && - strcmp(dirent->d_name, "..") != 0) { - auto sub_vector = FindFiles(path, recurse, predicate); - if (!sub_vector) { - closedir(dir); - return nullptr; - } - vector->insert(vector->end(), sub_vector->begin(), sub_vector->end()); - } - } - closedir(dir); - - return vector; -} - -std::unique_ptr<std::string> ReadFile(const std::string& path) { - std::unique_ptr<std::string> str(new std::string()); - std::ifstream fin(path); - str->append({std::istreambuf_iterator<char>(fin), std::istreambuf_iterator<char>()}); - fin.close(); - return str; -} - -std::unique_ptr<std::string> ReadFile(int fd) { - static constexpr const size_t kBufSize = 1024; - - std::unique_ptr<std::string> str(new std::string()); - char buf[kBufSize]; - ssize_t r; - while ((r = read(fd, buf, sizeof(buf))) > 0) { - str->append(buf, r); - } - return r == 0 ? std::move(str) : nullptr; -} - #ifdef __ANDROID__ bool UidHasWriteAccessToPath(uid_t uid, const std::string& path) { // resolve symlinks and relative paths; the directories must exist diff --git a/cmds/idmap2/tests/FileUtilsTests.cpp b/cmds/idmap2/tests/FileUtilsTests.cpp index 8af4037be954..5750ca1f49c5 100644 --- a/cmds/idmap2/tests/FileUtilsTests.cpp +++ b/cmds/idmap2/tests/FileUtilsTests.cpp @@ -14,73 +14,16 @@ * limitations under the License. */ -#include <dirent.h> -#include <fcntl.h> - -#include <set> #include <string> #include "TestHelpers.h" -#include "android-base/macros.h" #include "android-base/stringprintf.h" -#include "gmock/gmock.h" #include "gtest/gtest.h" #include "idmap2/FileUtils.h" #include "private/android_filesystem_config.h" -using ::testing::NotNull; - namespace android::idmap2::utils { -TEST(FileUtilsTests, FindFilesFindEverythingNonRecursive) { - const auto& root = GetTestDataPath(); - auto v = utils::FindFiles(root, false, - [](unsigned char type ATTRIBUTE_UNUSED, - const std::string& path ATTRIBUTE_UNUSED) -> bool { return true; }); - ASSERT_THAT(v, NotNull()); - ASSERT_EQ(v->size(), 7U); - ASSERT_EQ(std::set<std::string>(v->begin(), v->end()), std::set<std::string>({ - root + "/.", - root + "/..", - root + "/overlay", - root + "/target", - root + "/signature-overlay", - root + "/system-overlay", - root + "/system-overlay-invalid", - })); -} - -TEST(FileUtilsTests, FindFilesFindApkFilesRecursive) { - const auto& root = GetTestDataPath(); - auto v = utils::FindFiles(root, true, [](unsigned char type, const std::string& path) -> bool { - return type == DT_REG && path.size() > 4 && path.compare(path.size() - 4, 4, ".apk") == 0; - }); - ASSERT_THAT(v, NotNull()); - ASSERT_EQ(v->size(), 11U); - ASSERT_EQ(std::set<std::string>(v->begin(), v->end()), - std::set<std::string>( - {root + "/target/target.apk", root + "/target/target-no-overlayable.apk", - root + "/overlay/overlay.apk", root + "/overlay/overlay-no-name.apk", - root + "/overlay/overlay-no-name-static.apk", root + "/overlay/overlay-shared.apk", - root + "/overlay/overlay-static-1.apk", root + "/overlay/overlay-static-2.apk", - root + "/signature-overlay/signature-overlay.apk", - root + "/system-overlay/system-overlay.apk", - root + "/system-overlay-invalid/system-overlay-invalid.apk"})); -} - -TEST(FileUtilsTests, ReadFile) { - int pipefd[2]; - ASSERT_EQ(pipe2(pipefd, O_CLOEXEC), 0); - - ASSERT_EQ(write(pipefd[1], "foobar", 6), 6); - close(pipefd[1]); - - auto data = ReadFile(pipefd[0]); - ASSERT_THAT(data, NotNull()); - ASSERT_EQ(*data, "foobar"); - close(pipefd[0]); -} - #ifdef __ANDROID__ TEST(FileUtilsTests, UidHasWriteAccessToPath) { constexpr const char* tmp_path = "/data/local/tmp/test@idmap"; diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp index d896cf9c11ba..61751b33dcba 100644 --- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp +++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp @@ -159,131 +159,6 @@ TEST_F(Idmap2BinaryTests, Dump) { unlink(GetIdmapPath().c_str()); } -TEST_F(Idmap2BinaryTests, Scan) { - SKIP_TEST_IF_CANT_EXEC_IDMAP2; - - const std::string overlay_static_no_name_apk_path = - GetTestDataPath() + "/overlay/overlay-no-name-static.apk"; - const std::string overlay_static_1_apk_path = GetTestDataPath() + "/overlay/overlay-static-1.apk"; - const std::string overlay_static_2_apk_path = GetTestDataPath() + "/overlay/overlay-static-2.apk"; - const std::string idmap_static_no_name_path = - Idmap::CanonicalIdmapPathFor(GetTempDirPath(), overlay_static_no_name_apk_path); - const std::string idmap_static_1_path = - Idmap::CanonicalIdmapPathFor(GetTempDirPath(), overlay_static_1_apk_path); - const std::string idmap_static_2_path = - Idmap::CanonicalIdmapPathFor(GetTempDirPath(), overlay_static_2_apk_path); - - // single input directory, recursive - // clang-format off - auto result = ExecuteBinary({"idmap2", - "scan", - "--input-directory", GetTestDataPath(), - "--recursive", - "--target-package-name", "test.target", - "--target-apk-path", GetTargetApkPath(), - "--output-directory", GetTempDirPath(), - "--override-policy", "public"}); - // clang-format on - ASSERT_THAT(result, NotNull()); - ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; - std::stringstream expected; - expected << idmap_static_no_name_path << std::endl; - expected << idmap_static_1_path << std::endl; - expected << idmap_static_2_path << std::endl; - ASSERT_EQ(result->stdout, expected.str()); - - auto idmap_static_no_name_raw_string = utils::ReadFile(idmap_static_no_name_path); - auto idmap_static_no_name_raw_stream = std::istringstream(*idmap_static_no_name_raw_string); - auto idmap_static_no_name = Idmap::FromBinaryStream(idmap_static_no_name_raw_stream); - ASSERT_TRUE(idmap_static_no_name); - ASSERT_IDMAP(**idmap_static_no_name, GetTargetApkPath(), overlay_static_no_name_apk_path); - - auto idmap_static_1_raw_string = utils::ReadFile(idmap_static_1_path); - auto idmap_static_1_raw_stream = std::istringstream(*idmap_static_1_raw_string); - auto idmap_static_1 = Idmap::FromBinaryStream(idmap_static_1_raw_stream); - ASSERT_TRUE(idmap_static_1); - ASSERT_IDMAP(**idmap_static_1, GetTargetApkPath(), overlay_static_1_apk_path); - - auto idmap_static_2_raw_string = utils::ReadFile(idmap_static_2_path); - auto idmap_static_2_raw_stream = std::istringstream(*idmap_static_2_raw_string); - auto idmap_static_2 = Idmap::FromBinaryStream(idmap_static_2_raw_stream); - ASSERT_TRUE(idmap_static_2); - ASSERT_IDMAP(**idmap_static_2, GetTargetApkPath(), overlay_static_2_apk_path); - - unlink(idmap_static_no_name_path.c_str()); - unlink(idmap_static_2_path.c_str()); - unlink(idmap_static_1_path.c_str()); - - // multiple input directories, non-recursive - // clang-format off - result = ExecuteBinary({"idmap2", - "scan", - "--input-directory", GetTestDataPath() + "/target", - "--input-directory", GetTestDataPath() + "/overlay", - "--target-package-name", "test.target", - "--target-apk-path", GetTargetApkPath(), - "--output-directory", GetTempDirPath(), - "--override-policy", "public"}); - // clang-format on - ASSERT_THAT(result, NotNull()); - ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; - ASSERT_EQ(result->stdout, expected.str()); - unlink(idmap_static_no_name_path.c_str()); - unlink(idmap_static_2_path.c_str()); - unlink(idmap_static_1_path.c_str()); - - // the same input directory given twice, but no duplicate entries - // clang-format off - result = ExecuteBinary({"idmap2", - "scan", - "--input-directory", GetTestDataPath(), - "--input-directory", GetTestDataPath(), - "--recursive", - "--target-package-name", "test.target", - "--target-apk-path", GetTargetApkPath(), - "--output-directory", GetTempDirPath(), - "--override-policy", "public"}); - // clang-format on - ASSERT_THAT(result, NotNull()); - ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; - ASSERT_EQ(result->stdout, expected.str()); - unlink(idmap_static_no_name_path.c_str()); - unlink(idmap_static_2_path.c_str()); - unlink(idmap_static_1_path.c_str()); - - // no APKs in input-directory: ok, but no output - // clang-format off - result = ExecuteBinary({"idmap2", - "scan", - "--input-directory", GetTempDirPath(), - "--target-package-name", "test.target", - "--target-apk-path", GetTargetApkPath(), - "--output-directory", GetTempDirPath(), - "--override-policy", "public"}); - // clang-format on - ASSERT_THAT(result, NotNull()); - ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; - ASSERT_EQ(result->stdout, ""); - - // the signature idmap failing to generate should not cause scanning to fail - // clang-format off - result = ExecuteBinary({"idmap2", - "scan", - "--input-directory", GetTestDataPath(), - "--recursive", - "--target-package-name", "test.target", - "--target-apk-path", GetTargetApkPath(), - "--output-directory", GetTempDirPath(), - "--override-policy", "public"}); - // clang-format on - ASSERT_THAT(result, NotNull()); - ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; - ASSERT_EQ(result->stdout, expected.str()); - unlink(idmap_static_no_name_path.c_str()); - unlink(idmap_static_2_path.c_str()); - unlink(idmap_static_1_path.c_str()); -} - TEST_F(Idmap2BinaryTests, Lookup) { SKIP_TEST_IF_CANT_EXEC_IDMAP2; diff --git a/cmds/idmap2/valgrind.sh b/cmds/idmap2/valgrind.sh index b4ebab0c7ffe..84daeecdb21e 100755 --- a/cmds/idmap2/valgrind.sh +++ b/cmds/idmap2/valgrind.sh @@ -53,7 +53,5 @@ valgrind="valgrind --error-exitcode=1 -q --track-origins=yes --leak-check=full" _eval "idmap2 create" "$valgrind idmap2 create --policy public --target-apk-path $target_path --overlay-apk-path $overlay_path --idmap-path $idmap_path" _eval "idmap2 dump" "$valgrind idmap2 dump --idmap-path $idmap_path" _eval "idmap2 lookup" "$valgrind idmap2 lookup --idmap-path $idmap_path --config '' --resid test.target:string/str1" -_eval "idmap2 scan" "$valgrind idmap2 scan --input-directory ${prefix}/tests/data/overlay --recursive --target-package-name test.target --target-apk-path $target_path --output-directory /tmp --override-policy public" -_eval "idmap2 verify" "$valgrind idmap2 verify --idmap-path $idmap_path" _eval "idmap2_tests" "$valgrind $ANDROID_HOST_OUT/nativetest64/idmap2_tests/idmap2_tests" exit $errors diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index fc74fec45e47..e70eac88c769 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -586,7 +586,7 @@ message Atom { DataUsageBytesTransfer data_usage_bytes_transfer = 10082 [(module) = "framework", (truncate_timestamp) = true]; BytesTransferByTagAndMetered bytes_transfer_by_tag_and_metered = - 10083 [(module) = "framework"]; + 10083 [(module) = "framework", (truncate_timestamp) = true]; DNDModeProto dnd_mode_rule = 10084 [(module) = "framework"]; GeneralExternalStorageAccessStats general_external_storage_access_stats = 10085 [(module) = "mediaprovider"]; diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 7c4c19dde4d0..7a6f5584401d 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -4941,4 +4941,19 @@ public class ActivityManager { throw e.rethrowFromSystemServer(); } } + + /** + * Resets the state of the {@link com.android.server.am.AppErrors} instance. + * This is intended for use with CTS only. + * @hide + */ + @TestApi + @RequiresPermission(Manifest.permission.RESET_APP_ERRORS) + public void resetAppErrors() { + try { + getService().resetAppErrors(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 7ba50cadd959..9e15c1fca077 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -103,17 +103,16 @@ public abstract class ActivityManagerInternal { IBinder whitelistToken, long duration); /** - * Allows for a {@link PendingIntent} to be whitelisted to start activities from background. + * Allows a {@link PendingIntent} to start activities from background. */ public abstract void setPendingIntentAllowBgActivityStarts( - IIntentSender target, IBinder whitelistToken, int flags); + IIntentSender target, IBinder allowlistToken, int flags); /** - * Voids {@link PendingIntent}'s privilege to be whitelisted to start activities from - * background. + * Voids {@link PendingIntent}'s privilege to start activities from background. */ public abstract void clearPendingIntentAllowBgActivityStarts(IIntentSender target, - IBinder whitelistToken); + IBinder allowlistToken); /** * Allow DeviceIdleController to tell us about what apps are whitelisted. diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java index bac432e42318..15237beee805 100644 --- a/core/java/android/app/ApplicationLoaders.java +++ b/core/java/android/app/ApplicationLoaders.java @@ -48,17 +48,18 @@ public class ApplicationLoaders { ClassLoader parent, String classLoaderName) { return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled, librarySearchPath, libraryPermittedPath, parent, classLoaderName, - null); + null, null); } ClassLoader getClassLoaderWithSharedLibraries( String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, String classLoaderName, - List<ClassLoader> sharedLibraries) { + List<ClassLoader> sharedLibraries, List<String> nativeSharedLibraries) { // For normal usage the cache key used is the same as the zip path. return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath, - libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries); + libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries, + nativeSharedLibraries); } /** @@ -77,14 +78,22 @@ public class ApplicationLoaders { return loader; } + // TODO(b/142191088): allow (Java) shared libraries to have <uses-native-library> + // Until that is supported, assume that all native shared libraries are used. + // "ALL" is a magic string that libnativeloader uses to unconditionally add all available + // native shared libraries to the classloader. + List<String> nativeSharedLibraries = new ArrayList<>(); + nativeSharedLibraries.add("ALL"); return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled, - librarySearchPath, libraryPermittedPath, parent, classLoaderName, sharedLibraries); + librarySearchPath, libraryPermittedPath, parent, classLoaderName, sharedLibraries, + nativeSharedLibraries); } private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, String cacheKey, - String classLoaderName, List<ClassLoader> sharedLibraries) { + String classLoaderName, List<ClassLoader> sharedLibraries, + List<String> nativeSharedLibraries) { /* * This is the parent we use if they pass "null" in. In theory * this should be the "system" class loader; in practice we @@ -113,7 +122,8 @@ public class ApplicationLoaders { ClassLoader classloader = ClassLoaderFactory.createClassLoader( zip, librarySearchPath, libraryPermittedPath, parent, - targetSdkVersion, isBundled, classLoaderName, sharedLibraries); + targetSdkVersion, isBundled, classLoaderName, sharedLibraries, + nativeSharedLibraries); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); @@ -185,7 +195,8 @@ public class ApplicationLoaders { // assume cached libraries work with current sdk since they are built-in ClassLoader classLoader = getClassLoader(path, Build.VERSION.SDK_INT, true /*isBundled*/, null /*librarySearchPath*/, null /*libraryPermittedPath*/, null /*parent*/, - null /*cacheKey*/, null /*classLoaderName*/, sharedLibraries /*sharedLibraries*/); + null /*cacheKey*/, null /*classLoaderName*/, sharedLibraries /*sharedLibraries*/, + null /* nativeSharedLibraries */); if (classLoader == null) { // bad configuration or break in classloading code @@ -255,7 +266,8 @@ public class ApplicationLoaders { // The cache key is passed separately to enable the stub WebView to be cached under the // stub's APK path, when the actual package path is the donor APK. return getClassLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null, - cacheKey, null /* classLoaderName */, null /* sharedLibraries */); + cacheKey, null /* classLoaderName */, null /* sharedLibraries */, + null /* nativeSharedLibraries */); } /** diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index befd58824e63..3b6a7b8f7592 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -686,4 +686,11 @@ interface IActivityManager { * Kills uid with the reason of permission change. */ void killUidForPermissionChange(int appId, int userId, String reason); + + /** + * Resets the state of the {@link com.android.server.am.AppErrors} instance. + * This is intended for testing within the CTS only and is protected by + * android.permission.RESET_APP_ERRORS. + */ + void resetAppErrors(); } diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index f9b48e710148..1dc54ddbac4b 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -412,6 +412,12 @@ public final class LoadedApk { return; } for (SharedLibraryInfo lib : sharedLibraries) { + if (lib.isNative()) { + // Native shared lib doesn't contribute to the native lib search path. Its name is + // sent to libnativeloader and then the native shared lib is exported from the + // default linker namespace. + continue; + } List<String> paths = lib.getAllCodePaths(); outSeenPaths.addAll(paths); for (String path : paths) { @@ -696,6 +702,12 @@ public final class LoadedApk { } List<ClassLoader> loaders = new ArrayList<>(); for (SharedLibraryInfo info : sharedLibraries) { + if (info.isNative()) { + // Native shared lib doesn't contribute to the native lib search path. Its name is + // sent to libnativeloader and then the native shared lib is exported from the + // default linker namespace. + continue; + } loaders.add(createSharedLibraryLoader( info, isBundledApp, librarySearchPath, libraryPermittedPath)); } @@ -898,10 +910,19 @@ public final class LoadedApk { mApplicationInfo.sharedLibraryInfos, isBundledApp, librarySearchPath, libraryPermittedPath); + List<String> nativeSharedLibraries = new ArrayList<>(); + if (mApplicationInfo.sharedLibraryInfos != null) { + for (SharedLibraryInfo info : mApplicationInfo.sharedLibraryInfos) { + if (info.isNative()) { + nativeSharedLibraries.add(info.getName()); + } + } + } + mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoaderWithSharedLibraries( zip, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath, libraryPermittedPath, mBaseClassLoader, - mApplicationInfo.classLoaderName, sharedLibraries); + mApplicationInfo.classLoaderName, sharedLibraries, nativeSharedLibraries); mAppComponentFactory = createAppFactory(mApplicationInfo, mDefaultClassLoader); setThreadPolicy(oldPolicy); diff --git a/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl index d8675f39d452..6e93af6a053b 100644 --- a/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl +++ b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl @@ -41,6 +41,7 @@ interface ITimeZoneDetectorService { TimeZoneConfiguration getConfiguration(); boolean updateConfiguration(in TimeZoneConfiguration configuration); void addConfigurationListener(ITimeZoneConfigurationListener listener); + void removeConfigurationListener(ITimeZoneConfigurationListener listener); boolean suggestManualTimeZone(in ManualTimeZoneSuggestion timeZoneSuggestion); void suggestTelephonyTimeZone(in TelephonyTimeZoneSuggestion timeZoneSuggestion); diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java index 621ef526aacf..7885613bfb59 100644 --- a/core/java/android/app/timezonedetector/TimeZoneDetector.java +++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java @@ -74,11 +74,26 @@ public interface TimeZoneDetector { boolean updateConfiguration(@NonNull TimeZoneConfiguration configuration); /** + * An interface that can be used to listen for changes to the time zone detector configuration. + */ + interface TimeZoneConfigurationListener { + /** Called when the configuration changes. There are no guarantees about the thread used. */ + void onChange(@NonNull TimeZoneConfiguration configuration); + } + + /** * Registers a listener that will be informed when the configuration changes. The complete * configuration is passed to the listener, not just the properties that have changed. */ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) - void addConfigurationListener(@NonNull ITimeZoneConfigurationListener listener); + void addConfigurationListener(@NonNull TimeZoneConfigurationListener listener); + + /** + * Removes a listener previously passed to + * {@link #addConfigurationListener(ITimeZoneConfigurationListener)} + */ + @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) + void removeConfigurationListener(@NonNull TimeZoneConfigurationListener listener); /** * A shared utility method to create a {@link ManualTimeZoneSuggestion}. diff --git a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java index 978cb218fbba..6bd365fad6f6 100644 --- a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java +++ b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java @@ -21,6 +21,7 @@ import android.content.Context; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; +import android.util.ArraySet; import android.util.Log; /** @@ -34,13 +35,16 @@ public final class TimeZoneDetectorImpl implements TimeZoneDetector { private final ITimeZoneDetectorService mITimeZoneDetectorService; + private ITimeZoneConfigurationListener mConfigurationReceiver; + private ArraySet<TimeZoneConfigurationListener> mConfigurationListeners; + public TimeZoneDetectorImpl() throws ServiceNotFoundException { mITimeZoneDetectorService = ITimeZoneDetectorService.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.TIME_ZONE_DETECTOR_SERVICE)); } @Override - @NonNull + @NonNull public TimeZoneCapabilities getCapabilities() { if (DEBUG) { Log.d(TAG, "getCapabilities called"); @@ -78,14 +82,70 @@ public final class TimeZoneDetectorImpl implements TimeZoneDetector { } @Override - public void addConfigurationListener(@NonNull ITimeZoneConfigurationListener listener) { + public void addConfigurationListener(@NonNull TimeZoneConfigurationListener listener) { if (DEBUG) { Log.d(TAG, "addConfigurationListener called: " + listener); } - try { - mITimeZoneDetectorService.addConfigurationListener(listener); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + synchronized (this) { + if (mConfigurationListeners.contains(listener)) { + return; + } + if (mConfigurationReceiver == null) { + ITimeZoneConfigurationListener iListener = + new ITimeZoneConfigurationListener.Stub() { + @Override + public void onChange(@NonNull TimeZoneConfiguration configuration) { + notifyConfigurationListeners(configuration); + } + }; + mConfigurationReceiver = iListener; + } + if (mConfigurationListeners == null) { + mConfigurationListeners = new ArraySet<>(); + } + + boolean wasEmpty = mConfigurationListeners.isEmpty(); + mConfigurationListeners.add(listener); + if (wasEmpty) { + try { + mITimeZoneDetectorService.addConfigurationListener(mConfigurationReceiver); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + } + + private void notifyConfigurationListeners(@NonNull TimeZoneConfiguration configuration) { + ArraySet<TimeZoneConfigurationListener> configurationListeners; + synchronized (this) { + configurationListeners = new ArraySet<>(mConfigurationListeners); + } + int size = configurationListeners.size(); + for (int i = 0; i < size; i++) { + configurationListeners.valueAt(i).onChange(configuration); + } + } + + @Override + public void removeConfigurationListener(@NonNull TimeZoneConfigurationListener listener) { + if (DEBUG) { + Log.d(TAG, "removeConfigurationListener called: " + listener); + } + + synchronized (this) { + if (mConfigurationListeners == null) { + return; + } + boolean wasEmpty = mConfigurationListeners.isEmpty(); + mConfigurationListeners.remove(listener); + if (mConfigurationListeners.isEmpty() && !wasEmpty) { + try { + mITimeZoneDetectorService.removeConfigurationListener(mConfigurationReceiver); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } } diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java index da2a3d885fc6..862563706da7 100644 --- a/core/java/android/content/pm/SharedLibraryInfo.java +++ b/core/java/android/content/pm/SharedLibraryInfo.java @@ -79,6 +79,7 @@ public final class SharedLibraryInfo implements Parcelable { private final long mVersion; private final @Type int mType; + private final boolean mIsNative; private final VersionedPackage mDeclaringPackage; private final List<VersionedPackage> mDependentPackages; private List<SharedLibraryInfo> mDependencies; @@ -93,13 +94,14 @@ public final class SharedLibraryInfo implements Parcelable { * @param type The lib type. * @param declaringPackage The package that declares the library. * @param dependentPackages The packages that depend on the library. + * @param isNative indicate if this shared lib is a native lib or not (i.e. java) * * @hide */ public SharedLibraryInfo(String path, String packageName, List<String> codePaths, String name, long version, int type, VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages, - List<SharedLibraryInfo> dependencies) { + List<SharedLibraryInfo> dependencies, boolean isNative) { mPath = path; mPackageName = packageName; mCodePaths = codePaths; @@ -109,6 +111,16 @@ public final class SharedLibraryInfo implements Parcelable { mDeclaringPackage = declaringPackage; mDependentPackages = dependentPackages; mDependencies = dependencies; + mIsNative = isNative; + } + + /** @hide */ + public SharedLibraryInfo(String path, String packageName, List<String> codePaths, + String name, long version, int type, + VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages, + List<SharedLibraryInfo> dependencies) { + this(path, packageName, codePaths, name, version, type, declaringPackage, dependentPackages, + dependencies, false /* isNative */); } private SharedLibraryInfo(Parcel parcel) { @@ -125,6 +137,7 @@ public final class SharedLibraryInfo implements Parcelable { mDeclaringPackage = parcel.readParcelable(null); mDependentPackages = parcel.readArrayList(null); mDependencies = parcel.createTypedArrayList(SharedLibraryInfo.CREATOR); + mIsNative = parcel.readBoolean(); } /** @@ -137,6 +150,15 @@ public final class SharedLibraryInfo implements Parcelable { } /** + * Tells whether this library is a native shared library or not. + * + * @hide + */ + public boolean isNative() { + return mIsNative; + } + + /** * Gets the library name an app defines in its manifest * to depend on the library. * @@ -320,6 +342,7 @@ public final class SharedLibraryInfo implements Parcelable { parcel.writeParcelable(mDeclaringPackage, flags); parcel.writeList(mDependentPackages); parcel.writeTypedList(mDependencies); + parcel.writeBoolean(mIsNative); } private static String typeToString(int type) { diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java index 2ee0ad67b108..872098c8689e 100644 --- a/core/java/android/content/pm/parsing/ParsingPackage.java +++ b/core/java/android/content/pm/parsing/ParsingPackage.java @@ -92,6 +92,10 @@ public interface ParsingPackage extends ParsingPackageRead { ParsingPackage addUsesOptionalLibrary(String libraryName); + ParsingPackage addUsesNativeLibrary(String libraryName); + + ParsingPackage addUsesOptionalNativeLibrary(String libraryName); + ParsingPackage addUsesStaticLibrary(String libraryName); ParsingPackage addUsesStaticLibraryCertDigests(String[] certSha256Digests); @@ -219,6 +223,8 @@ public interface ParsingPackage extends ParsingPackageRead { ParsingPackage removeUsesOptionalLibrary(String libraryName); + ParsingPackage removeUsesOptionalNativeLibrary(String libraryName); + ParsingPackage setAnyDensity(int anyDensity); ParsingPackage setAppComponentFactory(String appComponentFactory); diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java index f932bc250e28..0c0dc313087e 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java +++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java @@ -186,6 +186,13 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @NonNull @DataClass.ParcelWith(ForInternedStringList.class) + protected List<String> usesNativeLibraries = emptyList(); + @NonNull + @DataClass.ParcelWith(ForInternedStringList.class) + protected List<String> usesOptionalNativeLibraries = emptyList(); + + @NonNull + @DataClass.ParcelWith(ForInternedStringList.class) private List<String> usesStaticLibraries = emptyList(); @Nullable private long[] usesStaticLibrariesVersions; @@ -669,6 +676,27 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { } @Override + public final ParsingPackageImpl addUsesOptionalNativeLibrary(String libraryName) { + this.usesOptionalNativeLibraries = CollectionUtils.add(this.usesOptionalNativeLibraries, + TextUtils.safeIntern(libraryName)); + return this; + } + + @Override + public final ParsingPackageImpl addUsesNativeLibrary(String libraryName) { + this.usesNativeLibraries = CollectionUtils.add(this.usesNativeLibraries, + TextUtils.safeIntern(libraryName)); + return this; + } + + + @Override public ParsingPackageImpl removeUsesOptionalNativeLibrary(String libraryName) { + this.usesOptionalNativeLibraries = CollectionUtils.remove(this.usesOptionalNativeLibraries, + libraryName); + return this; + } + + @Override public ParsingPackageImpl addUsesStaticLibrary(String libraryName) { this.usesStaticLibraries = CollectionUtils.add(this.usesStaticLibraries, TextUtils.safeIntern(libraryName)); @@ -982,6 +1010,8 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { sForInternedStringList.parcel(this.libraryNames, dest, flags); sForInternedStringList.parcel(this.usesLibraries, dest, flags); sForInternedStringList.parcel(this.usesOptionalLibraries, dest, flags); + sForInternedStringList.parcel(this.usesNativeLibraries, dest, flags); + sForInternedStringList.parcel(this.usesOptionalNativeLibraries, dest, flags); sForInternedStringList.parcel(this.usesStaticLibraries, dest, flags); dest.writeLongArray(this.usesStaticLibrariesVersions); @@ -1144,6 +1174,8 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { this.libraryNames = sForInternedStringList.unparcel(in); this.usesLibraries = sForInternedStringList.unparcel(in); this.usesOptionalLibraries = sForInternedStringList.unparcel(in); + this.usesNativeLibraries = sForInternedStringList.unparcel(in); + this.usesOptionalNativeLibraries = sForInternedStringList.unparcel(in); this.usesStaticLibraries = sForInternedStringList.unparcel(in); this.usesStaticLibrariesVersions = in.createLongArray(); @@ -1417,6 +1449,18 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @NonNull @Override + public List<String> getUsesNativeLibraries() { + return usesNativeLibraries; + } + + @NonNull + @Override + public List<String> getUsesOptionalNativeLibraries() { + return usesOptionalNativeLibraries; + } + + @NonNull + @Override public List<String> getUsesStaticLibraries() { return usesStaticLibraries; } diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java index 5b53c18b820c..7e0fe7dc41bf 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageRead.java +++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java @@ -230,6 +230,19 @@ public interface ParsingPackageRead extends Parcelable { @NonNull List<String> getUsesOptionalLibraries(); + /** @see R.styleabele#AndroidManifestUsesNativeLibrary */ + @NonNull + List<String> getUsesNativeLibraries(); + + /** + * Like {@link #getUsesNativeLibraries()}, but marked optional by setting + * {@link R.styleable#AndroidManifestUsesNativeLibrary_required} to false . Application is + * expected to handle absence manually. + * @see R.styleable#AndroidManifestUsesNativeLibrary + */ + @NonNull + List<String> getUsesOptionalNativeLibraries(); + /** * TODO(b/135203078): Move static library stuff to an inner data class * @see R.styleable#AndroidManifestUsesStaticLibrary diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java index 3688f1bda979..e1f08f3e55a1 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java +++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java @@ -701,6 +701,8 @@ public class ParsingPackageUtils { return parseUsesStaticLibrary(input, pkg, res, parser); case "uses-library": return parseUsesLibrary(input, pkg, res, parser); + case "uses-native-library": + return parseUsesNativeLibrary(input, pkg, res, parser); case "uses-package": // Dependencies for app installers; we don't currently try to // enforce this. @@ -2017,6 +2019,8 @@ public class ParsingPackageUtils { return parseUsesStaticLibrary(input, pkg, res, parser); case "uses-library": return parseUsesLibrary(input, pkg, res, parser); + case "uses-native-library": + return parseUsesNativeLibrary(input, pkg, res, parser); case "processes": return parseProcesses(input, pkg, res, parser, mSeparateProcesses, flags); case "uses-package": @@ -2178,6 +2182,37 @@ public class ParsingPackageUtils { } @NonNull + private static ParseResult<ParsingPackage> parseUsesNativeLibrary(ParseInput input, + ParsingPackage pkg, Resources res, XmlResourceParser parser) { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesNativeLibrary); + try { + // Note: don't allow this value to be a reference to a resource + // that may change. + String lname = sa.getNonResourceString( + R.styleable.AndroidManifestUsesNativeLibrary_name); + boolean req = sa.getBoolean(R.styleable.AndroidManifestUsesNativeLibrary_required, + true); + + if (lname != null) { + if (req) { + // Upgrade to treat as stronger constraint + pkg.addUsesNativeLibrary(lname) + .removeUsesOptionalNativeLibrary(lname); + } else { + // Ignore if someone already defined as required + if (!ArrayUtils.contains(pkg.getUsesNativeLibraries(), lname)) { + pkg.addUsesOptionalNativeLibrary(lname); + } + } + } + + return input.success(pkg); + } finally { + sa.recycle(); + } + } + + @NonNull private static ParseResult<ParsingPackage> parseProcesses(ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser, String[] separateProcesses, int flags) throws IOException, XmlPullParserException { diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 15a184f0e5ef..62c7b85fa62d 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -1573,7 +1573,6 @@ public final class AssetManager implements AutoCloseable { private static native long nativeAssetGetLength(long assetPtr); private static native long nativeAssetGetRemainingLength(long assetPtr); - private static native String[] nativeCreateIdmapsForStaticOverlaysTargetingAndroid(); private static native @Nullable Map nativeGetOverlayableMap(long ptr, @NonNull String packageName); private static native @Nullable String nativeGetOverlayablesToString(long ptr, diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index fb44b0b66fd8..ba0636fa80ff 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -83,7 +83,7 @@ interface IInputManager { int isMicMuted(); // Input device vibrator control. - void vibrate(int deviceId, in long[] pattern, int repeat, IBinder token); + void vibrate(int deviceId, in long[] pattern, in int[] amplitudes, int repeat, IBinder token); void cancelVibrate(int deviceId, IBinder token); void setPointerIconType(int typeId); diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 72217a1196ea..f0faeb078386 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -54,8 +54,8 @@ import com.android.internal.os.SomeArgs; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; -import java.util.concurrent.Executor; import java.util.List; +import java.util.concurrent.Executor; /** * Provides information about input devices and available key layouts. @@ -1298,14 +1298,17 @@ public final class InputManager { public void vibrate(int uid, String opPkg, VibrationEffect effect, String reason, AudioAttributes attributes) { long[] pattern; + int[] amplitudes; int repeat; if (effect instanceof VibrationEffect.OneShot) { VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) effect; pattern = new long[] { 0, oneShot.getDuration() }; + amplitudes = new int[] { 0, oneShot.getAmplitude() }; repeat = -1; } else if (effect instanceof VibrationEffect.Waveform) { VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) effect; pattern = waveform.getTimings(); + amplitudes = waveform.getAmplitudes(); repeat = waveform.getRepeatIndex(); } else { // TODO: Add support for prebaked effects @@ -1314,7 +1317,7 @@ public final class InputManager { } try { - mIm.vibrate(mDeviceId, pattern, repeat, mToken); + mIm.vibrate(mDeviceId, pattern, amplitudes, repeat, mToken); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl index d2fc1d3be40c..ce6c0ffbc10b 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -32,7 +32,6 @@ interface IPowerManager @UnsupportedAppUsage void releaseWakeLock(IBinder lock, int flags); void updateWakeLockUids(IBinder lock, in int[] uids); - oneway void powerHint(int hintId, int data); oneway void setPowerBoost(int boost, int durationMs); oneway void setPowerMode(int mode, boolean enabled); diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java index 653a5594f495..e30a40964992 100644 --- a/core/java/android/os/PowerManagerInternal.java +++ b/core/java/android/os/PowerManagerInternal.java @@ -196,12 +196,6 @@ public abstract class PowerManagerInternal { public abstract void uidIdle(int uid); /** - * The hintId sent through this method should be in-line with the - * PowerHint defined in android/hardware/power/<version 1.0 & up>/IPower.h - */ - public abstract void powerHint(int hintId, int data); - - /** * Boost: It is sent when user interacting with the device, for example, * touchscreen events are incoming. * Defined in hardware/interfaces/power/aidl/android/hardware/power/Boost.aidl diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java index 38ba47ab3701..ff1bcf6b3c5e 100644 --- a/core/java/android/os/UserHandle.java +++ b/core/java/android/os/UserHandle.java @@ -538,7 +538,7 @@ public final class UserHandle implements Parcelable { UserHandle other = (UserHandle)obj; return mHandle == other.mHandle; } - } catch (ClassCastException e) { + } catch (ClassCastException ignore) { } return false; } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index e1d48860b1e2..346522a504c8 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7614,6 +7614,8 @@ public final class Settings { * @hide */ @UnsupportedAppUsage + @TestApi + @SuppressLint("NoSettingsProvider") public static final String ANR_SHOW_BACKGROUND = "anr_show_background"; /** @@ -7621,6 +7623,8 @@ public final class Settings { * Otherwise, the process will be silently killed. * @hide */ + @TestApi + @SuppressLint("NoSettingsProvider") public static final String SHOW_FIRST_CRASH_DIALOG_DEV_OPTION = "show_first_crash_dialog_dev_option"; @@ -11862,21 +11866,6 @@ public final class Settings { "job_scheduler_quota_controller_constants"; /** - * Job scheduler TimeController specific settings. - * This is encoded as a key=value list, separated by commas. Ex: - * - * "skip_not_ready_jobs=true5,other_key=2" - * - * <p> - * Type: string - * - * @hide - * @see com.android.server.job.JobSchedulerService.Constants - */ - public static final String JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS = - "job_scheduler_time_controller_constants"; - - /** * ShortcutManager specific settings. * This is encoded as a key=value list, separated by commas. Ex: * @@ -14195,6 +14184,8 @@ public final class Settings { * Otherwise, the process will be silently killed. * @hide */ + @TestApi + @SuppressLint("NoSettingsProvider") public static final String SHOW_FIRST_CRASH_DIALOG = "show_first_crash_dialog"; /** diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java index 683c74737a2d..38e3b39f8cfc 100755 --- a/core/java/android/text/format/DateFormat.java +++ b/core/java/android/text/format/DateFormat.java @@ -19,14 +19,13 @@ package android.text.format; import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.icu.text.DateFormatSymbols; import android.icu.text.DateTimePatternGenerator; import android.provider.Settings; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.SpannedString; -import libcore.icu.LocaleData; - import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; @@ -286,8 +285,10 @@ public class DateFormat { */ @UnsupportedAppUsage public static String getTimeFormatString(Context context, int userHandle) { - final LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale); - return is24HourFormat(context, userHandle) ? d.timeFormat_Hm : d.timeFormat_hm; + DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance( + context.getResources().getConfiguration().locale); + return is24HourFormat(context, userHandle) ? dtpg.getBestPattern("Hm") + : dtpg.getBestPattern("hm"); } /** @@ -474,7 +475,8 @@ public class DateFormat { SpannableStringBuilder s = new SpannableStringBuilder(inFormat); int count; - LocaleData localeData = LocaleData.get(Locale.getDefault()); + DateFormatSymbols dfs = getIcuDateFormatSymbols(Locale.getDefault()); + String[] amPm = dfs.getAmPmStrings(); int len = inFormat.length(); @@ -496,14 +498,14 @@ public class DateFormat { switch (c) { case 'A': case 'a': - replacement = localeData.amPm[inDate.get(Calendar.AM_PM) - Calendar.AM]; + replacement = amPm[inDate.get(Calendar.AM_PM) - Calendar.AM]; break; case 'd': replacement = zeroPad(inDate.get(Calendar.DATE), count); break; case 'c': case 'E': - replacement = getDayOfWeekString(localeData, + replacement = getDayOfWeekString(dfs, inDate.get(Calendar.DAY_OF_WEEK), count, c); break; case 'K': // hour in am/pm (0-11) @@ -531,8 +533,7 @@ public class DateFormat { break; case 'L': case 'M': - replacement = getMonthString(localeData, - inDate.get(Calendar.MONTH), count, c); + replacement = getMonthString(dfs, inDate.get(Calendar.MONTH), count, c); break; case 'm': replacement = zeroPad(inDate.get(Calendar.MINUTE), count); @@ -565,25 +566,29 @@ public class DateFormat { } } - private static String getDayOfWeekString(LocaleData ld, int day, int count, int kind) { + private static String getDayOfWeekString(DateFormatSymbols dfs, int day, int count, int kind) { boolean standalone = (kind == 'c'); + int context = standalone ? DateFormatSymbols.STANDALONE : DateFormatSymbols.FORMAT; + final int width; if (count == 5) { - return standalone ? ld.tinyStandAloneWeekdayNames[day] : ld.tinyWeekdayNames[day]; + width = DateFormatSymbols.NARROW; } else if (count == 4) { - return standalone ? ld.longStandAloneWeekdayNames[day] : ld.longWeekdayNames[day]; + width = DateFormatSymbols.WIDE; } else { - return standalone ? ld.shortStandAloneWeekdayNames[day] : ld.shortWeekdayNames[day]; + width = DateFormatSymbols.ABBREVIATED; } + return dfs.getWeekdays(context, width)[day]; } - private static String getMonthString(LocaleData ld, int month, int count, int kind) { + private static String getMonthString(DateFormatSymbols dfs, int month, int count, int kind) { boolean standalone = (kind == 'L'); + int monthContext = standalone ? DateFormatSymbols.STANDALONE : DateFormatSymbols.FORMAT; if (count == 5) { - return standalone ? ld.tinyStandAloneMonthNames[month] : ld.tinyMonthNames[month]; + return dfs.getMonths(monthContext, DateFormatSymbols.NARROW)[month]; } else if (count == 4) { - return standalone ? ld.longStandAloneMonthNames[month] : ld.longMonthNames[month]; + return dfs.getMonths(monthContext, DateFormatSymbols.WIDE)[month]; } else if (count == 3) { - return standalone ? ld.shortStandAloneMonthNames[month] : ld.shortMonthNames[month]; + return dfs.getMonths(monthContext, DateFormatSymbols.ABBREVIATED)[month]; } else { // Calendar.JANUARY == 0, so add 1 to month. return zeroPad(month+1, count); @@ -678,4 +683,16 @@ public class DateFormat { private static String zeroPad(int inValue, int inMinDigits) { return String.format(Locale.getDefault(), "%0" + inMinDigits + "d", inValue); } + + /** + * We use Gregorian calendar for date formats in android.text.format and various UI widget + * historically. It's a utility method to get an {@link DateFormatSymbols} instance. Note that + * {@link DateFormatSymbols} has cache, and external cache is not needed unless same instance is + * requested repeatedly in the performance critical code. + * + * @hide + */ + public static DateFormatSymbols getIcuDateFormatSymbols(Locale locale) { + return new DateFormatSymbols(android.icu.util.GregorianCalendar.class, locale); + } } diff --git a/core/java/android/text/format/DateIntervalFormat.java b/core/java/android/text/format/DateIntervalFormat.java new file mode 100644 index 000000000000..de9ec7ab9ea9 --- /dev/null +++ b/core/java/android/text/format/DateIntervalFormat.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.text.format; + +import static android.text.format.DateUtils.FORMAT_SHOW_TIME; +import static android.text.format.DateUtils.FORMAT_UTC; + +import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; + +import android.icu.util.Calendar; +import android.icu.util.ULocale; +import android.util.LruCache; + +import com.android.internal.annotations.VisibleForTesting; + +import java.text.FieldPosition; +import java.util.TimeZone; + +/** + * A wrapper of {@link android.icu.text.DateIntervalFormat} used by {@link DateUtilsBridge}. + * + * @hide + */ +@VisibleForTesting(visibility = PACKAGE) +public final class DateIntervalFormat { + + private static final LruCache<String, android.icu.text.DateIntervalFormat> CACHED_FORMATTERS = + new LruCache<>(8); + + private DateIntervalFormat() { + } + + /** + * Format a date range. + */ + @VisibleForTesting(visibility = PACKAGE) + public static String formatDateRange(long startMs, long endMs, int flags, String olsonId) { + if ((flags & FORMAT_UTC) != 0) { + olsonId = "UTC"; + } + // We create a java.util.TimeZone here to use libcore's data and libcore's olson ID / + // pseudo-tz logic. + TimeZone tz = (olsonId != null) ? TimeZone.getTimeZone(olsonId) : TimeZone.getDefault(); + android.icu.util.TimeZone icuTimeZone = DateUtilsBridge.icuTimeZone(tz); + ULocale icuLocale = ULocale.getDefault(); + return formatDateRange(icuLocale, icuTimeZone, startMs, endMs, flags); + } + + /** + * Format a date range. This is our slightly more sensible internal API. + * A truly sane replacement would take a skeleton instead of int flags. + */ + @VisibleForTesting(visibility = PACKAGE) + public static String formatDateRange(ULocale icuLocale, android.icu.util.TimeZone icuTimeZone, + long startMs, long endMs, int flags) { + Calendar startCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale, startMs); + Calendar endCalendar; + if (startMs == endMs) { + endCalendar = startCalendar; + } else { + endCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale, endMs); + } + + // Special handling when the range ends at midnight: + // - If we're not showing times, and the range is non-empty, we fudge the end date so we + // don't count the day that's about to start. + // - If we are showing times, and the range ends at exactly 00:00 of the day following + // its start (which can be thought of as 24:00 the same day), we fudge the end date so we + // don't show the dates --- unless the start is anything displayed as 00:00, in which case + // we include both dates to disambiguate. + // This is not the behavior of icu4j's DateIntervalFormat, but it's the required behavior + // of Android's DateUtils.formatDateRange. + if (isExactlyMidnight(endCalendar)) { + boolean showTime = (flags & FORMAT_SHOW_TIME) == FORMAT_SHOW_TIME; + boolean endsDayAfterStart = DateUtilsBridge.dayDistance(startCalendar, endCalendar) + == 1; + if ((!showTime && startMs != endMs) + || (endsDayAfterStart + && !DateUtilsBridge.isDisplayMidnightUsingSkeleton(startCalendar))) { + endCalendar.add(Calendar.DAY_OF_MONTH, -1); + } + } + + String skeleton = DateUtilsBridge.toSkeleton(startCalendar, endCalendar, flags); + synchronized (CACHED_FORMATTERS) { + android.icu.text.DateIntervalFormat formatter = + getFormatter(skeleton, icuLocale, icuTimeZone); + return formatter.format(startCalendar, endCalendar, new StringBuffer(), + new FieldPosition(0)).toString(); + } + } + + private static android.icu.text.DateIntervalFormat getFormatter(String skeleton, ULocale locale, + android.icu.util.TimeZone icuTimeZone) { + String key = skeleton + "\t" + locale + "\t" + icuTimeZone; + android.icu.text.DateIntervalFormat formatter = CACHED_FORMATTERS.get(key); + if (formatter != null) { + return formatter; + } + formatter = android.icu.text.DateIntervalFormat.getInstance(skeleton, locale); + formatter.setTimeZone(icuTimeZone); + CACHED_FORMATTERS.put(key, formatter); + return formatter; + } + + private static boolean isExactlyMidnight(Calendar c) { + return c.get(Calendar.HOUR_OF_DAY) == 0 + && c.get(Calendar.MINUTE) == 0 + && c.get(Calendar.SECOND) == 0 + && c.get(Calendar.MILLISECOND) == 0; + } +} diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java index 51bea7753ba9..ff08269a93a4 100644 --- a/core/java/android/text/format/DateUtils.java +++ b/core/java/android/text/format/DateUtils.java @@ -20,6 +20,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; +import android.icu.text.DateFormatSymbols; import android.icu.text.MeasureFormat; import android.icu.text.MeasureFormat.FormatWidth; import android.icu.util.Measure; @@ -27,9 +28,6 @@ import android.icu.util.MeasureUnit; import com.android.internal.R; -import libcore.icu.DateIntervalFormat; -import libcore.icu.LocaleData; - import java.io.IOException; import java.time.Instant; import java.time.LocalDateTime; @@ -204,17 +202,23 @@ public class DateUtils */ @Deprecated public static String getDayOfWeekString(int dayOfWeek, int abbrev) { - LocaleData d = LocaleData.get(Locale.getDefault()); - String[] names; + DateFormatSymbols dfs = DateFormatSymbols.getInstance(); + final int width; switch (abbrev) { - case LENGTH_LONG: names = d.longWeekdayNames; break; - case LENGTH_MEDIUM: names = d.shortWeekdayNames; break; - case LENGTH_SHORT: names = d.shortWeekdayNames; break; // TODO - case LENGTH_SHORTER: names = d.shortWeekdayNames; break; // TODO - case LENGTH_SHORTEST: names = d.tinyWeekdayNames; break; - default: names = d.shortWeekdayNames; break; + case LENGTH_LONG: + width = DateFormatSymbols.WIDE; + break; + case LENGTH_SHORTEST: + width = DateFormatSymbols.NARROW; + break; + case LENGTH_MEDIUM: + case LENGTH_SHORT: // TODO + case LENGTH_SHORTER: // TODO + default: + width = DateFormatSymbols.ABBREVIATED; + break; } - return names[dayOfWeek]; + return dfs.getWeekdays(DateFormatSymbols.FORMAT, width)[dayOfWeek]; } /** @@ -226,7 +230,8 @@ public class DateUtils */ @Deprecated public static String getAMPMString(int ampm) { - return LocaleData.get(Locale.getDefault()).amPm[ampm - Calendar.AM]; + String[] amPm = DateFormat.getIcuDateFormatSymbols(Locale.getDefault()).getAmPmStrings(); + return amPm[ampm - Calendar.AM]; } /** @@ -242,17 +247,23 @@ public class DateUtils */ @Deprecated public static String getMonthString(int month, int abbrev) { - LocaleData d = LocaleData.get(Locale.getDefault()); - String[] names; + DateFormatSymbols dfs = DateFormat.getIcuDateFormatSymbols(Locale.getDefault()); + final int width; switch (abbrev) { - case LENGTH_LONG: names = d.longMonthNames; break; - case LENGTH_MEDIUM: names = d.shortMonthNames; break; - case LENGTH_SHORT: names = d.shortMonthNames; break; - case LENGTH_SHORTER: names = d.shortMonthNames; break; - case LENGTH_SHORTEST: names = d.tinyMonthNames; break; - default: names = d.shortMonthNames; break; + case LENGTH_LONG: + width = DateFormatSymbols.WIDE; + break; + case LENGTH_SHORTEST: + width = DateFormatSymbols.NARROW; + break; + case LENGTH_MEDIUM: + case LENGTH_SHORT: + case LENGTH_SHORTER: + default: + width = DateFormatSymbols.ABBREVIATED; + break; } - return names[month]; + return dfs.getMonths(DateFormatSymbols.FORMAT, width)[month]; } /** diff --git a/core/java/android/text/format/DateUtilsBridge.java b/core/java/android/text/format/DateUtilsBridge.java index 370d999abf3e..92ec9cf6d736 100644 --- a/core/java/android/text/format/DateUtilsBridge.java +++ b/core/java/android/text/format/DateUtilsBridge.java @@ -16,6 +16,20 @@ package android.text.format; +import static android.text.format.DateUtils.FORMAT_12HOUR; +import static android.text.format.DateUtils.FORMAT_24HOUR; +import static android.text.format.DateUtils.FORMAT_ABBREV_ALL; +import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH; +import static android.text.format.DateUtils.FORMAT_ABBREV_TIME; +import static android.text.format.DateUtils.FORMAT_ABBREV_WEEKDAY; +import static android.text.format.DateUtils.FORMAT_NO_MONTH_DAY; +import static android.text.format.DateUtils.FORMAT_NO_YEAR; +import static android.text.format.DateUtils.FORMAT_NUMERIC_DATE; +import static android.text.format.DateUtils.FORMAT_SHOW_DATE; +import static android.text.format.DateUtils.FORMAT_SHOW_TIME; +import static android.text.format.DateUtils.FORMAT_SHOW_WEEKDAY; +import static android.text.format.DateUtils.FORMAT_SHOW_YEAR; + import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; import android.icu.util.Calendar; @@ -33,24 +47,6 @@ import com.android.internal.annotations.VisibleForTesting; */ @VisibleForTesting(visibility = PACKAGE) public final class DateUtilsBridge { - // These are all public API in DateUtils. There are others, but they're either for use with - // other methods (like FORMAT_ABBREV_RELATIVE), don't internationalize (like FORMAT_CAP_AMPM), - // or have never been implemented anyway. - public static final int FORMAT_SHOW_TIME = 0x00001; - public static final int FORMAT_SHOW_WEEKDAY = 0x00002; - public static final int FORMAT_SHOW_YEAR = 0x00004; - public static final int FORMAT_NO_YEAR = 0x00008; - public static final int FORMAT_SHOW_DATE = 0x00010; - public static final int FORMAT_NO_MONTH_DAY = 0x00020; - public static final int FORMAT_12HOUR = 0x00040; - public static final int FORMAT_24HOUR = 0x00080; - public static final int FORMAT_UTC = 0x02000; - public static final int FORMAT_ABBREV_TIME = 0x04000; - public static final int FORMAT_ABBREV_WEEKDAY = 0x08000; - public static final int FORMAT_ABBREV_MONTH = 0x10000; - public static final int FORMAT_NUMERIC_DATE = 0x20000; - public static final int FORMAT_ABBREV_RELATIVE = 0x40000; - public static final int FORMAT_ABBREV_ALL = 0x80000; /** * Creates an immutable ICU timezone backed by the specified libcore timezone data. At the time diff --git a/core/java/android/text/format/RelativeDateTimeFormatter.java b/core/java/android/text/format/RelativeDateTimeFormatter.java index c5bca172873a..9096469699c1 100644 --- a/core/java/android/text/format/RelativeDateTimeFormatter.java +++ b/core/java/android/text/format/RelativeDateTimeFormatter.java @@ -16,14 +16,14 @@ package android.text.format; -import static android.text.format.DateUtilsBridge.FORMAT_ABBREV_ALL; -import static android.text.format.DateUtilsBridge.FORMAT_ABBREV_MONTH; -import static android.text.format.DateUtilsBridge.FORMAT_ABBREV_RELATIVE; -import static android.text.format.DateUtilsBridge.FORMAT_NO_YEAR; -import static android.text.format.DateUtilsBridge.FORMAT_NUMERIC_DATE; -import static android.text.format.DateUtilsBridge.FORMAT_SHOW_DATE; -import static android.text.format.DateUtilsBridge.FORMAT_SHOW_TIME; -import static android.text.format.DateUtilsBridge.FORMAT_SHOW_YEAR; +import static android.text.format.DateUtils.FORMAT_ABBREV_ALL; +import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH; +import static android.text.format.DateUtils.FORMAT_ABBREV_RELATIVE; +import static android.text.format.DateUtils.FORMAT_NO_YEAR; +import static android.text.format.DateUtils.FORMAT_NUMERIC_DATE; +import static android.text.format.DateUtils.FORMAT_SHOW_DATE; +import static android.text.format.DateUtils.FORMAT_SHOW_TIME; +import static android.text.format.DateUtils.FORMAT_SHOW_YEAR; import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; diff --git a/core/java/android/text/format/TimeFormatter.java b/core/java/android/text/format/TimeFormatter.java index cd541f2b829f..c71dfbbafd40 100644 --- a/core/java/android/text/format/TimeFormatter.java +++ b/core/java/android/text/format/TimeFormatter.java @@ -21,11 +21,11 @@ package android.text.format; import android.content.res.Resources; +import android.icu.text.DateFormatSymbols; +import android.icu.text.DecimalFormatSymbols; import com.android.i18n.timezone.ZoneInfoData; -import libcore.icu.LocaleData; - import java.nio.CharBuffer; import java.time.Instant; import java.time.LocalDateTime; @@ -52,15 +52,17 @@ class TimeFormatter { private static final int DAYSPERNYEAR = 365; /** - * The Locale for which the cached LocaleData and formats have been loaded. + * The Locale for which the cached symbols and formats have been loaded. */ private static Locale sLocale; - private static LocaleData sLocaleData; + private static DateFormatSymbols sDateFormatSymbols; + private static DecimalFormatSymbols sDecimalFormatSymbols; private static String sTimeOnlyFormat; private static String sDateOnlyFormat; private static String sDateTimeFormat; - private final LocaleData localeData; + private final DateFormatSymbols dateFormatSymbols; + private final DecimalFormatSymbols decimalFormatSymbols; private final String dateTimeFormat; private final String timeOnlyFormat; private final String dateOnlyFormat; @@ -74,7 +76,8 @@ class TimeFormatter { if (sLocale == null || !(locale.equals(sLocale))) { sLocale = locale; - sLocaleData = LocaleData.get(locale); + sDateFormatSymbols = DateFormat.getIcuDateFormatSymbols(locale); + sDecimalFormatSymbols = DecimalFormatSymbols.getInstance(locale); Resources r = Resources.getSystem(); sTimeOnlyFormat = r.getString(com.android.internal.R.string.time_of_day); @@ -82,10 +85,11 @@ class TimeFormatter { sDateTimeFormat = r.getString(com.android.internal.R.string.date_and_time); } + this.dateFormatSymbols = sDateFormatSymbols; + this.decimalFormatSymbols = sDecimalFormatSymbols; this.dateTimeFormat = sDateTimeFormat; this.timeOnlyFormat = sTimeOnlyFormat; this.dateOnlyFormat = sDateOnlyFormat; - localeData = sLocaleData; } } @@ -167,12 +171,12 @@ class TimeFormatter { } private String localizeDigits(String s) { - if (localeData.zeroDigit == '0') { + if (decimalFormatSymbols.getZeroDigit() == '0') { return s; } int length = s.length(); - int offsetToLocalizedDigits = localeData.zeroDigit - '0'; + int offsetToLocalizedDigits = decimalFormatSymbols.getZeroDigit() - '0'; StringBuilder result = new StringBuilder(length); for (int i = 0; i < length; ++i) { char ch = s.charAt(i); @@ -215,35 +219,44 @@ class TimeFormatter { char currentChar = formatBuffer.get(formatBuffer.position()); switch (currentChar) { case 'A': - modifyAndAppend((wallTime.getWeekDay() < 0 - || wallTime.getWeekDay() >= DAYSPERWEEK) - ? "?" : localeData.longWeekdayNames[wallTime.getWeekDay() + 1], + modifyAndAppend( + (wallTime.getWeekDay() < 0 || wallTime.getWeekDay() >= DAYSPERWEEK) + ? "?" + : dateFormatSymbols.getWeekdays(DateFormatSymbols.FORMAT, + DateFormatSymbols.WIDE)[wallTime.getWeekDay() + 1], modifier); return false; case 'a': - modifyAndAppend((wallTime.getWeekDay() < 0 - || wallTime.getWeekDay() >= DAYSPERWEEK) - ? "?" : localeData.shortWeekdayNames[wallTime.getWeekDay() + 1], + modifyAndAppend( + (wallTime.getWeekDay() < 0 || wallTime.getWeekDay() >= DAYSPERWEEK) + ? "?" + : dateFormatSymbols.getWeekdays(DateFormatSymbols.FORMAT, + DateFormatSymbols.ABBREVIATED)[wallTime.getWeekDay() + 1], modifier); return false; case 'B': if (modifier == '-') { - modifyAndAppend((wallTime.getMonth() < 0 - || wallTime.getMonth() >= MONSPERYEAR) - ? "?" - : localeData.longStandAloneMonthNames[wallTime.getMonth()], + modifyAndAppend( + (wallTime.getMonth() < 0 || wallTime.getMonth() >= MONSPERYEAR) + ? "?" + : dateFormatSymbols.getMonths(DateFormatSymbols.STANDALONE, + DateFormatSymbols.WIDE)[wallTime.getMonth()], modifier); } else { - modifyAndAppend((wallTime.getMonth() < 0 - || wallTime.getMonth() >= MONSPERYEAR) - ? "?" : localeData.longMonthNames[wallTime.getMonth()], + modifyAndAppend( + (wallTime.getMonth() < 0 || wallTime.getMonth() >= MONSPERYEAR) + ? "?" + : dateFormatSymbols.getMonths(DateFormatSymbols.FORMAT, + DateFormatSymbols.WIDE)[wallTime.getMonth()], modifier); } return false; case 'b': case 'h': modifyAndAppend((wallTime.getMonth() < 0 || wallTime.getMonth() >= MONSPERYEAR) - ? "?" : localeData.shortMonthNames[wallTime.getMonth()], + ? "?" + : dateFormatSymbols.getMonths(DateFormatSymbols.FORMAT, + DateFormatSymbols.ABBREVIATED)[wallTime.getMonth()], modifier); return false; case 'C': @@ -310,12 +323,14 @@ class TimeFormatter { outputBuilder.append('\n'); return false; case 'p': - modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2)) ? localeData.amPm[1] - : localeData.amPm[0], modifier); + modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2)) + ? dateFormatSymbols.getAmPmStrings()[1] + : dateFormatSymbols.getAmPmStrings()[0], modifier); return false; case 'P': - modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2)) ? localeData.amPm[1] - : localeData.amPm[0], FORCE_LOWER_CASE); + modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2)) + ? dateFormatSymbols.getAmPmStrings()[1] + : dateFormatSymbols.getAmPmStrings()[0], FORCE_LOWER_CASE); return false; case 'R': formatInternal("%H:%M", wallTime, zoneInfoData); diff --git a/core/java/android/text/method/NumberKeyListener.java b/core/java/android/text/method/NumberKeyListener.java index d40015ee17a8..2b038dd11348 100644 --- a/core/java/android/text/method/NumberKeyListener.java +++ b/core/java/android/text/method/NumberKeyListener.java @@ -29,8 +29,6 @@ import android.text.format.DateFormat; import android.view.KeyEvent; import android.view.View; -import libcore.icu.LocaleData; - import java.util.Collection; import java.util.Locale; @@ -228,7 +226,7 @@ public abstract class NumberKeyListener extends BaseKeyListener if (locale == null) { return false; } - final String[] amPm = LocaleData.get(locale).amPm; + final String[] amPm = DateFormat.getIcuDateFormatSymbols(locale).getAmPmStrings(); for (int i = 0; i < amPm.length; i++) { for (int j = 0; j < amPm[i].length(); j++) { final char ch = amPm[i].charAt(j); diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 19eff72ca814..51b0c6b59f3c 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -487,6 +487,21 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int FLAG_TAINTED = 0x80000000; /** + * Private flag indicating that this event was synthesized by the system and should be delivered + * to the accessibility focused view first. When being dispatched such an event is not handled + * by predecessors of the accessibility focused view and after the event reaches that view the + * flag is cleared and normal event dispatch is performed. This ensures that the platform can + * click on any view that has accessibility focus which is semantically equivalent to asking the + * view to perform a click accessibility action but more generic as views not implementing click + * action correctly can still be activated. + * + * @hide + * @see #isTargetAccessibilityFocus() + * @see #setTargetAccessibilityFocus(boolean) + */ + public static final int FLAG_TARGET_ACCESSIBILITY_FOCUS = 0x40000000; + + /** * Flag indicating the motion event intersected the top edge of the screen. */ public static final int EDGE_TOP = 0x00000001; @@ -2140,6 +2155,20 @@ public final class MotionEvent extends InputEvent implements Parcelable { } /** @hide */ + public boolean isTargetAccessibilityFocus() { + final int flags = getFlags(); + return (flags & FLAG_TARGET_ACCESSIBILITY_FOCUS) != 0; + } + + /** @hide */ + public void setTargetAccessibilityFocus(boolean targetsFocus) { + final int flags = getFlags(); + nativeSetFlags(mNativePtr, targetsFocus + ? flags | FLAG_TARGET_ACCESSIBILITY_FOCUS + : flags & ~FLAG_TARGET_ACCESSIBILITY_FOCUS); + } + + /** @hide */ public final boolean isHoverExitPending() { final int flags = getFlags(); return (flags & FLAG_HOVER_EXIT_PENDING) != 0; diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 361c46a77850..6beea8764ed1 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -49,7 +49,6 @@ import android.os.Build; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; -import android.os.Trace; import android.util.ArrayMap; import android.util.Log; import android.util.SparseIntArray; @@ -1455,6 +1454,22 @@ public final class SurfaceControl implements Parcelable { + ", secure=" + secure + ", deviceProductInfo=" + deviceProductInfo + "}"; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DisplayInfo that = (DisplayInfo) o; + return isInternal == that.isInternal + && density == that.density + && secure == that.secure + && Objects.equals(deviceProductInfo, that.deviceProductInfo); + } + + @Override + public int hashCode() { + return Objects.hash(isInternal, density, secure, deviceProductInfo); + } } /** diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 4e63a3392d48..e951156ec4cc 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -14391,6 +14391,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public boolean dispatchTouchEvent(MotionEvent event) { // If the event should be handled by accessibility focus first. + if (event.isTargetAccessibilityFocus()) { + // We don't have focus or no virtual descendant has it, do not handle the event. + if (!isAccessibilityFocusedViewOrHost()) { + return false; + } + // We have focus and got the event, then use normal event dispatch. + event.setTargetAccessibilityFocus(false); + } boolean result = false; if (mInputEventConsistencyVerifier != null) { diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 4a37f8005c65..f648292d3118 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -2048,8 +2048,26 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager for (int i = childrenCount - 1; i >= 0; i--) { final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex); + View childWithAccessibilityFocus = + event.isTargetAccessibilityFocus() + ? findChildWithAccessibilityFocus() + : null; + if (!child.canReceivePointerEvents() || !isTransformedTouchPointInView(x, y, child, null)) { + + // If there is a view that has accessibility focus we want it + // to get the event first and if not handled we will perform a + // normal dispatch. We may do a double iteration but this is + // safer given the timeframe. + if (childWithAccessibilityFocus != null) { + if (childWithAccessibilityFocus != child) { + continue; + } + childWithAccessibilityFocus = null; + i = childrenCount - 1; + } + event.setTargetAccessibilityFocus(false); continue; } final PointerIcon pointerIcon = @@ -2617,6 +2635,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager mInputEventConsistencyVerifier.onTouchEvent(ev, 1); } + // If the event targets the accessibility focused view and this is it, start + // normal event dispatch. Maybe a descendant is what will handle the click. + if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) { + ev.setTargetAccessibilityFocus(false); + } + boolean handled = false; if (onFilterTouchEventForSecurity(ev)) { final int action = ev.getAction(); @@ -2647,6 +2671,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // so this view group continues to intercept touches. intercepted = true; } + + // If intercepted, start normal event dispatch. Also if there is already + // a view that is handling the gesture, do normal event dispatch. + if (intercepted || mFirstTouchTarget != null) { + ev.setTargetAccessibilityFocus(false); + } + // Check for cancelation. final boolean canceled = resetCancelNextUpFlag(this) || actionMasked == MotionEvent.ACTION_CANCEL; @@ -2658,6 +2689,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager TouchTarget newTouchTarget = null; boolean alreadyDispatchedToNewTouchTarget = false; if (!canceled && !intercepted) { + // If the event is targeting accessibility focus we give it to the + // view that has accessibility focus and if it does not handle it + // we clear the flag and dispatch the event to all children as usual. + // We are looking up the accessibility focused host to avoid keeping + // state since these events are very rare. + View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus() + ? findChildWithAccessibilityFocus() : null; + if (actionMasked == MotionEvent.ACTION_DOWN || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN) || actionMasked == MotionEvent.ACTION_HOVER_MOVE) { @@ -2720,6 +2759,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager alreadyDispatchedToNewTouchTarget = true; break; } + + // The accessibility focus didn't handle the event, so clear + // the flag and do a normal dispatch to all children. + ev.setTargetAccessibilityFocus(false); } if (preorderedList != null) preorderedList.clear(); } @@ -2803,6 +2846,34 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return buildOrderedChildList(); } + /** + * Finds the child which has accessibility focus. + * + * @return The child that has focus. + */ + private View findChildWithAccessibilityFocus() { + ViewRootImpl viewRoot = getViewRootImpl(); + if (viewRoot == null) { + return null; + } + + View current = viewRoot.getAccessibilityFocusedHost(); + if (current == null) { + return null; + } + + ViewParent parent = current.getParent(); + while (parent instanceof View) { + if (parent == this) { + return current; + } + current = (View) parent; + parent = current.getParent(); + } + + return null; + } + /** * Resets all touch state in preparation for a new cycle. */ @@ -3258,8 +3329,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } default: throw new IllegalStateException("descendant focusability must be " - + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS " - + "but is " + descendantFocusability); + + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS " + + "but is " + descendantFocusability); } if (result && !isLayoutValid() && ((mPrivateFlags & PFLAG_WANTS_FOCUS) == 0)) { mPrivateFlags |= PFLAG_WANTS_FOCUS; @@ -4923,7 +4994,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (params == null) { params = generateDefaultLayoutParams(); if (params == null) { - throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null"); + throw new IllegalArgumentException( + "generateDefaultLayoutParams() cannot return null "); } } addView(child, index, params); diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 5d50515a1227..708e27771ef2 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -1768,7 +1768,7 @@ public class AccessibilityNodeInfo implements Parcelable { * <strong>Note:</strong> The primary usage of this API is for UI test automation * and in order to report the fully qualified view id if an {@link AccessibilityNodeInfo} * the client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS} - * flag when configuring his {@link android.accessibilityservice.AccessibilityService}. + * flag when configuring their {@link android.accessibilityservice.AccessibilityService}. * </p> * <p> * <strong>Note:</strong> If this view hierarchy has a {@link SurfaceView} embedding another @@ -3206,7 +3206,7 @@ public class AccessibilityNodeInfo implements Parcelable { * <strong>Note:</strong> The primary usage of this API is for UI test automation * and in order to report the source view id of an {@link AccessibilityNodeInfo} the * client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS} - * flag when configuring his {@link android.accessibilityservice.AccessibilityService}. + * flag when configuring their {@link android.accessibilityservice.AccessibilityService}. * </p> * @return The id resource name. diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java index 07fef76961f9..c5f2299e4f83 100644 --- a/core/java/android/view/inputmethod/EditorInfo.java +++ b/core/java/android/view/inputmethod/EditorInfo.java @@ -27,6 +27,7 @@ import android.os.LocaleList; import android.os.Parcel; import android.os.Parcelable; import android.os.UserHandle; +import android.text.Editable; import android.text.InputType; import android.text.TextUtils; import android.util.Printer; @@ -567,7 +568,8 @@ public class EditorInfo implements InputType, Parcelable { * editor wants to trim out the first 10 chars, subTextStart should be 10. */ public void setInitialSurroundingSubText(@NonNull CharSequence subText, int subTextStart) { - Objects.requireNonNull(subText); + CharSequence newSubText = Editable.Factory.getInstance().newEditable(subText); + Objects.requireNonNull(newSubText); // Swap selection start and end if necessary. final int subTextSelStart = initialSelStart > initialSelEnd @@ -575,7 +577,7 @@ public class EditorInfo implements InputType, Parcelable { final int subTextSelEnd = initialSelStart > initialSelEnd ? initialSelStart - subTextStart : initialSelEnd - subTextStart; - final int subTextLength = subText.length(); + final int subTextLength = newSubText.length(); // Unknown or invalid selection. if (subTextStart < 0 || subTextSelStart < 0 || subTextSelEnd > subTextLength) { mInitialSurroundingText = new InitialSurroundingText(); @@ -589,12 +591,12 @@ public class EditorInfo implements InputType, Parcelable { } if (subTextLength <= MEMORY_EFFICIENT_TEXT_LENGTH) { - mInitialSurroundingText = new InitialSurroundingText(subText, subTextSelStart, + mInitialSurroundingText = new InitialSurroundingText(newSubText, subTextSelStart, subTextSelEnd); return; } - trimLongSurroundingText(subText, subTextSelStart, subTextSelEnd); + trimLongSurroundingText(newSubText, subTextSelStart, subTextSelEnd); } /** diff --git a/core/java/android/widget/CalendarViewLegacyDelegate.java b/core/java/android/widget/CalendarViewLegacyDelegate.java index 1b899dbf6d03..33e64f4d37e9 100644 --- a/core/java/android/widget/CalendarViewLegacyDelegate.java +++ b/core/java/android/widget/CalendarViewLegacyDelegate.java @@ -38,8 +38,6 @@ import android.view.ViewGroup; import com.android.internal.R; -import libcore.icu.LocaleData; - import java.util.Locale; /** @@ -264,7 +262,7 @@ class CalendarViewLegacyDelegate extends CalendarView.AbstractCalendarViewDelega mShowWeekNumber = a.getBoolean(R.styleable.CalendarView_showWeekNumber, DEFAULT_SHOW_WEEK_NUMBER); mFirstDayOfWeek = a.getInt(R.styleable.CalendarView_firstDayOfWeek, - LocaleData.get(Locale.getDefault()).firstDayOfWeek); + Calendar.getInstance().getFirstDayOfWeek()); final String minDate = a.getString(R.styleable.CalendarView_minDate); if (!CalendarView.parseDate(minDate, mMinDate)) { CalendarView.parseDate(DEFAULT_MIN_DATE, mMinDate); diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java index 67fef13d23f2..7de2bd10482f 100644 --- a/core/java/android/widget/DayPickerView.java +++ b/core/java/android/widget/DayPickerView.java @@ -33,10 +33,6 @@ import com.android.internal.R; import com.android.internal.widget.ViewPager; import com.android.internal.widget.ViewPager.OnPageChangeListener; -import libcore.icu.LocaleData; - -import java.util.Locale; - class DayPickerView extends ViewGroup { private static final int DEFAULT_LAYOUT = R.layout.day_picker_content_material; private static final int DEFAULT_START_YEAR = 1900; @@ -86,7 +82,7 @@ class DayPickerView extends ViewGroup { attrs, a, defStyleAttr, defStyleRes); final int firstDayOfWeek = a.getInt(R.styleable.CalendarView_firstDayOfWeek, - LocaleData.get(Locale.getDefault()).firstDayOfWeek); + Calendar.getInstance().getFirstDayOfWeek()); final String minDate = a.getString(R.styleable.CalendarView_minDate); final String maxDate = a.getString(R.styleable.CalendarView_maxDate); diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 346bbb6fd409..c4eb39626d8b 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -6053,9 +6053,8 @@ public class Editor { return trueLine; } - final int lineHeight = layout.getLineBottom(prevLine) - layout.getLineTop(prevLine); - int slop = (int)(mLineSlopRatio - * (layout.getLineBottom(trueLine) - layout.getLineTop(trueLine))); + final int lineHeight = mTextView.getLineHeight(); + int slop = (int)(mLineSlopRatio * lineHeight); slop = Math.max(mLineChangeSlopMin, Math.min(mLineChangeSlopMax, lineHeight + slop)) - lineHeight; slop = Math.max(0, slop); diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java index baaf2a763487..3b482a8b2d54 100644 --- a/core/java/android/widget/NumberPicker.java +++ b/core/java/android/widget/NumberPicker.java @@ -34,6 +34,7 @@ import android.graphics.Paint; import android.graphics.Paint.Align; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.icu.text.DecimalFormatSymbols; import android.os.Build; import android.os.Bundle; import android.text.InputFilter; @@ -61,8 +62,6 @@ import android.view.inputmethod.InputMethodManager; import com.android.internal.R; -import libcore.icu.LocaleData; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -209,7 +208,7 @@ public class NumberPicker extends LinearLayout { } private static char getZeroDigit(Locale locale) { - return LocaleData.get(locale).zeroDigit; + return DecimalFormatSymbols.getInstance(locale).getZeroDigit(); } private java.util.Formatter createFormatter(Locale locale) { diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java index 61c77bc2f90e..695a253a04e0 100644 --- a/core/java/android/widget/SimpleMonthView.java +++ b/core/java/android/widget/SimpleMonthView.java @@ -27,6 +27,7 @@ import android.graphics.Paint.Align; import android.graphics.Paint.Style; import android.graphics.Rect; import android.graphics.Typeface; +import android.icu.text.DateFormatSymbols; import android.icu.text.DisplayContext; import android.icu.text.RelativeDateTimeFormatter; import android.icu.text.SimpleDateFormat; @@ -50,8 +51,6 @@ import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import com.android.internal.R; import com.android.internal.widget.ExploreByTouchHelper; -import libcore.icu.LocaleData; - import java.text.NumberFormat; import java.util.Locale; @@ -194,7 +193,8 @@ class SimpleMonthView extends View { private void updateDayOfWeekLabels() { // Use tiny (e.g. single-character) weekday names from ICU. The indices // for this list correspond to Calendar days, e.g. SUNDAY is index 1. - final String[] tinyWeekdayNames = LocaleData.get(mLocale).tinyWeekdayNames; + final String[] tinyWeekdayNames = DateFormatSymbols.getInstance(mLocale) + .getWeekdays(DateFormatSymbols.FORMAT, DateFormatSymbols.NARROW); for (int i = 0; i < DAYS_IN_WEEK; i++) { mDayOfWeekLabels[i] = tinyWeekdayNames[(mWeekStart + i - 1) % DAYS_IN_WEEK + 1]; } diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java index 6432438b6630..95c0e8658c57 100644 --- a/core/java/android/widget/TextClock.java +++ b/core/java/android/widget/TextClock.java @@ -30,6 +30,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.res.TypedArray; import android.database.ContentObserver; +import android.icu.text.DateTimePatternGenerator; import android.net.Uri; import android.os.Handler; import android.os.SystemClock; @@ -43,8 +44,6 @@ import android.view.inspector.InspectableProperty; import com.android.internal.R; -import libcore.icu.LocaleData; - import java.util.Calendar; import java.util.TimeZone; @@ -262,14 +261,11 @@ public class TextClock extends TextView { } private void init() { - if (mFormat12 == null || mFormat24 == null) { - LocaleData ld = LocaleData.get(getContext().getResources().getConfiguration().locale); - if (mFormat12 == null) { - mFormat12 = ld.timeFormat_hm; - } - if (mFormat24 == null) { - mFormat24 = ld.timeFormat_Hm; - } + if (mFormat12 == null) { + mFormat12 = getBestDateTimePattern("hm"); + } + if (mFormat24 == null) { + mFormat24 = getBestDateTimePattern("Hm"); } createTime(mTimeZone); @@ -510,13 +506,11 @@ public class TextClock extends TextView { private void chooseFormat() { final boolean format24Requested = is24HourModeEnabled(); - LocaleData ld = LocaleData.get(getContext().getResources().getConfiguration().locale); - if (format24Requested) { - mFormat = abc(mFormat24, mFormat12, ld.timeFormat_Hm); + mFormat = abc(mFormat24, mFormat12, getBestDateTimePattern("Hm")); mDescFormat = abc(mDescFormat24, mDescFormat12, mFormat); } else { - mFormat = abc(mFormat12, mFormat24, ld.timeFormat_hm); + mFormat = abc(mFormat12, mFormat24, getBestDateTimePattern("hm")); mDescFormat = abc(mDescFormat12, mDescFormat24, mFormat); } @@ -529,6 +523,12 @@ public class TextClock extends TextView { } } + private String getBestDateTimePattern(String skeleton) { + DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance( + getContext().getResources().getConfiguration().locale); + return dtpg.getBestPattern(skeleton); + } + /** * Returns a if not null, else return b if not null, else return c. */ diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java index 51b18473f1ac..1c219eb95479 100644 --- a/core/java/android/widget/TimePicker.java +++ b/core/java/android/widget/TimePicker.java @@ -24,9 +24,11 @@ import android.annotation.Widget; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; +import android.icu.text.DateFormatSymbols; import android.icu.util.Calendar; import android.os.Parcel; import android.os.Parcelable; +import android.text.format.DateFormat; import android.util.AttributeSet; import android.util.Log; import android.util.MathUtils; @@ -39,8 +41,6 @@ import android.view.inspector.InspectableProperty; import com.android.internal.R; -import libcore.icu.LocaleData; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Locale; @@ -421,11 +421,13 @@ public class TimePicker extends FrameLayout { static String[] getAmPmStrings(Context context) { final Locale locale = context.getResources().getConfiguration().locale; - final LocaleData d = LocaleData.get(locale); + DateFormatSymbols dfs = DateFormat.getIcuDateFormatSymbols(locale); + String[] amPm = dfs.getAmPmStrings(); + String[] narrowAmPm = dfs.getAmpmNarrowStrings(); final String[] result = new String[2]; - result[0] = d.amPm[0].length() > 4 ? d.narrowAm : d.amPm[0]; - result[1] = d.amPm[1].length() > 4 ? d.narrowPm : d.amPm[1]; + result[0] = amPm[0].length() > 4 ? narrowAmPm[0] : amPm[0]; + result[1] = amPm[1].length() > 4 ? narrowAmPm[1] : amPm[1]; return result; } diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java index 83c86d5ce36b..bd2fa5965bc9 100644 --- a/core/java/android/widget/TimePickerSpinnerDelegate.java +++ b/core/java/android/widget/TimePickerSpinnerDelegate.java @@ -35,8 +35,6 @@ import android.view.inputmethod.InputMethodManager; import com.android.internal.R; -import libcore.icu.LocaleData; - import java.util.Calendar; /** @@ -143,7 +141,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate { mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT); // Get the localized am/pm strings and use them in the spinner. - mAmPmStrings = getAmPmStrings(context); + mAmPmStrings = TimePicker.getAmPmStrings(context); // am/pm final View amPmView = mDelegator.findViewById(R.id.amPm); @@ -574,12 +572,4 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate { target.setContentDescription(mContext.getString(contDescResId)); } } - - public static String[] getAmPmStrings(Context context) { - String[] result = new String[2]; - LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale); - result[0] = d.amPm[0].length() > 4 ? d.narrowAm : d.amPm[0]; - result[1] = d.amPm[1].length() > 4 ? d.narrowPm : d.amPm[1]; - return result; - } } diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index fbf050ad08f6..3a89dcd96487 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -3134,6 +3134,7 @@ public class ChooserActivity extends ResolverActivity implements // ends up disabled. That's because at some point the old tab's vertical scrolling is // disabled and the new tab's is enabled. For context, see b/159997845 setVerticalScrollEnabled(true); + mResolverDrawerLayout.scrollNestedScrollableChildBackToTop(); } @Override diff --git a/core/java/com/android/internal/app/ProcessMap.java b/core/java/com/android/internal/app/ProcessMap.java index 81036f7ecba8..719c79b2540f 100644 --- a/core/java/com/android/internal/app/ProcessMap.java +++ b/core/java/com/android/internal/app/ProcessMap.java @@ -58,4 +58,8 @@ public class ProcessMap<E> { public int size() { return mMap.size(); } + + public void clear() { + mMap.clear(); + } } diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java index d238d0eb916d..ea3d2de13ce6 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java @@ -120,6 +120,13 @@ public final class SystemUiDeviceConfigFlags { */ public static final String HASH_SALT_MAX_DAYS = "hash_salt_max_days"; + // Flag related to Privacy Indicators + + /** + * Whether the Permissions Hub is showing. + */ + public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_2_enabled"; + // Flags related to Assistant /** diff --git a/core/java/com/android/internal/os/ClassLoaderFactory.java b/core/java/com/android/internal/os/ClassLoaderFactory.java index a18943c264f5..f83c5bdc4e28 100644 --- a/core/java/com/android/internal/os/ClassLoaderFactory.java +++ b/core/java/com/android/internal/os/ClassLoaderFactory.java @@ -101,7 +101,7 @@ public class ClassLoaderFactory { String librarySearchPath, String libraryPermittedPath, ClassLoader parent, int targetSdkVersion, boolean isNamespaceShared, String classLoaderName) { return createClassLoader(dexPath, librarySearchPath, libraryPermittedPath, - parent, targetSdkVersion, isNamespaceShared, classLoaderName, null); + parent, targetSdkVersion, isNamespaceShared, classLoaderName, null, null); } @@ -111,18 +111,24 @@ public class ClassLoaderFactory { public static ClassLoader createClassLoader(String dexPath, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, int targetSdkVersion, boolean isNamespaceShared, String classLoaderName, - List<ClassLoader> sharedLibraries) { + List<ClassLoader> sharedLibraries, List<String> nativeSharedLibraries) { final ClassLoader classLoader = createClassLoader(dexPath, librarySearchPath, parent, classLoaderName, sharedLibraries); + String sonameList = ""; + if (nativeSharedLibraries != null) { + sonameList = String.join(":", nativeSharedLibraries); + } + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "createClassloaderNamespace"); String errorMessage = createClassloaderNamespace(classLoader, targetSdkVersion, librarySearchPath, libraryPermittedPath, isNamespaceShared, - dexPath); + dexPath, + sonameList); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); if (errorMessage != null) { @@ -139,5 +145,6 @@ public class ClassLoaderFactory { String librarySearchPath, String libraryPermittedPath, boolean isNamespaceShared, - String dexPath); + String dexPath, + String sonameList); } diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java index dc8d57ab709e..a2de0aff5dfa 100644 --- a/core/java/com/android/internal/widget/PointerLocationView.java +++ b/core/java/com/android/internal/widget/PointerLocationView.java @@ -371,7 +371,7 @@ public class PointerLocationView extends View implements InputDeviceListener, } if (haveLast) { canvas.drawLine(lastX, lastY, x, y, mPathPaint); - final Paint paint = ps.mTraceCurrent[i] ? mCurrentPointPaint : mPaint; + final Paint paint = ps.mTraceCurrent[i - 1] ? mCurrentPointPaint : mPaint; canvas.drawPoint(lastX, lastY, paint); drawn = true; } diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java index 3f708f84750c..90eeabb47e9a 100644 --- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java +++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java @@ -464,11 +464,7 @@ public class ResolverDrawerLayout extends ViewGroup { smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, yvel); mDismissOnScrollerFinished = true; } else { - if (isNestedListChildScrolled()) { - mNestedListChild.smoothScrollToPosition(0); - } else if (isNestedRecyclerChildScrolled()) { - mNestedRecyclerChild.smoothScrollToPosition(0); - } + scrollNestedScrollableChildBackToTop(); smoothScrollTo(yvel < 0 ? 0 : mCollapsibleHeight, yvel); } } @@ -493,6 +489,17 @@ public class ResolverDrawerLayout extends ViewGroup { return handled; } + /** + * Scroll nested scrollable child back to top if it has been scrolled. + */ + public void scrollNestedScrollableChildBackToTop() { + if (isNestedListChildScrolled()) { + mNestedListChild.smoothScrollToPosition(0); + } else if (isNestedRecyclerChildScrolled()) { + mNestedRecyclerChild.smoothScrollToPosition(0); + } + } + private void onSecondaryPointerUp(MotionEvent ev) { final int pointerIndex = ev.getActionIndex(); final int pointerId = ev.getPointerId(pointerIndex); diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index 0eb3981ed598..957cc76b3e54 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -49,10 +49,12 @@ import libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; +import java.util.Arrays; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -104,11 +106,17 @@ public class SystemConfig { public final String name; public final String filename; public final String[] dependencies; + public final boolean isNative; SharedLibraryEntry(String name, String filename, String[] dependencies) { + this(name, filename, dependencies, false /* isNative */); + } + + SharedLibraryEntry(String name, String filename, String[] dependencies, boolean isNative) { this.name = name; this.filename = filename; this.dependencies = dependencies; + this.isNative = isNative; } } @@ -457,6 +465,7 @@ public class SystemConfig { log.traceBegin("readAllPermissions"); try { readAllPermissions(); + readPublicNativeLibrariesList(); } finally { log.traceEnd(); } @@ -1513,6 +1522,37 @@ public class SystemConfig { } } + private void readPublicNativeLibrariesList() { + readPublicLibrariesListFile(new File("/vendor/etc/public.libraries.txt")); + String[] dirs = {"/system/etc", "/system_ext/etc", "/product/etc"}; + for (String dir : dirs) { + for (File f : (new File(dir)).listFiles()) { + String name = f.getName(); + if (name.startsWith("public.libraries-") && name.endsWith(".txt")) { + readPublicLibrariesListFile(f); + } + } + } + } + + private void readPublicLibrariesListFile(File listFile) { + try (BufferedReader br = new BufferedReader(new FileReader(listFile))) { + String line; + while ((line = br.readLine()) != null) { + if (line.isEmpty() || line.startsWith("#")) { + continue; + } + // Line format is <soname> [abi]. We take the soname part. + String soname = line.trim().split(" ")[0]; + SharedLibraryEntry entry = new SharedLibraryEntry( + soname, soname, new String[0], true); + mSharedLibraries.put(entry.name, entry); + } + } catch (IOException e) { + Slog.w(TAG, "Failed to read public libraries file " + listFile, e); + } + } + private static boolean isSystemProcess() { return Process.myUid() == Process.SYSTEM_UID; } diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 3da2fa26ffe6..d6e8531fa6ca 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -853,9 +853,8 @@ static jboolean android_os_Debug_isVmapStack(JNIEnv *env, jobject clazz) } cfg_state = CONFIG_UNKNOWN; if (cfg_state == CONFIG_UNKNOWN) { - auto runtime_info = vintf::VintfObject::GetInstance() - ->getRuntimeInfo(false /* skip cache */, - vintf::RuntimeInfo::FetchFlag::CONFIG_GZ); + auto runtime_info = vintf::VintfObject::GetInstance()->getRuntimeInfo( + vintf::RuntimeInfo::FetchFlag::CONFIG_GZ); CHECK(runtime_info != nullptr) << "Kernel configs cannot be fetched. b/151092221"; const std::map<std::string, std::string>& configs = runtime_info->kernelConfigs(); std::map<std::string, std::string>::const_iterator it = configs.find("CONFIG_VMAP_STACK"); diff --git a/core/jni/android_os_VintfRuntimeInfo.cpp b/core/jni/android_os_VintfRuntimeInfo.cpp index 9379ea6dcd10..b0271b9e92af 100644 --- a/core/jni/android_os_VintfRuntimeInfo.cpp +++ b/core/jni/android_os_VintfRuntimeInfo.cpp @@ -29,14 +29,12 @@ namespace android { using vintf::RuntimeInfo; using vintf::VintfObject; -#define MAP_STRING_METHOD(javaMethod, cppString, flags) \ - static jstring android_os_VintfRuntimeInfo_##javaMethod(JNIEnv* env, jclass clazz) \ - { \ - std::shared_ptr<const RuntimeInfo> info = VintfObject::GetRuntimeInfo( \ - false /* skipCache */, flags); \ - if (info == nullptr) return nullptr; \ - return env->NewStringUTF((cppString).c_str()); \ - } \ +#define MAP_STRING_METHOD(javaMethod, cppString, flags) \ + static jstring android_os_VintfRuntimeInfo_##javaMethod(JNIEnv* env, jclass clazz) { \ + std::shared_ptr<const RuntimeInfo> info = VintfObject::GetRuntimeInfo(flags); \ + if (info == nullptr) return nullptr; \ + return env->NewStringUTF((cppString).c_str()); \ + } MAP_STRING_METHOD(getCpuInfo, info->cpuInfo(), RuntimeInfo::FetchFlag::CPU_INFO); MAP_STRING_METHOD(getOsName, info->osName(), RuntimeInfo::FetchFlag::CPU_VERSION); @@ -54,8 +52,8 @@ MAP_STRING_METHOD(getBootVbmetaAvbVersion, vintf::to_string(info->bootVbmetaAvbV static jlong android_os_VintfRuntimeInfo_getKernelSepolicyVersion(JNIEnv *env, jclass clazz) { - std::shared_ptr<const RuntimeInfo> info = VintfObject::GetRuntimeInfo( - false /* skipCache */, RuntimeInfo::FetchFlag::POLICYVERS); + std::shared_ptr<const RuntimeInfo> info = + VintfObject::GetRuntimeInfo(RuntimeInfo::FetchFlag::POLICYVERS); if (info == nullptr) return 0; return static_cast<jlong>(info->kernelSepolicyVersion()); } diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index e6881b3995a8..efca33aaf520 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -39,7 +39,6 @@ #include "androidfw/AssetManager2.h" #include "androidfw/AttributeResolution.h" #include "androidfw/MutexGuard.h" -#include "androidfw/PosixUtils.h" #include "androidfw/ResourceTypes.h" #include "androidfw/ResourceUtils.h" @@ -58,7 +57,6 @@ extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap); extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap); using ::android::base::StringPrintf; -using ::android::util::ExecuteBinary; namespace android { @@ -114,88 +112,6 @@ constexpr inline static ApkAssetsCookie JavaCookieToApkAssetsCookie(jint cookie) return cookie > 0 ? static_cast<ApkAssetsCookie>(cookie - 1) : kInvalidCookie; } -static jobjectArray NativeCreateIdmapsForStaticOverlaysTargetingAndroid(JNIEnv* env, - jclass /*clazz*/) { - // --input-directory can be given multiple times, but idmap2 expects the directory to exist - std::vector<std::string> input_dirs; - struct stat st; - if (stat(AssetManager::VENDOR_OVERLAY_DIR, &st) == 0) { - input_dirs.push_back(AssetManager::VENDOR_OVERLAY_DIR); - } - - if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) { - input_dirs.push_back(AssetManager::PRODUCT_OVERLAY_DIR); - } - - if (stat(AssetManager::SYSTEM_EXT_OVERLAY_DIR, &st) == 0) { - input_dirs.push_back(AssetManager::SYSTEM_EXT_OVERLAY_DIR); - } - - if (stat(AssetManager::ODM_OVERLAY_DIR, &st) == 0) { - input_dirs.push_back(AssetManager::ODM_OVERLAY_DIR); - } - - if (stat(AssetManager::OEM_OVERLAY_DIR, &st) == 0) { - input_dirs.push_back(AssetManager::OEM_OVERLAY_DIR); - } - - if (input_dirs.empty()) { - LOG(WARNING) << "no directories for idmap2 to scan"; - return env->NewObjectArray(0, g_stringClass, nullptr); - } - - if (access("/system/bin/idmap2", X_OK) == -1) { - PLOG(WARNING) << "unable to execute idmap2"; - return nullptr; - } - - std::vector<std::string> argv{"/system/bin/idmap2", - "scan", - "--recursive", - "--target-package-name", "android", - "--target-apk-path", "/system/framework/framework-res.apk", - "--output-directory", "/data/resource-cache"}; - - for (const auto& dir : input_dirs) { - argv.push_back("--input-directory"); - argv.push_back(dir); - } - - const auto result = ExecuteBinary(argv); - - if (!result) { - LOG(ERROR) << "failed to execute idmap2"; - return nullptr; - } - - if (result->status != 0) { - LOG(ERROR) << "idmap2: " << result->stderr; - return nullptr; - } - - std::vector<std::string> idmap_paths; - std::istringstream input(result->stdout); - std::string path; - while (std::getline(input, path)) { - idmap_paths.push_back(path); - } - - jobjectArray array = env->NewObjectArray(idmap_paths.size(), g_stringClass, nullptr); - if (array == nullptr) { - return nullptr; - } - for (size_t i = 0; i < idmap_paths.size(); i++) { - const std::string path = idmap_paths[i]; - jstring java_string = env->NewStringUTF(path.c_str()); - if (env->ExceptionCheck()) { - return nullptr; - } - env->SetObjectArrayElement(array, i, java_string); - env->DeleteLocalRef(java_string); - } - return array; -} - static jint CopyValue(JNIEnv* env, ApkAssetsCookie cookie, const Res_value& value, uint32_t ref, uint32_t type_spec_flags, ResTable_config* config, jobject out_typed_value) { env->SetIntField(out_typed_value, gTypedValueOffsets.mType, value.dataType); @@ -1563,8 +1479,6 @@ static const JNINativeMethod gAssetManagerMethods[] = { {"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength}, // System/idmap related methods. - {"nativeCreateIdmapsForStaticOverlaysTargetingAndroid", "()[Ljava/lang/String;", - (void*)NativeCreateIdmapsForStaticOverlaysTargetingAndroid}, {"nativeGetOverlayableMap", "(JLjava/lang/String;)Ljava/util/Map;", (void*)NativeGetOverlayableMap}, {"nativeGetOverlayablesToString", "(JLjava/lang/String;)Ljava/lang/String;", diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp index 8153166d4695..2436b23a45d0 100644 --- a/core/jni/android_view_InputChannel.cpp +++ b/core/jni/android_view_InputChannel.cpp @@ -43,25 +43,24 @@ static struct { class NativeInputChannel { public: - explicit NativeInputChannel(const sp<InputChannel>& inputChannel); + explicit NativeInputChannel(const std::shared_ptr<InputChannel>& inputChannel); ~NativeInputChannel(); - inline sp<InputChannel> getInputChannel() { return mInputChannel; } + inline std::shared_ptr<InputChannel> getInputChannel() { return mInputChannel; } void setDisposeCallback(InputChannelObjDisposeCallback callback, void* data); void dispose(JNIEnv* env, jobject obj); private: - sp<InputChannel> mInputChannel; + std::shared_ptr<InputChannel> mInputChannel; InputChannelObjDisposeCallback mDisposeCallback; void* mDisposeData; }; // ---------------------------------------------------------------------------- -NativeInputChannel::NativeInputChannel(const sp<InputChannel>& inputChannel) : - mInputChannel(inputChannel), mDisposeCallback(nullptr) { -} +NativeInputChannel::NativeInputChannel(const std::shared_ptr<InputChannel>& inputChannel) + : mInputChannel(inputChannel), mDisposeCallback(nullptr) {} NativeInputChannel::~NativeInputChannel() { } @@ -81,7 +80,7 @@ void NativeInputChannel::dispose(JNIEnv* env, jobject obj) { mDisposeCallback = nullptr; mDisposeData = nullptr; } - mInputChannel.clear(); + mInputChannel.reset(); } // ---------------------------------------------------------------------------- @@ -92,7 +91,8 @@ static NativeInputChannel* android_view_InputChannel_getNativeInputChannel(JNIEn return reinterpret_cast<NativeInputChannel*>(longPtr); } -sp<InputChannel> android_view_InputChannel_getInputChannel(JNIEnv* env, jobject inputChannelObj) { +std::shared_ptr<InputChannel> android_view_InputChannel_getInputChannel(JNIEnv* env, + jobject inputChannelObj) { NativeInputChannel* nativeInputChannel = android_view_InputChannel_getNativeInputChannel(env, inputChannelObj); return nativeInputChannel != nullptr ? nativeInputChannel->getInputChannel() : nullptr; @@ -109,8 +109,8 @@ void android_view_InputChannel_setDisposeCallback(JNIEnv* env, jobject inputChan } } -static jlong android_view_InputChannel_createInputChannel(JNIEnv* env, - sp<InputChannel> inputChannel) { +static jlong android_view_InputChannel_createInputChannel( + JNIEnv* env, std::shared_ptr<InputChannel> inputChannel) { std::unique_ptr<NativeInputChannel> nativeInputChannel = std::make_unique<NativeInputChannel>(inputChannel); @@ -122,8 +122,8 @@ static jlongArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* e ScopedUtfChars nameChars(env, nameObj); std::string name = nameChars.c_str(); - sp<InputChannel> serverChannel; - sp<InputChannel> clientChannel; + std::unique_ptr<InputChannel> serverChannel; + std::unique_ptr<InputChannel> clientChannel; status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel); if (result) { @@ -139,12 +139,12 @@ static jlongArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* e } jlong* outArray = env->GetLongArrayElements(channelPair, 0); - outArray[0] = android_view_InputChannel_createInputChannel(env, serverChannel); + outArray[0] = android_view_InputChannel_createInputChannel(env, std::move(serverChannel)); if (env->ExceptionCheck()) { return nullptr; } - outArray[1] = android_view_InputChannel_createInputChannel(env, clientChannel); + outArray[1] = android_view_InputChannel_createInputChannel(env, std::move(clientChannel)); if (env->ExceptionCheck()) { return nullptr; } @@ -180,7 +180,7 @@ static jlong android_view_InputChannel_nativeReadFromParcel(JNIEnv* env, jobject if (parcel) { bool isInitialized = parcel->readInt32(); if (isInitialized) { - sp<InputChannel> inputChannel = new InputChannel(); + std::shared_ptr<InputChannel> inputChannel = std::make_shared<InputChannel>(); inputChannel->readFromParcel(parcel); NativeInputChannel* nativeInputChannel = new NativeInputChannel(inputChannel); return reinterpret_cast<jlong>(nativeInputChannel); @@ -227,13 +227,13 @@ static jlong android_view_InputChannel_nativeDup(JNIEnv* env, jobject obj, jlong return 0; } - sp<InputChannel> inputChannel = nativeInputChannel->getInputChannel(); + std::shared_ptr<InputChannel> inputChannel = nativeInputChannel->getInputChannel(); if (inputChannel == nullptr) { jniThrowRuntimeException(env, "NativeInputChannel has no corresponding InputChannel"); return 0; } - sp<InputChannel> dupInputChannel = inputChannel->dup(); + std::shared_ptr<InputChannel> dupInputChannel = inputChannel->dup(); if (dupInputChannel == nullptr) { std::string message = android::base::StringPrintf( "Could not duplicate input channel %s", inputChannel->getName().c_str()); diff --git a/core/jni/android_view_InputChannel.h b/core/jni/android_view_InputChannel.h index 2ba2dc0516d0..8030c96ab19f 100644 --- a/core/jni/android_view_InputChannel.h +++ b/core/jni/android_view_InputChannel.h @@ -24,10 +24,11 @@ namespace android { typedef void (*InputChannelObjDisposeCallback)(JNIEnv* env, jobject inputChannelObj, - const sp<InputChannel>& inputChannel, void* data); + const std::shared_ptr<InputChannel>& inputChannel, + void* data); -extern sp<InputChannel> android_view_InputChannel_getInputChannel(JNIEnv* env, - jobject inputChannelObj); +extern std::shared_ptr<InputChannel> android_view_InputChannel_getInputChannel( + JNIEnv* env, jobject inputChannelObj); /* Sets a callback that is invoked when the InputChannel DVM object is disposed (or finalized). * This is used to automatically dispose of other native objects in the input dispatcher diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp index cc94d6ff5d67..979a69aa3ce2 100644 --- a/core/jni/android_view_InputEventReceiver.cpp +++ b/core/jni/android_view_InputEventReceiver.cpp @@ -55,9 +55,9 @@ static struct { class NativeInputEventReceiver : public LooperCallback { public: - NativeInputEventReceiver(JNIEnv* env, - jobject receiverWeak, const sp<InputChannel>& inputChannel, - const sp<MessageQueue>& messageQueue); + NativeInputEventReceiver(JNIEnv* env, jobject receiverWeak, + const std::shared_ptr<InputChannel>& inputChannel, + const sp<MessageQueue>& messageQueue); status_t initialize(); void dispose(); @@ -91,13 +91,14 @@ private: virtual int handleEvent(int receiveFd, int events, void* data) override; }; - -NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env, - jobject receiverWeak, const sp<InputChannel>& inputChannel, - const sp<MessageQueue>& messageQueue) : - mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)), - mInputConsumer(inputChannel), mMessageQueue(messageQueue), - mBatchedInputEventPending(false), mFdEvents(0) { +NativeInputEventReceiver::NativeInputEventReceiver( + JNIEnv* env, jobject receiverWeak, const std::shared_ptr<InputChannel>& inputChannel, + const sp<MessageQueue>& messageQueue) + : mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)), + mInputConsumer(inputChannel), + mMessageQueue(messageQueue), + mBatchedInputEventPending(false), + mFdEvents(0) { if (kDebugDispatchCycle) { ALOGD("channel '%s' ~ Initializing input event receiver.", getInputChannelName().c_str()); } @@ -356,8 +357,8 @@ status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject inputChannelObj, jobject messageQueueObj) { - sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, - inputChannelObj); + std::shared_ptr<InputChannel> inputChannel = + android_view_InputChannel_getInputChannel(env, inputChannelObj); if (inputChannel == nullptr) { jniThrowRuntimeException(env, "InputChannel is not initialized."); return 0; diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp index 0a2b1d4a661f..3ca43ce915cf 100644 --- a/core/jni/android_view_InputEventSender.cpp +++ b/core/jni/android_view_InputEventSender.cpp @@ -48,9 +48,9 @@ static struct { class NativeInputEventSender : public LooperCallback { public: - NativeInputEventSender(JNIEnv* env, - jobject senderWeak, const sp<InputChannel>& inputChannel, - const sp<MessageQueue>& messageQueue); + NativeInputEventSender(JNIEnv* env, jobject senderWeak, + const std::shared_ptr<InputChannel>& inputChannel, + const sp<MessageQueue>& messageQueue); status_t initialize(); void dispose(); @@ -76,12 +76,12 @@ private: status_t receiveFinishedSignals(JNIEnv* env); }; - -NativeInputEventSender::NativeInputEventSender(JNIEnv* env, - jobject senderWeak, const sp<InputChannel>& inputChannel, - const sp<MessageQueue>& messageQueue) : - mSenderWeakGlobal(env->NewGlobalRef(senderWeak)), - mInputPublisher(inputChannel), mMessageQueue(messageQueue), +NativeInputEventSender::NativeInputEventSender(JNIEnv* env, jobject senderWeak, + const std::shared_ptr<InputChannel>& inputChannel, + const sp<MessageQueue>& messageQueue) + : mSenderWeakGlobal(env->NewGlobalRef(senderWeak)), + mInputPublisher(inputChannel), + mMessageQueue(messageQueue), mNextPublishedSeq(1) { if (kDebugDispatchCycle) { ALOGD("channel '%s' ~ Initializing input event sender.", getInputChannelName().c_str()); @@ -249,8 +249,8 @@ status_t NativeInputEventSender::receiveFinishedSignals(JNIEnv* env) { static jlong nativeInit(JNIEnv* env, jclass clazz, jobject senderWeak, jobject inputChannelObj, jobject messageQueueObj) { - sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, - inputChannelObj); + std::shared_ptr<InputChannel> inputChannel = + android_view_InputChannel_getInputChannel(env, inputChannelObj); if (inputChannel == NULL) { jniThrowRuntimeException(env, "InputChannel is not initialized."); return 0; diff --git a/core/jni/com_android_internal_os_ClassLoaderFactory.cpp b/core/jni/com_android_internal_os_ClassLoaderFactory.cpp index f8d41e4bef54..59c413ff58a6 100644 --- a/core/jni/com_android_internal_os_ClassLoaderFactory.cpp +++ b/core/jni/com_android_internal_os_ClassLoaderFactory.cpp @@ -28,16 +28,19 @@ static jstring createClassloaderNamespace_native(JNIEnv* env, jstring librarySearchPath, jstring libraryPermittedPath, jboolean isShared, - jstring dexPath) { + jstring dexPath, + jstring sonameList) { return android::CreateClassLoaderNamespace(env, targetSdkVersion, classLoader, isShared == JNI_TRUE, dexPath, - librarySearchPath, libraryPermittedPath); + librarySearchPath, + libraryPermittedPath, + sonameList); } static const JNINativeMethod g_methods[] = { { "createClassloaderNamespace", - "(Ljava/lang/ClassLoader;ILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;)Ljava/lang/String;", + "(Ljava/lang/ClassLoader;ILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)Ljava/lang/String;", reinterpret_cast<void*>(createClassloaderNamespace_native) }, }; diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index 9bbe0caa9e98..ac143ac1a147 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -508,7 +508,7 @@ message GlobalSettingsProto { optional SettingProto job_scheduler_constants = 66 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto job_scheduler_quota_controller_constants = 149 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto job_scheduler_time_controller_constants = 150 [ (android.privacy).dest = DEST_AUTOMATIC ]; + reserved 150; // job_scheduler_time_controller_constants optional SettingProto keep_profile_in_background = 67 [ (android.privacy).dest = DEST_AUTOMATIC ]; diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto index f2f20e3ac12e..76b7fc028a98 100644 --- a/core/proto/android/server/jobscheduler.proto +++ b/core/proto/android/server/jobscheduler.proto @@ -324,7 +324,7 @@ message ConstantsProto { // ready now. reserved 1; // skip_not_ready_jobs // Whether or not TimeController will use a non-wakeup alarm for delay constraints. - optional bool use_non_wakeup_alarm_for_delay = 2; + reserved 2; // use_non_wakeup_alarm_for_delay } optional TimeController time_controller = 25; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index ef50fc8e2b6e..fe290f3e97e8 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -5034,6 +5034,11 @@ <permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS" android:protectionLevel="signature|appPredictor" /> + <!-- @hide @TestApi Allows apps to reset the state of {@link com.android.server.am.AppErrors}. + <p>CTS tests will use UiAutomation.adoptShellPermissionIdentity() to gain access. --> + <permission android:name="android.permission.RESET_APP_ERRORS" + android:protectionLevel="signature" /> + <!-- Attribution for Geofencing service. --> <attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/> <!-- Attribution for Country Detector. --> diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 3b61c367e1bf..03c682fd74af 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Druk kieslys om oop te sluit of maak noodoproep."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Druk kieslys om oop te maak."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Teken patroon om te ontsluit"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Noodgeval"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Keer terug na oproep"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Reg!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Probeer weer"</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 9ce214fdf3ab..f80da896d8fa 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"ለመክፈት ምናሌ ተጫንወይም የአደጋ ጊዜ ጥሪ አድርግ።"</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"ለመክፈት ምናሌ ተጫን"</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"ለመክፈት ስርዓተ ጥለት ሳል"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"ድንገተኛ አደጋ"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"ወደ ጥሪ ተመለስ"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ትክክል!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"እንደገና ሞክር"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index e80720d9a2b8..41e3e26afc2c 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -844,7 +844,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"اضغط على \"القائمة\" لإلغاء التأمين أو إجراء اتصال بالطوارئ."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"اضغط على \"القائمة\" لإلغاء التأمين."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"رسم نقش لإلغاء التأمين"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"الطوارئ"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"العودة إلى الاتصال"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"صحيح!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"أعد المحاولة"</string> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 881a1278666c..c6c8bb502ba8 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"আনলক কৰিবলৈ বা জৰুৰীকালীন কল কৰিবলৈ মেনু টিপক।"</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"আনলক কৰিবলৈ মেনু টিপক।"</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"আনলক কৰিবলৈ আর্হি আঁকক"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"জৰুৰীকালীন"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"কললৈ উভতি যাওক"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"শুদ্ধ!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"আকৌ চেষ্টা কৰক"</string> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index 6408ef629b36..f0ff88365173 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Təcili zəng kilidini açmaq və ya yerləşdirmək üçün Menyu düyməsinə basın."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Kilidi açmaq üçün Menyu düyməsinə basın."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Kilidi açmaq üçün model çəkin"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Təcili"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Zəngə qayıt"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Düzdür!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Bir də cəhd edin"</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 2bcf9095cb04..8319da7ca7ee 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -835,7 +835,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pritisnite „Meni“ da biste otključali telefon ili uputite hitan poziv."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pritisnite „Meni“ za otključavanje."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Unesite šablon za otključavanje"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Hitne službe"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Nazad na poziv"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Tačno!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Probajte ponovo"</string> @@ -1145,7 +1146,7 @@ <string name="capital_off" msgid="7443704171014626777">"NE"</string> <string name="checked" msgid="9179896827054513119">"označeno je"</string> <string name="not_checked" msgid="7972320087569023342">"nije označeno"</string> - <string name="whichApplication" msgid="5432266899591255759">"Dovršavanje radnje pomoću"</string> + <string name="whichApplication" msgid="5432266899591255759">"Dovrši radnju preko"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Završite radnju pomoću aplikacije %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Završi radnju"</string> <string name="whichViewApplication" msgid="5733194231473132945">"Otvorite pomoću"</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index ed781fb25698..3540516fd9f3 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -838,7 +838,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Націсніце \"Меню\", каб разблакаваць, або зрабіце экстраны выклік."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Націсніце \"Меню\", каб разблакаваць."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Намалюйце камбінацыю разблакоўкі, каб разблакаваць"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Экстранны выклік"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Вярнуцца да выкліку"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Правільна!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Паспрабуйце яшчэ раз"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index f089d62707b5..6643bcfa822c 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Натиснете „Меню“, за да отключите или да извършите спешно обаждане."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Натиснете „Меню“, за да отключите."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Нарисувайте фигура, за да отключите"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Спешни случаи"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Назад към обаждането"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Правилно!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Опитайте отново"</string> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index 1ac213f01d6b..cbec4ac51d09 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"আনলক করতে বা জরুরি কল করতে মেনু টিপুন৷"</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"আনলক করতে মেনু টিপুন৷"</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"আনলক করতে প্যাটার্ন আঁকুন"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"জরুরী"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"কলে ফিরুন"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"সঠিক!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"আবার চেষ্টা করুন"</string> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index f27441a667e7..87b02f553037 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -835,7 +835,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pritisnite dugme Meni kako biste otključali uređaj ili obavili hitni poziv."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pritisnite dugme Meni za otključavanje uređaja."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Nacrtajte uzorak za otključavanje"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Hitno"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Povratak na poziv"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Ispravno!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Pokušajte ponovo"</string> @@ -1145,8 +1146,8 @@ <string name="capital_off" msgid="7443704171014626777">"Isključeno"</string> <string name="checked" msgid="9179896827054513119">"označeno"</string> <string name="not_checked" msgid="7972320087569023342">"nije označeno"</string> - <string name="whichApplication" msgid="5432266899591255759">"Izvrši akciju koristeći"</string> - <string name="whichApplicationNamed" msgid="6969946041713975681">"Dovršite akciju koristeći %1$s"</string> + <string name="whichApplication" msgid="5432266899591255759">"Završite radnju pomoću aplikacije"</string> + <string name="whichApplicationNamed" msgid="6969946041713975681">"Završite radnju pomoću aplikacije %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Izvršiti akciju"</string> <string name="whichViewApplication" msgid="5733194231473132945">"Otvori koristeći"</string> <string name="whichViewApplicationNamed" msgid="415164730629690105">"Otvori koristeći %1$s"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 856176455150..c69ca37d0f1c 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -838,7 +838,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Chcete-li odemknout telefon nebo provést tísňové volání, stiskněte Menu."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Telefon odemknete stisknutím tlačítka Menu."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Odblokujte pomocí gesta"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Stav nouze"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Zavolat zpět"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Správně!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Zkusit znovu"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 1b3dab2352f4..fb100773dfa6 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Tryk på Menu for at låse op eller foretage et nødopkald."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Tryk på Menu for at låse op."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Tegn oplåsningsmønster"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Nødsituation"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Tilbage til opkald"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Rigtigt!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Prøv igen"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 296200f8004c..4adcf0ae48ec 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Drücke die Menütaste, um das Telefon zu entsperren oder einen Notruf zu tätigen."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Zum Entsperren die Menütaste drücken"</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Muster zum Entsperren zeichnen"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Notfall"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Zurück zum Anruf"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Korrekt!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Erneut versuchen"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index e790c9a071a9..23895f4fbf57 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Πατήστε \"Menu\" για ξεκλείδωμα ή για κλήση έκτακτης ανάγκης."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Πατήστε \"Μενού\" για ξεκλείδωμα."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Σχεδιασμός μοτίβου για ξεκλείδωμα"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Κλήση έκτακτης ανάγκης"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Επιστροφή στην κλήση"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Σωστό!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Προσπαθήστε ξανά"</string> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 0f1566b10347..0484ccd8abaa 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Press Menu to unlock or place emergency call."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Press Menu to unlock."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Draw pattern to unlock"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Emergency"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Return to call"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correct!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Try again"</string> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 84b3ce1ffc22..9981c1212123 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Press Menu to unlock or place emergency call."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Press Menu to unlock."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Draw pattern to unlock"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Emergency"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Return to call"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correct!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Try again"</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index d9a2bdba5f10..02cdf69a2cd8 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Press Menu to unlock or place emergency call."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Press Menu to unlock."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Draw pattern to unlock"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Emergency"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Return to call"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correct!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Try again"</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index 1209f2bc4318..3b18aca951f7 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Press Menu to unlock or place emergency call."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Press Menu to unlock."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Draw pattern to unlock"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Emergency"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Return to call"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correct!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Try again"</string> diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index 7f29fd463403..6503f7ce65a7 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -832,7 +832,7 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Press Menu to unlock or place emergency call."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Press Menu to unlock."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Draw pattern to unlock"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Emergency"</string> + <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Emergency call"</string> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Return to call"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correct!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Try again"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index f8ead2795a9a..7e8a89aa5a94 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Presiona el Menú para desbloquear o realizar una llamada de emergencia."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Presionar Menú para desbloquear."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Dibujar el patrón de desbloqueo"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Emergencia"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Regresar a llamada"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correcto"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Vuelve a intentarlo."</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 741c89f0e5d9..02aafa75945a 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pulsa la tecla de menú para desbloquear el teléfono o realizar una llamada de emergencia."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pulsa la tecla de menú para desbloquear la pantalla."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Dibujar patrón de desbloqueo"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Emergencia"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Volver a llamada"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correcto"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Vuelve a intentarlo"</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index d724046c2a73..813629417a8e 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Vajutage avamiseks või hädaabikõne tegemiseks menüünuppu"</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Vajutage avamiseks menüüklahvi."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Avamiseks joonistage muster"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Hädaabi"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Kõne juurde tagasi"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Õige."</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Proovige uuesti"</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 24d3eef619e8..1b88f2708782 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Desblokeatzeko edo larrialdi-deia egiteko, sakatu Menua."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Desblokeatzeko, sakatu Menua."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Desblokeatzeko, marraztu eredua"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Larrialdi-deiak"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Itzuli deira"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Eredua zuzena da!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Saiatu berriro"</string> @@ -846,7 +847,7 @@ <string name="lockscreen_missing_sim_instructions" msgid="8473601862688263903">"Sartu SIM txartela."</string> <string name="lockscreen_missing_sim_instructions_long" msgid="3664999892038416334">"SIM txartela falta da edo ezin da irakurri. Sartu SIM txartel bat."</string> <string name="lockscreen_permanent_disabled_sim_message_short" msgid="3812893366715730539">"SIM txartela hondatuta dago."</string> - <string name="lockscreen_permanent_disabled_sim_instructions" msgid="4358929052509450807">"SIM txartela behin betiko desgaitu zaizu.\n Beste SIM txartel bat lortzeko, jarri zerbitzu-hornitzailearekin harremanetan."</string> + <string name="lockscreen_permanent_disabled_sim_instructions" msgid="4358929052509450807">"SIM txartela betiko desgaitu zaizu.\n Beste SIM txartel bat lortzeko, jarri zerbitzu-hornitzailearekin harremanetan."</string> <string name="lockscreen_transport_prev_description" msgid="2879469521751181478">"Aurreko pista"</string> <string name="lockscreen_transport_next_description" msgid="2931509904881099919">"Hurrengo pista"</string> <string name="lockscreen_transport_pause_description" msgid="6705284702135372494">"Pausatu"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index b0b533858b3a..506a7ee79dcb 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"برای بازگشایی قفل یا انجام تماس اضطراری روی منو فشار دهید."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"برای بازگشایی قفل روی منو فشار دهید."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"الگو را بکشید تا قفل آن باز شود"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"اضطراری"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"بازگشت به تماس"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"صحیح است!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"دوباره امتحان کنید"</string> @@ -1125,8 +1126,8 @@ <string name="capital_off" msgid="7443704171014626777">"خاموش"</string> <string name="checked" msgid="9179896827054513119">"علامتزدهشده"</string> <string name="not_checked" msgid="7972320087569023342">"بدون علامت"</string> - <string name="whichApplication" msgid="5432266899591255759">"تکمیل عملکرد با استفاده از"</string> - <string name="whichApplicationNamed" msgid="6969946041713975681">"تکمیل عملکرد با استفاده از %1$s"</string> + <string name="whichApplication" msgid="5432266899591255759">"تکمیل کنش بااستفاده از"</string> + <string name="whichApplicationNamed" msgid="6969946041713975681">"تکمیل کنش بااستفاده از %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"تکمیل عملکرد"</string> <string name="whichViewApplication" msgid="5733194231473132945">"باز کردن با"</string> <string name="whichViewApplicationNamed" msgid="415164730629690105">"باز کردن با %1$s"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 815daaa5d7ae..01db781a6ccd 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Poista lukitus tai soita hätäpuhelu painamalla Valikko-painiketta."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Poista lukitus painamalla Valikko-painiketta."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Poista lukitus piirtämällä kuvio"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Hätäpuhelu"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Palaa puheluun"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Oikein!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Yritä uudelleen"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index d3323d733824..f5adc779e082 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Appuyez sur \"Menu\" pour débloquer le téléphone ou appeler un numéro d\'urgence."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Appuyez sur \"Menu\" pour déverrouiller l\'appareil."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Dessinez un schéma pour déverrouiller le téléphone"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Urgence"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Retour à l\'appel"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"C\'est exact!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Réessayer"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 4a1646f8ba30..8880dc63428f 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Appuyez sur \"Menu\" pour déverrouiller le téléphone ou appeler un numéro d\'urgence"</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Appuyez sur \"Menu\" pour déverrouiller le téléphone."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Dessinez un schéma pour déverrouiller le téléphone"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Urgences"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Retour à l\'appel"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Combinaison correcte !"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Veuillez réessayer."</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 54e17faf9b4a..dffca1c2abcd 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Preme Menú para desbloquear ou realizar unha chamada de emerxencia."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Preme Menú para desbloquear."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Crea o padrón de desbloqueo"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Emerxencia"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Volver á chamada"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correcto!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Téntao de novo"</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index be17cfd03115..784e85f9a174 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"અનલૉક કરવા માટે અથવા કટોકટીનો કૉલ કરવા માટે મેનૂ દબાવો."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"અનલૉક કરવા માટે મેનૂ દબાવો."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"અનલૉક કરવા માટે પૅટર્ન દોરો."</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"ઇમર્જન્સી"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"કૉલ પર પાછા ફરો"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"સાચું!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ફરી પ્રયાસ કરો"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 97118f8bffae..82a106295acb 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"लॉक खोलने के लिए मेन्यू दबाएं या आपातलकालीन कॉल करें."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"लॉक खोलने के लिए मेन्यू दबाएं."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"अनलॉक करने के लिए आकार आरेखित करें"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"आपातकाल"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"कॉल पर वापस लौटें"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"सही!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"फिर से कोशिश करें"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index a1b303ee7cd4..f1bcd398c65f 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -835,7 +835,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pritisnite Izbornik za otključavanje ili pozivanje hitnih službi."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pritisnite Izbornik za otključavanje."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Iscrtajte uzorak za otključavanje"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Hitne službe"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Uzvrati poziv"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Ispravno!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Pokušajte ponovo"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index ff0d4709c970..3106371a2a33 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"A feloldáshoz vagy segélyhívás kezdeményezéséhez nyomja meg a Menü gombot."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"A feloldáshoz nyomja meg a Menü gombot."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Rajzolja le a mintát a feloldáshoz"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Segélyhívás"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Hívás folytatása"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Helyes!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Próbálja újra"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 05c447d50f7b..85afc27bb14c 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Ապակողպելու կամ շտապ կանչ անելու համար սեղմեք «Ընտրացանկ»"</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Ապակողպելու համար սեղմեք Ցանկը:"</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Հավաքեք սխեման` ապակողպելու համար"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Շտապ կանչ"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Վերադառնալ զանգին"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Ճիշտ է:"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Կրկին փորձեք"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index a6f68d171ec4..8ec1f50eaceb 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Tekan Menu untuk membuka atau melakukan panggilan darurat."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Tekan Menu untuk membuka."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Buat pola untuk membuka"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Darurat"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Kembali ke panggilan"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Perbaiki!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Coba lagi"</string> @@ -1125,7 +1126,7 @@ <string name="capital_off" msgid="7443704171014626777">"MATI"</string> <string name="checked" msgid="9179896827054513119">"dicentang"</string> <string name="not_checked" msgid="7972320087569023342">"tidak dicentang"</string> - <string name="whichApplication" msgid="5432266899591255759">"Tindakan lengkap menggunakan"</string> + <string name="whichApplication" msgid="5432266899591255759">"Selesaikan tindakan menggunakan"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Selesaikan tindakan menggunakan %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Selesaikan tindakan"</string> <string name="whichViewApplication" msgid="5733194231473132945">"Buka dengan"</string> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index 92f6f2488d18..1b0c2fe24521 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Ýttu á valmyndartakkann til að taka úr lás eða hringja neyðarsímtal."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Ýttu á valmyndartakkann til að taka úr lás."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Teiknaðu mynstur til að taka úr lás"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Neyðarsímtal"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Aftur í símtal"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Rétt!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Reyndu aftur"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 8f857fa32c73..d2bf62d94a40 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Premi Menu per sbloccare o effettuare chiamate di emergenza."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Premi Menu per sbloccare."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Traccia la sequenza di sblocco"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Emergenza"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Torna a chiamata"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Corretta."</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Riprova"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 27889fb9b512..f9674bd0db11 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"MENUキーでロック解除(または緊急通報)"</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"MENUキーでロック解除"</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"パターンを入力"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"緊急通報"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"通話に戻る"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"一致しました"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"もう一度お試しください"</string> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 6547185c4beb..3d1e9c799a4d 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"განბლოკვისთვის ან გადაუდებელი ზარისთვის დააჭირეთ მენიუს."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"განბლოკვისთვის დააჭირეთ მენიუს."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"განსაბლოკად დახატეთ ნიმუში"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"საგანგებო სამსახურები"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"ზარზე დაბრუნება"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"სწორია!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"კიდევ სცადეთ"</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 3d53912ad62b..38a50abfe6e7 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Бекітпесін ашу үшін немесе төтенше қоңырауды табу үшін Мәзір тармағын басыңыз."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Ашу үшін Мәзір пернесін басыңыз."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Бекітпесін ашу үшін кескінді сызыңыз"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Төтенше жағдай"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Қоңырауға оралу"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Дұрыс!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Қайталап көріңіз"</string> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 760d256ca62c..4e646c5d2a07 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"ចុចម៉ឺនុយ ដើម្បីដោះសោ ឬហៅពេលអាសន្ន។"</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"ចុចម៉ឺនុយ ដើម្បីដោះសោ។"</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"គូរលំនាំ ដើម្បីដោះសោ"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"បន្ទាន់"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"ត្រឡប់ទៅការហៅ"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ត្រឹមត្រូវ!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ព្យាយាមម្ដងទៀត"</string> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 6513481089ad..8d742156ca2c 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"ಅನ್ಲಾಕ್ ಮಾಡಲು ಮೆನು ಒತ್ತಿರಿ ಇಲ್ಲವೇ ತುರ್ತು ಕರೆಯನ್ನು ಮಾಡಿ."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"ಅನ್ಲಾಕ್ ಮಾಡಲು ಮೆನು ಒತ್ತಿರಿ."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"ಅನ್ಲಾಕ್ ಮಾಡಲು ಪ್ಯಾಟರ್ನ್ ಚಿತ್ರಿಸಿ"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"ತುರ್ತು"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"ಕರೆಗೆ ಹಿಂತಿರುಗು"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ಸರಿಯಾಗಿದೆ!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index db8d379c4083..5d960dcc0aa7 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"비상 전화를 걸거나 잠금해제하려면 메뉴를 누르세요."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"잠금해제하려면 메뉴를 누르세요."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"잠금해제를 위해 패턴 그리기"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"긴급 전화"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"통화로 돌아가기"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"맞습니다."</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"다시 시도"</string> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index c208396b278a..c97324f738b3 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Кулпусун ачып же Шашылыш чалуу аткаруу үчүн менюну басыңыз."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Бөгөттөн чыгаруу үчүн Менюну басыңыз."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Кулпуну ачуу үчүн, үлгүнү тартыңыз"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Тез жардам"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Чалууга кайтуу"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Туура!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Дагы аракет кылыңыз"</string> @@ -1125,7 +1126,7 @@ <string name="capital_off" msgid="7443704171014626777">"ӨЧҮК"</string> <string name="checked" msgid="9179896827054513119">"белгиленген"</string> <string name="not_checked" msgid="7972320087569023342">"белгилене элек"</string> - <string name="whichApplication" msgid="5432266899591255759">"Аракет колдонууну бүтүрүү"</string> + <string name="whichApplication" msgid="5432266899591255759">"Кайсынысын колдоносуз?"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s аркылуу аракетти аягына чейин чыгаруу"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Аракетти аягына чыгаруу"</string> <string name="whichViewApplication" msgid="5733194231473132945">"Төмөнкү менен ачуу"</string> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index f388cfaed0ca..c1b3fe473aed 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"ກົດ ເມນູ ເພື່ອປົດລັອກ ຫຼື ໂທອອກຫາເບີສຸກເສີນ."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"ກົດ \"ເມນູ\" ເພື່ອປົດລັອກ."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"ແຕ້ມຮູບແບບເພື່ອປົດລັອກ"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"ສຸກເສີນ"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"ກັບໄປຫາການໂທ"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ຖືກຕ້ອງ!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ລອງໃໝ່ອີກຄັ້ງ"</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index d68cd8d3c822..fc5709c0e089 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -838,7 +838,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Paspauskite „Meniu“, kad atrakintumėte ar skambintumėte pagalbos numeriu."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Paspauskite „Meniu“, jei norite atrakinti."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Nustatyti modelį, kad atrakintų"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Skambutis pagalbos numeriu"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"grįžti prie skambučio"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Teisingai!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Bandykite dar kartą"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 9462c227a3cf..d780b14ae11a 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -835,7 +835,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Nospiediet Izvēlne, lai atbloķētu, vai veiciet ārkārtas zvanu."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Lai atbloķētu, nospiediet vienumu Izvēlne."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Zīmējiet kombināciju, lai atbloķētu."</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Ārkārtas situācija"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Atpakaļ pie zvana"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Pareizi!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Mēģināt vēlreiz"</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index aee1fca01cb1..b50c608190e4 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Притисни „Мени“ да се отклучи или да направи итен повик."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Притиснете „Мени“ за да се отклучи."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Употребете ја шемата за да се отклучи"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Итен случај"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Врати се на повик"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Точно!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Обидете се повторно"</string> @@ -1125,7 +1126,7 @@ <string name="capital_off" msgid="7443704171014626777">"ИСКЛУЧЕНО"</string> <string name="checked" msgid="9179896827054513119">"штиклирано"</string> <string name="not_checked" msgid="7972320087569023342">"не е штиклирано"</string> - <string name="whichApplication" msgid="5432266899591255759">"Заврши дејство со"</string> + <string name="whichApplication" msgid="5432266899591255759">"Активирај со"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Остварете го дејството со %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Заврши го дејството"</string> <string name="whichViewApplication" msgid="5733194231473132945">"Отвори со"</string> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 375cb98b0c4f..b769fd23ab1e 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"അൺലോക്ക് ചെയ്യുന്നതിനായി മെനു അമർത്തുക അല്ലെങ്കിൽ അടിയന്തര കോൾ വിളിക്കുക."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"അൺലോക്കുചെയ്യാൻ മെനു അമർത്തുക."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"അൺലോക്ക് ചെയ്യാൻ പാറ്റേൺ വരയ്ക്കുക"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"എമർജൻസി"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"കോളിലേക്ക് മടങ്ങുക"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ശരി!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"വീണ്ടും ശ്രമിക്കുക"</string> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 1472c4e9f178..7b41501e6a0f 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Яаралтай дуудлага хийх буюу эсвэл түгжээг тайлах бол цэсийг дарна уу."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Тайлах бол цэсийг дарна уу."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Тайлах хээгээ зурна уу"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Яаралтай тусламж"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Дуудлагаруу буцах"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Зөв!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Дахин оролдох"</string> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 6695de6c7a33..577803334c33 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"अनलॉक करण्यासाठी मेनू दाबा किंवा आणीबाणीचा कॉल करा."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"अनलॉक करण्यासाठी मेनू दाबा."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"अनलॉक करण्यासाठी पॅटर्न काढा"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"आणीबाणी"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"कॉलवर परत या"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"अचूक!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"पुन्हा प्रयत्न करा"</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index c8f37c305ff7..c30bcfc1800f 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Tekan Menu untuk menyahsekat atau membuat panggilan kecemasan."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Tekan Menu untuk membuka kunci."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Lukiskan corak untuk membuka kunci"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Kecemasan"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Kembali ke panggilan"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Betul!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Cuba lagi"</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index dcb4e3cfc634..243357eca3c2 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"ဖွင့်ရန်သို့မဟုတ်အရေးပေါ်ခေါ်ဆိုခြင်းပြုလုပ်ရန် မီနူးကိုနှိပ်ပါ"</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"မီးနူးကို နှိပ်ခြင်းဖြင့် သော့ဖွင့်ပါ"</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"ဖွင့်ရန်ပုံစံဆွဲပါ"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"အရေးပေါ်"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"ခေါ်ဆိုမှုထံပြန်သွားရန်"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"မှန်ပါသည်"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ထပ် စမ်းပါ"</string> @@ -1102,7 +1103,7 @@ <string name="delete" msgid="1514113991712129054">"ဖျက်ရန်"</string> <string name="copyUrl" msgid="6229645005987260230">"URLအား ကူးခြင်း"</string> <string name="selectTextMode" msgid="3225108910999318778">"စာသား ရွေးရန်"</string> - <string name="undo" msgid="3175318090002654673">"ပြန်ဖျက်ရန်"</string> + <string name="undo" msgid="3175318090002654673">"တစ်ဆင့်နောက်ပြန်ရန်"</string> <string name="redo" msgid="7231448494008532233">"ထပ်လုပ်ပါ"</string> <string name="autofill" msgid="511224882647795296">"အော်တိုဖြည့်"</string> <string name="textSelectionCABTitle" msgid="5151441579532476940">"စာတိုရွေးချယ်မှု"</string> @@ -1125,7 +1126,7 @@ <string name="capital_off" msgid="7443704171014626777">"ပိတ်"</string> <string name="checked" msgid="9179896827054513119">"အမှန်ခြစ်ပြီး"</string> <string name="not_checked" msgid="7972320087569023342">"ခြစ် မထား"</string> - <string name="whichApplication" msgid="5432266899591255759">"အသုံးပြု၍ ဆောင်ရွက်မှုအားပြီးဆုံးစေခြင်း"</string> + <string name="whichApplication" msgid="5432266899591255759">"အောက်ပါတို့ကို အသုံးပြုမှု အပြီးသတ်ခြင်း"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ကို သုံးပြီး လုပ်ဆောင်ချက် ပြီးဆုံးပါစေ"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"လုပ်ဆောင်ချက်ကို အပြီးသတ်ပါ"</string> <string name="whichViewApplication" msgid="5733194231473132945">"...ဖြင့် ဖွင့်မည်"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 6926d659ed3f..0a31b49c555c 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Trykk på menyknappen for å låse opp eller ringe et nødnummer."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Trykk på menyknappen for å låse opp."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Tegn mønster for å låse opp"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Nødssituasjon"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Tilbake til samtale"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Riktig!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Prøv på nytt"</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index c9ac6ec47001..9712b480b97b 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"अनलक वा आपतकालीन कल गर्न मेनु थिच्नुहोस्।"</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"अनलक गर्न मेनु थिच्नुहोस्।"</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"अनलक गर्नु ढाँचा खिच्नुहोस्"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"आपतकालीन"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"कलमा फर्किनुहोस्"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"सही!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"फेरि प्रयास गर्नुहोस्"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 904c90665229..d1a342c99590 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Druk op \'Menu\' om te ontgrendelen of noodoproep te plaatsen."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Druk op \'Menu\' om te ontgrendelen."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Patroon tekenen om te ontgrendelen"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Noodgeval"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Terug naar gesprek"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Juist!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Opnieuw proberen"</string> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index 62505a31a169..84815f7a6133 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"ଅନଲକ୍ କରିବା ପାଇଁ ମେନୁକୁ ଦବାନ୍ତୁ କିମ୍ବା ଜରୁରୀକାଳୀନ କଲ୍ କରନ୍ତୁ।"</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"ଅନଲକ୍ କରିବା ପାଇଁ ମେନୁକୁ ଦବାନ୍ତୁ।"</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"ଅନଲକ୍ କରିବା ପାଇଁ ପାଟର୍ନ ଆଙ୍କନ୍ତୁ"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"ଜରୁରୀକାଳୀନ"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"କଲ୍କୁ ଫେରନ୍ତୁ"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ଠିକ୍!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 346ee9a476c7..c29308fd4c5b 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਮੀਨੂ ਦਬਾਓ ਜਾਂ ਸੰਕਟਕਾਲੀਨ ਕਾਲ ਕਰੋ।"</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਮੀਨੂ ਦਬਾਓ।"</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਪੈਟਰਨ ਡ੍ਰਾ ਕਰੋ"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"ਸੰਕਟਕਾਲ"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"ਕਾਲ ਤੇ ਵਾਪਸ ਜਾਓ"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ਸਹੀ!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 7d2795e2db0f..df56457da65a 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -838,7 +838,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Naciśnij Menu, aby odblokować lub wykonać połączenie alarmowe."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Naciśnij Menu, aby odblokować."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Narysuj wzór, aby odblokować"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Alarmowe"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Powrót do połączenia"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Poprawnie!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Spróbuj ponownie."</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 4fec5b3779a2..3ecf28d34ffd 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pressione Menu para desbloquear ou fazer uma chamada de emergência."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pressione Menu para desbloquear."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Desenhe o padrão para desbloquear"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Emergência"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Retornar à chamada"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correto!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Tente novamente"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 5f6fb5cf553c..dcc8e17609ac 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -286,7 +286,7 @@ <string name="notification_channel_retail_mode" msgid="3732239154256431213">"Demonstração para retalho"</string> <string name="notification_channel_usb" msgid="1528280969406244896">"Ligação USB"</string> <string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Aplicação em execução"</string> - <string name="notification_channel_foreground_service" msgid="7102189948158885178">"Aplicações que estão a consumir bateria"</string> + <string name="notification_channel_foreground_service" msgid="7102189948158885178">"Apps que estão a consumir bateria"</string> <string name="foreground_service_app_in_background" msgid="1439289699671273555">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a consumir bateria."</string> <string name="foreground_service_apps_in_background" msgid="7340037176412387863">"<xliff:g id="NUMBER">%1$d</xliff:g> aplicações estão a consumir bateria."</string> <string name="foreground_service_tap_for_details" msgid="9078123626015586751">"Toque para obter detalhes acerca da utilização da bateria e dos dados"</string> @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Prima Menu para desbloquear ou efectuar uma chamada de emergência."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Prima Menu para desbloquear."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Desenhar padrão para desbloquear"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Emergência"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Regressar à chamada"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correcto!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Tentar novamente"</string> @@ -1153,7 +1154,7 @@ <string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"Capturar imagem"</string> <string name="alwaysUse" msgid="3153558199076112903">"Utilizar por predefinição para esta ação."</string> <string name="use_a_different_app" msgid="4987790276170972776">"Utilizar outra app"</string> - <string name="clearDefaultHintMsg" msgid="1325866337702524936">"Limpar a predefinição nas Definições do Sistema > Aplicações > Transferidas."</string> + <string name="clearDefaultHintMsg" msgid="1325866337702524936">"Limpar a predefinição nas Definições do Sistema > Apps > Transferidas."</string> <string name="chooseActivity" msgid="8563390197659779956">"Escolha uma ação"</string> <string name="chooseUsbActivity" msgid="2096269989990986612">"Escolher uma app para o dispositivo USB"</string> <string name="noApplications" msgid="1186909265235544019">"Nenhuma app pode efetuar esta ação."</string> @@ -1181,7 +1182,7 @@ <string name="launch_warning_original" msgid="3332206576800169626">"<xliff:g id="APP_NAME">%1$s</xliff:g> foi originalmente iniciado."</string> <string name="screen_compat_mode_scale" msgid="8627359598437527726">"Escala"</string> <string name="screen_compat_mode_show" msgid="5080361367584709857">"Mostrar sempre"</string> - <string name="screen_compat_mode_hint" msgid="4032272159093750908">"Reative este modo nas Definições do Sistema > Aplicações > Transferidas."</string> + <string name="screen_compat_mode_hint" msgid="4032272159093750908">"Reative este modo nas Definições do Sistema > Apps > Transferidas."</string> <string name="unsupported_display_size_message" msgid="7265211375269394699">"<xliff:g id="APP_NAME">%1$s</xliff:g> não suporta a definição de Tamanho do ecrã atual e pode ter um comportamento inesperado."</string> <string name="unsupported_display_size_show" msgid="980129850974919375">"Mostrar sempre"</string> <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> foi concebida para uma versão incompatível do SO Android e pode ter um comportamento inesperado. Pode estar disponível uma versão atualizada da app."</string> @@ -1274,7 +1275,7 @@ <string name="sms_short_code_confirm_allow" msgid="920477594325526691">"Enviar"</string> <string name="sms_short_code_confirm_deny" msgid="1356917469323768230">"Cancelar"</string> <string name="sms_short_code_remember_choice" msgid="1374526438647744862">"Memorizar a minha escolha"</string> - <string name="sms_short_code_remember_undo_instruction" msgid="2620984439143080410">"Pode alterar mais tarde em Definições > Aplicações"</string> + <string name="sms_short_code_remember_undo_instruction" msgid="2620984439143080410">"Pode alterar mais tarde em Definições > Apps"</string> <string name="sms_short_code_confirm_always_allow" msgid="2223014893129755950">"Permitir Sempre"</string> <string name="sms_short_code_confirm_never_allow" msgid="2688828813521652079">"Nunca Permitir"</string> <string name="sim_removed_title" msgid="5387212933992546283">"Cartão SIM removido"</string> @@ -1284,8 +1285,8 @@ <string name="sim_added_message" msgid="6602906609509958680">"Reinicie o aparelho para aceder à rede de telemóvel."</string> <string name="sim_restart_button" msgid="8481803851341190038">"Reiniciar"</string> <string name="install_carrier_app_notification_title" msgid="5712723402213090102">"Ativar o serviço móvel"</string> - <string name="install_carrier_app_notification_text" msgid="2781317581274192728">"Transfira a app do operador para ativar o seu novo SIM."</string> - <string name="install_carrier_app_notification_text_app_name" msgid="4086877327264106484">"Transfira a app <xliff:g id="APP_NAME">%1$s</xliff:g> para ativar o novo SIM."</string> + <string name="install_carrier_app_notification_text" msgid="2781317581274192728">"Descarregue a app do operador para ativar o seu novo SIM."</string> + <string name="install_carrier_app_notification_text_app_name" msgid="4086877327264106484">"Descarregue a app <xliff:g id="APP_NAME">%1$s</xliff:g> para ativar o novo SIM."</string> <string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Transferir app"</string> <string name="carrier_app_notification_title" msgid="5815477368072060250">"Novo SIM inserido"</string> <string name="carrier_app_notification_text" msgid="6567057546341958637">"Toque para configurar"</string> @@ -2035,7 +2036,7 @@ <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Esta app não recebeu autorização de gravação, mas pode capturar áudio através deste dispositivo USB."</string> <string name="accessibility_system_action_home_label" msgid="3234748160850301870">"Página inicial"</string> <string name="accessibility_system_action_back_label" msgid="4205361367345537608">"Anterior"</string> - <string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"Aplicações recentes"</string> + <string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"Apps recentes"</string> <string name="accessibility_system_action_notifications_label" msgid="6083767351772162010">"Notificações"</string> <string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"Definições rápidas"</string> <string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Caixa de diálogo de energia"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 4fec5b3779a2..3ecf28d34ffd 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pressione Menu para desbloquear ou fazer uma chamada de emergência."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pressione Menu para desbloquear."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Desenhe o padrão para desbloquear"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Emergência"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Retornar à chamada"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correto!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Tente novamente"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index a0e35985b142..64936689ee6e 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -835,7 +835,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Apăsați Meniu pentru a debloca sau pentru a efectua apeluri de urgență."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Apăsați Meniu pentru deblocare."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Desenați modelul pentru a debloca"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Urgență"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Reveniți la apel"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Corect!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Încercați din nou"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 1a65847fecf4..07abf6dbb28d 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -838,7 +838,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Нажмите \"Меню\", чтобы разблокировать экран или вызвать службу экстренной помощи."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Для разблокировки нажмите \"Меню\"."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Введите графический ключ"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Экстренный вызов"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Вернуться к вызову"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Правильно!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Повторите попытку"</string> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index db759f62b8ae..d494a36520bf 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"අගුළු හැරීමට මෙනුව ඔබන්න හෝ හදිසි ඇමතුම ලබාගන්න."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"අගුළු හැරීමට මෙනු ඔබන්න."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"අගුළු ඇරීමට රටාව අඳින්න"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"හදිසි"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"ඇමතුම වෙත නැවත යන්න"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"නිවැරදියි!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"නැවත උත්සාහ කරන්න"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 5f80364368eb..52c53015743b 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -838,7 +838,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Ak chcete odomknúť telefón alebo uskutočniť tiesňové volanie, stlačte Menu."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Telefón odomknete stlačením tlačidla Menu."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Odomknite nakreslením vzoru"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Stav tiesne"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Zavolať späť"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Správne!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Skúsiť znova"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 4e3705976e5f..a43c900fb585 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -838,7 +838,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Če želite odkleniti napravo ali opraviti klic v sili, pritisnite meni."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Če želite odkleniti, pritisnite meni."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Če želite odkleniti, narišite vzorec"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Klic v sili"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Nazaj na klic"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Pravilno."</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Poskusi znova"</string> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index 30e75558bb76..625962fb9bd1 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Shtyp \"Meny\" për të shkyçur ose për të kryer telefonatë urgjence."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Shtyp \"Meny\" për të shkyçur."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Vizato modelin për ta shkyçur"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Urgjenca"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Kthehu te telefonata"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Saktë!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Provo sërish"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 6890b800ac1e..6101dac65f95 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -835,7 +835,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Притисните „Мени“ да бисте откључали телефон или упутите хитан позив."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Притисните „Мени“ за откључавање."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Унесите шаблон за откључавање"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Хитне службе"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Назад на позив"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Тачно!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Пробајте поново"</string> @@ -1145,7 +1146,7 @@ <string name="capital_off" msgid="7443704171014626777">"НЕ"</string> <string name="checked" msgid="9179896827054513119">"означено је"</string> <string name="not_checked" msgid="7972320087569023342">"није означено"</string> - <string name="whichApplication" msgid="5432266899591255759">"Довршавање радње помоћу"</string> + <string name="whichApplication" msgid="5432266899591255759">"Доврши радњу преко"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Завршите радњу помоћу апликације %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Заврши радњу"</string> <string name="whichViewApplication" msgid="5733194231473132945">"Отворите помоћу"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 87b087203a6a..e30bb14384f9 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Tryck på Menu för att låsa upp eller ringa nödsamtal."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Tryck på Menu för att låsa upp."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Rita grafiskt lösenord för att låsa upp"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Nödsamtal"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Tillbaka till samtal"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Korrekt!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Försök igen"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index fbf4ccae2e4a..4e4c0f656c9f 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Bonyeza Menyu ili kufungua au kupiga simu ya dharura."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Bonyeza Menyu ili kufungua."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Chora ruwaza ili kufungua"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Dharura"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Rudi kwa kupiga simu"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Sahihi!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Jaribu tena"</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 731a796a9d08..a617248071e0 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"தடைநீக்க மெனுவை அழுத்தவும் அல்லது அவசர அழைப்பை மேற்கொள்ளவும்."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"திறக்க, மெனுவை அழுத்தவும்."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"திறக்க வடிவத்தை வரையவும்"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"அவசர அழைப்பு"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"அழைப்பிற்குத் திரும்பு"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"சரி!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"மீண்டும் முயற்சிக்கவும்"</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index a2ec7872113b..794fec85bcf7 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"అన్లాక్ చేయడానికి లేదా అత్యవసర కాల్ చేయడానికి మెను నొక్కండి."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"అన్లాక్ చేయడానికి మెను నొక్కండి."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"అన్లాక్ చేయడానికి నమూనాను గీయండి"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"అత్యవసరం"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"కాల్కు తిరిగి వెళ్లు"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"సరైనది!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"మళ్లీ ప్రయత్నించండి"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 6773014ec2f8..3deb9b2b7b82 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"กด เมนู เพื่อปลดล็อกหรือโทรฉุกเฉิน"</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"กด เมนู เพื่อปลดล็อก"</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"วาดรูปแบบเพื่อปลดล็อก"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"เหตุฉุกเฉิน"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"กลับสู่การโทร"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ถูกต้อง!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ลองอีกครั้ง"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index da3e4373382a..ccda1c46059e 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pindutin ang Menu upang i-unlock o magsagawa ng pang-emergency na tawag."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pindutin ang Menu upang i-unlock."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Iguhit ang pattern upang i-unlock"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Emergency"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Bumalik sa tawag"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Tama!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Subukang muli"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index bf17f6c360d4..85c69860eb81 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Kilidi açmak veya acil çağrı yapmak için Menü\'ye basın."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Kilidi açmak için Menü\'ye basın."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Kilit açmak için deseni çizin"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Acil durum çağrısı"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Çağrıya dön"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Doğru!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Tekrar deneyin"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 9464efa043f0..8ae20a50f7f3 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -838,7 +838,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Натис. меню, щоб розбл. чи зробити авар. виклик."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Натисн. меню, щоб розбл."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Намал. ключ, щоб розбл."</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Екстрений виклик"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Поверн. до дзвін."</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Правильно!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Повторіть спробу"</string> @@ -1165,7 +1166,7 @@ <string name="capital_off" msgid="7443704171014626777">"ВИМК"</string> <string name="checked" msgid="9179896827054513119">"вибрано"</string> <string name="not_checked" msgid="7972320087569023342">"не вибрано"</string> - <string name="whichApplication" msgid="5432266899591255759">"Завершити дію за доп."</string> + <string name="whichApplication" msgid="5432266899591255759">"Що використовувати?"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Завершити дію за допомогою %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Завершити дію"</string> <string name="whichViewApplication" msgid="5733194231473132945">"Відкрити за допомогою"</string> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 15a1fe7d45f0..94c6cd450a6c 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"غیر مقفل کرنے کیلئے مینو دبائیں یا ہنگامی کال کریں۔"</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"غیر مقفل کرنے کیلئے مینو دبائیں۔"</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"غیر مقفل کرنے کیلئے پیٹرن کو ڈرا کریں"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"ہنگامی"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"کال پر واپس جائیں"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"صحیح!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"دوبارہ کوشش کریں"</string> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index 76d2c609b63d..74676dfcf226 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Qulfdan chiqarish yoki favqulodda qo‘ng‘iroqni amalga oshirish uchun \"Menyu\"ni bosing."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Qulfni ochish uchun \"Menyu\"ga bosing."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Qulfni ochish uchun grafik kalitni chizing"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Favqulodda chaqiruv"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Qo‘ng‘iroqni qaytarish"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"To‘g‘ri!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Qaytadan urining"</string> @@ -1125,7 +1126,7 @@ <string name="capital_off" msgid="7443704171014626777">"O"</string> <string name="checked" msgid="9179896827054513119">"belgilandi"</string> <string name="not_checked" msgid="7972320087569023342">"belgilanmadi"</string> - <string name="whichApplication" msgid="5432266899591255759">"Ilovani tanlang"</string> + <string name="whichApplication" msgid="5432266899591255759">"Nima ishlatilsin?"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"“%1$s” bilan ochish"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Amalni bajarish"</string> <string name="whichViewApplication" msgid="5733194231473132945">"Ochish…"</string> @@ -1548,7 +1549,7 @@ <string name="launchBrowserDefault" msgid="6328349989932924119">"Brauzer ishga tushirilsinmi?"</string> <string name="SetupCallDefault" msgid="5581740063237175247">"Qo‘ng‘iroqni qabul qilasizmi?"</string> <string name="activity_resolver_use_always" msgid="5575222334666843269">"Har doim"</string> - <string name="activity_resolver_use_once" msgid="948462794469672658">"Faqat hozir"</string> + <string name="activity_resolver_use_once" msgid="948462794469672658">"Faqat shu safar"</string> <string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"“%1$s” ishchi profilni qo‘llab-quvvatlamaydi"</string> <string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"Planshet"</string> <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 9f44841f573c..48f38583220d 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Nhấn vào Menu để mở khóa hoặc thực hiện cuộc gọi khẩn cấp."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Nhấn vào Menu để mở khóa."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Vẽ hình để mở khóa"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Khẩn cấp"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Quay lại cuộc gọi"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Chính xác!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Thử lại"</string> @@ -1125,8 +1126,8 @@ <string name="capital_off" msgid="7443704171014626777">"TẮT"</string> <string name="checked" msgid="9179896827054513119">"đã chọn"</string> <string name="not_checked" msgid="7972320087569023342">"chưa chọn"</string> - <string name="whichApplication" msgid="5432266899591255759">"Hoàn tất tác vụ đang sử dụng"</string> - <string name="whichApplicationNamed" msgid="6969946041713975681">"Hoàn tất tác vụ bằng %1$s"</string> + <string name="whichApplication" msgid="5432266899591255759">"Hoàn tất thao tác bằng"</string> + <string name="whichApplicationNamed" msgid="6969946041713975681">"Hoàn tất thao tác bằng %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Hoàn thành tác vụ"</string> <string name="whichViewApplication" msgid="5733194231473132945">"Mở bằng"</string> <string name="whichViewApplicationNamed" msgid="415164730629690105">"Mở bằng %1$s"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 32ac0cf297c4..bf381ec53751 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"按 Menu 解锁或进行紧急呼救。"</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"按 MENU 解锁。"</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"绘制解锁图案"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"紧急呼救"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"返回通话"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"正确!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"重试"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 82b079fd98af..a3b20d128726 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"按選單鍵解鎖或撥打緊急電話。"</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"按選單鍵解鎖。"</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"畫出解鎖圖形以解除鎖定螢幕"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"緊急電話"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"返回通話"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"正確!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"再試一次"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 02c02008dea3..f6543c9285d2 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"按下 [Menu] 解鎖或撥打緊急電話。"</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"按下 Menu 鍵解鎖。"</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"畫出解鎖圖案"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"緊急撥號"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"返回通話"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"正確!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"再試一次"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 7fe333d4bc33..85f54e9f9f5e 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -832,7 +832,8 @@ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Chofoza Menyu ukuvula noma ukwenza ikholi ephuthumayo."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Chofoza Menyu ukuvula."</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Dweba iphathini ukuvula"</string> - <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Isimo esiphuthumayo"</string> + <!-- no translation found for lockscreen_emergency_call (7549683825868928636) --> + <skip /> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Buyela ekholini"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Lungile!"</string> <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Zama futhi"</string> diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index eb30c9be4eba..ac08d96ab303 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -2173,6 +2173,29 @@ <attr name="required" /> </declare-styleable> + <!-- The <code>uses-native-library</code> specifies a native shared library that this + package requires to be linked against. Specifying this flag tells the + system to make the native library to be available to your app. + + <p>On devices running R or lower, this is ignored and the app has access to all + the public native shared libraries that are exported from the platform. This is + also ignored if the app is targeting R or lower. + + <p>This appears as a child tag of the + {@link #AndroidManifestApplication application} tag. --> + <declare-styleable name="AndroidManifestUsesNativeLibrary" parent="AndroidManifestApplication"> + <!-- Required name of the library you use. --> + <attr name="name" /> + <!-- Specify whether this native library is required for the application. + The default is true, meaning the application requires the + library, and does not want to be installed on devices that + don't support it. If you set this to false, then this will + allow the application to be installed even if the library + doesn't exist, and you will need to check for its presence + dynamically at runtime. --> + <attr name="required" /> + </declare-styleable> + <!-- The <code>uses-static-library</code> specifies a shared <strong>static</strong> library that this package requires to be statically linked against. Specifying this tag tells the system to include this library's code in your class loader. diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 12275dceafdd..4d74cf7d79bc 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -2128,7 +2128,7 @@ <!-- On the unlock pattern screen, shown at the top of the unlock screen to tell the user what to do. Below this text is the place for theu ser to draw the pattern. --> <string name="lockscreen_pattern_instructions">Draw pattern to unlock</string> <!-- Button at the bottom of the unlock screen to make an emergency call or access other emergency assistance functions. --> - <string name="lockscreen_emergency_call">Emergency</string> + <string name="lockscreen_emergency_call">Emergency call</string> <!-- Button at the bottom of the unlock screen that lets the user return to a call --> <string name="lockscreen_return_to_call">Return to call</string> <!-- Shown to confirm that the user entered their lock pattern correctly. --> diff --git a/core/tests/coretests/src/android/text/format/DateFormatTest.java b/core/tests/coretests/src/android/text/format/DateFormatTest.java index fa1d56f2e68d..a3434e885012 100644 --- a/core/tests/coretests/src/android/text/format/DateFormatTest.java +++ b/core/tests/coretests/src/android/text/format/DateFormatTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.icu.text.DateFormatSymbols; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; @@ -60,6 +61,15 @@ public class DateFormatTest { } @Test + public void testgetIcuDateFormatSymbols() { + DateFormatSymbols dfs = DateFormat.getIcuDateFormatSymbols(Locale.US); + assertEquals("AM", dfs.getAmPmStrings()[0]); + assertEquals("PM", dfs.getAmPmStrings()[1]); + assertEquals("a", dfs.getAmpmNarrowStrings()[0]); + assertEquals("p", dfs.getAmpmNarrowStrings()[1]); + } + + @Test public void testGetDateFormatOrder() { // lv and fa use differing orders depending on whether you're using numeric or // textual months. diff --git a/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java b/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java new file mode 100644 index 000000000000..0f17d27048f3 --- /dev/null +++ b/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java @@ -0,0 +1,671 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.text.format; + +import static android.icu.util.TimeZone.GMT_ZONE; +import static android.icu.util.ULocale.ENGLISH; +import static android.text.format.DateIntervalFormat.formatDateRange; +import static android.text.format.DateUtils.FORMAT_12HOUR; +import static android.text.format.DateUtils.FORMAT_24HOUR; +import static android.text.format.DateUtils.FORMAT_ABBREV_ALL; +import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH; +import static android.text.format.DateUtils.FORMAT_ABBREV_TIME; +import static android.text.format.DateUtils.FORMAT_ABBREV_WEEKDAY; +import static android.text.format.DateUtils.FORMAT_NO_MONTH_DAY; +import static android.text.format.DateUtils.FORMAT_NO_YEAR; +import static android.text.format.DateUtils.FORMAT_NUMERIC_DATE; +import static android.text.format.DateUtils.FORMAT_SHOW_DATE; +import static android.text.format.DateUtils.FORMAT_SHOW_TIME; +import static android.text.format.DateUtils.FORMAT_SHOW_WEEKDAY; +import static android.text.format.DateUtils.FORMAT_SHOW_YEAR; +import static android.text.format.DateUtils.FORMAT_UTC; + +import static org.junit.Assert.assertEquals; + +import android.icu.util.Calendar; +import android.icu.util.TimeZone; +import android.icu.util.ULocale; +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.function.BiFunction; + +@Presubmit +@SmallTest +@RunWith(AndroidJUnit4.class) +public class DateIntervalFormatTest { + private static final long MINUTE = 60 * 1000; + private static final long HOUR = 60 * MINUTE; + private static final long DAY = 24 * HOUR; + private static final long MONTH = 31 * DAY; + private static final long YEAR = 12 * MONTH; + + // These are the old CTS tests for DateIntervalFormat.formatDateRange. + @Test + public void test_formatDateInterval() throws Exception { + TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles"); + + Calendar c = Calendar.getInstance(tz, ULocale.US); + c.set(Calendar.MONTH, Calendar.JANUARY); + c.set(Calendar.DAY_OF_MONTH, 19); + c.set(Calendar.HOUR_OF_DAY, 3); + c.set(Calendar.MINUTE, 30); + c.set(Calendar.SECOND, 15); + c.set(Calendar.MILLISECOND, 0); + long timeWithCurrentYear = c.getTimeInMillis(); + + c.set(Calendar.YEAR, 2009); + long fixedTime = c.getTimeInMillis(); + + c.set(Calendar.MINUTE, 0); + c.set(Calendar.SECOND, 0); + long onTheHour = c.getTimeInMillis(); + + long noonDuration = (8 * 60 + 30) * 60 * 1000 - 15 * 1000; + long midnightDuration = (3 * 60 + 30) * 60 * 1000 + 15 * 1000; + + ULocale de_DE = new ULocale("de", "DE"); + ULocale en_US = new ULocale("en", "US"); + ULocale es_ES = new ULocale("es", "ES"); + ULocale es_US = new ULocale("es", "US"); + + assertEquals("Monday", + formatDateRange(en_US, tz, fixedTime, fixedTime + HOUR, FORMAT_SHOW_WEEKDAY)); + assertEquals("January 19", + formatDateRange(en_US, tz, timeWithCurrentYear, timeWithCurrentYear + HOUR, + FORMAT_SHOW_DATE)); + assertEquals("3:30 AM", formatDateRange(en_US, tz, fixedTime, fixedTime, FORMAT_SHOW_TIME)); + assertEquals("January 19, 2009", + formatDateRange(en_US, tz, fixedTime, fixedTime + HOUR, FORMAT_SHOW_YEAR)); + assertEquals("January 19", + formatDateRange(en_US, tz, fixedTime, fixedTime + HOUR, FORMAT_NO_YEAR)); + assertEquals("January", + formatDateRange(en_US, tz, timeWithCurrentYear, timeWithCurrentYear + HOUR, + FORMAT_NO_MONTH_DAY)); + assertEquals("3:30 AM", + formatDateRange(en_US, tz, fixedTime, fixedTime, FORMAT_12HOUR | FORMAT_SHOW_TIME)); + assertEquals("03:30", + formatDateRange(en_US, tz, fixedTime, fixedTime, FORMAT_24HOUR | FORMAT_SHOW_TIME)); + assertEquals("3:30 AM", formatDateRange(en_US, tz, fixedTime, fixedTime, + FORMAT_12HOUR /*| FORMAT_CAP_AMPM*/ | FORMAT_SHOW_TIME)); + assertEquals("12:00 PM", + formatDateRange(en_US, tz, fixedTime + noonDuration, fixedTime + noonDuration, + FORMAT_12HOUR | FORMAT_SHOW_TIME)); + assertEquals("12:00 PM", + formatDateRange(en_US, tz, fixedTime + noonDuration, fixedTime + noonDuration, + FORMAT_12HOUR | FORMAT_SHOW_TIME /*| FORMAT_CAP_NOON*/)); + assertEquals("12:00 PM", + formatDateRange(en_US, tz, fixedTime + noonDuration, fixedTime + noonDuration, + FORMAT_12HOUR /*| FORMAT_NO_NOON*/ | FORMAT_SHOW_TIME)); + assertEquals("12:00 AM", formatDateRange(en_US, tz, fixedTime - midnightDuration, + fixedTime - midnightDuration, + FORMAT_12HOUR | FORMAT_SHOW_TIME /*| FORMAT_NO_MIDNIGHT*/)); + assertEquals("3:30 AM", + formatDateRange(en_US, tz, fixedTime, fixedTime, FORMAT_SHOW_TIME | FORMAT_UTC)); + assertEquals("3 AM", formatDateRange(en_US, tz, onTheHour, onTheHour, + FORMAT_SHOW_TIME | FORMAT_ABBREV_TIME)); + assertEquals("Mon", formatDateRange(en_US, tz, fixedTime, fixedTime + HOUR, + FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_WEEKDAY)); + assertEquals("Jan 19", + formatDateRange(en_US, tz, timeWithCurrentYear, timeWithCurrentYear + HOUR, + FORMAT_SHOW_DATE | FORMAT_ABBREV_MONTH)); + assertEquals("Jan 19", + formatDateRange(en_US, tz, timeWithCurrentYear, timeWithCurrentYear + HOUR, + FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL)); + + assertEquals("1/19/2009", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * HOUR, + FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE)); + assertEquals("1/19/2009 – 1/22/2009", + formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * DAY, + FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE)); + assertEquals("1/19/2009 – 4/22/2009", + formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * MONTH, + FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE)); + assertEquals("1/19/2009 – 2/9/2012", + formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR, + FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE)); + + assertEquals("19.1.2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + HOUR, + FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE)); + assertEquals("19.–22.01.2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, + FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE)); + assertEquals("19.01. – 22.04.2009", + formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, + FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE)); + assertEquals("19.01.2009 – 09.02.2012", + formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, + FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE)); + + assertEquals("19/1/2009", formatDateRange(es_US, tz, fixedTime, fixedTime + HOUR, + FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE)); + assertEquals("19/1/2009–22/1/2009", + formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, + FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE)); + assertEquals("19/1/2009–22/4/2009", + formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, + FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE)); + assertEquals("19/1/2009–9/2/2012", + formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, + FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE)); + + assertEquals("19/1/2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + HOUR, + FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE)); + assertEquals("19/1/2009–22/1/2009", + formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, + FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE)); + assertEquals("19/1/2009–22/4/2009", + formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, + FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE)); + assertEquals("19/1/2009–9/2/2012", + formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, + FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE)); + + // These are some random other test cases I came up with. + + assertEquals("January 19 – 22, 2009", + formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * DAY, 0)); + assertEquals("Jan 19 – 22, 2009", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * DAY, + FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL)); + assertEquals("Mon, Jan 19 – Thu, Jan 22, 2009", + formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * DAY, + FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL)); + assertEquals("Monday, January 19 – Thursday, January 22, 2009", + formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY)); + + assertEquals("January 19 – April 22, 2009", + formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * MONTH, 0)); + assertEquals("Jan 19 – Apr 22, 2009", + formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * MONTH, + FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL)); + assertEquals("Mon, Jan 19 – Wed, Apr 22, 2009", + formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * MONTH, + FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL)); + assertEquals("January – April 2009", + formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY)); + + assertEquals("Jan 19, 2009 – Feb 9, 2012", + formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR, + FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL)); + assertEquals("Jan 2009 – Feb 2012", + formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR, + FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL)); + assertEquals("January 19, 2009 – February 9, 2012", + formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR, 0)); + assertEquals("Monday, January 19, 2009 – Thursday, February 9, 2012", + formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY)); + + // The same tests but for de_DE. + + assertEquals("19.–22. Januar 2009", + formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, 0)); + assertEquals("19.–22. Jan. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, + FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL)); + assertEquals("Mo., 19. – Do., 22. Jan. 2009", + formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, + FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL)); + assertEquals("Montag, 19. – Donnerstag, 22. Januar 2009", + formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY)); + + assertEquals("19. Januar – 22. April 2009", + formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, 0)); + assertEquals("19. Jan. – 22. Apr. 2009", + formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, + FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL)); + assertEquals("Mo., 19. Jan. – Mi., 22. Apr. 2009", + formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, + FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL)); + assertEquals("Januar–April 2009", + formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY)); + + assertEquals("19. Jan. 2009 – 9. Feb. 2012", + formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, + FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL)); + assertEquals("Jan. 2009 – Feb. 2012", + formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, + FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL)); + assertEquals("19. Januar 2009 – 9. Februar 2012", + formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, 0)); + assertEquals("Montag, 19. Januar 2009 – Donnerstag, 9. Februar 2012", + formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY)); + + // The same tests but for es_US. + + assertEquals("19–22 de enero de 2009", + formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, 0)); + assertEquals("19–22 de ene. de 2009", + formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, + FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL)); + assertEquals("lun., 19 de ene. – jue., 22 de ene. de 2009", + formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, + FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL)); + assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009", + formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY)); + + assertEquals("19 de enero–22 de abril de 2009", + formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, 0)); + assertEquals("19 de ene. – 22 de abr. 2009", + formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, + FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL)); + assertEquals("lun., 19 de ene. – mié., 22 de abr. de 2009", + formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, + FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL)); + assertEquals("enero–abril de 2009", + formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY)); + + assertEquals("19 de ene. de 2009 – 9 de feb. de 2012", + formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, + FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL)); + assertEquals("ene. de 2009 – feb. de 2012", + formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, + FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL)); + assertEquals("19 de enero de 2009–9 de febrero de 2012", + formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, 0)); + assertEquals("lunes, 19 de enero de 2009–jueves, 9 de febrero de 2012", + formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY)); + + // The same tests but for es_ES. + + assertEquals("19–22 de enero de 2009", + formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, 0)); + assertEquals("19–22 ene. 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, + FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL)); + assertEquals("lun., 19 ene. – jue., 22 ene. 2009", + formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, + FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL)); + assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009", + formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY)); + + assertEquals("19 de enero–22 de abril de 2009", + formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, 0)); + assertEquals("19 ene. – 22 abr. 2009", + formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, + FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL)); + assertEquals("lun., 19 ene. – mié., 22 abr. 2009", + formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, + FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL)); + assertEquals("enero–abril de 2009", + formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY)); + + assertEquals("19 ene. 2009 – 9 feb. 2012", + formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, + FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL)); + assertEquals("ene. 2009 – feb. 2012", + formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, + FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL)); + assertEquals("19 de enero de 2009–9 de febrero de 2012", + formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, 0)); + assertEquals("lunes, 19 de enero de 2009–jueves, 9 de febrero de 2012", + formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY)); + } + + // http://b/8862241 - we should be able to format dates past 2038. + // See also http://code.google.com/p/android/issues/detail?id=13050. + @Test + public void test8862241() throws Exception { + ULocale l = ULocale.US; + TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles"); + Calendar c = Calendar.getInstance(tz, l); + c.clear(); + c.set(2042, Calendar.JANUARY, 19, 3, 30); + long jan_19_2042 = c.getTimeInMillis(); + c.set(2046, Calendar.OCTOBER, 4, 3, 30); + long oct_4_2046 = c.getTimeInMillis(); + int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL; + assertEquals("Jan 19, 2042 – Oct 4, 2046", + formatDateRange(l, tz, jan_19_2042, oct_4_2046, flags)); + } + + // http://b/10089890 - we should take the given time zone into account. + @Test + public void test10089890() throws Exception { + ULocale l = ULocale.US; + TimeZone utc = TimeZone.getTimeZone("UTC"); + TimeZone pacific = TimeZone.getTimeZone("America/Los_Angeles"); + int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL | FORMAT_SHOW_TIME | FORMAT_24HOUR; + + // The Unix epoch is UTC, so 0 is 1970-01-01T00:00Z... + assertEquals("Jan 1, 1970, 00:00 – Jan 2, 1970, 00:00", + formatDateRange(l, utc, 0, DAY + 1, flags)); + // But MTV is hours behind, so 0 was still the afternoon of the previous day... + assertEquals("Dec 31, 1969, 16:00 – Jan 1, 1970, 16:00", + formatDateRange(l, pacific, 0, DAY, flags)); + } + + // http://b/10318326 - we can drop the minutes in a 12-hour time if they're zero, + // but not if we're using the 24-hour clock. That is: "4 PM" is reasonable, "16" is not. + @Test + public void test10318326() throws Exception { + long midnight = 0; + long teaTime = 16 * HOUR; + + int time12 = FORMAT_12HOUR | FORMAT_SHOW_TIME; + int time24 = FORMAT_24HOUR | FORMAT_SHOW_TIME; + int abbr12 = time12 | FORMAT_ABBREV_ALL; + int abbr24 = time24 | FORMAT_ABBREV_ALL; + + ULocale l = ULocale.US; + TimeZone utc = TimeZone.getTimeZone("UTC"); + + // Full length on-the-hour times. + assertEquals("00:00", formatDateRange(l, utc, midnight, midnight, time24)); + assertEquals("12:00 AM", formatDateRange(l, utc, midnight, midnight, time12)); + assertEquals("16:00", formatDateRange(l, utc, teaTime, teaTime, time24)); + assertEquals("4:00 PM", formatDateRange(l, utc, teaTime, teaTime, time12)); + + // Abbreviated on-the-hour times. + assertEquals("00:00", formatDateRange(l, utc, midnight, midnight, abbr24)); + assertEquals("12 AM", formatDateRange(l, utc, midnight, midnight, abbr12)); + assertEquals("16:00", formatDateRange(l, utc, teaTime, teaTime, abbr24)); + assertEquals("4 PM", formatDateRange(l, utc, teaTime, teaTime, abbr12)); + + // Abbreviated on-the-hour ranges. + assertEquals("00:00 – 16:00", formatDateRange(l, utc, midnight, teaTime, abbr24)); + assertEquals("12 AM – 4 PM", formatDateRange(l, utc, midnight, teaTime, abbr12)); + + // Abbreviated mixed ranges. + assertEquals("00:00 – 16:01", formatDateRange(l, utc, midnight, teaTime + MINUTE, abbr24)); + assertEquals("12:00 AM – 4:01 PM", + formatDateRange(l, utc, midnight, teaTime + MINUTE, abbr12)); + } + + // http://b/10560853 - when the time is not displayed, an end time 0 ms into the next day is + // considered to belong to the previous day. + @Test + public void test10560853_when_time_not_displayed() throws Exception { + ULocale l = ULocale.US; + TimeZone utc = TimeZone.getTimeZone("UTC"); + + long midnight = 0; + long midnightNext = 1 * DAY; + + int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY; + + // An all-day event runs until 0 milliseconds into the next day, but is formatted as if it's + // just the first day. + assertEquals("Thursday, January 1, 1970", + formatDateRange(l, utc, midnight, midnightNext, flags)); + + // Run one millisecond over, though, and you're into the next day. + long nextMorning = 1 * DAY + 1; + assertEquals("Thursday, January 1 – Friday, January 2, 1970", + formatDateRange(l, utc, midnight, nextMorning, flags)); + + // But the same reasoning applies for that day. + long nextMidnight = 2 * DAY; + assertEquals("Thursday, January 1 – Friday, January 2, 1970", + formatDateRange(l, utc, midnight, nextMidnight, flags)); + } + + // http://b/10560853 - when the start and end times are otherwise on the same day, + // an end time 0 ms into the next day is considered to belong to the previous day. + @Test + public void test10560853_for_single_day_events() throws Exception { + ULocale l = ULocale.US; + TimeZone utc = TimeZone.getTimeZone("UTC"); + + int flags = FORMAT_SHOW_TIME | FORMAT_24HOUR | FORMAT_SHOW_DATE; + + assertEquals("January 1, 1970, 22:00 – 00:00", + formatDateRange(l, utc, 22 * HOUR, 24 * HOUR, flags)); + assertEquals("January 1, 1970, 22:00 – January 2, 1970, 00:30", + formatDateRange(l, utc, 22 * HOUR, 24 * HOUR + 30 * MINUTE, flags)); + } + + // The fix for http://b/10560853 didn't work except for the day around the epoch, which was + // all the unit test checked! + @Test + public void test_single_day_events_later_than_epoch() throws Exception { + ULocale l = ULocale.US; + TimeZone utc = TimeZone.getTimeZone("UTC"); + + int flags = FORMAT_SHOW_TIME | FORMAT_24HOUR | FORMAT_SHOW_DATE; + + Calendar c = Calendar.getInstance(utc, l); + c.clear(); + c.set(1980, Calendar.JANUARY, 1, 0, 0); + long jan_1_1980 = c.getTimeInMillis(); + assertEquals("January 1, 1980, 22:00 – 00:00", + formatDateRange(l, utc, jan_1_1980 + 22 * HOUR, jan_1_1980 + 24 * HOUR, flags)); + assertEquals("January 1, 1980, 22:00 – January 2, 1980, 00:30", + formatDateRange(l, utc, jan_1_1980 + 22 * HOUR, + jan_1_1980 + 24 * HOUR + 30 * MINUTE, flags)); + } + + // The fix for http://b/10560853 didn't work except for UTC, which was + // all the unit test checked! + @Test + public void test_single_day_events_not_in_UTC() throws Exception { + ULocale l = ULocale.US; + TimeZone pacific = TimeZone.getTimeZone("America/Los_Angeles"); + + int flags = FORMAT_SHOW_TIME | FORMAT_24HOUR | FORMAT_SHOW_DATE; + + Calendar c = Calendar.getInstance(pacific, l); + c.clear(); + c.set(1980, Calendar.JANUARY, 1, 0, 0); + long jan_1_1980 = c.getTimeInMillis(); + assertEquals("January 1, 1980, 22:00 – 00:00", + formatDateRange(l, pacific, jan_1_1980 + 22 * HOUR, jan_1_1980 + 24 * HOUR, flags)); + + c.set(1980, Calendar.JULY, 1, 0, 0); + long jul_1_1980 = c.getTimeInMillis(); + assertEquals("July 1, 1980, 22:00 – 00:00", + formatDateRange(l, pacific, jul_1_1980 + 22 * HOUR, jul_1_1980 + 24 * HOUR, flags)); + } + + // http://b/10209343 - even if the caller didn't explicitly ask us to include the year, + // we should do so for years other than the current year. + @Test + public void test10209343_when_not_this_year() { + ULocale l = ULocale.US; + TimeZone utc = TimeZone.getTimeZone("UTC"); + + int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY | FORMAT_SHOW_TIME | FORMAT_24HOUR; + + assertEquals("Thursday, January 1, 1970, 00:00", formatDateRange(l, utc, 0L, 0L, flags)); + + long t1833 = ((long) Integer.MIN_VALUE + Integer.MIN_VALUE) * 1000L; + assertEquals("Sunday, November 24, 1833, 17:31", + formatDateRange(l, utc, t1833, t1833, flags)); + + long t1901 = Integer.MIN_VALUE * 1000L; + assertEquals("Friday, December 13, 1901, 20:45", + formatDateRange(l, utc, t1901, t1901, flags)); + + long t2038 = Integer.MAX_VALUE * 1000L; + assertEquals("Tuesday, January 19, 2038, 03:14", + formatDateRange(l, utc, t2038, t2038, flags)); + + long t2106 = (2L + Integer.MAX_VALUE + Integer.MAX_VALUE) * 1000L; + assertEquals("Sunday, February 7, 2106, 06:28", + formatDateRange(l, utc, t2106, t2106, flags)); + } + + // http://b/10209343 - for the current year, we should honor the FORMAT_SHOW_YEAR flags. + @Test + public void test10209343_when_this_year() { + // Construct a date in the current year (whenever the test happens to be run). + ULocale l = ULocale.US; + TimeZone utc = TimeZone.getTimeZone("UTC"); + Calendar c = Calendar.getInstance(utc, l); + c.set(Calendar.MONTH, Calendar.FEBRUARY); + c.set(Calendar.DAY_OF_MONTH, 10); + c.set(Calendar.HOUR_OF_DAY, 0); + long thisYear = c.getTimeInMillis(); + + // You don't get the year if it's this year... + assertEquals("February 10", formatDateRange(l, utc, thisYear, thisYear, FORMAT_SHOW_DATE)); + + // ...unless you explicitly ask for it. + assertEquals(String.format("February 10, %d", c.get(Calendar.YEAR)), + formatDateRange(l, utc, thisYear, thisYear, FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR)); + + // ...or it's not actually this year... + Calendar c2 = (Calendar) c.clone(); + c2.set(Calendar.YEAR, 1980); + long oldYear = c2.getTimeInMillis(); + assertEquals("February 10, 1980", + formatDateRange(l, utc, oldYear, oldYear, FORMAT_SHOW_DATE)); + + // (But you can disable that!) + assertEquals("February 10", + formatDateRange(l, utc, oldYear, oldYear, FORMAT_SHOW_DATE | FORMAT_NO_YEAR)); + + // ...or the start and end years aren't the same... + assertEquals(String.format("February 10, 1980 – February 10, %d", c.get(Calendar.YEAR)), + formatDateRange(l, utc, oldYear, thisYear, FORMAT_SHOW_DATE)); + + // (And you can't avoid that --- icu4c steps in and overrides you.) + assertEquals(String.format("February 10, 1980 – February 10, %d", c.get(Calendar.YEAR)), + formatDateRange(l, utc, oldYear, thisYear, FORMAT_SHOW_DATE | FORMAT_NO_YEAR)); + } + + // http://b/8467515 - yet another y2k38 bug report. + @Test + public void test8467515() throws Exception { + ULocale l = ULocale.US; + TimeZone utc = TimeZone.getTimeZone("UTC"); + int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY | FORMAT_SHOW_YEAR | FORMAT_ABBREV_MONTH + | FORMAT_ABBREV_WEEKDAY; + long t; + + Calendar calendar = Calendar.getInstance(utc, l); + calendar.clear(); + + calendar.set(2038, Calendar.JANUARY, 19, 12, 0, 0); + t = calendar.getTimeInMillis(); + assertEquals("Tue, Jan 19, 2038", formatDateRange(l, utc, t, t, flags)); + + calendar.set(1900, Calendar.JANUARY, 1, 0, 0, 0); + t = calendar.getTimeInMillis(); + assertEquals("Mon, Jan 1, 1900", formatDateRange(l, utc, t, t, flags)); + } + + // http://b/12004664 + @Test + public void test12004664() throws Exception { + TimeZone utc = TimeZone.getTimeZone("UTC"); + Calendar c = Calendar.getInstance(utc, ULocale.US); + c.clear(); + c.set(Calendar.YEAR, 1980); + c.set(Calendar.MONTH, Calendar.FEBRUARY); + c.set(Calendar.DAY_OF_MONTH, 10); + c.set(Calendar.HOUR_OF_DAY, 0); + long thisYear = c.getTimeInMillis(); + + int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY | FORMAT_SHOW_YEAR; + assertEquals("Sunday, February 10, 1980", + formatDateRange(new ULocale("en", "US"), utc, thisYear, thisYear, flags)); + + // If we supported non-Gregorian calendars, this is what that we'd expect for these + // ULocales. + // This is really the correct behavior, but since java.util.Calendar currently only supports + // the Gregorian calendar, we want to deliberately force icu4c to agree, otherwise we'd have + // a mix of calendars throughout an app's UI depending on whether Java or native code + // formatted + // the date. + // assertEquals("یکشنبه ۲۱ بهمن ۱۳۵۸ ه.ش.", formatDateRange(new ULocale("fa"), utc, + // thisYear, thisYear, flags)); + // assertEquals("AP ۱۳۵۸ سلواغه ۲۱, یکشنبه", formatDateRange(new ULocale("ps"), utc, + // thisYear, thisYear, flags)); + // assertEquals("วันอาทิตย์ 10 กุมภาพันธ์ 2523", formatDateRange(new ULocale("th"), utc, + // thisYear, thisYear, flags)); + + // For now, here are the localized Gregorian strings instead... + assertEquals("یکشنبه ۱۰ فوریهٔ ۱۹۸۰", + formatDateRange(new ULocale("fa"), utc, thisYear, thisYear, flags)); + assertEquals("يونۍ د ۱۹۸۰ د فبروري ۱۰", + formatDateRange(new ULocale("ps"), utc, thisYear, thisYear, flags)); + assertEquals("วันอาทิตย์ที่ 10 กุมภาพันธ์ ค.ศ. 1980", + formatDateRange(new ULocale("th"), utc, thisYear, thisYear, flags)); + } + + // http://b/13234532 + @Test + public void test13234532() throws Exception { + ULocale l = ULocale.US; + TimeZone utc = TimeZone.getTimeZone("UTC"); + + int flags = FORMAT_SHOW_TIME | FORMAT_ABBREV_ALL | FORMAT_12HOUR; + + assertEquals("10 – 11 AM", formatDateRange(l, utc, 10 * HOUR, 11 * HOUR, flags)); + assertEquals("11 AM – 1 PM", formatDateRange(l, utc, 11 * HOUR, 13 * HOUR, flags)); + assertEquals("2 – 3 PM", formatDateRange(l, utc, 14 * HOUR, 15 * HOUR, flags)); + } + + // http://b/20708022 + @Test + public void testEndOfDayOnLastDayOfMonth() throws Exception { + final ULocale locale = new ULocale("en"); + final TimeZone timeZone = TimeZone.getTimeZone("UTC"); + + assertEquals("11:00 PM – 12:00 AM", formatDateRange(locale, timeZone, + 1430434800000L, 1430438400000L, FORMAT_SHOW_TIME)); + } + + // http://b/68847519 + @Test + public void testEndAtMidnight_dateAndTime() { + BiFunction<Long, Long, String> fmt = (from, to) -> formatDateRange( + ENGLISH, GMT_ZONE, from, to, FORMAT_SHOW_DATE | FORMAT_SHOW_TIME | FORMAT_24HOUR); + // If we're showing times and the end-point is midnight the following day, we want the + // behaviour of suppressing the date for the end... + assertEquals("February 27, 2007, 04:00 – 00:00", fmt.apply(1172548800000L, 1172620800000L)); + // ...unless the start-point is also midnight, in which case we need dates to disambiguate. + assertEquals("February 27, 2007, 00:00 – February 28, 2007, 00:00", + fmt.apply(1172534400000L, 1172620800000L)); + // We want to show the date if the end-point is a millisecond after midnight the following + // day, or if it is exactly midnight the day after that. + assertEquals("February 27, 2007, 04:00 – February 28, 2007, 00:00", + fmt.apply(1172548800000L, 1172620800001L)); + assertEquals("February 27, 2007, 04:00 – March 1, 2007, 00:00", + fmt.apply(1172548800000L, 1172707200000L)); + // We want to show the date if the start-point is anything less than a minute after + // midnight, + // since that gets displayed as midnight... + assertEquals("February 27, 2007, 00:00 – February 28, 2007, 00:00", + fmt.apply(1172534459999L, 1172620800000L)); + // ...but not if it is exactly one minute after midnight. + assertEquals("February 27, 2007, 00:01 – 00:00", fmt.apply(1172534460000L, 1172620800000L)); + } + + // http://b/68847519 + @Test + public void testEndAtMidnight_dateOnly() { + BiFunction<Long, Long, String> fmt = (from, to) -> formatDateRange( + ENGLISH, GMT_ZONE, from, to, FORMAT_SHOW_DATE); + // If we're only showing dates and the end-point is midnight of any day, we want the + // behaviour of showing an end date one earlier. So if the end-point is March 2, 2007 00:00, + // show March 1, 2007 instead (whether the start-point is midnight or not). + assertEquals("February 27 – March 1, 2007", fmt.apply(1172534400000L, 1172793600000L)); + assertEquals("February 27 – March 1, 2007", fmt.apply(1172548800000L, 1172793600000L)); + // We want to show the true date if the end-point is a millisecond after midnight. + assertEquals("February 27 – March 2, 2007", fmt.apply(1172534400000L, 1172793600001L)); + + // 2006-02-27 00:00:00.000 GMT - 2007-03-02 00:00:00.000 GMT + assertEquals("February 27, 2006 – March 1, 2007", + fmt.apply(1140998400000L, 1172793600000L)); + + // Spans a leap year's Feb 29th. + assertEquals("February 27 – March 1, 2004", fmt.apply(1077840000000L, 1078185600000L)); + } +} diff --git a/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java b/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java index d9ba8fb81d3c..4b3b5735b4f3 100644 --- a/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java +++ b/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java @@ -16,11 +16,11 @@ package android.text.format; -import static android.text.format.DateUtilsBridge.FORMAT_ABBREV_ALL; -import static android.text.format.DateUtilsBridge.FORMAT_ABBREV_RELATIVE; -import static android.text.format.DateUtilsBridge.FORMAT_NO_YEAR; -import static android.text.format.DateUtilsBridge.FORMAT_NUMERIC_DATE; -import static android.text.format.DateUtilsBridge.FORMAT_SHOW_YEAR; +import static android.text.format.DateUtils.FORMAT_ABBREV_ALL; +import static android.text.format.DateUtils.FORMAT_ABBREV_RELATIVE; +import static android.text.format.DateUtils.FORMAT_NO_YEAR; +import static android.text.format.DateUtils.FORMAT_NUMERIC_DATE; +import static android.text.format.DateUtils.FORMAT_SHOW_YEAR; import static android.text.format.RelativeDateTimeFormatter.DAY_IN_MILLIS; import static android.text.format.RelativeDateTimeFormatter.HOUR_IN_MILLIS; import static android.text.format.RelativeDateTimeFormatter.MINUTE_IN_MILLIS; diff --git a/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java index 02ffc00dcba5..93de03adfa84 100644 --- a/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java +++ b/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java @@ -264,6 +264,25 @@ public class EditorInfoTest { InputConnection.GET_TEXT_WITH_STYLES))); } + @Test + public void surroundingTextRetrieval_writeToParcel_noException() { + StringBuilder sb = new StringBuilder("abcdefg"); + Parcel parcel = Parcel.obtain(); + EditorInfo editorInfo = new EditorInfo(); + editorInfo.initialSelStart = 2; + editorInfo.initialSelEnd = 5; + editorInfo.inputType = EditorInfo.TYPE_CLASS_TEXT; + + editorInfo.setInitialSurroundingText(sb); + sb.setLength(0); + editorInfo.writeToParcel(parcel, 0); + + try { + editorInfo.getInitialTextBeforeCursor(60, 1); + fail("Test shouldn't have exception"); + } catch (AssertionError e) { } + } + private static void assertExpectedTextLength(EditorInfo editorInfo, @Nullable Integer expectBeforeCursorLength, @Nullable Integer expectSelectionLength, @Nullable Integer expectAfterCursorLength) { diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml index a5a2221e5532..ada8b000a26b 100644 --- a/data/etc/com.android.systemui.xml +++ b/data/etc/com.android.systemui.xml @@ -39,6 +39,7 @@ <permission name="android.permission.MODIFY_PHONE_STATE"/> <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <permission name="android.permission.OBSERVE_NETWORK_POLICY"/> + <permission name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS" /> <permission name="android.permission.OVERRIDE_WIFI_CONFIG"/> <permission name="android.permission.PACKAGE_USAGE_STATS" /> <permission name="android.permission.READ_DREAM_STATE"/> diff --git a/data/etc/preinstalled-packages-platform-overlays.xml b/data/etc/preinstalled-packages-platform-overlays.xml index 84c1897a2b62..83323beb8dd4 100644 --- a/data/etc/preinstalled-packages-platform-overlays.xml +++ b/data/etc/preinstalled-packages-platform-overlays.xml @@ -19,250 +19,188 @@ <config> <install-in-user-type package="com.android.internal.display.cutout.emulation.corner"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.internal.display.cutout.emulation.double"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.internal.display.cutout.emulation.hole"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.internal.display.cutout.emulation.tall"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.internal.display.cutout.emulation.waterfall"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> - </install-in-user-type> - <install-in-user-type package="com.android.internal.systemui.navbar.twobutton"> - <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> - </install-in-user-type> - <install-in-user-type package="com.android.internal.systemui.navbar.threebutton"> - <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.internal.systemui.navbar.gestural"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.internal.systemui.navbar.gestural_extra_wide_back"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.internal.systemui.navbar.gestural_narrow_back"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.internal.systemui.navbar.gestural_wide_back"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> + </install-in-user-type> + <install-in-user-type package="com.android.internal.systemui.navbar.threebutton"> + <install-in user-type="FULL" /> + </install-in-user-type> + <install-in-user-type package="com.android.internal.systemui.navbar.twobutton"> + <install-in user-type="FULL" /> </install-in-user-type> <install-in-user-type package="com.android.internal.systemui.onehanded.gestural"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.color.amethyst"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.color.aquamarine"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.color.black"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.color.carbon"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.color.cinnamon"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.color.green"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.color.ocean"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.color.orchid"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.color.palette"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.color.purple"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.color.sand"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.color.space"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.color.tangerine"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.font.notoserifsource"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.circular.android"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.circular.launcher"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.circular.settings"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.circular.systemui"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.circular.themepicker"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.filled.android"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.filled.launcher"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.filled.settings"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.filled.systemui"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.filled.themepicker"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.kai.android"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.kai.launcher"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.kai.settings"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.kai.systemui"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.kai.themepicker"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.rounded.android"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.rounded.launcher"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.rounded.settings"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.rounded.systemui"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.rounded.themepicker"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.sam.android"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.sam.launcher"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.sam.settings"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.sam.systemui"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.sam.themepicker"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.victor.android"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.victor.launcher"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.victor.settings"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.victor.systemui"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon_pack.victor.themepicker"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon.pebble"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon.roundedrect"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon.squircle"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon.taperedrect"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon.teardrop"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> <install-in-user-type package="com.android.theme.icon.vessel"> <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> </install-in-user-type> </config> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 6798c0a3f87e..0286a7148b0b 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -143,6 +143,9 @@ applications that come with the platform <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" /> <permission name="android.permission.PACKAGE_USAGE_STATS" /> <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" /> + + <!-- For permission hub 2 debugging only --> + <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/> </privapp-permissions> <privapp-permissions package="com.android.phone"> diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl index 51500439d3cf..d92dbb2125ab 100644 --- a/data/keyboards/Generic.kl +++ b/data/keyboards/Generic.kl @@ -317,7 +317,7 @@ key 366 DVR # key 367 "KEY_MHP" # key 368 "KEY_LANGUAGE" # key 369 "KEY_TITLE" -# key 370 "KEY_SUBTITLE" +key 370 CAPTIONS # key 371 "KEY_ANGLE" # key 372 "KEY_ZOOM" # key 373 "KEY_MODE" @@ -352,7 +352,7 @@ key 397 CALENDAR key 402 CHANNEL_UP key 403 CHANNEL_DOWN # key 404 "KEY_FIRST" -# key 405 "KEY_LAST" +key 405 LAST_CHANNEL # key 406 "KEY_AB" # key 407 "KEY_NEXT" # key 408 "KEY_RESTART" diff --git a/diff b/diff deleted file mode 100644 index 5c75d88e6789..000000000000 --- a/diff +++ /dev/null @@ -1,25 +0,0 @@ -diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java -index fc43882..832dc91 100644 ---- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java -+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java -@@ -67,6 +67,7 @@ import java.util.Arrays; - import java.util.HashSet; - import java.util.List; - import java.util.Set; -+import java.util.NoSuchElementException; - - /** - * This class represents an accessibility client - either an AccessibilityService or a UiAutomation. -@@ -978,7 +979,11 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ - /* ignore */ - } - if (mService != null) { -- mService.unlinkToDeath(this, 0); -+ try { -+ mService.unlinkToDeath(this, 0); -+ }catch(NoSuchElementException e) { -+ Slog.e(LOG_TAG, "Failed unregistering death link"); -+ } - mService = null; - } - diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayChangeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java index 6eba9acbab4e..3263f79888d6 100644 --- a/packages/SystemUI/src/com/android/systemui/wm/DisplayChangeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.wm; +package com.android.wm.shell.common; import android.os.Handler; import android.os.RemoteException; diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java index 083c2439aa87..418973204add 100644 --- a/packages/SystemUI/src/com/android/systemui/wm/DisplayController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.wm; +package com.android.wm.shell.common; import android.annotation.Nullable; import android.content.Context; @@ -28,21 +28,16 @@ import android.view.Display; import android.view.IDisplayWindowListener; import android.view.IWindowManager; -import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.wm.DisplayChangeController.OnDisplayChangingListener; +import com.android.wm.shell.common.DisplayChangeController.OnDisplayChangingListener; import java.util.ArrayList; -import javax.inject.Inject; -import javax.inject.Singleton; - /** * This module deals with display rotations coming from WM. When WM starts a rotation: after it has * frozen the screen, it will call into this class. This will then call all registered local * controllers and give them a chance to queue up task changes to be applied synchronously with that * rotation. */ -@Singleton public class DisplayController { private static final String TAG = "DisplayController"; @@ -55,7 +50,7 @@ public class DisplayController { private final ArrayList<OnDisplaysChangedListener> mDisplayChangedListeners = new ArrayList<>(); /** - * Get's a display by id from DisplayManager. + * Gets a display by id from DisplayManager. */ public Display getDisplay(int displayId) { final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class); @@ -169,10 +164,9 @@ public class DisplayController { } }; - @Inject - public DisplayController(Context context, @Main Handler mainHandler, + public DisplayController(Context context, Handler handler, IWindowManager wmService) { - mHandler = mainHandler; + mHandler = handler; mContext = context; mWmService = wmService; mChangeController = new DisplayChangeController(mHandler, mWmService); diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java index 89f469a438a9..338ece5afbc2 100644 --- a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.wm; +package com.android.wm.shell.common; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -30,6 +30,7 @@ import android.os.ServiceManager; import android.util.Slog; import android.util.SparseArray; import android.view.IDisplayWindowInsetsController; +import android.view.IWindowManager; import android.view.InsetsSource; import android.view.InsetsSourceControl; import android.view.InsetsState; @@ -40,18 +41,12 @@ import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; import com.android.internal.view.IInputMethodManager; -import com.android.systemui.TransactionPool; -import com.android.systemui.dagger.qualifiers.Main; import java.util.ArrayList; -import javax.inject.Inject; -import javax.inject.Singleton; - /** * Manages IME control at the display-level. This occurs when IME comes up in multi-window mode. */ -@Singleton public class DisplayImeController implements DisplayController.OnDisplaysChangedListener { private static final String TAG = "DisplayImeController"; @@ -66,21 +61,20 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged private static final int DIRECTION_HIDE = 2; private static final int FLOATING_IME_BOTTOM_INSET = -80; - SystemWindows mSystemWindows; - final Handler mHandler; - final TransactionPool mTransactionPool; - - final SparseArray<PerDisplay> mImePerDisplay = new SparseArray<>(); - - final ArrayList<ImePositionProcessor> mPositionProcessors = new ArrayList<>(); + protected final IWindowManager mWmService; + protected final Handler mHandler; + private final TransactionPool mTransactionPool; + private final DisplayController mDisplayController; + private final SparseArray<PerDisplay> mImePerDisplay = new SparseArray<>(); + private final ArrayList<ImePositionProcessor> mPositionProcessors = new ArrayList<>(); - @Inject - public DisplayImeController(SystemWindows syswin, DisplayController displayController, - @Main Handler mainHandler, TransactionPool transactionPool) { + public DisplayImeController(IWindowManager wmService, DisplayController displayController, + Handler mainHandler, TransactionPool transactionPool) { mHandler = mainHandler; - mSystemWindows = syswin; + mWmService = wmService; mTransactionPool = transactionPool; - displayController.addDisplayWindowListener(this); + mDisplayController = displayController; + mDisplayController.addDisplayWindowListener(this); } @Override @@ -88,9 +82,9 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged // Add's a system-ui window-manager specifically for ime. This type is special because // WM will defer IME inset handling to it in multi-window scenarious. PerDisplay pd = new PerDisplay(displayId, - mSystemWindows.mDisplayController.getDisplayLayout(displayId).rotation()); + mDisplayController.getDisplayLayout(displayId).rotation()); try { - mSystemWindows.mWmService.setDisplayWindowInsetsController(displayId, pd); + mWmService.setDisplayWindowInsetsController(displayId, pd); } catch (RemoteException e) { Slog.w(TAG, "Unable to set insets controller on display " + displayId); } @@ -103,7 +97,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged if (pd == null) { return; } - if (mSystemWindows.mDisplayController.getDisplayLayout(displayId).rotation() + if (mDisplayController.getDisplayLayout(displayId).rotation() != pd.mRotation && isImeShowing(displayId)) { pd.startAnimation(true, false /* forceRestart */); } @@ -112,7 +106,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged @Override public void onDisplayRemoved(int displayId) { try { - mSystemWindows.mWmService.setDisplayWindowInsetsController(displayId, null); + mWmService.setDisplayWindowInsetsController(displayId, null); } catch (RemoteException e) { Slog.w(TAG, "Unable to remove insets controller on display " + displayId); } @@ -270,7 +264,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged private void setVisibleDirectly(boolean visible) { mInsetsState.getSource(InsetsState.ITYPE_IME).setVisible(visible); try { - mSystemWindows.mWmService.modifyDisplayWindowInsets(mDisplayId, mInsetsState); + mWmService.modifyDisplayWindowInsets(mDisplayId, mInsetsState); } catch (RemoteException e) { } } @@ -289,7 +283,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged // an IME inset). For now, we assume that no non-floating IME will be <= this nav bar // frame height so any reported frame that is <= nav-bar frame height is assumed to // be floating. - return frame.height() <= mSystemWindows.mDisplayController.getDisplayLayout(mDisplayId) + return frame.height() <= mDisplayController.getDisplayLayout(mDisplayId) .navBarFrameHeight(); } @@ -304,9 +298,8 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged // This is a "floating" or "expanded" IME, so to get animations, just // pretend the ime has some size just below the screen. mImeFrame.set(newFrame); - final int floatingInset = (int) ( - mSystemWindows.mDisplayController.getDisplayLayout(mDisplayId).density() - * FLOATING_IME_BOTTOM_INSET); + final int floatingInset = (int) (mDisplayController.getDisplayLayout(mDisplayId) + .density() * FLOATING_IME_BOTTOM_INSET); mImeFrame.bottom -= floatingInset; } else if (newFrame.height() != 0) { // Don't set a new frame if it's empty and hiding -- this maintains continuity @@ -364,6 +357,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged mAnimation.setInterpolator(INTERPOLATOR); mAnimation.addListener(new AnimatorListenerAdapter() { private boolean mCancelled = false; + @Override public void onAnimationStart(Animator animation) { SurfaceControl.Transaction t = mTransactionPool.acquire(); @@ -386,10 +380,12 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged t.apply(); mTransactionPool.release(t); } + @Override public void onAnimationCancel(Animator animation) { mCancelled = true; } + @Override public void onAnimationEnd(Animator animation) { if (DEBUG) Slog.d(TAG, "onAnimationEnd " + mCancelled); @@ -449,18 +445,19 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged int IME_ANIMATION_NO_ALPHA = 1; /** @hide */ - @IntDef(prefix = { "IME_ANIMATION_" }, value = { + @IntDef(prefix = {"IME_ANIMATION_"}, value = { IME_ANIMATION_NO_ALPHA, }) - @interface ImeAnimationFlags {} + @interface ImeAnimationFlags { + } /** * Called when the IME position is starting to animate. * - * @param hiddenTop The y position of the top of the IME surface when it is hidden. - * @param shownTop The y position of the top of the IME surface when it is shown. - * @param showing {@code true} when we are animating from hidden to shown, {@code false} - * when animating from shown to hidden. + * @param hiddenTop The y position of the top of the IME surface when it is hidden. + * @param shownTop The y position of the top of the IME surface when it is shown. + * @param showing {@code true} when we are animating from hidden to shown, {@code false} + * when animating from shown to hidden. * @param isFloating {@code true} when the ime is a floating ime (doesn't inset). * @return flags that may alter how ime itself is animated (eg. no-alpha). */ @@ -476,8 +473,8 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged * * @param imeTop The current y position of the top of the IME surface. */ - default void onImePositionChanged(int displayId, int imeTop, - SurfaceControl.Transaction t) {} + default void onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t) { + } /** * Called when the IME position is done animating. @@ -485,7 +482,8 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged * @param cancel {@code true} if this was cancelled. This implies another start is coming. */ default void onImeEndPositioning(int displayId, boolean cancel, - SurfaceControl.Transaction t) {} + SurfaceControl.Transaction t) { + } } public IInputMethodManager getImms() { diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java index a341f3050ea6..3181dbf74ace 100644 --- a/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.wm; +package com.android.wm.shell.common; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; @@ -52,7 +52,7 @@ import java.lang.annotation.RetentionPolicy; /** * Contains information about the layout-properties of a display. This refers to internal layout - * like insets/cutout/rotation. In general, this can be thought of as the System-UI analog to + * like insets/cutout/rotation. In general, this can be thought of as the shell analog to * DisplayPolicy. */ public class DisplayLayout { @@ -345,9 +345,9 @@ public class DisplayLayout { /** Retrieve the statusbar height from resources. */ static int getStatusBarHeight(boolean landscape, Resources res) { return landscape ? res.getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height_landscape) - : res.getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height_portrait); + com.android.internal.R.dimen.status_bar_height_landscape) + : res.getDimensionPixelSize( + com.android.internal.R.dimen.status_bar_height_portrait); } /** Calculate the DisplayCutout for a particular display size/rotation. */ diff --git a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java index 21f67aef5604..8abe9eeb6a9a 100644 --- a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.wm; +package com.android.wm.shell.common; import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; @@ -52,23 +52,18 @@ import com.android.internal.os.IResultReceiver; import java.util.HashMap; -import javax.inject.Inject; -import javax.inject.Singleton; - /** - * Represents the "windowing" layer of the System-UI. This layer allows system-ui components to - * place and manipulate windows without talking to WindowManager. + * Represents the "windowing" layer of the WM Shell. This layer allows shell components to place and + * manipulate windows without talking to WindowManager. */ -@Singleton public class SystemWindows { private static final String TAG = "SystemWindows"; private final SparseArray<PerDisplay> mPerDisplay = new SparseArray<>(); - final HashMap<View, SurfaceControlViewHost> mViewRoots = new HashMap<>(); - Context mContext; - IWindowSession mSession; - DisplayController mDisplayController; - IWindowManager mWmService; + private final HashMap<View, SurfaceControlViewHost> mViewRoots = new HashMap<>(); + private final DisplayController mDisplayController; + private final IWindowManager mWmService; + private IWindowSession mSession; private final DisplayController.OnDisplaysChangedListener mDisplayListener = new DisplayController.OnDisplaysChangedListener() { @@ -88,10 +83,7 @@ public class SystemWindows { public void onDisplayRemoved(int displayId) { } }; - @Inject - public SystemWindows(Context context, DisplayController displayController, - IWindowManager wmService) { - mContext = context; + public SystemWindows(DisplayController displayController, IWindowManager wmService) { mWmService = wmService; mDisplayController = displayController; mDisplayController.addDisplayWindowListener(mDisplayListener); @@ -172,7 +164,7 @@ public class SystemWindows { /** * Get the IWindow token for a specific root. * - * @param windowType A window type from {@link android.view.WindowManager}. + * @param windowType A window type from {@link WindowManager}. */ IWindow getWindow(int displayId, int windowType) { PerDisplay pd = mPerDisplay.get(displayId); @@ -215,8 +207,8 @@ public class SystemWindows { } final Display display = mDisplayController.getDisplay(mDisplayId); SurfaceControlViewHost viewRoot = - new SurfaceControlViewHost(mContext, display, wwm, - true /* useSfChoreographer */); + new SurfaceControlViewHost( + view.getContext(), display, wwm, true /* useSfChoreographer */); attrs.flags |= FLAG_HARDWARE_ACCELERATED; viewRoot.setView(view, attrs); mViewRoots.put(view, viewRoot); @@ -318,7 +310,7 @@ public class SystemWindows { } } - class ContainerWindow extends IWindow.Stub { + static class ContainerWindow extends IWindow.Stub { ContainerWindow() {} @Override diff --git a/packages/SystemUI/src/com/android/systemui/TransactionPool.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TransactionPool.java index 801cf8a7523b..4c34566b0d98 100644 --- a/packages/SystemUI/src/com/android/systemui/TransactionPool.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TransactionPool.java @@ -14,24 +14,19 @@ * limitations under the License. */ -package com.android.systemui; +package com.android.wm.shell.common; import android.util.Pools; import android.view.SurfaceControl; -import javax.inject.Inject; -import javax.inject.Singleton; - /** * Provides a synchronized pool of {@link SurfaceControl.Transaction}s to minimize allocations. */ -@Singleton public class TransactionPool { private final Pools.SynchronizedPool<SurfaceControl.Transaction> mTransactionPool = new Pools.SynchronizedPool<>(4); - @Inject - TransactionPool() { + public TransactionPool() { } /** Gets a transaction from the pool. */ diff --git a/libs/WindowManager/Shell/tests/Android.bp b/libs/WindowManager/Shell/tests/Android.bp index 78fa45ebdf94..9868879cebb9 100644 --- a/libs/WindowManager/Shell/tests/Android.bp +++ b/libs/WindowManager/Shell/tests/Android.bp @@ -36,9 +36,6 @@ android_test { "libstaticjvmtiagent", ], - sdk_version: "current", - platform_apis: true, - optimize: { enabled: false, }, diff --git a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/tests/WindowManagerShellTest.java b/libs/WindowManager/Shell/tests/src/com/android/wm/shell/WindowManagerShellTest.java index 376875b143a1..f1ead3c8a441 100644 --- a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/tests/WindowManagerShellTest.java +++ b/libs/WindowManager/Shell/tests/src/com/android/wm/shell/WindowManagerShellTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 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,13 +14,11 @@ * limitations under the License. */ -package com.android.wm.shell.tests; +package com.android.wm.shell; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; -import com.android.wm.shell.WindowManagerShell; - import org.junit.Test; import org.junit.runner.RunWith; diff --git a/packages/SystemUI/tests/src/com/android/systemui/wm/DisplayLayoutTest.java b/libs/WindowManager/Shell/tests/src/com/android/wm/shell/common/DisplayLayoutTest.java index 9596a73eaf3e..2b5b77e49e3a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wm/DisplayLayoutTest.java +++ b/libs/WindowManager/Shell/tests/src/com/android/wm/shell/common/DisplayLayoutTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.wm; +package com.android.wm.shell.common; import static android.content.res.Configuration.UI_MODE_TYPE_NORMAL; import static android.view.Surface.ROTATION_0; @@ -35,12 +35,11 @@ import android.view.DisplayInfo; import androidx.test.filters.SmallTest; import com.android.internal.R; -import com.android.systemui.SysuiTestCase; import org.junit.Test; @SmallTest -public class DisplayLayoutTest extends SysuiTestCase { +public class DisplayLayoutTest { @Test public void testInsets() { diff --git a/libs/androidfw/fuzz/resourcefile_fuzzer/Android.bp b/libs/androidfw/fuzz/resourcefile_fuzzer/Android.bp new file mode 100644 index 000000000000..77ef8dfb9725 --- /dev/null +++ b/libs/androidfw/fuzz/resourcefile_fuzzer/Android.bp @@ -0,0 +1,46 @@ +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_fuzz { + name: "resourcefile_fuzzer", + srcs: [ + "resourcefile_fuzzer.cpp", + ], + host_supported: true, + corpus: ["corpus/*"], + static_libs: ["libgmock"], + target: { + android: { + shared_libs:[ + "libandroidfw", + "libbase", + "libcutils", + "libutils", + "libziparchive", + "libui", + ], + }, + host: { + static_libs: [ + "libandroidfw", + "libbase", + "libcutils", + "libutils", + "libziparchive", + "liblog", + "libz", + ], + }, + }, +} diff --git a/libs/androidfw/fuzz/resourcefile_fuzzer/corpus/resources.arsc b/libs/androidfw/fuzz/resourcefile_fuzzer/corpus/resources.arsc Binary files differnew file mode 100644 index 000000000000..3cf2ea733d28 --- /dev/null +++ b/libs/androidfw/fuzz/resourcefile_fuzzer/corpus/resources.arsc diff --git a/libs/androidfw/fuzz/resourcefile_fuzzer/resourcefile_fuzzer.cpp b/libs/androidfw/fuzz/resourcefile_fuzzer/resourcefile_fuzzer.cpp new file mode 100644 index 000000000000..96d44ab8e45c --- /dev/null +++ b/libs/androidfw/fuzz/resourcefile_fuzzer/resourcefile_fuzzer.cpp @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#include <string> +#include <memory> + +#include <androidfw/ApkAssets.h> +#include <androidfw/LoadedArsc.h> +#include <androidfw/StringPiece.h> + +#include <fuzzer/FuzzedDataProvider.h> + +using android::ApkAssets; +using android::LoadedArsc; +using android::StringPiece; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + + std::unique_ptr<const LoadedArsc> loaded_arsc = + LoadedArsc::Load(StringPiece(reinterpret_cast<const char*>(data), size)); + + return 0; +}
\ No newline at end of file diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java index 00a4c7e19f34..6e3fb1991acc 100644 --- a/media/java/android/media/AudioDeviceInfo.java +++ b/media/java/android/media/AudioDeviceInfo.java @@ -18,7 +18,6 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.SystemApi; import android.util.SparseIntArray; import java.lang.annotation.Retention; @@ -137,13 +136,15 @@ public final class AudioDeviceInfo { */ public static final int TYPE_BUILTIN_SPEAKER_SAFE = 24; /** - * @hide * A device type for rerouting audio within the Android framework between mixes and - * system applications. Typically created when using - * {@link android.media.audiopolicy.AudioPolicy} for mixes created with the - * {@link android.media.audiopolicy.AudioMix#ROUTE_FLAG_RENDER} flag. - */ - @SystemApi + * system applications. + * This type is for instance encountered when querying the output device of a track + * (with {@link AudioTrack#getRoutedDevice()} playing from a device in screen mirroring mode, + * where the audio is not heard on the device, but on the remote device. + */ + // Typically created when using + // {@link android.media.audiopolicy.AudioPolicy} for mixes created with the + // {@link android.media.audiopolicy.AudioMix#ROUTE_FLAG_LOOP_BACK} flag. public static final int TYPE_REMOTE_SUBMIX = 25; /** @hide */ diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java index 42635216e98f..f4fd1fca2ff9 100644 --- a/media/java/android/media/audiofx/AudioEffect.java +++ b/media/java/android/media/audiofx/AudioEffect.java @@ -53,6 +53,7 @@ import java.util.UUID; * <li> {@link android.media.audiofx.PresetReverb}</li> * <li> {@link android.media.audiofx.EnvironmentalReverb}</li> * <li> {@link android.media.audiofx.DynamicsProcessing}</li> + * <li> {@link android.media.audiofx.HapticGenerator}</li> * </ul> * <p>To apply the audio effect to a specific AudioTrack or MediaPlayer instance, * the application must specify the audio session ID of that instance when creating the AudioEffect. @@ -146,6 +147,14 @@ public class AudioEffect { .fromString("7261676f-6d75-7369-6364-28e2fd3ac39e"); /** + * UUID for Haptic Generator. + */ + // This is taken from system/media/audio/include/system/audio_effects/effect_hapticgenerator.h + @NonNull + public static final UUID EFFECT_TYPE_HAPTIC_GENERATOR = UUID + .fromString("1411e6d6-aecd-4021-a1cf-a6aceb0d71e5"); + + /** * Null effect UUID. See {@link AudioEffect(UUID, UUID, int, int)} for use. * @hide */ @@ -225,7 +234,8 @@ public class AudioEffect { * {@link AudioEffect#EFFECT_TYPE_BASS_BOOST}, {@link AudioEffect#EFFECT_TYPE_ENV_REVERB}, * {@link AudioEffect#EFFECT_TYPE_EQUALIZER}, {@link AudioEffect#EFFECT_TYPE_NS}, * {@link AudioEffect#EFFECT_TYPE_PRESET_REVERB}, {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER}, - * {@link AudioEffect#EFFECT_TYPE_DYNAMICS_PROCESSING}. + * {@link AudioEffect#EFFECT_TYPE_DYNAMICS_PROCESSING}, + * {@link AudioEffect#EFFECT_TYPE_HAPTIC_GENERATOR}. * </li> * <li>uuid: UUID for this particular implementation</li> * <li>connectMode: {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY}</li> @@ -246,8 +256,9 @@ public class AudioEffect { * {@link AudioEffect#EFFECT_TYPE_AGC}, {@link AudioEffect#EFFECT_TYPE_BASS_BOOST}, * {@link AudioEffect#EFFECT_TYPE_ENV_REVERB}, {@link AudioEffect#EFFECT_TYPE_EQUALIZER}, * {@link AudioEffect#EFFECT_TYPE_NS}, {@link AudioEffect#EFFECT_TYPE_PRESET_REVERB} - * {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER} - * or {@link AudioEffect#EFFECT_TYPE_DYNAMICS_PROCESSING}.<br> + * {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER}, + * {@link AudioEffect#EFFECT_TYPE_DYNAMICS_PROCESSING}, + * or {@link AudioEffect#EFFECT_TYPE_HAPTIC_GENERATOR}.<br> * For reverberation, bass boost, EQ and virtualizer, the UUID * corresponds to the OpenSL ES Interface ID. */ @@ -284,7 +295,8 @@ public class AudioEffect { * {@link AudioEffect#EFFECT_TYPE_EQUALIZER}, {@link AudioEffect#EFFECT_TYPE_NS}, * {@link AudioEffect#EFFECT_TYPE_PRESET_REVERB}, * {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER}, - * {@link AudioEffect#EFFECT_TYPE_DYNAMICS_PROCESSING}. + * {@link AudioEffect#EFFECT_TYPE_DYNAMICS_PROCESSING}, + * {@link AudioEffect#EFFECT_TYPE_HAPTIC_GENERATOR}. * @param uuid UUID for this particular implementation * @param connectMode {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY} * @param name human readable effect name diff --git a/media/java/android/media/audiofx/HapticGenerator.java b/media/java/android/media/audiofx/HapticGenerator.java new file mode 100644 index 000000000000..f8529eb05c03 --- /dev/null +++ b/media/java/android/media/audiofx/HapticGenerator.java @@ -0,0 +1,128 @@ +/* + * 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.media.audiofx; + +import android.annotation.NonNull; +import android.media.AudioManager; +import android.util.Log; + +import java.util.UUID; + +/** + * Haptic Generator(HG). + * <p>HG is an audio post-processor which generates haptic data based on the audio channels. The + * generated haptic data is sent along with audio data down to the audio HAL, which will require the + * device to support audio-coupled-haptic playback. In that case, the effect will only be created on + * device supporting audio-coupled-haptic playback. Call {@link HapticGenerator#isAvailable()} to + * check if the device supports this effect. + * <p>An application can create a HapticGenerator object to initiate and control this audio effect + * in the audio framework. An application can set which audio channel to be used to generate + * haptic data. + * <p>To attach the HapticGenerator to a particular AudioTrack or MediaPlayer, specify the audio + * session ID of this AudioTrack or MediaPlayer when constructing the HapticGenerator. + * <p>See {@link android.media.MediaPlayer#getAudioSessionId()} for details on audio sessions. + * <p>See {@link android.media.audiofx.AudioEffect} class for more details on controlling audio + * effects. + */ +public class HapticGenerator extends AudioEffect implements AutoCloseable { + + private static final String TAG = "HapticGenerator"; + + // For every HapticGenerator, it contains a volume control effect so that the volume control + // will always be handled in the effect chain. In that case, the HapticGenerator can generate + // haptic data based on the raw audio data. + private AudioEffect mVolumeControlEffect; + + public static boolean isAvailable() { + return AudioManager.isHapticPlaybackSupported() + && AudioEffect.isEffectTypeAvailable(AudioEffect.EFFECT_TYPE_HAPTIC_GENERATOR); + } + + /** + * Creates a HapticGenerator and attaches it to the given audio session. + * Use {@link android.media.AudioTrack#getAudioSessionId()} or + * {@link android.media.MediaPlayer#getAudioSessionId()} to + * apply this effect on specific AudioTrack or MediaPlayer instance. + * + * @param audioSession system wide unique audio session identifier. The HapticGenerator will be + * applied to the players with the same audio session. + * @return HapticGenerator created or null if the device does not support HapticGenerator or + * the audio session is invalid. + * @throws java.lang.IllegalArgumentException when HapticGenerator is not supported + * @throws java.lang.UnsupportedOperationException when the effect library is not loaded. + * @throws java.lang.RuntimeException for all other error + */ + public static @NonNull HapticGenerator create(int audioSession) { + return new HapticGenerator(audioSession); + } + + /** + * Class constructor. + * + * @param audioSession system wide unique audio session identifier. The HapticGenerator will be + * attached to the MediaPlayer or AudioTrack in the same audio session. + * @throws java.lang.IllegalArgumentException + * @throws java.lang.UnsupportedOperationException + * @throws java.lang.RuntimeException + */ + private HapticGenerator(int audioSession) { + super(EFFECT_TYPE_HAPTIC_GENERATOR, EFFECT_TYPE_NULL, 0, audioSession); + mVolumeControlEffect = new AudioEffect( + AudioEffect.EFFECT_TYPE_NULL, + UUID.fromString("119341a0-8469-11df-81f9-0002a5d5c51b"), + 0, + audioSession); + } + + /** + * Enable or disable the effect. + * + * @param enabled the requested enable state + * @return {@link #SUCCESS} in case of success, {@link #ERROR_INVALID_OPERATION} + * or {@link #ERROR_DEAD_OBJECT} in case of failure. + */ + @Override + public int setEnabled(boolean enabled) { + int ret = super.setEnabled(enabled); + if (ret == SUCCESS) { + if (mVolumeControlEffect == null + || mVolumeControlEffect.setEnabled(enabled) != SUCCESS) { + Log.w(TAG, "Failed to enable volume control effect for HapticGenerator"); + } + } + return ret; + } + + /** + * Releases the native AudioEffect resources. + */ + @Override + public void release() { + if (mVolumeControlEffect != null) { + mVolumeControlEffect.release(); + } + super.release(); + } + + /** + * Release the resources that are held by the effect. + */ + @Override + public void close() { + release(); + } +} diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java index 3c2be5f93e30..029e61492b6d 100644 --- a/media/java/android/media/browse/MediaBrowser.java +++ b/media/java/android/media/browse/MediaBrowser.java @@ -25,7 +25,6 @@ import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.ParceledListSlice; import android.media.MediaDescription; -import android.media.session.MediaController; import android.media.session.MediaSession; import android.os.Binder; import android.os.Bundle; @@ -757,8 +756,8 @@ public final class MediaBrowser { * Flag: Indicates that the item is playable. * <p> * The id of this item may be passed to - * {@link MediaController.TransportControls#playFromMediaId(String, Bundle)} - * to start playing it. + * {@link android.media.session.MediaController.TransportControls + * #playFromMediaId(String, Bundle)} to start playing it. * </p> */ public static final int FLAG_PLAYABLE = 1 << 1; @@ -1107,13 +1106,7 @@ public final class MediaBrowser { } @Override - public void onLoadChildren(String parentId, ParceledListSlice list) { - onLoadChildrenWithOptions(parentId, list, null); - } - - @Override - public void onLoadChildrenWithOptions(String parentId, ParceledListSlice list, - final Bundle options) { + public void onLoadChildren(String parentId, ParceledListSlice list, Bundle options) { MediaBrowser mediaBrowser = mMediaBrowser.get(); if (mediaBrowser != null) { mediaBrowser.onLoadChildren(this, parentId, list, options); diff --git a/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl index 7e3f2f8868fb..a8772076af97 100644 --- a/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl +++ b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl @@ -23,7 +23,5 @@ oneway interface IMediaBrowserServiceCallbacks { void onConnect(String root, in MediaSession.Token session, in Bundle extras); @UnsupportedAppUsage void onConnectFailed(); - void onLoadChildren(String mediaId, in ParceledListSlice list); - void onLoadChildrenWithOptions(String mediaId, in ParceledListSlice list, - in Bundle options); + void onLoadChildren(String mediaId, in ParceledListSlice list, in Bundle options); } diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java index 06adf30a8303..39c7682a2a74 100644 --- a/media/java/android/service/media/MediaBrowserService.java +++ b/media/java/android/service/media/MediaBrowserService.java @@ -687,7 +687,7 @@ public abstract class MediaBrowserService extends Service { final ParceledListSlice<MediaBrowser.MediaItem> pls = filteredList == null ? null : new ParceledListSlice<>(filteredList); try { - connection.callbacks.onLoadChildrenWithOptions(parentId, pls, options); + connection.callbacks.onLoadChildren(parentId, pls, options); } catch (RemoteException ex) { // The other side is in the process of crashing. Log.w(TAG, "Calling onLoadChildren() failed for id=" + parentId diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index df022d562768..6e26f2c2da9e 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -3497,6 +3497,10 @@ static jlong android_media_tv_Tuner_read_dvr(JNIEnv *env, jobject dvr, jlong siz } else { ALOGE("dvrMq.beginWrite failed"); } + + if (ret > 0) { + dvrSp->mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY)); + } return (jlong) ret; } @@ -3524,7 +3528,7 @@ static jlong android_media_tv_Tuner_read_dvr_from_array( if (dvrSp->mDvrMQ->write(reinterpret_cast<unsigned char*>(src) + offset, size)) { env->ReleaseByteArrayElements(buffer, src, 0); - dvrSp->mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED)); + dvrSp->mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY)); } else { ALOGD("Failed to write FMQ"); env->ReleaseByteArrayElements(buffer, src, 0); @@ -3585,6 +3589,9 @@ static jlong android_media_tv_Tuner_write_dvr(JNIEnv *env, jobject dvr, jlong si } else { ALOGE("dvrMq.beginRead failed"); } + if (ret > 0) { + dvrSp->mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED)); + } return (jlong) ret; } diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt index c14f23f6ace0..2b95992b1edf 100644 --- a/non-updatable-api/current.txt +++ b/non-updatable-api/current.txt @@ -24061,6 +24061,7 @@ package android.media { field public static final int TYPE_IP = 20; // 0x14 field public static final int TYPE_LINE_ANALOG = 5; // 0x5 field public static final int TYPE_LINE_DIGITAL = 6; // 0x6 + field public static final int TYPE_REMOTE_SUBMIX = 25; // 0x19 field public static final int TYPE_TELEPHONY = 18; // 0x12 field public static final int TYPE_TV_TUNER = 17; // 0x11 field public static final int TYPE_UNKNOWN = 0; // 0x0 @@ -27666,6 +27667,7 @@ package android.media.audiofx { field public static final java.util.UUID EFFECT_TYPE_DYNAMICS_PROCESSING; field public static final java.util.UUID EFFECT_TYPE_ENV_REVERB; field public static final java.util.UUID EFFECT_TYPE_EQUALIZER; + field @NonNull public static final java.util.UUID EFFECT_TYPE_HAPTIC_GENERATOR; field public static final java.util.UUID EFFECT_TYPE_LOUDNESS_ENHANCER; field public static final java.util.UUID EFFECT_TYPE_NS; field public static final java.util.UUID EFFECT_TYPE_PRESET_REVERB; @@ -28018,6 +28020,13 @@ package android.media.audiofx { field public short numBands; } + public class HapticGenerator extends android.media.audiofx.AudioEffect implements java.lang.AutoCloseable { + method public void close(); + method @NonNull public static android.media.audiofx.HapticGenerator create(int); + method public static boolean isAvailable(); + method public int setEnabled(boolean); + } + public class LoudnessEnhancer extends android.media.audiofx.AudioEffect { ctor public LoudnessEnhancer(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.RuntimeException, java.lang.UnsupportedOperationException; method public float getTargetGain() throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException; diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt index b41ab93295b5..222e563d4f96 100644 --- a/non-updatable-api/system-current.txt +++ b/non-updatable-api/system-current.txt @@ -4112,10 +4112,6 @@ package android.media { field public static final int ROLE_OUTPUT = 2; // 0x2 } - public final class AudioDeviceInfo { - field public static final int TYPE_REMOTE_SUBMIX = 25; // 0x19 - } - public final class AudioFocusInfo implements android.os.Parcelable { method public int describeContents(); method @NonNull public android.media.AudioAttributes getAttributes(); diff --git a/packages/CarSystemUI/res/layout/super_notification_shade.xml b/packages/CarSystemUI/res/layout/super_notification_shade.xml deleted file mode 100644 index db71c91ca695..000000000000 --- a/packages/CarSystemUI/res/layout/super_notification_shade.xml +++ /dev/null @@ -1,80 +0,0 @@ -<?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. -*/ ---> - -<!-- This is the notification shade window. --> -<com.android.systemui.statusbar.phone.NotificationShadeWindowView - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:sysui="http://schemas.android.com/apk/res-auto" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:fitsSystemWindows="true"> - - <com.android.systemui.statusbar.BackDropView - android:id="@+id/backdrop" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" - sysui:ignoreRightInset="true" - > - <ImageView android:id="@+id/backdrop_back" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:scaleType="centerCrop"/> - <ImageView android:id="@+id/backdrop_front" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:scaleType="centerCrop" - android:visibility="invisible"/> - </com.android.systemui.statusbar.BackDropView> - - <com.android.systemui.statusbar.ScrimView - android:id="@+id/scrim_behind" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:importantForAccessibility="no" - sysui:ignoreRightInset="true" - /> - - <include layout="@layout/brightness_mirror"/> - - <ViewStub android:id="@+id/fullscreen_user_switcher_stub" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout="@layout/car_fullscreen_user_switcher"/> - - <include layout="@layout/notification_center_activity" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_marginBottom="@dimen/navigation_bar_height" - android:visibility="invisible"/> - - <include layout="@layout/status_bar_expanded" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="invisible"/> - - <com.android.systemui.statusbar.ScrimView - android:id="@+id/scrim_in_front" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:importantForAccessibility="no" - sysui:ignoreRightInset="true" - /> - -</com.android.systemui.statusbar.phone.NotificationShadeWindowView> diff --git a/packages/CarSystemUI/res/layout/super_status_bar.xml b/packages/CarSystemUI/res/layout/super_status_bar.xml deleted file mode 100644 index d93f62f8809d..000000000000 --- a/packages/CarSystemUI/res/layout/super_status_bar.xml +++ /dev/null @@ -1,46 +0,0 @@ -<?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. -*/ ---> - -<!-- This is the status bar window. --> -<com.android.systemui.statusbar.phone.StatusBarWindowView - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:sysui="http://schemas.android.com/apk/res-auto" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:fitsSystemWindows="true"> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - > - <FrameLayout - android:id="@+id/status_bar_container" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:visibility="gone" - /> - - <FrameLayout - android:id="@+id/car_top_navigation_bar_container" - android:layout_width="match_parent" - android:layout_height="wrap_content"/> - </LinearLayout> - -</com.android.systemui.statusbar.phone.StatusBarWindowView> diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml index cb321cdc6c4d..8359dac6a30f 100644 --- a/packages/CarSystemUI/res/values/dimens.xml +++ b/packages/CarSystemUI/res/values/dimens.xml @@ -81,6 +81,21 @@ <dimen name="car_keyline_2">96dp</dimen> <dimen name="car_keyline_3">128dp</dimen> + <!-- Height of icons in Ongoing App Ops dialog. Both App Op icon and application icon --> + <dimen name="ongoing_appops_dialog_icon_height">48dp</dimen> + <!-- Margin between text lines in Ongoing App Ops dialog --> + <dimen name="ongoing_appops_dialog_text_margin">15dp</dimen> + <!-- Padding around Ongoing App Ops dialog content --> + <dimen name="ongoing_appops_dialog_content_padding">24dp</dimen> + <!-- Margins around the Ongoing App Ops chip. In landscape, the side margins are 0 --> + <dimen name="ongoing_appops_chip_margin">12dp</dimen> + <!-- Start and End padding for Ongoing App Ops chip --> + <dimen name="ongoing_appops_chip_side_padding">6dp</dimen> + <!-- Padding between background of Ongoing App Ops chip and content --> + <dimen name="ongoing_appops_chip_bg_padding">4dp</dimen> + <!-- Radius of Ongoing App Ops chip corners --> + <dimen name="ongoing_appops_chip_bg_corner_radius">12dp</dimen> + <!-- Car volume dimens. --> <dimen name="car_volume_item_icon_size">@dimen/car_primary_icon_size</dimen> <dimen name="car_volume_item_height">@*android:dimen/car_single_line_list_item_height</dimen> diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java index ffdf378959c9..797a178c9a4b 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java @@ -21,8 +21,6 @@ import com.android.systemui.bubbles.dagger.BubbleModule; import com.android.systemui.car.navigationbar.CarNavigationBar; import com.android.systemui.car.notification.CarNotificationModule; import com.android.systemui.car.sideloaded.SideLoadedAppController; -import com.android.systemui.car.statusbar.CarStatusBar; -import com.android.systemui.car.statusbar.CarStatusBarModule; import com.android.systemui.car.voicerecognition.ConnectedDeviceVoiceRecognitionNotifier; import com.android.systemui.car.volume.VolumeUI; import com.android.systemui.car.window.OverlayWindowModule; @@ -37,10 +35,10 @@ import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsModule; import com.android.systemui.shortcut.ShortcutKeyDispatcher; import com.android.systemui.stackdivider.Divider; +import com.android.systemui.statusbar.dagger.StatusBarModule; import com.android.systemui.statusbar.notification.InstantAppNotifier; import com.android.systemui.statusbar.notification.dagger.NotificationsModule; import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.tv.TvStatusBar; import com.android.systemui.theme.ThemeOverlayController; import com.android.systemui.toast.ToastUI; import com.android.systemui.util.leak.GarbageMonitor; @@ -51,7 +49,7 @@ import dagger.multibindings.ClassKey; import dagger.multibindings.IntoMap; /** Binder for car specific {@link SystemUI} modules. */ -@Module(includes = {RecentsModule.class, CarStatusBarModule.class, NotificationsModule.class, +@Module(includes = {RecentsModule.class, StatusBarModule.class, NotificationsModule.class, BubbleModule.class, KeyguardModule.class, OverlayWindowModule.class, CarNotificationModule.class}) public abstract class CarSystemUIBinder { @@ -162,19 +160,7 @@ public abstract class CarSystemUIBinder { @Binds @IntoMap @ClassKey(StatusBar.class) - public abstract SystemUI bindsStatusBar(CarStatusBar sysui); - - /** Inject into TvStatusBar. */ - @Binds - @IntoMap - @ClassKey(TvStatusBar.class) - public abstract SystemUI bindsTvStatusBar(TvStatusBar sysui); - - /** Inject into StatusBarGoogle. */ - @Binds - @IntoMap - @ClassKey(CarStatusBar.class) - public abstract SystemUI bindsCarStatusBar(CarStatusBar sysui); + public abstract SystemUI bindsStatusBar(StatusBar sysui); /** Inject into VolumeUI. */ @Binds diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java index 496742680893..7b6dceb5fcd7 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java @@ -22,14 +22,13 @@ import static com.android.systemui.Dependency.LEAK_REPORT_EMAIL_NAME; import android.content.Context; import android.os.Handler; import android.os.PowerManager; +import android.view.IWindowManager; import com.android.keyguard.KeyguardViewController; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.car.CarDeviceProvisionedController; import com.android.systemui.car.CarDeviceProvisionedControllerImpl; import com.android.systemui.car.keyguard.CarKeyguardViewController; -import com.android.systemui.car.statusbar.CarStatusBar; -import com.android.systemui.car.statusbar.CarStatusBarKeyguardViewManager; import com.android.systemui.car.statusbar.DozeServiceHost; import com.android.systemui.car.statusbar.DummyNotificationShadeWindowController; import com.android.systemui.car.volume.CarVolumeDialogComponent; @@ -59,16 +58,17 @@ 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.phone.ShadeControllerImpl; -import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.BatteryControllerImpl; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.volume.VolumeDialogComponent; -import com.android.systemui.wm.DisplayImeController; import com.android.systemui.wm.DisplaySystemBarsController; +import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.DisplayImeController; +import com.android.wm.shell.common.SystemWindows; +import com.android.wm.shell.common.TransactionPool; import javax.inject.Named; import javax.inject.Singleton; @@ -99,10 +99,6 @@ public abstract class CarSystemUIModule { groupManager, configurationController); } - @Binds - abstract DisplayImeController bindDisplayImeController( - DisplaySystemBarsController displaySystemBarsController); - @Singleton @Provides @Named(LEAK_REPORT_EMAIL_NAME) @@ -117,6 +113,31 @@ public abstract class CarSystemUIModule { return new Recents(context, recentsImplementation, commandQueue); } + @Singleton + @Provides + static TransactionPool provideTransactionPool() { + return new TransactionPool(); + } + + @Singleton + @Provides + static DisplayController providerDisplayController(Context context, @Main Handler handler, + IWindowManager wmService) { + return new DisplayController(context, handler, wmService); + } + + @Singleton + @Provides + static SystemWindows provideSystemWindows(DisplayController displayController, + IWindowManager wmService) { + return new SystemWindows(displayController, wmService); + } + + @Singleton + @Binds + abstract DisplayImeController bindDisplayImeController( + DisplaySystemBarsController displaySystemBarsController); + @Binds abstract HeadsUpManager bindHeadsUpManagerPhone(HeadsUpManagerPhone headsUpManagerPhone); @@ -158,17 +179,10 @@ public abstract class CarSystemUIModule { CarSystemUIRootComponent systemUIRootComponent); @Binds - public abstract StatusBar bindStatusBar(CarStatusBar statusBar); - - @Binds abstract VolumeDialogComponent bindVolumeDialogComponent( CarVolumeDialogComponent carVolumeDialogComponent); @Binds - abstract StatusBarKeyguardViewManager bindStatusBarKeyguardViewManager( - CarStatusBarKeyguardViewManager keyguardViewManager); - - @Binds abstract KeyguardViewController bindKeyguardViewController( CarKeyguardViewController carKeyguardViewController); diff --git a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBar.java deleted file mode 100644 index d692487d410e..000000000000 --- a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBar.java +++ /dev/null @@ -1,519 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.car.statusbar; - -import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME; - -import android.annotation.Nullable; -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.os.PowerManager; -import android.util.DisplayMetrics; -import android.util.Log; -import android.view.View; - -import com.android.internal.logging.MetricsLogger; -import com.android.internal.statusbar.RegisterStatusBarResult; -import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.keyguard.ViewMediatorCallback; -import com.android.systemui.BatteryMeterView; -import com.android.systemui.Dependency; -import com.android.systemui.InitController; -import com.android.systemui.Prefs; -import com.android.systemui.R; -import com.android.systemui.assist.AssistManager; -import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.bubbles.BubbleController; -import com.android.systemui.car.CarDeviceProvisionedController; -import com.android.systemui.car.CarDeviceProvisionedListener; -import com.android.systemui.car.bluetooth.CarBatteryController; -import com.android.systemui.car.navigationbar.CarNavigationBarController; -import com.android.systemui.classifier.FalsingLog; -import com.android.systemui.colorextraction.SysuiColorExtractor; -import com.android.systemui.dagger.qualifiers.UiBackground; -import com.android.systemui.fragments.FragmentHostManager; -import com.android.systemui.keyguard.DismissCallbackRegistry; -import com.android.systemui.keyguard.KeyguardViewMediator; -import com.android.systemui.keyguard.ScreenLifecycle; -import com.android.systemui.keyguard.WakefulnessLifecycle; -import com.android.systemui.plugins.DarkIconDispatcher; -import com.android.systemui.plugins.FalsingManager; -import com.android.systemui.plugins.PluginDependencyProvider; -import com.android.systemui.plugins.qs.QS; -import com.android.systemui.recents.Recents; -import com.android.systemui.recents.ScreenPinningRequest; -import com.android.systemui.shared.plugins.PluginManager; -import com.android.systemui.stackdivider.Divider; -import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.KeyguardIndicationController; -import com.android.systemui.statusbar.NavigationBarController; -import com.android.systemui.statusbar.NotificationLockscreenUserManager; -import com.android.systemui.statusbar.NotificationMediaManager; -import com.android.systemui.statusbar.NotificationRemoteInputManager; -import com.android.systemui.statusbar.NotificationShadeDepthController; -import com.android.systemui.statusbar.NotificationViewHierarchyManager; -import com.android.systemui.statusbar.PulseExpansionHandler; -import com.android.systemui.statusbar.SuperStatusBarViewFactory; -import com.android.systemui.statusbar.SysuiStatusBarStateController; -import com.android.systemui.statusbar.VibratorHelper; -import com.android.systemui.statusbar.notification.DynamicPrivacyController; -import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; -import com.android.systemui.statusbar.notification.VisualStabilityManager; -import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.init.NotificationsController; -import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier; -import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; -import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor; -import com.android.systemui.statusbar.notification.logging.NotificationLogger; -import com.android.systemui.statusbar.notification.row.NotificationGutsManager; -import com.android.systemui.statusbar.phone.AutoHideController; -import com.android.systemui.statusbar.phone.BiometricUnlockController; -import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment; -import com.android.systemui.statusbar.phone.DozeParameters; -import com.android.systemui.statusbar.phone.DozeScrimController; -import com.android.systemui.statusbar.phone.DozeServiceHost; -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; -import com.android.systemui.statusbar.phone.KeyguardBypassController; -import com.android.systemui.statusbar.phone.KeyguardDismissUtil; -import com.android.systemui.statusbar.phone.LightBarController; -import com.android.systemui.statusbar.phone.LightsOutNotifController; -import com.android.systemui.statusbar.phone.LockscreenLockIconController; -import com.android.systemui.statusbar.phone.LockscreenWallpaper; -import com.android.systemui.statusbar.phone.NotificationGroupManager; -import com.android.systemui.statusbar.phone.NotificationShadeWindowController; -import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy; -import com.android.systemui.statusbar.phone.ScrimController; -import com.android.systemui.statusbar.phone.ShadeController; -import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.phone.StatusBarIconController; -import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; -import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter; -import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager; -import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; -import com.android.systemui.statusbar.policy.BatteryController; -import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.statusbar.policy.ExtensionController; -import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.statusbar.policy.NetworkController; -import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; -import com.android.systemui.statusbar.policy.UserInfoControllerImpl; -import com.android.systemui.statusbar.policy.UserSwitcherController; -import com.android.systemui.volume.VolumeComponent; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.Executor; - -import javax.inject.Named; -import javax.inject.Provider; - -import dagger.Lazy; - -/** - * A status bar tailored for the automotive use case. - */ -public class CarStatusBar extends StatusBar implements CarBatteryController.BatteryViewHandler { - private static final String TAG = "CarStatusBar"; - - private final UserSwitcherController mUserSwitcherController; - private final ScrimController mScrimController; - - private CarBatteryController mCarBatteryController; - private BatteryMeterView mBatteryMeterView; - private Drawable mNotificationPanelBackground; - - private final Object mQueueLock = new Object(); - private final CarNavigationBarController mCarNavigationBarController; - private final CarDeviceProvisionedController mCarDeviceProvisionedController; - private final ScreenLifecycle mScreenLifecycle; - - private boolean mDeviceIsSetUpForUser = true; - private boolean mIsUserSetupInProgress = false; - - public CarStatusBar( - Context context, - NotificationsController notificationsController, - LightBarController lightBarController, - AutoHideController autoHideController, - KeyguardUpdateMonitor keyguardUpdateMonitor, - StatusBarIconController statusBarIconController, - PulseExpansionHandler pulseExpansionHandler, - NotificationWakeUpCoordinator notificationWakeUpCoordinator, - KeyguardBypassController keyguardBypassController, - KeyguardStateController keyguardStateController, - HeadsUpManagerPhone headsUpManagerPhone, - DynamicPrivacyController dynamicPrivacyController, - BypassHeadsUpNotifier bypassHeadsUpNotifier, - FalsingManager falsingManager, - BroadcastDispatcher broadcastDispatcher, - RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, - NotificationGutsManager notificationGutsManager, - NotificationLogger notificationLogger, - NotificationInterruptStateProvider notificationInterruptStateProvider, - NotificationViewHierarchyManager notificationViewHierarchyManager, - KeyguardViewMediator keyguardViewMediator, - DisplayMetrics displayMetrics, - MetricsLogger metricsLogger, - @UiBackground Executor uiBgExecutor, - NotificationMediaManager notificationMediaManager, - NotificationLockscreenUserManager lockScreenUserManager, - NotificationRemoteInputManager remoteInputManager, - UserSwitcherController userSwitcherController, - NetworkController networkController, - BatteryController batteryController, - SysuiColorExtractor colorExtractor, - ScreenLifecycle screenLifecycle, - WakefulnessLifecycle wakefulnessLifecycle, - SysuiStatusBarStateController statusBarStateController, - VibratorHelper vibratorHelper, - BubbleController bubbleController, - NotificationGroupManager groupManager, - VisualStabilityManager visualStabilityManager, - CarDeviceProvisionedController carDeviceProvisionedController, - NavigationBarController navigationBarController, - Lazy<AssistManager> assistManagerLazy, - ConfigurationController configurationController, - NotificationShadeWindowController notificationShadeWindowController, - LockscreenLockIconController lockscreenLockIconController, - DozeParameters dozeParameters, - ScrimController scrimController, - Lazy<LockscreenWallpaper> lockscreenWallpaperLazy, - Lazy<BiometricUnlockController> biometricUnlockControllerLazy, - DozeServiceHost dozeServiceHost, - PowerManager powerManager, - ScreenPinningRequest screenPinningRequest, - DozeScrimController dozeScrimController, - VolumeComponent volumeComponent, - CommandQueue commandQueue, - Optional<Recents> recents, - Provider<StatusBarComponent.Builder> statusBarComponentBuilder, - PluginManager pluginManager, - Optional<Divider> dividerOptional, - SuperStatusBarViewFactory superStatusBarViewFactory, - LightsOutNotifController lightsOutNotifController, - StatusBarNotificationActivityStarter.Builder - statusBarNotificationActivityStarterBuilder, - ShadeController shadeController, - StatusBarKeyguardViewManager statusBarKeyguardViewManager, - ViewMediatorCallback viewMediatorCallback, - InitController initController, - DarkIconDispatcher darkIconDispatcher, - @Named(TIME_TICK_HANDLER_NAME) Handler timeTickHandler, - PluginDependencyProvider pluginDependencyProvider, - KeyguardDismissUtil keyguardDismissUtil, - ExtensionController extensionController, - UserInfoControllerImpl userInfoControllerImpl, - PhoneStatusBarPolicy phoneStatusBarPolicy, - KeyguardIndicationController keyguardIndicationController, - DismissCallbackRegistry dismissCallbackRegistry, - StatusBarTouchableRegionManager statusBarTouchableRegionManager, - Lazy<NotificationShadeDepthController> depthControllerLazy, - /* Car Settings injected components. */ - CarNavigationBarController carNavigationBarController) { - super( - context, - notificationsController, - lightBarController, - autoHideController, - keyguardUpdateMonitor, - statusBarIconController, - pulseExpansionHandler, - notificationWakeUpCoordinator, - keyguardBypassController, - keyguardStateController, - headsUpManagerPhone, - dynamicPrivacyController, - bypassHeadsUpNotifier, - falsingManager, - broadcastDispatcher, - remoteInputQuickSettingsDisabler, - notificationGutsManager, - notificationLogger, - notificationInterruptStateProvider, - notificationViewHierarchyManager, - keyguardViewMediator, - displayMetrics, - metricsLogger, - uiBgExecutor, - notificationMediaManager, - lockScreenUserManager, - remoteInputManager, - userSwitcherController, - networkController, - batteryController, - colorExtractor, - screenLifecycle, - wakefulnessLifecycle, - statusBarStateController, - vibratorHelper, - bubbleController, - groupManager, - visualStabilityManager, - carDeviceProvisionedController, - navigationBarController, - assistManagerLazy, - configurationController, - notificationShadeWindowController, - lockscreenLockIconController, - dozeParameters, - scrimController, - null /* keyguardLiftController */, - lockscreenWallpaperLazy, - biometricUnlockControllerLazy, - dozeServiceHost, - powerManager, - screenPinningRequest, - dozeScrimController, - volumeComponent, - commandQueue, - recents, - statusBarComponentBuilder, - pluginManager, - dividerOptional, - lightsOutNotifController, - statusBarNotificationActivityStarterBuilder, - shadeController, - superStatusBarViewFactory, - statusBarKeyguardViewManager, - viewMediatorCallback, - initController, - darkIconDispatcher, - timeTickHandler, - pluginDependencyProvider, - keyguardDismissUtil, - extensionController, - userInfoControllerImpl, - phoneStatusBarPolicy, - keyguardIndicationController, - dismissCallbackRegistry, - depthControllerLazy, - statusBarTouchableRegionManager); - mUserSwitcherController = userSwitcherController; - mScrimController = scrimController; - mCarDeviceProvisionedController = carDeviceProvisionedController; - mCarNavigationBarController = carNavigationBarController; - mScreenLifecycle = screenLifecycle; - } - - @Override - public void start() { - mDeviceIsSetUpForUser = mCarDeviceProvisionedController.isCurrentUserSetup(); - mIsUserSetupInProgress = mCarDeviceProvisionedController.isCurrentUserSetupInProgress(); - - super.start(); - - createBatteryController(); - mCarBatteryController.startListening(); - - mCarDeviceProvisionedController.addCallback( - new CarDeviceProvisionedListener() { - @Override - public void onUserSetupInProgressChanged() { - mDeviceIsSetUpForUser = mCarDeviceProvisionedController - .isCurrentUserSetup(); - mIsUserSetupInProgress = mCarDeviceProvisionedController - .isCurrentUserSetupInProgress(); - } - - @Override - public void onUserSetupChanged() { - mDeviceIsSetUpForUser = mCarDeviceProvisionedController - .isCurrentUserSetup(); - mIsUserSetupInProgress = mCarDeviceProvisionedController - .isCurrentUserSetupInProgress(); - } - - @Override - public void onUserSwitched() { - mDeviceIsSetUpForUser = mCarDeviceProvisionedController - .isCurrentUserSetup(); - mIsUserSetupInProgress = mCarDeviceProvisionedController - .isCurrentUserSetupInProgress(); - } - }); - - mNotificationInterruptStateProvider.addSuppressor(new NotificationInterruptSuppressor() { - @Override - public String getName() { - return TAG; - } - - @Override - public boolean suppressInterruptions(NotificationEntry entry) { - // Because space is usually constrained in the auto use-case, there should not be a - // pinned notification when the shade has been expanded. - // Ensure this by not allowing any interruptions (ie: pinning any notifications) if - // the shade is already opened. - return !getPresenter().isPresenterFullyCollapsed(); - } - }); - } - - @Override - public boolean hideKeyguard() { - boolean result = super.hideKeyguard(); - mCarNavigationBarController.hideAllKeyguardButtons(isDeviceSetupForUser()); - return result; - } - - @Override - public void showKeyguard() { - super.showKeyguard(); - mCarNavigationBarController.showAllKeyguardButtons(isDeviceSetupForUser()); - } - - private boolean isDeviceSetupForUser() { - return mDeviceIsSetUpForUser && !mIsUserSetupInProgress; - } - - @Override - protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) { - super.makeStatusBarView(result); - - mNotificationPanelBackground = getDefaultWallpaper(); - mScrimController.setScrimBehindDrawable(mNotificationPanelBackground); - - FragmentHostManager manager = FragmentHostManager.get(mPhoneStatusBarWindow); - manager.addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> { - mBatteryMeterView = fragment.getView().findViewById(R.id.battery); - - // By default, the BatteryMeterView should not be visible. It will be toggled - // when a device has connected by bluetooth. - mBatteryMeterView.setVisibility(View.GONE); - }); - } - - @Override - public void animateExpandNotificationsPanel() { - // No op. - } - - @Override - protected QS createDefaultQSFragment() { - return null; - } - - private BatteryController createBatteryController() { - mCarBatteryController = new CarBatteryController(mContext); - mCarBatteryController.addBatteryViewHandler(this); - return mCarBatteryController; - } - - @Override - protected void createNavigationBar(@Nullable RegisterStatusBarResult result) { - // No op. - } - - @Override - public void notifyBiometricAuthModeChanged() { - // No op. - } - - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - //When executing dump() function simultaneously, we need to serialize them - //to get mStackScroller's position correctly. - synchronized (mQueueLock) { - pw.println(" mStackScroller: " + viewInfo(mStackScroller)); - pw.println(" mStackScroller: " + viewInfo(mStackScroller) - + " scroll " + mStackScroller.getScrollX() - + "," + mStackScroller.getScrollY()); - } - pw.print(" mCarBatteryController="); - pw.println(mCarBatteryController); - pw.print(" mBatteryMeterView="); - pw.println(mBatteryMeterView); - - if (Dependency.get(KeyguardUpdateMonitor.class) != null) { - Dependency.get(KeyguardUpdateMonitor.class).dump(fd, pw, args); - } - - FalsingLog.dump(pw); - - pw.println("SharedPreferences:"); - for (Map.Entry<String, ?> entry : Prefs.getAll(mContext).entrySet()) { - pw.print(" "); - pw.print(entry.getKey()); - pw.print("="); - pw.println(entry.getValue()); - } - } - - @Override - public void showBatteryView() { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "showBatteryView(). mBatteryMeterView: " + mBatteryMeterView); - } - - if (mBatteryMeterView != null) { - mBatteryMeterView.setVisibility(View.VISIBLE); - } - } - - @Override - public void hideBatteryView() { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "hideBatteryView(). mBatteryMeterView: " + mBatteryMeterView); - } - - if (mBatteryMeterView != null) { - mBatteryMeterView.setVisibility(View.GONE); - } - } - - @Override - protected void createUserSwitcher() { - if (!mUserSwitcherController.useFullscreenUserSwitcher()) { - super.createUserSwitcher(); - } - } - - /** - * Dismisses the keyguard and shows bouncer if authentication is necessary. - */ - public void dismissKeyguard() { - // Don't dismiss keyguard when the screen is off. - if (mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_OFF) { - return; - } - executeRunnableDismissingKeyguard(null/* runnable */, null /* cancelAction */, - true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */); - } - - /** - * Ensures that relevant child views are appropriately recreated when the device's density - * changes. - */ - @Override - public void onDensityOrFontScaleChanged() { - super.onDensityOrFontScaleChanged(); - // Need to update the background on density changed in case the change was due to night - // mode. - mNotificationPanelBackground = getDefaultWallpaper(); - mScrimController.setScrimBehindDrawable(mNotificationPanelBackground); - } - - /** - * Returns the {@link Drawable} that represents the wallpaper that the user has currently set. - */ - private Drawable getDefaultWallpaper() { - return mContext.getDrawable(com.android.internal.R.drawable.default_wallpaper); - } -} diff --git a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBarKeyguardViewManager.java b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBarKeyguardViewManager.java deleted file mode 100644 index 96a998a500e1..000000000000 --- a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBarKeyguardViewManager.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.car.statusbar; - -import android.content.Context; -import android.view.View; - -import com.android.internal.widget.LockPatternUtils; -import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.keyguard.ViewMediatorCallback; -import com.android.systemui.R; -import com.android.systemui.car.navigationbar.CarNavigationBarController; -import com.android.systemui.dock.DockManager; -import com.android.systemui.statusbar.NotificationMediaManager; -import com.android.systemui.statusbar.SysuiStatusBarStateController; -import com.android.systemui.statusbar.phone.NavigationModeController; -import com.android.systemui.statusbar.phone.NotificationShadeWindowController; -import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; -import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.statusbar.policy.KeyguardStateController; - -import java.util.HashSet; -import java.util.Set; - -import javax.inject.Inject; -import javax.inject.Singleton; - -/** Car implementation of the {@link StatusBarKeyguardViewManager}. */ -@Singleton -public class CarStatusBarKeyguardViewManager extends StatusBarKeyguardViewManager { - - protected boolean mShouldHideNavBar; - private final CarNavigationBarController mCarNavigationBarController; - private Set<OnKeyguardCancelClickedListener> mKeygaurdCancelClickedListenerSet; - - @Inject - public CarStatusBarKeyguardViewManager(Context context, - ViewMediatorCallback callback, - LockPatternUtils lockPatternUtils, - SysuiStatusBarStateController sysuiStatusBarStateController, - ConfigurationController configurationController, - KeyguardUpdateMonitor keyguardUpdateMonitor, - NavigationModeController navigationModeController, - DockManager dockManager, - NotificationShadeWindowController notificationShadeWindowController, - KeyguardStateController keyguardStateController, - NotificationMediaManager notificationMediaManager, - CarNavigationBarController carNavigationBarController) { - super(context, callback, lockPatternUtils, sysuiStatusBarStateController, - configurationController, keyguardUpdateMonitor, navigationModeController, - dockManager, notificationShadeWindowController, keyguardStateController, - notificationMediaManager); - mShouldHideNavBar = context.getResources() - .getBoolean(R.bool.config_hideNavWhenKeyguardBouncerShown); - mCarNavigationBarController = carNavigationBarController; - mKeygaurdCancelClickedListenerSet = new HashSet<>(); - } - - @Override - protected void updateNavigationBarVisibility(boolean navBarVisible) { - if (!mShouldHideNavBar) { - return; - } - int visibility = navBarVisible ? View.VISIBLE : View.GONE; - mCarNavigationBarController.setBottomWindowVisibility(visibility); - mCarNavigationBarController.setLeftWindowVisibility(visibility); - mCarNavigationBarController.setRightWindowVisibility(visibility); - } - - /** - * Car is a multi-user system. There's a cancel button on the bouncer that allows the user to - * go back to the user switcher and select another user. Different user may have different - * security mode which requires bouncer container to be resized. For this reason, the bouncer - * view is destroyed on cancel. - */ - @Override - protected boolean shouldDestroyViewOnReset() { - return true; - } - - /** - * Called when cancel button in bouncer is pressed. - */ - @Override - public void onCancelClicked() { - mKeygaurdCancelClickedListenerSet.forEach(OnKeyguardCancelClickedListener::onCancelClicked); - } - - /** - * Do nothing on this change. - * The base class hides the keyguard which for automotive we want to avoid b/c this would happen - * on a configuration change due to day/night (headlight state). - */ - @Override - public void onDensityOrFontScaleChanged() { } - - /** - * Add listener for keyguard cancel clicked. - */ - public void addOnKeyguardCancelClickedListener( - OnKeyguardCancelClickedListener keyguardCancelClickedListener) { - mKeygaurdCancelClickedListenerSet.add(keyguardCancelClickedListener); - } - - /** - * Remove listener for keyguard cancel clicked. - */ - public void removeOnKeyguardCancelClickedListener( - OnKeyguardCancelClickedListener keyguardCancelClickedListener) { - mKeygaurdCancelClickedListenerSet.remove(keyguardCancelClickedListener); - } - - - /** - * Defines a callback for keyguard cancel button clicked listeners. - */ - public interface OnKeyguardCancelClickedListener { - /** - * Called when keyguard cancel button is clicked. - */ - void onCancelClicked(); - } -} diff --git a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBarModule.java deleted file mode 100644 index dc2eb04c2990..000000000000 --- a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBarModule.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.car.statusbar; - -import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME; - -import android.content.Context; -import android.os.Handler; -import android.os.PowerManager; -import android.util.DisplayMetrics; - -import com.android.internal.logging.MetricsLogger; -import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.keyguard.ViewMediatorCallback; -import com.android.systemui.InitController; -import com.android.systemui.assist.AssistManager; -import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.bubbles.BubbleController; -import com.android.systemui.car.CarDeviceProvisionedController; -import com.android.systemui.car.navigationbar.CarNavigationBarController; -import com.android.systemui.colorextraction.SysuiColorExtractor; -import com.android.systemui.dagger.qualifiers.UiBackground; -import com.android.systemui.keyguard.DismissCallbackRegistry; -import com.android.systemui.keyguard.KeyguardViewMediator; -import com.android.systemui.keyguard.ScreenLifecycle; -import com.android.systemui.keyguard.WakefulnessLifecycle; -import com.android.systemui.plugins.DarkIconDispatcher; -import com.android.systemui.plugins.FalsingManager; -import com.android.systemui.plugins.PluginDependencyProvider; -import com.android.systemui.recents.Recents; -import com.android.systemui.recents.ScreenPinningRequest; -import com.android.systemui.shared.plugins.PluginManager; -import com.android.systemui.stackdivider.Divider; -import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.KeyguardIndicationController; -import com.android.systemui.statusbar.NavigationBarController; -import com.android.systemui.statusbar.NotificationLockscreenUserManager; -import com.android.systemui.statusbar.NotificationMediaManager; -import com.android.systemui.statusbar.NotificationRemoteInputManager; -import com.android.systemui.statusbar.NotificationShadeDepthController; -import com.android.systemui.statusbar.NotificationViewHierarchyManager; -import com.android.systemui.statusbar.PulseExpansionHandler; -import com.android.systemui.statusbar.SuperStatusBarViewFactory; -import com.android.systemui.statusbar.SysuiStatusBarStateController; -import com.android.systemui.statusbar.VibratorHelper; -import com.android.systemui.statusbar.dagger.StatusBarDependenciesModule; -import com.android.systemui.statusbar.notification.DynamicPrivacyController; -import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; -import com.android.systemui.statusbar.notification.VisualStabilityManager; -import com.android.systemui.statusbar.notification.init.NotificationsController; -import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier; -import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; -import com.android.systemui.statusbar.notification.logging.NotificationLogger; -import com.android.systemui.statusbar.notification.row.NotificationGutsManager; -import com.android.systemui.statusbar.notification.row.NotificationRowModule; -import com.android.systemui.statusbar.phone.AutoHideController; -import com.android.systemui.statusbar.phone.BiometricUnlockController; -import com.android.systemui.statusbar.phone.DozeParameters; -import com.android.systemui.statusbar.phone.DozeScrimController; -import com.android.systemui.statusbar.phone.DozeServiceHost; -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; -import com.android.systemui.statusbar.phone.KeyguardBypassController; -import com.android.systemui.statusbar.phone.KeyguardDismissUtil; -import com.android.systemui.statusbar.phone.LightBarController; -import com.android.systemui.statusbar.phone.LightsOutNotifController; -import com.android.systemui.statusbar.phone.LockscreenLockIconController; -import com.android.systemui.statusbar.phone.LockscreenWallpaper; -import com.android.systemui.statusbar.phone.NotificationGroupManager; -import com.android.systemui.statusbar.phone.NotificationShadeWindowController; -import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy; -import com.android.systemui.statusbar.phone.ScrimController; -import com.android.systemui.statusbar.phone.ShadeController; -import com.android.systemui.statusbar.phone.StatusBarIconController; -import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; -import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter; -import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager; -import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; -import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneDependenciesModule; -import com.android.systemui.statusbar.policy.BatteryController; -import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.statusbar.policy.ExtensionController; -import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.statusbar.policy.NetworkController; -import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; -import com.android.systemui.statusbar.policy.UserInfoControllerImpl; -import com.android.systemui.statusbar.policy.UserSwitcherController; -import com.android.systemui.volume.VolumeComponent; - -import java.util.Optional; -import java.util.concurrent.Executor; - -import javax.inject.Named; -import javax.inject.Provider; -import javax.inject.Singleton; - -import dagger.Lazy; -import dagger.Module; -import dagger.Provides; - -/** - * Dagger Module providing {@link CarStatusBar}. - */ -@Module(includes = {StatusBarDependenciesModule.class, StatusBarPhoneDependenciesModule.class, - NotificationRowModule.class}) -public class CarStatusBarModule { - /** - * Provides our instance of StatusBar which is considered optional. - */ - @Provides - @Singleton - static CarStatusBar provideStatusBar( - Context context, - NotificationsController notificationsController, - LightBarController lightBarController, - AutoHideController autoHideController, - KeyguardUpdateMonitor keyguardUpdateMonitor, - StatusBarIconController statusBarIconController, - PulseExpansionHandler pulseExpansionHandler, - NotificationWakeUpCoordinator notificationWakeUpCoordinator, - KeyguardBypassController keyguardBypassController, - KeyguardStateController keyguardStateController, - HeadsUpManagerPhone headsUpManagerPhone, - DynamicPrivacyController dynamicPrivacyController, - BypassHeadsUpNotifier bypassHeadsUpNotifier, - FalsingManager falsingManager, - BroadcastDispatcher broadcastDispatcher, - RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, - NotificationGutsManager notificationGutsManager, - NotificationLogger notificationLogger, - NotificationInterruptStateProvider notificationInterruptionStateProvider, - NotificationViewHierarchyManager notificationViewHierarchyManager, - KeyguardViewMediator keyguardViewMediator, - DisplayMetrics displayMetrics, - MetricsLogger metricsLogger, - @UiBackground Executor uiBgExecutor, - NotificationMediaManager notificationMediaManager, - NotificationLockscreenUserManager lockScreenUserManager, - NotificationRemoteInputManager remoteInputManager, - UserSwitcherController userSwitcherController, - NetworkController networkController, - BatteryController batteryController, - SysuiColorExtractor colorExtractor, - ScreenLifecycle screenLifecycle, - WakefulnessLifecycle wakefulnessLifecycle, - SysuiStatusBarStateController statusBarStateController, - VibratorHelper vibratorHelper, - BubbleController bubbleController, - NotificationGroupManager groupManager, - VisualStabilityManager visualStabilityManager, - CarDeviceProvisionedController carDeviceProvisionedController, - NavigationBarController navigationBarController, - Lazy<AssistManager> assistManagerLazy, - ConfigurationController configurationController, - NotificationShadeWindowController notificationShadeWindowController, - LockscreenLockIconController lockscreenLockIconController, - DozeParameters dozeParameters, - ScrimController scrimController, - Lazy<LockscreenWallpaper> lockscreenWallpaperLazy, - Lazy<BiometricUnlockController> biometricUnlockControllerLazy, - DozeServiceHost dozeServiceHost, - PowerManager powerManager, - ScreenPinningRequest screenPinningRequest, - DozeScrimController dozeScrimController, - VolumeComponent volumeComponent, - CommandQueue commandQueue, - Optional<Recents> recentsOptional, - Provider<StatusBarComponent.Builder> statusBarComponentBuilder, - PluginManager pluginManager, - Optional<Divider> dividerOptional, - SuperStatusBarViewFactory superStatusBarViewFactory, - LightsOutNotifController lightsOutNotifController, - StatusBarNotificationActivityStarter.Builder - statusBarNotificationActivityStarterBuilder, - ShadeController shadeController, - StatusBarKeyguardViewManager statusBarKeyguardViewManager, - ViewMediatorCallback viewMediatorCallback, - InitController initController, - DarkIconDispatcher darkIconDispatcher, - @Named(TIME_TICK_HANDLER_NAME) Handler timeTickHandler, - PluginDependencyProvider pluginDependencyProvider, - KeyguardDismissUtil keyguardDismissUtil, - ExtensionController extensionController, - UserInfoControllerImpl userInfoControllerImpl, - PhoneStatusBarPolicy phoneStatusBarPolicy, - KeyguardIndicationController keyguardIndicationController, - DismissCallbackRegistry dismissCallbackRegistry, - StatusBarTouchableRegionManager statusBarTouchableRegionManager, - Lazy<NotificationShadeDepthController> notificationShadeDepthControllerLazy, - CarNavigationBarController carNavigationBarController) { - return new CarStatusBar( - context, - notificationsController, - lightBarController, - autoHideController, - keyguardUpdateMonitor, - statusBarIconController, - pulseExpansionHandler, - notificationWakeUpCoordinator, - keyguardBypassController, - keyguardStateController, - headsUpManagerPhone, - dynamicPrivacyController, - bypassHeadsUpNotifier, - falsingManager, - broadcastDispatcher, - remoteInputQuickSettingsDisabler, - notificationGutsManager, - notificationLogger, - notificationInterruptionStateProvider, - notificationViewHierarchyManager, - keyguardViewMediator, - displayMetrics, - metricsLogger, - uiBgExecutor, - notificationMediaManager, - lockScreenUserManager, - remoteInputManager, - userSwitcherController, - networkController, - batteryController, - colorExtractor, - screenLifecycle, - wakefulnessLifecycle, - statusBarStateController, - vibratorHelper, - bubbleController, - groupManager, - visualStabilityManager, - carDeviceProvisionedController, - navigationBarController, - assistManagerLazy, - configurationController, - notificationShadeWindowController, - lockscreenLockIconController, - dozeParameters, - scrimController, - lockscreenWallpaperLazy, - biometricUnlockControllerLazy, - dozeServiceHost, - powerManager, - screenPinningRequest, - dozeScrimController, - volumeComponent, - commandQueue, - recentsOptional, - statusBarComponentBuilder, - pluginManager, - dividerOptional, - superStatusBarViewFactory, - lightsOutNotifController, - statusBarNotificationActivityStarterBuilder, - shadeController, - statusBarKeyguardViewManager, - viewMediatorCallback, - initController, - darkIconDispatcher, - timeTickHandler, - pluginDependencyProvider, - keyguardDismissUtil, - extensionController, - userInfoControllerImpl, - phoneStatusBarPolicy, - keyguardIndicationController, - dismissCallbackRegistry, - statusBarTouchableRegionManager, - notificationShadeDepthControllerLazy, - carNavigationBarController); - } -} diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullScreenUserSwitcherViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullScreenUserSwitcherViewController.java index 10b2b973071a..1a8f19e46798 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullScreenUserSwitcherViewController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullScreenUserSwitcherViewController.java @@ -18,6 +18,8 @@ package com.android.systemui.car.userswitcher; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.car.Car; +import android.car.user.CarUserManager; import android.content.Context; import android.content.res.Resources; import android.view.View; @@ -25,6 +27,7 @@ import android.view.View; import androidx.recyclerview.widget.GridLayoutManager; import com.android.systemui.R; +import com.android.systemui.car.CarServiceProvider; import com.android.systemui.car.window.OverlayViewController; import com.android.systemui.car.window.OverlayViewGlobalStateController; import com.android.systemui.dagger.qualifiers.Main; @@ -39,7 +42,9 @@ import javax.inject.Singleton; public class FullScreenUserSwitcherViewController extends OverlayViewController { private final Context mContext; private final Resources mResources; + private final CarServiceProvider mCarServiceProvider; private final int mShortAnimationDuration; + private CarUserManager mCarUserManager; private UserGridRecyclerView mUserGridView; private UserGridRecyclerView.UserSelectionListener mUserSelectionListener; @@ -47,10 +52,16 @@ public class FullScreenUserSwitcherViewController extends OverlayViewController public FullScreenUserSwitcherViewController( Context context, @Main Resources resources, + CarServiceProvider carServiceProvider, OverlayViewGlobalStateController overlayViewGlobalStateController) { super(R.id.fullscreen_user_switcher_stub, overlayViewGlobalStateController); mContext = context; mResources = resources; + mCarServiceProvider = carServiceProvider; + mCarServiceProvider.addListener(car -> { + mCarUserManager = (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE); + registerCarUserManagerIfPossible(); + }); mShortAnimationDuration = mResources.getInteger(android.R.integer.config_shortAnimTime); } @@ -63,6 +74,7 @@ public class FullScreenUserSwitcherViewController extends OverlayViewController mUserGridView.setLayoutManager(layoutManager); mUserGridView.buildAdapter(); mUserGridView.setUserSelectionListener(mUserSelectionListener); + registerCarUserManagerIfPossible(); } @Override @@ -91,18 +103,6 @@ public class FullScreenUserSwitcherViewController extends OverlayViewController } /** - * Invalidate underlying view. - */ - void invalidate() { - if (getLayout() == null) { - // layout hasn't been inflated. - return; - } - - getLayout().invalidate(); - } - - /** * Set {@link UserGridRecyclerView.UserSelectionListener}. */ void setUserGridSelectionListener( @@ -110,15 +110,9 @@ public class FullScreenUserSwitcherViewController extends OverlayViewController mUserSelectionListener = userGridSelectionListener; } - /** - * Returns {@code true} when layout is visible. - */ - boolean isVisible() { - if (getLayout() == null) { - // layout hasn't been inflated. - return false; + private void registerCarUserManagerIfPossible() { + if (mUserGridView != null && mCarUserManager != null) { + mUserGridView.setCarUserManager(mCarUserManager); } - - return getLayout().getVisibility() == View.VISIBLE; } } diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java index 2ff667093e58..d0a2aebdb80a 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java @@ -24,11 +24,15 @@ import static android.view.WindowInsets.Type.statusBars; import android.annotation.IntDef; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.app.Dialog; -import android.car.userlib.CarUserManagerHelper; +import android.car.user.CarUserManager; +import android.car.user.UserCreationResult; +import android.car.user.UserSwitchResult; +import android.car.userlib.UserHelper; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; @@ -40,7 +44,9 @@ import android.graphics.Rect; import android.os.AsyncTask; import android.os.UserHandle; import android.os.UserManager; +import android.sysprop.CarProperties; import android.util.AttributeSet; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -54,6 +60,7 @@ import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import com.android.internal.infra.AndroidFuture; import com.android.internal.util.UserIcons; import com.android.systemui.R; @@ -61,6 +68,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** @@ -68,9 +76,12 @@ import java.util.stream.Collectors; * One of the uses of this is for the lock screen in auto. */ public class UserGridRecyclerView extends RecyclerView { + private static final String TAG = UserGridRecyclerView.class.getSimpleName(); + private static final int TIMEOUT_MS = CarProperties.user_hal_timeout().orElse(5_000) + 500; + private UserSelectionListener mUserSelectionListener; private UserAdapter mAdapter; - private CarUserManagerHelper mCarUserManagerHelper; + private CarUserManager mCarUserManager; private UserManager mUserManager; private Context mContext; private UserIconProvider mUserIconProvider; @@ -85,7 +96,6 @@ public class UserGridRecyclerView extends RecyclerView { public UserGridRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; - mCarUserManagerHelper = new CarUserManagerHelper(mContext); mUserManager = UserManager.get(mContext); mUserIconProvider = new UserIconProvider(); @@ -184,6 +194,11 @@ public class UserGridRecyclerView extends RecyclerView { mUserSelectionListener = userSelectionListener; } + /** Sets a {@link CarUserManager}. */ + public void setCarUserManager(CarUserManager carUserManager) { + mCarUserManager = carUserManager; + } + private void onUsersUpdate() { mAdapter.clearUsers(); mAdapter.updateUsers(createUserRecords(getUsersForUserGrid())); @@ -273,7 +288,9 @@ public class UserGridRecyclerView extends RecyclerView { notifyUserSelected(userRecord); UserInfo guest = createNewOrFindExistingGuest(mContext); if (guest != null) { - mCarUserManagerHelper.switchToUser(guest); + if (!switchUser(guest.id)) { + Log.e(TAG, "Failed to switch to guest user: " + guest.id); + } } break; case UserRecord.ADD_USER: @@ -289,7 +306,9 @@ public class UserGridRecyclerView extends RecyclerView { // If the user doesn't want to be a guest or add a user, switch to the user // selected notifyUserSelected(userRecord); - mCarUserManagerHelper.switchToUser(userRecord.mInfo); + if (!switchUser(userRecord.mInfo.id)) { + Log.e(TAG, "Failed to switch users: " + userRecord.mInfo.id); + } } }); @@ -430,8 +449,9 @@ public class UserGridRecyclerView extends RecyclerView { */ @Nullable public UserInfo createNewOrFindExistingGuest(Context context) { + AndroidFuture<UserCreationResult> future = mCarUserManager.createGuest(mGuestName); // CreateGuest will return null if a guest already exists. - UserInfo newGuest = mUserManager.createGuest(context, mGuestName); + UserInfo newGuest = getUserInfo(future); if (newGuest != null) { new UserIconProvider().assignDefaultIcon( mUserManager, context.getResources(), newGuest); @@ -444,7 +464,6 @@ public class UserGridRecyclerView extends RecyclerView { @Override public void onClick(DialogInterface dialog, int which) { if (which == BUTTON_POSITIVE) { - notifyUserSelected(mAddUserRecord); new AddNewUserTask().execute(mNewUserName); } else if (which == BUTTON_NEGATIVE) { // Enable the add button only if cancel @@ -462,11 +481,77 @@ public class UserGridRecyclerView extends RecyclerView { } } + @Nullable + private UserInfo getUserInfo(AndroidFuture<UserCreationResult> future) { + UserCreationResult userCreationResult; + try { + userCreationResult = future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } catch (Exception e) { + Log.w(TAG, "Could not create user.", e); + return null; + } + + if (userCreationResult == null) { + Log.w(TAG, "Timed out while creating user: " + TIMEOUT_MS + "ms"); + return null; + } + if (!userCreationResult.isSuccess() || userCreationResult.getUser() == null) { + Log.w(TAG, "Could not create user: " + userCreationResult); + return null; + } + + return userCreationResult.getUser(); + } + + private boolean switchUser(@UserIdInt int userId) { + AndroidFuture<UserSwitchResult> userSwitchResultFuture = + mCarUserManager.switchUser(userId); + UserSwitchResult userSwitchResult; + try { + userSwitchResult = userSwitchResultFuture.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } catch (Exception e) { + Log.w(TAG, "Could not switch user.", e); + return false; + } + + if (userSwitchResult == null) { + Log.w(TAG, "Timed out while switching user: " + TIMEOUT_MS + "ms"); + return false; + } + if (!userSwitchResult.isSuccess()) { + Log.w(TAG, "Could not switch user: " + userSwitchResult); + return false; + } + + return true; + } + + // TODO(b/161539497): Replace AsyncTask with standard {@link java.util.concurrent} code. private class AddNewUserTask extends AsyncTask<String, Void, UserInfo> { @Override protected UserInfo doInBackground(String... userNames) { - return mCarUserManagerHelper.createNewNonAdminUser(userNames[0]); + AndroidFuture<UserCreationResult> future = mCarUserManager.createUser(userNames[0], + /* flags= */ 0); + try { + UserInfo user = getUserInfo(future); + if (user != null) { + UserHelper.setDefaultNonAdminRestrictions(mContext, user, + /* enable= */ true); + UserHelper.assignDefaultIcon(mContext, user); + mAddUserRecord = new UserRecord(user, UserRecord.ADD_USER); + return user; + } else { + Log.e(TAG, "Failed to create user in the background"); + return user; + } + } catch (Exception e) { + if (e instanceof InterruptedException) { + Thread.currentThread().interrupt(); + } + Log.e(TAG, "Error creating new user: ", e); + } + return null; } @Override @@ -476,7 +561,11 @@ public class UserGridRecyclerView extends RecyclerView { @Override protected void onPostExecute(UserInfo user) { if (user != null) { - mCarUserManagerHelper.switchToUser(user); + notifyUserSelected(mAddUserRecord); + mAddUserView.setEnabled(true); + if (!switchUser(user.id)) { + Log.e(TAG, "Failed to switch to new user: " + user.id); + } } } } diff --git a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java index a831464e7987..5c80202ba592 100644 --- a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java +++ b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java @@ -16,12 +16,14 @@ package com.android.systemui.wm; +import android.content.Context; import android.os.Handler; import android.os.RemoteException; import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; import android.view.IDisplayWindowInsetsController; +import android.view.IWindowManager; import android.view.InsetsController; import android.view.InsetsSourceControl; import android.view.InsetsState; @@ -29,8 +31,10 @@ import android.view.WindowInsets; import androidx.annotation.VisibleForTesting; -import com.android.systemui.TransactionPool; import com.android.systemui.dagger.qualifiers.Main; +import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.DisplayImeController; +import com.android.wm.shell.common.TransactionPool; import javax.inject.Inject; import javax.inject.Singleton; @@ -47,29 +51,32 @@ public class DisplaySystemBarsController extends DisplayImeController { private static final String TAG = "DisplaySystemBarsController"; private SparseArray<PerDisplay> mPerDisplaySparseArray; + private final Context mContext; @Inject public DisplaySystemBarsController( - SystemWindows syswin, + Context context, + IWindowManager wmService, DisplayController displayController, @Main Handler mainHandler, TransactionPool transactionPool) { - super(syswin, displayController, mainHandler, transactionPool); + super(wmService, displayController, mainHandler, transactionPool); + mContext = context; } @Override public void onDisplayAdded(int displayId) { PerDisplay pd = new PerDisplay(displayId); try { - mSystemWindows.mWmService.setDisplayWindowInsetsController(displayId, pd); + mWmService.setDisplayWindowInsetsController(displayId, pd); } catch (RemoteException e) { Slog.w(TAG, "Unable to set insets controller on display " + displayId); } // Lazy loading policy control filters instead of during boot. if (mPerDisplaySparseArray == null) { mPerDisplaySparseArray = new SparseArray<>(); - BarControlPolicy.reloadFromSetting(mSystemWindows.mContext); - BarControlPolicy.registerContentObserver(mSystemWindows.mContext, mHandler, () -> { + BarControlPolicy.reloadFromSetting(mContext); + BarControlPolicy.registerContentObserver(mContext, mHandler, () -> { int size = mPerDisplaySparseArray.size(); for (int i = 0; i < size; i++) { mPerDisplaySparseArray.valueAt(i).modifyDisplayWindowInsets(); @@ -82,7 +89,7 @@ public class DisplaySystemBarsController extends DisplayImeController { @Override public void onDisplayRemoved(int displayId) { try { - mSystemWindows.mWmService.setDisplayWindowInsetsController(displayId, null); + mWmService.setDisplayWindowInsetsController(displayId, null); } catch (RemoteException e) { Slog.w(TAG, "Unable to remove insets controller on display " + displayId); } @@ -152,7 +159,7 @@ public class DisplaySystemBarsController extends DisplayImeController { showInsets(barVisibilities[0], /* fromIme= */ false); hideInsets(barVisibilities[1], /* fromIme= */ false); try { - mSystemWindows.mWmService.modifyDisplayWindowInsets(mDisplayId, mInsetsState); + mWmService.modifyDisplayWindowInsets(mDisplayId, mInsetsState); } catch (RemoteException e) { Slog.w(TAG, "Unable to update window manager service."); } diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java index 29cc8eec4bc3..391f75e35382 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java @@ -33,7 +33,8 @@ import android.view.IWindowManager; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; -import com.android.systemui.TransactionPool; +import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.TransactionPool; import org.junit.Before; import org.junit.Test; @@ -51,8 +52,6 @@ public class DisplaySystemBarsControllerTest extends SysuiTestCase { private static final int DISPLAY_ID = 1; @Mock - private SystemWindows mSystemWindows; - @Mock private IWindowManager mIWindowManager; @Mock private DisplayController mDisplayController; @@ -64,11 +63,10 @@ public class DisplaySystemBarsControllerTest extends SysuiTestCase { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mSystemWindows.mContext = mContext; - mSystemWindows.mWmService = mIWindowManager; mController = new DisplaySystemBarsController( - mSystemWindows, + mContext, + mIWindowManager, mDisplayController, mHandler, mTransactionPool diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java index ac7a12187fd6..121f5492a5ab 100644 --- a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java +++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java @@ -38,7 +38,10 @@ public class LicenseHtmlLoaderCompat extends AsyncLoaderCompat<File> { "/odm/etc/NOTICE.xml.gz", "/oem/etc/NOTICE.xml.gz", "/product/etc/NOTICE.xml.gz", - "/system_ext/etc/NOTICE.xml.gz"}; + "/system_ext/etc/NOTICE.xml.gz", + "/vendor_dlkm/etc/NOTICE.xml.gz", + "/odm_dlkm/etc/NOTICE.xml.gz", + }; static final String NOTICE_HTML_FILE_NAME = "NOTICE.html"; private final Context mContext; diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java index 6269a717b333..fd986e5d13fd 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java @@ -90,7 +90,7 @@ public class AccessPointPreference extends Preference { return frictionSld != null ? (StateListDrawable) frictionSld.getDrawable(0) : null; } - // Used for dummy pref. + // Used for fake pref. public AccessPointPreference(Context context, AttributeSet attrs) { super(context, attrs); mFrictionSld = null; @@ -142,7 +142,7 @@ public class AccessPointPreference extends Preference { public void onBindViewHolder(final PreferenceViewHolder view) { super.onBindViewHolder(view); if (mAccessPoint == null) { - // Used for dummy pref. + // Used for fake pref. return; } Drawable drawable = getIcon(); diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java index 3015397ff1a3..bf5ab1c9951a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java @@ -256,7 +256,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro } /** - * Sanity warning: this wipes out mScoreCache, so use with extreme caution + * Validity warning: this wipes out mScoreCache, so use with extreme caution * @param workThread substitute Handler thread, for testing purposes only */ @VisibleForTesting diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java index 0e6a60bf47c1..1ace0b4250b9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java @@ -118,7 +118,7 @@ public class WifiUtils { final int maxDisplayedScans = 4; int num5 = 0; // number of scanned BSSID on 5GHz band int num24 = 0; // number of scanned BSSID on 2.4Ghz band - int numBlackListed = 0; + int numBlockListed = 0; // TODO: sort list by RSSI or age long nowMs = SystemClock.elapsedRealtime(); @@ -170,8 +170,8 @@ public class WifiUtils { } visibility.append(scans5GHz.toString()); } - if (numBlackListed > 0) { - visibility.append("!").append(numBlackListed); + if (numBlockListed > 0) { + visibility.append("!").append(numBlockListed); } visibility.append("]"); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 27576b107efd..ef3bdbc95809 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -866,9 +866,6 @@ class SettingsProtoDumpUtil { Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS, GlobalSettingsProto.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS); dumpSetting(s, p, - Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS, - GlobalSettingsProto.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS); - dumpSetting(s, p, Settings.Global.KEEP_PROFILE_IN_BACKGROUND, GlobalSettingsProto.KEEP_PROFILE_IN_BACKGROUND); diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index b90b9c1208ae..2f1191a6325a 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -311,7 +311,6 @@ public class SettingsBackupTest { Settings.Global.INTENT_FIREWALL_UPDATE_METADATA_URL, Settings.Global.JOB_SCHEDULER_CONSTANTS, Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS, - Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS, Settings.Global.KEEP_PROFILE_IN_BACKGROUND, Settings.Global.KERNEL_CPU_THREAD_READER, Settings.Global.LANG_ID_UPDATE_CONTENT_URL, diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 7f7afcbf11f5..8253c5e642f3 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -214,6 +214,9 @@ <!-- Permission needed to test tcp keepalive offload. --> <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" /> + <!-- Permission needed for CTS test - UnsupportedErrorDialogTests --> + <uses-permission android:name="android.permission.RESET_APP_ERRORS" /> + <!-- Permission needed to run keyguard manager tests in CTS --> <uses-permission android:name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS" /> diff --git a/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java b/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java index d2f168eb5e3e..d69f3d620d48 100644 --- a/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java +++ b/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java @@ -333,6 +333,9 @@ public final class RingtonePickerActivity extends AlertActivity implements @Override public void onDestroy() { + if (mHandler != null) { + mHandler.removeCallbacksAndMessages(null); + } if (mCursor != null) { mCursor.close(); mCursor = null; diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index dfc47587b91c..2fbd9ba05817 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -45,7 +45,7 @@ android_library { "WindowManager-Shell", "SystemUIPluginLib", "SystemUISharedLib", - "SystemUI-statsd", + "SystemUI-statsd", "SettingsLib", "androidx.viewpager2_viewpager2", "androidx.legacy_legacy-support-v4", diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 6aa233b2f292..98d3553287d1 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -239,6 +239,7 @@ <!-- Listen app op changes --> <uses-permission android:name="android.permission.WATCH_APPOPS" /> + <uses-permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS" /> <!-- to read and change hvac values in a car --> <uses-permission android:name="android.car.permission.CONTROL_CAR_CLIMATE" /> @@ -395,19 +396,15 @@ <!-- Springboard for launching the share and edit activity. This needs to be in the main system ui process since we need to notify the status bar to dismiss the keyguard --> - <receiver android:name=".screenshot.GlobalScreenshot$ActionProxyReceiver" - android:exported="false" /> - - <!-- Callback for dismissing screenshot notification after a share target is picked --> - <receiver android:name=".screenshot.GlobalScreenshot$TargetChosenReceiver" + <receiver android:name=".screenshot.ActionProxyReceiver" android:exported="false" /> <!-- Callback for deleting screenshot notification --> - <receiver android:name=".screenshot.GlobalScreenshot$DeleteScreenshotReceiver" + <receiver android:name=".screenshot.DeleteScreenshotReceiver" android:exported="false" /> <!-- Callback for invoking a smart action from the screenshot notification. --> - <receiver android:name=".screenshot.GlobalScreenshot$SmartActionsReceiver" + <receiver android:name=".screenshot.SmartActionsReceiver" android:exported="false"/> <!-- started from UsbDeviceSettingsManager --> diff --git a/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml b/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml new file mode 100644 index 000000000000..cc2089f69287 --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<ripple xmlns:android="http://schemas.android.com/apk/res/android" + android:color="?attr/wallpaperTextColorSecondary"> + <item android:id="@android:id/background"> + <shape + android:color="@android:color/transparent"> + <stroke android:width="1dp" android:color="?attr/wallpaperTextColorSecondary"/> + <corners android:radius="24dp"/> + </shape> + </item> + <item android:id="@android:id/mask"> + <shape android:shape="rectangle"> + <solid android:color="?attr/wallpaperTextColorSecondary"/> + <corners android:radius="24dp"/> + </shape> + </item> +</ripple>
\ No newline at end of file diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_emergency_carrier_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_emergency_carrier_area.xml index 3018a022e763..370576b43463 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_emergency_carrier_area.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_emergency_carrier_area.xml @@ -33,6 +33,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" style="@style/Keyguard.TextView" + android:layout_marginBottom="8dp" android:singleLine="true" android:ellipsize="marquee" android:visibility="gone" @@ -42,11 +43,9 @@ <com.android.keyguard.EmergencyButton android:id="@+id/emergency_call_button" android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_weight="1" - android:layout_marginTop="@dimen/eca_overlap" + android:layout_height="32dp" + android:layout_marginBottom="12dp" android:text="@*android:string/lockscreen_emergency_call" - style="@style/Keyguard.TextView.EmergencyButton" - android:textAllCaps="@bool/kg_use_all_caps" /> + style="@style/Keyguard.TextView.EmergencyButton" /> </com.android.keyguard.EmergencyCarrierArea> diff --git a/packages/SystemUI/res-keyguard/values-af/strings.xml b/packages/SystemUI/res-keyguard/values-af/strings.xml index 8a1f6de432f8..92dd9fd96111 100644 --- a/packages/SystemUI/res-keyguard/values-af/strings.xml +++ b/packages/SystemUI/res-keyguard/values-af/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Geen diens nie."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Wissel invoermetode"</string> <string name="airplane_mode" msgid="2528005343938497866">"Vliegtuigmodus"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"PIN word vereis om vir opdatering voor te berei"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Patroon word vereis om vir opdatering voor te berei"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Wagwoord word vereis om vir opdatering voor te berei"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Patroon word vereis nadat toestel herbegin het"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN word vereis nadat toestel herbegin het"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Wagwoord word vereis nadat toestel herbegin het"</string> diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml index 0a4aee53b7be..f94c20f9ad01 100644 --- a/packages/SystemUI/res-keyguard/values-am/strings.xml +++ b/packages/SystemUI/res-keyguard/values-am/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"ከአገልግሎት መስጫ ክልል ውጪ።"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"የግቤት ስልት ቀይር"</string> <string name="airplane_mode" msgid="2528005343938497866">"የአውሮፕላን ሁነታ"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"ለዝማኔ ለማዘጋጀት ፒን ያስፈልጋል"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"ለዝማኔ ለማዘጋጀት ሥርዓተ ጥለት ያስፈልጋል"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"ለዝማኔ ለማዘጋጀት የይለፍ ቃል ያስፈልጋል"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"መሣሪያ ዳግም ከጀመረ በኋላ ሥርዓተ ጥለት ያስፈልጋል"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"መሣሪያ ዳግም ከተነሳ በኋላ ፒን ያስፈልጋል"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"መሣሪያ ዳግም ከጀመረ በኋላ የይለፍ ቃል ያስፈልጋል"</string> diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml index 491dc39aa08d..6d86a78360d8 100644 --- a/packages/SystemUI/res-keyguard/values-ar/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml @@ -113,9 +113,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"لا تتوفر خدمة."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"تبديل أسلوب الإدخال"</string> <string name="airplane_mode" msgid="2528005343938497866">"وضع الطائرة"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"يجب إدخال رقم التعريف الشخصي للتحضير للتحديث."</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"يجب رسم النقش للتحضير للتحديث."</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"يجب إدخال كلمة المرور للتحضير للتحديث."</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"يجب رسم النقش بعد إعادة تشغيل الجهاز"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"يجب إدخال رقم التعريف الشخصي بعد إعادة تشغيل الجهاز"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"يجب إدخال كلمة المرور بعد إعادة تشغيل الجهاز"</string> diff --git a/packages/SystemUI/res-keyguard/values-as/strings.xml b/packages/SystemUI/res-keyguard/values-as/strings.xml index 4367efb8c679..3b51e480b7dd 100644 --- a/packages/SystemUI/res-keyguard/values-as/strings.xml +++ b/packages/SystemUI/res-keyguard/values-as/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"কোনো সেৱা নাই।"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ইনপুট পদ্ধতি সলনি কৰক"</string> <string name="airplane_mode" msgid="2528005343938497866">"এয়াৰপ্লেন ম\'ড"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"আপডে\'টৰ বাবে সাজু হ\'বলৈ পিনৰ আৱশ্যক"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"আপডে\'টৰ বাবে সাজু হ\'বলৈ আর্হিৰ আৱশ্যক"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"আপডে\'টৰ বাবে সাজু হ\'বলৈ পাছৱৰ্ডৰ আৱশ্যক"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ডিভাইচ ৰিষ্টাৰ্ট হোৱাৰ পিছত আৰ্হি দিয়াটো বাধ্যতামূলক"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ডিভাইচ ৰিষ্টাৰ্ট হোৱাৰ পিছত পিন দিয়াটো বাধ্যতামূলক"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ডিভাইচ ৰিষ্টাৰ্ট হোৱাৰ পিছত পাছৱৰ্ড দিয়াটো বাধ্যতামূলক"</string> diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml index d89bf6a8c0ae..ea07c3db4354 100644 --- a/packages/SystemUI/res-keyguard/values-az/strings.xml +++ b/packages/SystemUI/res-keyguard/values-az/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Xidmət yoxdur."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Daxiletmə metoduna keçin"</string> <string name="airplane_mode" msgid="2528005343938497866">"Təyyarə rejimi"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Güncəlləməyə hazırlıq üçün PIN kod tələb olunur"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Güncəlləməyə hazırlıq üçün model tələb olunur"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Güncəlləməyə hazırlıq üçün parol tələb olunur"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Cihaz yenidən başladıqdan sonra model tələb olunur"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Cihaz yeniden başladıqdan sonra PIN tələb olunur"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Cihaz yeniden başladıqdan sonra parol tələb olunur"</string> diff --git a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml index 656e32301153..e206958d1e95 100644 --- a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml @@ -104,9 +104,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Mreža nije dostupna."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Promeni metod unosa"</string> <string name="airplane_mode" msgid="2528005343938497866">"Režim rada u avionu"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"PIN je obavezan radi pripreme za ažuriranje"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Šablon je obavezan radi pripreme za ažuriranje"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Lozinka je obavezna radi pripreme za ažuriranje"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Treba da unesete šablon kada se uređaj ponovo pokrene"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Treba da unesete PIN kada se uređaj ponovo pokrene"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Treba da unesete lozinku kada se uređaj ponovo pokrene"</string> diff --git a/packages/SystemUI/res-keyguard/values-be/strings.xml b/packages/SystemUI/res-keyguard/values-be/strings.xml index 07b6f358dcfc..569e705fbcc2 100644 --- a/packages/SystemUI/res-keyguard/values-be/strings.xml +++ b/packages/SystemUI/res-keyguard/values-be/strings.xml @@ -107,9 +107,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Не абслугоўваецца."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Пераключэнне рэжыму ўводу"</string> <string name="airplane_mode" msgid="2528005343938497866">"Рэжым палёту"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Для падрыхтоўкі да абнаўлення неабходна ўвесці PIN-код"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Для падрыхтоўкі да абнаўлення неабходна ўвесці ўзор разблакіроўкі"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Для падрыхтоўкі да абнаўлення неабходна ўвесці пароль"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Пасля перазапуску прылады патрабуецца ўзор"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Пасля перазапуску прылады патрабуецца PIN-код"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Пасля перазапуску прылады патрабуецца пароль"</string> diff --git a/packages/SystemUI/res-keyguard/values-bg/strings.xml b/packages/SystemUI/res-keyguard/values-bg/strings.xml index a8c64f5d9551..d015be320e20 100644 --- a/packages/SystemUI/res-keyguard/values-bg/strings.xml +++ b/packages/SystemUI/res-keyguard/values-bg/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Няма покритие."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Превключване на метода на въвеждане"</string> <string name="airplane_mode" msgid="2528005343938497866">"Самолетен режим"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"За подготовката за актуализация се изисква ПИН код"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"За подготовката за актуализация се изисква фигура"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"За подготовката за актуализация се изисква парола"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"След рестартиране на устройството се изисква фигура"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"След рестартиране на устройството се изисква ПИН код"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"След рестартиране на устройството се изисква парола"</string> diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml index 479e83ab3954..8eae6e6e2e18 100644 --- a/packages/SystemUI/res-keyguard/values-bn/strings.xml +++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"কোনো পরিষেবা নেই।"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ইনপুট পদ্ধতি পরিবর্তন করুন"</string> <string name="airplane_mode" msgid="2528005343938497866">"বিমান মোড"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"আপডেট প্রস্তুত করতে পিন দরকার"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"আপডেট প্রস্তুত করতে প্যাটার্ন দরকার"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"আপডেট প্রস্তুত করতে পাসওয়ার্ড দরকার"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ডিভাইসটি পুনরায় চালু হওয়ার পর প্যাটার্নের প্রয়োজন হবে"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ডিভাইসটি পুনরায় চালু হওয়ার পর পিন প্রয়োজন হবে"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ডিভাইসটি পুনরায় চালু হওয়ার পর পাসওয়ার্ডের প্রয়োজন হবে"</string> diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml index ada4c134fce7..286b08be1c5e 100644 --- a/packages/SystemUI/res-keyguard/values-bs/strings.xml +++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml @@ -104,9 +104,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Nema mreže."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Promjena načina unosa"</string> <string name="airplane_mode" msgid="2528005343938497866">"Način rada u avionu"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Za pripremu ažuriranja potreban je PIN"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Za pripremu ažuriranja potreban je uzorak"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Za pripremu ažuriranja potrebna je lozinka"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Potreban je uzorak nakon što se uređaj ponovo pokrene"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Potreban je PIN nakon što se uređaj ponovo pokrene"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Potrebna je lozinka nakon što se uređaj ponovo pokrene"</string> diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml index 6f5b6829c3e0..cb7fa37b281d 100644 --- a/packages/SystemUI/res-keyguard/values-ca/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Sense servei"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Canvia el mètode d\'introducció"</string> <string name="airplane_mode" msgid="2528005343938497866">"Mode d\'avió"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Cal introduir el PIN per preparar l\'actualització"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Cal introduir el patró per preparar l\'actualització"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Cal introduir la contrasenya per preparar l\'actualització"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Cal introduir el patró quan es reinicia el dispositiu"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Cal introduir el PIN quan es reinicia el dispositiu"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Cal introduir la contrasenya quan es reinicia el dispositiu"</string> diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml index a2f79adff1db..4f0c0ffa4962 100644 --- a/packages/SystemUI/res-keyguard/values-cs/strings.xml +++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml @@ -107,9 +107,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Žádný signál"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Přepnout metodu zadávání"</string> <string name="airplane_mode" msgid="2528005343938497866">"Režim Letadlo"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Příprava na aktualizaci vyžaduje PIN"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Příprava na aktualizaci vyžaduje gesto"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Příprava na aktualizaci vyžaduje heslo"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Po restartování zařízení je vyžadováno gesto"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Po restartování zařízení je vyžadován kód PIN"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Po restartování zařízení je vyžadováno heslo"</string> diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml index ef06269b5630..e486fc625699 100644 --- a/packages/SystemUI/res-keyguard/values-da/strings.xml +++ b/packages/SystemUI/res-keyguard/values-da/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Ingen dækning."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Skift indtastningsmetode"</string> <string name="airplane_mode" msgid="2528005343938497866">"Flytilstand"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Du skal angive din pinkode for at forberede opdateringen"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Du skal angive dit mønster for at forberede opdateringen"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Du skal angive din adgangskode for at forberede opdateringen"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Du skal angive et mønster, når du har genstartet enheden"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Der skal angives en pinkode efter genstart af enheden"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Der skal angives en adgangskode efter genstart af enheden"</string> diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml index fdfce1ffb338..06d012f4e84d 100644 --- a/packages/SystemUI/res-keyguard/values-de/strings.xml +++ b/packages/SystemUI/res-keyguard/values-de/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Dienst nicht verfügbar"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Eingabemethode wechseln"</string> <string name="airplane_mode" msgid="2528005343938497866">"Flugmodus"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Zur Vorbereitung auf das Update ist eine PIN erforderlich"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Zur Vorbereitung auf das Update ist ein Muster erforderlich"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Zur Vorbereitung auf das Update ist ein Passwort erforderlich"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Nach dem Neustart des Geräts ist die Eingabe des Musters erforderlich"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Nach dem Neustart des Geräts ist die Eingabe der PIN erforderlich"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Nach dem Neustart des Geräts ist die Eingabe des Passworts erforderlich"</string> diff --git a/packages/SystemUI/res-keyguard/values-el/strings.xml b/packages/SystemUI/res-keyguard/values-el/strings.xml index 8e4578f8445c..176428421476 100644 --- a/packages/SystemUI/res-keyguard/values-el/strings.xml +++ b/packages/SystemUI/res-keyguard/values-el/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Καμία υπηρεσία."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Εναλλαγή μεθόδου εισαγωγής"</string> <string name="airplane_mode" msgid="2528005343938497866">"Λειτουργία πτήσης"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Απαιτείται PIN για την προετοιμασία για ενημέρωση"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Απαιτείται μοτίβο για την προετοιμασία για ενημέρωση"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Απαιτείται κωδικός πρόσβασης για την προετοιμασία για ενημέρωση"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Απαιτείται μοτίβο μετά από την επανεκκίνηση της συσκευής"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Απαιτείται PIN μετά από την επανεκκίνηση της συσκευής"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Απαιτείται κωδικός πρόσβασης μετά από την επανεκκίνηση της συσκευής"</string> diff --git a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml index 21cfe48689ae..92a15949a8ab 100644 --- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"No service"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Switch input method"</string> <string name="airplane_mode" msgid="2528005343938497866">"Aeroplane mode"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"PIN required to prepare for update"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Pattern required to prepare for update"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Password required to prepare for update"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pattern required after device restarts"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN required after device restarts"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Password required after device restarts"</string> diff --git a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml index 921ba6b59af9..719f1a18a744 100644 --- a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"No service"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Switch input method"</string> <string name="airplane_mode" msgid="2528005343938497866">"Airplane mode"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"PIN required to prepare for update"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Pattern required to prepare for update"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Password required to prepare for update"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pattern required after device restarts"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN required after device restarts"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Password required after device restarts"</string> diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml index 21cfe48689ae..92a15949a8ab 100644 --- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"No service"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Switch input method"</string> <string name="airplane_mode" msgid="2528005343938497866">"Aeroplane mode"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"PIN required to prepare for update"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Pattern required to prepare for update"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Password required to prepare for update"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pattern required after device restarts"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN required after device restarts"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Password required after device restarts"</string> diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml index 21cfe48689ae..92a15949a8ab 100644 --- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"No service"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Switch input method"</string> <string name="airplane_mode" msgid="2528005343938497866">"Aeroplane mode"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"PIN required to prepare for update"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Pattern required to prepare for update"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Password required to prepare for update"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pattern required after device restarts"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN required after device restarts"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Password required after device restarts"</string> diff --git a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml index fc59d0dfcdc5..975b1f644ef8 100644 --- a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"No service."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Switch input method"</string> <string name="airplane_mode" msgid="2528005343938497866">"Airplane mode"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"PIN required to prepare for update"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Pattern required to prepare for update"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Password required to prepare for update"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pattern required after device restarts"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN required after device restarts"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Password required after device restarts"</string> diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml index ab0c8f351562..25ab6159998e 100644 --- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml +++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Sin servicio"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Cambiar método de entrada"</string> <string name="airplane_mode" msgid="2528005343938497866">"Modo de avión"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Se requiere el PIN para actualizar el sistema"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Se requiere el patrón para actualizar el sistema"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Se requiere la contraseña para actualizar el sistema"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Se requiere el patrón después de reiniciar el dispositivo"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Se requiere el PIN después de reiniciar el dispositivo"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Se requiere la contraseña después de reiniciar el dispositivo"</string> diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml index 38451c7cfba5..0754681215cc 100644 --- a/packages/SystemUI/res-keyguard/values-es/strings.xml +++ b/packages/SystemUI/res-keyguard/values-es/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Sin servicio"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Cambiar método de introducción"</string> <string name="airplane_mode" msgid="2528005343938497866">"Modo avión"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Debes introducir el PIN para prepararte para la actualización"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Debes dibujar el patrón para prepararte para la actualización"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Debes introducir la contraseña para prepararte para la actualización"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Debes introducir el patrón después de reiniciar el dispositivo"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Debes introducir el PIN después de reiniciar el dispositivo"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Debes introducir la contraseña después de reiniciar el dispositivo"</string> diff --git a/packages/SystemUI/res-keyguard/values-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml index f8ad18bba2f7..331a95c73c5e 100644 --- a/packages/SystemUI/res-keyguard/values-et/strings.xml +++ b/packages/SystemUI/res-keyguard/values-et/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Teenus puudub."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Vaheta sisestusmeetodit"</string> <string name="airplane_mode" msgid="2528005343938497866">"Lennukirežiim"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Värskendamiseks ettevalmistuste tegemiseks tuleb sisestada PIN-kood"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Värskendamiseks ettevalmistuste tegemiseks tuleb sisestada muster"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Värskendamiseks ettevalmistuste tegemiseks tuleb sisestada parool"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pärast seadme taaskäivitamist tuleb sisestada muster"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Pärast seadme taaskäivitamist tuleb sisestada PIN-kood"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Pärast seadme taaskäivitamist tuleb sisestada parool"</string> diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml index 8510bee0711b..3ff224b9e55a 100644 --- a/packages/SystemUI/res-keyguard/values-eu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Ez dago konektatuta inongo saretara."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Aldatu idazketa-metodoa"</string> <string name="airplane_mode" msgid="2528005343938497866">"Hegaldi modua"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"PIN kodea behar da eguneratzea prestatzeko"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Eredua behar da eguneratzea prestatzeko"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Pasahitza behar da eguneratzea prestatzeko"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Eredua marraztu beharko duzu gailua berrabiarazten denean"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN kodea idatzi beharko duzu gailua berrabiarazten denean"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Pasahitza idatzi beharko duzu gailua berrabiarazten denean"</string> diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml index 43d32140b153..5e696369634e 100644 --- a/packages/SystemUI/res-keyguard/values-fa/strings.xml +++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"سرویسی وجود ندارد."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"تغییر روش ورودی"</string> <string name="airplane_mode" msgid="2528005343938497866">"حالت هواپیما"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"آمادهسازی برای بهروزرسانی به پین نیاز دارد"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"آمادهسازی برای بهروزرسانی به الگو نیاز دارد"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"آمادهسازی برای بهروزرسانی به گذرواژه نیاز دارد"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"بعد از بازنشانی دستگاه باید الگو وارد شود"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"بعد از بازنشانی دستگاه باید پین وارد شود"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"بعد از بازنشانی دستگاه باید گذرواژه وارد شود"</string> diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml index 7dc12c93e45e..54bc4d8cba58 100644 --- a/packages/SystemUI/res-keyguard/values-fi/strings.xml +++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Ei yhteyttä"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Vaihda syöttötapaa."</string> <string name="airplane_mode" msgid="2528005343938497866">"Lentokonetila"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Päivitykseen valmistautuminen edellyttää PIN-koodia"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Päivitykseen valmistautuminen edellyttää kuviota"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Päivitykseen valmistautuminen edellyttää salasanaa"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Kuvio vaaditaan laitteen uudelleenkäynnistyksen jälkeen."</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN-koodi vaaditaan laitteen uudelleenkäynnistyksen jälkeen."</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Salasana vaaditaan laitteen uudelleenkäynnistyksen jälkeen."</string> diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml index f093c1745e76..3e858c2ecf12 100644 --- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Aucun service"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Changer de méthode d\'entrée"</string> <string name="airplane_mode" msgid="2528005343938497866">"Mode Avion"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Le NIP est nécessaire pour préparer la mise à jour"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Le schéma est nécessaire pour préparer la mise à jour"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Le mot de passe est nécessaire pour préparer la mise à jour"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Le schéma est exigé après le redémarrage de l\'appareil"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Le NIP est exigé après le redémarrage de l\'appareil"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Le mot de passe est exigé après le redémarrage de l\'appareil"</string> diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml index d6d5a32874c2..8551fab7281f 100644 --- a/packages/SystemUI/res-keyguard/values-fr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Aucun service."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Changer le mode de saisie"</string> <string name="airplane_mode" msgid="2528005343938497866">"Mode Avion"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Veuillez saisir le code pour lancer la préparation de la mise à jour"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Veuillez saisir le schéma pour lancer la préparation de la mise à jour"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Veuillez saisir le mot de passe pour lancer la préparation de la mise à jour"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Veuillez dessiner le schéma après le redémarrage de l\'appareil"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Veuillez saisir le code après le redémarrage de l\'appareil"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Veuillez saisir le mot de passe après le redémarrage de l\'appareil"</string> diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml index f5d5bb4d13d4..46079810aee4 100644 --- a/packages/SystemUI/res-keyguard/values-gl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Non hai servizo."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Cambia o método de introdución"</string> <string name="airplane_mode" msgid="2528005343938497866">"Modo avión"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Necesítase o PIN para preparar o dispositivo co fin de actualizalo"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Necesítase o padrón para preparar o dispositivo co fin de actualizalo"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Necesítase o contrasinal para preparar o dispositivo co fin de actualizalo"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"É necesario o padrón despois do reinicio do dispositivo"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"É necesario o PIN despois do reinicio do dispositivo"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"É necesario o contrasinal despois do reinicio do dispositivo"</string> diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml index 29e2fe040082..b02d3d97b39f 100644 --- a/packages/SystemUI/res-keyguard/values-gu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"કોઈ સેવા નથી."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ઇનપુટ પદ્ધતિ સ્વિચ કરો"</string> <string name="airplane_mode" msgid="2528005343938497866">"એરપ્લેન મોડ"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"અપડેટ માટે તૈયાર કરવા માટે પિન જરુરી છે"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"અપડેટ માટે તૈયાર કરવા માટે પૅટર્ન જરુરી છે"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"અપડેટ માટે તૈયાર કરવા માટે પાસવર્ડ જરુરી છે"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ઉપકરણનો પુનઃપ્રારંભ થાય તે પછી પૅટર્ન જરૂરી છે"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ઉપકરણનો પુનઃપ્રારંભ થાય તે પછી પિન જરૂરી છે"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ઉપકરણનો પુનઃપ્રારંભ થાય તે પછી પાસવર્ડ જરૂરી છે"</string> diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml index d26c79f9c420..f6b15de0e97e 100644 --- a/packages/SystemUI/res-keyguard/values-hi/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"कोई सेवा नहीं."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"इनपुट का तरीका बदलें"</string> <string name="airplane_mode" msgid="2528005343938497866">"हवाई जहाज़ मोड"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"अपडेट के लिए पिन डालना ज़रूरी है"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"अपडेट के लिए पैटर्न डालना ज़रूरी है"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"अपडेट के लिए पासवर्ड डालना ज़रूरी है"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"डिवाइस फिर से चालू होने के बाद पैटर्न ज़रूरी है"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"डिवाइस फिर से चालू होने के बाद पिन ज़रूरी है"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"डिवाइस फिर से चालू होने के बाद पासवर्ड ज़रूरी है"</string> diff --git a/packages/SystemUI/res-keyguard/values-hr/strings.xml b/packages/SystemUI/res-keyguard/values-hr/strings.xml index c8dd9b0a0932..49db3f88669a 100644 --- a/packages/SystemUI/res-keyguard/values-hr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hr/strings.xml @@ -104,9 +104,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Nema usluge."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Promjena načina unosa"</string> <string name="airplane_mode" msgid="2528005343938497866">"Način rada u zrakoplovu"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Za pripremu ažuriranja potreban je PIN"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Za pripremu ažuriranja potreban je uzorak"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Za pripremu ažuriranja potrebna je zaporka"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Nakon ponovnog pokretanja uređaja morate unijeti uzorak"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Nakon ponovnog pokretanja uređaja morate unijeti PIN"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Nakon ponovnog pokretanja uređaja morate unijeti zaporku"</string> diff --git a/packages/SystemUI/res-keyguard/values-hu/strings.xml b/packages/SystemUI/res-keyguard/values-hu/strings.xml index f0023d20e6bd..c26998f01ff0 100644 --- a/packages/SystemUI/res-keyguard/values-hu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hu/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Nincs szolgáltatás."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Beviteli módszer váltása"</string> <string name="airplane_mode" msgid="2528005343938497866">"Repülős üzemmód"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"A frissítésre való felkészüléshez meg kell adni a PIN-kódot"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"A frissítésre való felkészüléshez meg kell adni a mintát"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"A frissítésre való felkészüléshez meg kell adni a jelszót"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Az eszköz újraindítását követően meg kell adni a mintát"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Az eszköz újraindítását követően meg kell adni a PIN-kódot"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Az eszköz újraindítását követően meg kell adni a jelszót"</string> diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml index 42247052014f..ad949d48fe0c 100644 --- a/packages/SystemUI/res-keyguard/values-hy/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Ծառայությունն անհասանելի է։"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Փոխել ներածման եղանակը"</string> <string name="airplane_mode" msgid="2528005343938497866">"Ավիառեժիմ"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Թարմացմանը պատրաստվելու համար անհրաժեշտ է մուտքագրել PIN-ը"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Թարմացմանը պատրաստվելու համար անհրաժեշտ է մուտքագրել նախշը"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Թարմացմանը պատրաստվելու համար անհրաժեշտ է մուտքագրել գաղտնաբառը"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Սարքը վերագործարկելուց հետո անհրաժեշտ է մուտքագրել նախշը"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Սարքը վերագործարկելուց հետո անհրաժեշտ է մուտքագրել PIN կոդը"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Սարքը վերագործարկելուց հետո անհրաժեշտ է մուտքագրել գաղտնաբառը"</string> diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml index d62795ba1b14..85b2a4726fa2 100644 --- a/packages/SystemUI/res-keyguard/values-in/strings.xml +++ b/packages/SystemUI/res-keyguard/values-in/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Tidak ada layanan."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Beralih metode masukan"</string> <string name="airplane_mode" msgid="2528005343938497866">"Mode pesawat"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"PIN diwajibkan untuk menyiapkan update"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Pola diwajibkan untuk menyiapkan update"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Sandi diwajibkan untuk menyiapkan update"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pola diperlukan setelah perangkat dimulai ulang"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN diperlukan setelah perangkat dimulai ulang"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Sandi diperlukan setelah perangkat dimulai ulang"</string> diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml index 5e3765571c02..e40cdca33034 100644 --- a/packages/SystemUI/res-keyguard/values-is/strings.xml +++ b/packages/SystemUI/res-keyguard/values-is/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Ekkert símasamband."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Skipta um innsláttaraðferð"</string> <string name="airplane_mode" msgid="2528005343938497866">"Flugstilling"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Slá þarf inn PIN-númer til að undirbúa uppfærsluna"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Teikna þarf mynstur til að undirbúa uppfærsluna"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Gefa þarf upp aðgangsorð til að undirbúa uppfærsluna"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Mynsturs er krafist þegar tækið er endurræst"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN-númers er krafist þegar tækið er endurræst"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Aðgangsorðs er krafist þegar tækið er endurræst"</string> diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml index fe460e38dc0b..e1c9ee8b7d34 100644 --- a/packages/SystemUI/res-keyguard/values-it/strings.xml +++ b/packages/SystemUI/res-keyguard/values-it/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Nessun servizio."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Cambia metodo di immissione"</string> <string name="airplane_mode" msgid="2528005343938497866">"Modalità aereo"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"PIN obbligatorio per la preparazione all\'aggiornamento"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Sequenza obbligatoria per la preparazione all\'aggiornamento"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Password obbligatoria per la preparazione all\'aggiornamento"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Sequenza obbligatoria dopo il riavvio del dispositivo"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN obbligatorio dopo il riavvio del dispositivo"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Password obbligatoria dopo il riavvio del dispositivo"</string> diff --git a/packages/SystemUI/res-keyguard/values-iw/strings.xml b/packages/SystemUI/res-keyguard/values-iw/strings.xml index 71f3048ba11c..e054f629836e 100644 --- a/packages/SystemUI/res-keyguard/values-iw/strings.xml +++ b/packages/SystemUI/res-keyguard/values-iw/strings.xml @@ -107,9 +107,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"אין שירות."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"החלפת שיטת קלט"</string> <string name="airplane_mode" msgid="2528005343938497866">"מצב טיסה"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"נדרש קוד אימות להכנת העדכון"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"נדרש קו ביטול נעילה להכנת העדכון"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"נדרשת סיסמה להכנת העדכון"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"יש להזין את קו ביטול הנעילה לאחר הפעלה מחדש של המכשיר"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"יש להזין קוד גישה לאחר הפעלה מחדש של המכשיר"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"יש להזין סיסמה לאחר הפעלה מחדש של המכשיר"</string> diff --git a/packages/SystemUI/res-keyguard/values-ja/strings.xml b/packages/SystemUI/res-keyguard/values-ja/strings.xml index 23ff82c6f2a7..957d78a8b440 100644 --- a/packages/SystemUI/res-keyguard/values-ja/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ja/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"通信サービスはありません。"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"入力方法の切り替え"</string> <string name="airplane_mode" msgid="2528005343938497866">"機内モード"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"更新の準備には PIN の入力が必要です"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"更新の準備にはパターンの入力が必要です"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"更新の準備にはパスワードが必要です"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"デバイスの再起動後はパターンの入力が必要となります"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"デバイスの再起動後は PIN の入力が必要となります"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"デバイスの再起動後はパスワードの入力が必要となります"</string> diff --git a/packages/SystemUI/res-keyguard/values-ka/strings.xml b/packages/SystemUI/res-keyguard/values-ka/strings.xml index 25b9b1b22c1c..d0d15fec7172 100644 --- a/packages/SystemUI/res-keyguard/values-ka/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ka/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"სერვისი არ არის."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"შეყვანის მეთოდის გადართვა"</string> <string name="airplane_mode" msgid="2528005343938497866">"თვითმფრინავის რეჟიმი"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"განახლების მოსამზადებლად საჭიროა PIN-კოდი"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"განახლების მოსამზადებლად საჭიროა ნიმუში"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"განახლების მოსამზადებლად საჭიროა პაროლი"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"მოწყობილობის გადატვირთვის შემდეგ საჭიროა ნიმუშის დახატვა"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"მოწყობილობის გადატვირთვის შემდეგ საჭიროა PIN-კოდის შეყვანა"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"მოწყობილობის გადატვირთვის შემდეგ საჭიროა პაროლის შეყვანა"</string> diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml index 456088181d7f..62afd1e45df8 100644 --- a/packages/SystemUI/res-keyguard/values-kk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Қызмет көрсетілмейді."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Енгізу әдісін ауыстыру"</string> <string name="airplane_mode" msgid="2528005343938497866">"Ұшақ режимі"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Жаңа нұсқа орнатуға дайындау үшін PIN кодын енгізу қажет."</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Жаңа нұсқа орнатуға дайындау үшін өрнек енгізу қажет."</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Жаңа нұсқа орнатуға дайындау үшін құпия сөз енгізу қажет."</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Құрылғы қайта іске қосылғаннан кейін, өрнекті енгізу қажет"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Құрылғы қайта іске қосылғаннан кейін, PIN кодын енгізу қажет"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Құрылғы қайта іске қосылғаннан кейін, құпия сөзді енгізу қажет"</string> diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml index e5ea9ea105dd..24b5c23a6732 100644 --- a/packages/SystemUI/res-keyguard/values-km/strings.xml +++ b/packages/SystemUI/res-keyguard/values-km/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"គ្មានសេវាទេ។"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ប្ដូរវិធីបញ្ចូល"</string> <string name="airplane_mode" msgid="2528005343938497866">"មុខងារពេលជិះយន្តហោះ"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"តម្រូវឱ្យមានកូដ PIN ដើម្បីរៀបចំធ្វើបច្ចុប្បន្នភាព"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"តម្រូវឱ្យមានលំនាំ ដើម្បីរៀបចំធ្វើបច្ចុប្បន្នភាព"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"តម្រូវឱ្យមានពាក្យសម្ងាត់ ដើម្បីរៀបចំធ្វើបច្ចុប្បន្នភាព"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"តម្រូវឲ្យប្រើលំនាំ បន្ទាប់ពីឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"តម្រូវឲ្យបញ្ចូលកូដ PIN បន្ទាប់ពីឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"តម្រូវឲ្យបញ្ចូលពាក្យសម្ងាត់ បន្ទាប់ពីឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string> diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml index 8173ca047fe3..785ca4338326 100644 --- a/packages/SystemUI/res-keyguard/values-kn/strings.xml +++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"ಸೇವೆ ಇಲ್ಲ."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ಇನ್ಪುಟ್ ವಿಧಾನ ಬದಲಿಸಿ"</string> <string name="airplane_mode" msgid="2528005343938497866">"ಏರ್ಪ್ಲೇನ್ ಮೋಡ್"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"ಅಪ್ಡೇಟ್ಗಾಗಿ ಸಿದ್ಧಗೊಳಿಸಲು, ಪಿನ್ ಅಗತ್ಯವಿದೆ"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"ಅಪ್ಡೇಟ್ಗಾಗಿ ಸಿದ್ಧಗೊಳಿಸಲು, ಪ್ಯಾಟರ್ನ್ ಅಗತ್ಯವಿದೆ"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"ಅಪ್ಡೇಟ್ಗಾಗಿ ಸಿದ್ಧಗೊಳಿಸಲು, ಪಾಸ್ವರ್ಡ್ ಅಗತ್ಯವಿದೆ"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ಸಾಧನ ಮರುಪ್ರಾರಂಭಗೊಂಡ ನಂತರ ಪ್ಯಾಟರ್ನ್ ಅಗತ್ಯವಿರುತ್ತದೆ"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ಸಾಧನ ಮರುಪ್ರಾರಂಭಗೊಂಡ ನಂತರ ಪಿನ್ ಅಗತ್ಯವಿರುತ್ತದೆ"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ಸಾಧನ ಮರುಪ್ರಾರಂಭಗೊಂಡ ನಂತರ ಪಾಸ್ವರ್ಡ್ ಅಗತ್ಯವಿರುತ್ತದೆ"</string> diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml index 606bb5047245..848490ebb9b8 100644 --- a/packages/SystemUI/res-keyguard/values-ko/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"서비스 불가"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"입력 방법 전환"</string> <string name="airplane_mode" msgid="2528005343938497866">"비행기 모드"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"업데이트를 준비하려면 PIN이 필요합니다."</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"업데이트를 준비하려면 패턴이 필요합니다."</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"업데이트를 준비하려면 비밀번호가 필요합니다."</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"기기가 다시 시작되면 패턴이 필요합니다."</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"기기가 다시 시작되면 PIN이 필요합니다."</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"기기가 다시 시작되면 비밀번호가 필요합니다."</string> diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml index 72f95dbfa59f..d868788a3eca 100644 --- a/packages/SystemUI/res-keyguard/values-ky/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Интернет жок."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Киргизүү ыкмасын өзгөртүү"</string> <string name="airplane_mode" msgid="2528005343938497866">"Учак режими"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Жаңыртууга даярдоо үчүн PIN код талап кылынат"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Жаңыртууга даярдоо үчүн графикалык ачкыч талап кылынат"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Жаңыртууга даярдоо үчүн сырсөз талап кылынат"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Түзмөк кайра күйгүзүлгөндөн кийин графикалык ачкычты тартуу талап кылынат"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Түзмөк кайра күйгүзүлгөндөн кийин PIN-кодду киргизүү талап кылынат"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Түзмөк кайра күйгүзүлгөндөн кийин сырсөздү киргизүү талап кылынат"</string> diff --git a/packages/SystemUI/res-keyguard/values-lo/strings.xml b/packages/SystemUI/res-keyguard/values-lo/strings.xml index 25e36c1b3115..ebaffb13d5b4 100644 --- a/packages/SystemUI/res-keyguard/values-lo/strings.xml +++ b/packages/SystemUI/res-keyguard/values-lo/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"ບໍ່ມີບໍລິການ"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ສະລັບຮູບແບບການປ້ອນຂໍ້ມູນ"</string> <string name="airplane_mode" msgid="2528005343938497866">"ໂໝດໃນຍົນ"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"ຕ້ອງໃຊ້ PIN ເພື່ອກະກຽມອັບເດດ"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"ຕ້ອງໃຊ້ຮູບແບບເພື່ອກະກຽມອັບເດດ"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"ຕ້ອງໃຊ້ລະຫັດຜ່ານເພື່ອກະກຽມອັບເດດ"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ຈຳເປັນຕ້ອງມີແບບຮູບປົດລັອກຫຼັງຈາກອຸປະກອນເລີ່ມລະບົບໃໝ່"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ຈຳເປັນຕ້ອງມີ PIN ຫຼັງຈາກອຸປະກອນເລີ່ມລະບົບໃໝ່"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ຈຳເປັນຕ້ອງມີລະຫັດຜ່ານຫຼັງຈາກອຸປະກອນເລີ່ມລະບົບໃໝ່"</string> diff --git a/packages/SystemUI/res-keyguard/values-lt/strings.xml b/packages/SystemUI/res-keyguard/values-lt/strings.xml index 158efe2feabb..4d598f6bfb6d 100644 --- a/packages/SystemUI/res-keyguard/values-lt/strings.xml +++ b/packages/SystemUI/res-keyguard/values-lt/strings.xml @@ -107,9 +107,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Nėra paslaugos."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Perjungti įvesties metodą"</string> <string name="airplane_mode" msgid="2528005343938497866">"Lėktuvo režimas"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Kad būtų pasiruošta atnaujinti, reikia įvesti PIN kodą"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Kad būtų pasiruošta atnaujinti, reikia įvesti atrakinimo piešinį"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Kad būtų pasiruošta atnaujinti, reikia įvesti slaptažodį"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Iš naujo paleidus įrenginį būtinas atrakinimo piešinys"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Iš naujo paleidus įrenginį būtinas PIN kodas"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Iš naujo paleidus įrenginį būtinas slaptažodis"</string> diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml index c4a4e7f45b38..fad67d536e58 100644 --- a/packages/SystemUI/res-keyguard/values-lv/strings.xml +++ b/packages/SystemUI/res-keyguard/values-lv/strings.xml @@ -104,9 +104,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Nav pakalpojuma."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Pārslēgt ievades metodi"</string> <string name="airplane_mode" msgid="2528005343938497866">"Lidojuma režīms"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Lai sagatavotos atjauninājumam, nepieciešams PIN."</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Lai sagatavotos atjauninājumam, nepieciešama kombinācija."</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Lai sagatavotos atjauninājumam, nepieciešama parole."</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pēc ierīces restartēšanas ir jāievada atbloķēšanas kombinācija."</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Pēc ierīces restartēšanas ir jāievada PIN kods."</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Pēc ierīces restartēšanas ir jāievada parole."</string> diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml index de4a83b97021..1397f467e116 100644 --- a/packages/SystemUI/res-keyguard/values-mk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-mk/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Нема услуга."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Префрли метод за внесување"</string> <string name="airplane_mode" msgid="2528005343938497866">"Авионски режим"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Потребен е PIN за да се подготви за ажурирање"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Потребна е шема за да се подготви за ажурирање"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Потребна е лозинка за да се подготви за ажурирање"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Потребна е шема по рестартирање на уредот"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Потребен е PIN-код по рестартирање на уредот"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Потребна е лозинка по рестартирање на уредот"</string> diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml index da26ba788932..f82f822ca26c 100644 --- a/packages/SystemUI/res-keyguard/values-ml/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"സേവനമില്ല"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ഇൻപുട്ട് രീതി മാറുക"</string> <string name="airplane_mode" msgid="2528005343938497866">"ഫ്ലൈറ്റ് മോഡ്"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"അപ്ഡേറ്റിനായി തയ്യാറെടുക്കാൻ പിൻ ആവശ്യമാണ്"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"അപ്ഡേറ്റിനായി തയ്യാറെടുക്കാൻ പാറ്റേൺ ആവശ്യമാണ്"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"അപ്ഡേറ്റിനായി തയ്യാറെടുക്കാൻ പാസ്വേഡ് ആവശ്യമാണ്"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ഉപകരണം റീസ്റ്റാർട്ടായശേഷം പാറ്റേൺ വരയ്ക്കേണ്ടതുണ്ട്"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ഉപകരണം റീസ്റ്റാർട്ടായശേഷം പിൻ നൽകേണ്ടതുണ്ട്"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ഉപകരണം റീസ്റ്റാർട്ടായശേഷം പാസ്വേഡ് നൽകേണ്ടതുണ്ട്"</string> diff --git a/packages/SystemUI/res-keyguard/values-mn/strings.xml b/packages/SystemUI/res-keyguard/values-mn/strings.xml index fb032f15df7f..462017af1922 100644 --- a/packages/SystemUI/res-keyguard/values-mn/strings.xml +++ b/packages/SystemUI/res-keyguard/values-mn/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Үйлчилгээ алга."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Оруулах аргыг сэлгэх"</string> <string name="airplane_mode" msgid="2528005343938497866">"Нислэгийн горим"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Шинэчлэхэд бэлтгэхийн тулд ПИН шаардлагатай"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Шинэчлэхэд бэлтгэхийн тулд хээ шаардлагатай"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Шинэчлэхэд бэлтгэхийн тулд нууц үг шаардлагатай"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Төхөөрөмжийг дахин эхлүүлсний дараа загвар оруулах шаардлагатай"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Төхөөрөмжийг дахин эхлүүлсний дараа ПИН оруулах шаардлагатай"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Төхөөрөмжийг дахин эхлүүлсний дараа нууц үг оруулах шаардлагатай"</string> diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml index e79e5c5d9234..0166791dc3ba 100644 --- a/packages/SystemUI/res-keyguard/values-mr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"सेवा नाही."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"इनपुट पद्धत स्विच करा"</string> <string name="airplane_mode" msgid="2528005343938497866">"विमान मोड"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"अपडेटसाठी तयार करण्याकरिता पिन आवश्यक आहे"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"अपडेटसाठी तयार करण्याकरिता पॅटर्न आवश्यक आहे"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"अपडेटसाठी तयार करण्याकरिता पासवर्ड आवश्यक आहे"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"डिव्हाइस रीस्टार्ट झाल्यावर पॅटर्न आवश्यक आहे"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"डिव्हाइस रीस्टार्ट झाल्यावर पिन आवश्यक आहे"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"डिव्हाइस रीस्टार्ट झाल्यावर पासवर्ड आवश्यक आहे"</string> diff --git a/packages/SystemUI/res-keyguard/values-ms/strings.xml b/packages/SystemUI/res-keyguard/values-ms/strings.xml index 5bc5df4d7c26..67500866f3d4 100644 --- a/packages/SystemUI/res-keyguard/values-ms/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ms/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Tiada perkhidmatan."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Tukar kaedah masukan"</string> <string name="airplane_mode" msgid="2528005343938497866">"Mod Pesawat"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"PIN diperlukan untuk menyediakan kemas kini"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Corak diperlukan untuk menyediakan kemas kini"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Kata laluan diperlukan untuk menyediakan kemas kini"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Corak diperlukan setelah peranti dimulakan semula"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN diperlukan setelah peranti dimulakan semula"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Kata laluan diperlukan setelah peranti dimulakan semula"</string> diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml index 43732d8ff260..3b32f06e19cd 100644 --- a/packages/SystemUI/res-keyguard/values-my/strings.xml +++ b/packages/SystemUI/res-keyguard/values-my/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"ဝန်ဆောင်မှု မရှိပါ။"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"စာရိုက်စနစ်ပြောင်းရန်"</string> <string name="airplane_mode" msgid="2528005343938497866">"လေယာဉ်ပျံမုဒ်"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"အပ်ဒိတ်အတွက် ပြင်ဆင်ရန် ပင်နံပါတ် လိုပါသည်"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"အပ်ဒိတ်အတွက် ပြင်ဆင်ရန် ပုံစံလိုပါသည်"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"အပ်ဒိတ်အတွက် ပြင်ဆင်ရန် စကားဝှက် လိုပါသည်"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"စက်ပစ္စည်းကို ပိတ်ပြီးပြန်ဖွင့်လိုက်သည့်အခါတွင် ပုံစံ လိုအပ်ပါသည်"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"စက်ပစ္စည်းကို ပိတ်ပြီးပြန်ဖွင့်လိုက်သည့်အခါတွင် ပင်နံပါတ် လိုအပ်ပါသည်"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"စက်ပစ္စည်းကို ပိတ်ပြီးပြန်ဖွင့်လိုက်သည့်အခါတွင် စကားဝှက် လိုအပ်ပါသည်"</string> diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml index 6dd3b2ad6e72..ebd8f2922ba2 100644 --- a/packages/SystemUI/res-keyguard/values-nb/strings.xml +++ b/packages/SystemUI/res-keyguard/values-nb/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Ingen tilkobling."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Bytt inndatametode"</string> <string name="airplane_mode" msgid="2528005343938497866">"Flymodus"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"PIN-koden kreves for å klargjøre for oppdateringen"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Mønsteret kreves for å klargjøre for oppdateringen"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Passordet kreves for å klargjøre for oppdateringen"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Du må tegne mønsteret etter at enheten har startet på nytt"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Du må skrive inn PIN-koden etter at enheten har startet på nytt"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Du må skrive inn passordet etter at enheten har startet på nytt"</string> diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml index a1e6d62234e9..ce05e38dca10 100644 --- a/packages/SystemUI/res-keyguard/values-ne/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"सेवा उपलब्ध छैन।"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"इनपुट विधिलाई स्विच गर्नुहोस्"</string> <string name="airplane_mode" msgid="2528005343938497866">"हवाइजहाज मोड"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"अद्यावधिक गर्ने कार्यका लागि तयार पार्न PIN चाहिन्छ"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"अद्यावधिक गर्ने कार्यका लागि तयार पार्न प्याटर्न चाहिन्छ"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"अद्यावधिक गर्ने कार्यका लागि तयार पार्न पासवर्ड चाहिन्छ"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"यन्त्र पुनः सुरु भएपछि ढाँचा आवश्यक पर्दछ"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"यन्त्र पुनः सुरु भएपछि PIN आवश्यक पर्दछ"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"यन्त्र पुनः सुरु भएपछि पासवर्ड आवश्यक पर्दछ"</string> diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml index f3c35a405bd6..aa783e84b892 100644 --- a/packages/SystemUI/res-keyguard/values-nl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Geen service."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Invoermethode wijzigen"</string> <string name="airplane_mode" msgid="2528005343938497866">"Vliegtuigmodus"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Pincode vereist voor voorbereiding op update"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Patroon vereist voor voorbereiding op update"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Wachtwoord vereist voor voorbereiding op update"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Patroon vereist nadat het apparaat opnieuw is opgestart"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Pincode vereist nadat het apparaat opnieuw is opgestart"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Wachtwoord vereist nadat het apparaat opnieuw is opgestart"</string> diff --git a/packages/SystemUI/res-keyguard/values-or/strings.xml b/packages/SystemUI/res-keyguard/values-or/strings.xml index e92dc42680e1..8bbdcf1e9eb6 100644 --- a/packages/SystemUI/res-keyguard/values-or/strings.xml +++ b/packages/SystemUI/res-keyguard/values-or/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"କୌଣସି ସେବା ନାହିଁ।"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ଇନପୁଟ୍ ପଦ୍ଧତି ବଦଳାନ୍ତୁ"</string> <string name="airplane_mode" msgid="2528005343938497866">"ଏରୋପ୍ଲେନ୍ ମୋଡ୍"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"ଅପଡେଟ୍ ପାଇଁ ପ୍ରସ୍ତୁତ ହେବାକୁ PIN ଆବଶ୍ୟକ"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"ଅପଡେଟ୍ ପାଇଁ ପ୍ରସ୍ତୁତ ହେବାକୁ ପାଟର୍ନ ଆବଶ୍ୟକ"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"ଅପଡେଟ୍ ପାଇଁ ପ୍ରସ୍ତୁତ ହେବାକୁ ପାସୱାର୍ଡ ଆବଶ୍ୟକ"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ଡିଭାଇସ୍ ରିଷ୍ଟାର୍ଟ ହେବା ପରେ ପାଟର୍ନ ଆବଶ୍ୟକ ଅଟେ"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ଡିଭାଇସ୍ ରିଷ୍ଟାର୍ଟ ହେବାପରେ ପାସ୍ୱର୍ଡ ଆବଶ୍ୟକ"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ଡିଭାଇସ୍ ରିଷ୍ଟାର୍ଟ ହେବା ପରେ ପାସୱର୍ଡ ଆବଶ୍ୟକ ଅଟେ"</string> diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml index 5c83ab8a354c..78e066526840 100644 --- a/packages/SystemUI/res-keyguard/values-pa/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"ਕੋਈ ਸੇਵਾ ਨਹੀਂ।"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ਇਨਪੁੱਟ ਵਿਧੀ ਸਵਿੱਚ ਕਰੋ"</string> <string name="airplane_mode" msgid="2528005343938497866">"ਹਵਾਈ-ਜਹਾਜ਼ ਮੋਡ"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"ਅੱਪਡੇਟ ਨੂੰ ਤਿਆਰ ਕਰਨ ਲਈ ਪਿੰਨ ਲੋੜੀਂਦਾ ਹੈ"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"ਅੱਪਡੇਟ ਨੂੰ ਤਿਆਰ ਕਰਨ ਲਈ ਪੈਟਰਨ ਲੋੜੀਂਦਾ ਹੈ"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"ਅੱਪਡੇਟ ਨੂੰ ਤਿਆਰ ਕਰਨ ਲਈ ਪਾਸਵਰਡ ਲੋੜੀਂਦਾ ਹੈ"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ਡੀਵਾਈਸ ਦੇ ਮੁੜ-ਚਾਲੂ ਹੋਣ \'ਤੇ ਪੈਟਰਨ ਦੀ ਲੋੜ ਹੈ"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ਡੀਵਾਈਸ ਦੇ ਮੁੜ-ਚਾਲੂ ਹੋਣ \'ਤੇ ਪਿੰਨ ਦੀ ਲੋੜ ਹੈ"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ਡੀਵਾਈਸ ਦੇ ਮੁੜ-ਚਾਲੂ ਹੋਣ \'ਤੇ ਪਾਸਵਰਡ ਦੀ ਲੋੜ ਹੈ"</string> diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml index 5f1df3e109b1..5094cf9983a1 100644 --- a/packages/SystemUI/res-keyguard/values-pl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml @@ -107,9 +107,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Brak usługi."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Przełączanie metody wprowadzania"</string> <string name="airplane_mode" msgid="2528005343938497866">"Tryb samolotowy"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Aby przygotować się do aktualizacji, wymagany jest kod PIN"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Aby przygotować się do aktualizacji, wymagany jest wzór"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Aby przygotować się do aktualizacji, wymagane jest hasło"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Po ponownym uruchomieniu urządzenia wymagany jest wzór"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Po ponownym uruchomieniu urządzenia wymagany jest kod PIN"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Po ponownym uruchomieniu urządzenia wymagane jest hasło"</string> diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml index 1e47efa2cc4f..5bfc3dbc900d 100644 --- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Sem serviço."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Alterar o método de entrada"</string> <string name="airplane_mode" msgid="2528005343938497866">"Modo avião"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Insira o PIN para se preparar para a atualização"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Insira o padrão para se preparar para a atualização"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Insira a senha para se preparar para a atualização"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"O padrão é exigido após a reinicialização do dispositivo"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"O PIN é exigido após a reinicialização do dispositivo"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"A senha é exigida após a reinicialização do dispositivo"</string> diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml index 09cfcf1da02f..5af8bc09a05b 100644 --- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Sem serviço."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Alternar o método de introdução"</string> <string name="airplane_mode" msgid="2528005343938497866">"Modo de avião"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"É necessário introduzir o PIN para a preparação para a atualização."</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"É necessário introduzir o padrão para a preparação para a atualização."</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"É necessário introduzir a palavra-passe para a preparação para a atualização."</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"É necessário um padrão após reiniciar o dispositivo"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"É necessário um PIN após reiniciar o dispositivo"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"É necessária uma palavra-passe após reiniciar o dispositivo"</string> diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml index 1e47efa2cc4f..5bfc3dbc900d 100644 --- a/packages/SystemUI/res-keyguard/values-pt/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Sem serviço."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Alterar o método de entrada"</string> <string name="airplane_mode" msgid="2528005343938497866">"Modo avião"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Insira o PIN para se preparar para a atualização"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Insira o padrão para se preparar para a atualização"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Insira a senha para se preparar para a atualização"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"O padrão é exigido após a reinicialização do dispositivo"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"O PIN é exigido após a reinicialização do dispositivo"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"A senha é exigida após a reinicialização do dispositivo"</string> diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml index 7df2db6f03f1..8122241e6613 100644 --- a/packages/SystemUI/res-keyguard/values-ro/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml @@ -104,9 +104,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Fără serviciu."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Comutați metoda de introducere"</string> <string name="airplane_mode" msgid="2528005343938497866">"Mod Avion"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Pentru a vă pregăti pentru actualizare este necesar codul PIN"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Pentru a vă pregăti pentru actualizare este necesar modelul"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Pentru a vă pregăti pentru actualizare este necesară parola"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Modelul este necesar după repornirea dispozitivului"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Codul PIN este necesar după repornirea dispozitivului"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Parola este necesară după repornirea dispozitivului"</string> diff --git a/packages/SystemUI/res-keyguard/values-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml index ccd3c968cd51..b80b479ca29a 100644 --- a/packages/SystemUI/res-keyguard/values-ru/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ru/strings.xml @@ -107,9 +107,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Нет сигнала."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Сменить способ ввода"</string> <string name="airplane_mode" msgid="2528005343938497866">"Режим полета"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Для подготовки к обновлению необходимо ввести PIN-код."</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Для подготовки к обновлению необходимо ввести графический ключ."</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Для подготовки к обновлению необходимо ввести пароль."</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"После перезагрузки устройства необходимо ввести графический ключ"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"После перезагрузки устройства необходимо ввести PIN-код"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"После перезагрузки устройства необходимо ввести пароль"</string> diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml index 3dfc282ccae5..1cd876f15d47 100644 --- a/packages/SystemUI/res-keyguard/values-si/strings.xml +++ b/packages/SystemUI/res-keyguard/values-si/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"සේවාව නැත."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ආදාන ක්රමය මාරු කිරීම"</string> <string name="airplane_mode" msgid="2528005343938497866">"ගුවන් යානා ප්රකාරය"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"යාවත්කාලීනය සඳහා සුදානම් කිරීමට PIN අවශ්යය"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"යාවත්කාලීනය සඳහා සුදානම් කිරීමට රටාව අවශ්යය"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"යාවත්කාලීනය සඳහා සුදානම් කිරීමට මුරපදය අවශ්යය"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"උපාංගය නැවත ආරම්භ වූ පසු රටාව අවශ්යයි"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"උපාංගය නැවත ආරම්භ වූ පසු PIN අංකය අවශ්යයි"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"උපාංගය නැවත ආරම්භ වූ පසු මුරපදය අවශ්යයි"</string> diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml index 8568e14fecc3..801a7dbccf6d 100644 --- a/packages/SystemUI/res-keyguard/values-sk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sk/strings.xml @@ -107,9 +107,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Žiadny signál."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Prepnúť metódu vstupu"</string> <string name="airplane_mode" msgid="2528005343938497866">"Režim v lietadle"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Príprava na aktualizáciu vyžaduje zadanie kódu PIN"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Príprava na aktualizáciu vyžaduje zadanie vzoru"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Príprava na aktualizáciu vyžaduje zadanie hesla"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Po reštartovaní zariadenia musíte zadať bezpečnostný vzor"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Po reštartovaní zariadenia musíte zadať kód PIN"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Po reštartovaní zariadenia musíte zadať heslo"</string> diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml index 168158d9d602..967255cb50e7 100644 --- a/packages/SystemUI/res-keyguard/values-sl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml @@ -107,9 +107,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Ni storitve."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Preklop načina vnosa"</string> <string name="airplane_mode" msgid="2528005343938497866">"Način za letalo"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Za pripravo na posodobitev morate vnesti kodo PIN"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Za pripravo na posodobitev morate vnesti vzorec"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Za pripravo na posodobitev morate vnesti geslo"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Po vnovičnem zagonu naprave je treba vnesti vzorec"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Po vnovičnem zagonu naprave je treba vnesti kodo PIN"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Po vnovičnem zagonu naprave je treba vnesti geslo"</string> diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml index 14973f82dc4d..382a4dcafed7 100644 --- a/packages/SystemUI/res-keyguard/values-sq/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Nuk ka shërbim."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Ndërro metodën e hyrjes"</string> <string name="airplane_mode" msgid="2528005343938497866">"Modaliteti i aeroplanit"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Kërkohet kodi PIN për t\'u përgatitur për përditësimin"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Kërkohet motivi për t\'u përgatitur për përditësimin"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Kërkohet fjalëkalimi për t\'u përgatitur për përditësimin"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Kërkohet motivi pas rinisjes së pajisjes"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Kërkohet kodi PIN pas rinisjes së pajisjes"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Kërkohet fjalëkalimi pas rinisjes së pajisjes"</string> diff --git a/packages/SystemUI/res-keyguard/values-sr/strings.xml b/packages/SystemUI/res-keyguard/values-sr/strings.xml index 24a1125f9a7d..f83df3f8925e 100644 --- a/packages/SystemUI/res-keyguard/values-sr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sr/strings.xml @@ -104,9 +104,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Мрежа није доступна."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Промени метод уноса"</string> <string name="airplane_mode" msgid="2528005343938497866">"Режим рада у авиону"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"PIN је обавезан ради припреме за ажурирање"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Шаблон је обавезан ради припреме за ажурирање"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Лозинка је обавезна ради припреме за ажурирање"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Треба да унесете шаблон када се уређај поново покрене"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Треба да унесете PIN када се уређај поново покрене"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Треба да унесете лозинку када се уређај поново покрене"</string> diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml index a37c4809ccdb..a037bffa4da2 100644 --- a/packages/SystemUI/res-keyguard/values-sv/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Ingen tjänst."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Byt inmatningsmetod"</string> <string name="airplane_mode" msgid="2528005343938497866">"Flygplansläge"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Pinkod krävs för att förbereda för uppdatering"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Grafiskt lösenord krävs för att förbereda för uppdatering"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Lösenord krävs för att förbereda för uppdatering"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Du måste ange grafiskt lösenord när du har startat om enheten"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Du måste ange pinkod när du har startat om enheten"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Du måste ange lösenord när du har startat om enheten"</string> diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml index c4a9a1445ceb..efa5ecfd44fd 100644 --- a/packages/SystemUI/res-keyguard/values-sw/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Hakuna mtandao."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Kubadili mbinu ya kuingiza data"</string> <string name="airplane_mode" msgid="2528005343938497866">"Hali ya ndegeni"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Inahitaji PIN ili kujiandaa kwa ajili ya sasisho"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Inahitaji mchoro ili kujiandaa kwa ajili ya sasisho"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Inahitaji nenosiri ili kujiandaa kwa ajili ya sasisho"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Unafaa kuchora mchoro baada ya kuwasha kifaa upya"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Unafaa kuweka PIN baada ya kuwasha kifaa upya"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Unafaa kuweka nenosiri baada ya kuwasha kifaa upya"</string> diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml index a4dc0be3496f..96dbbb0314d6 100644 --- a/packages/SystemUI/res-keyguard/values-ta/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"சேவை இல்லை."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"உள்ளீட்டு முறையை மாற்றும்"</string> <string name="airplane_mode" msgid="2528005343938497866">"விமானப் பயன்முறை"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"புதுப்பிப்பிற்குத் தயார்செய்ய பின் தேவை"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"புதுப்பிப்பிற்குத் தயார்செய்ய பேட்டர்ன் தேவை"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"புதுப்பிப்பிற்குத் தயார்செய்ய கடவுச்சொல் தேவை"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"சாதனத்தை மீண்டும் தொடங்கியதும், பேட்டர்னை வரைய வேண்டும்"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"சாதனத்தை மீண்டும் தொடங்கியதும், பின்னை உள்ளிட வேண்டும்"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"சாதனத்தை மீண்டும் தொடங்கியதும், கடவுச்சொல்லை உள்ளிட வேண்டும்"</string> diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml index 3e27ce8ba702..74386bc7a487 100644 --- a/packages/SystemUI/res-keyguard/values-te/strings.xml +++ b/packages/SystemUI/res-keyguard/values-te/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"సేవ లేదు."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ఇన్పుట్ పద్ధతిని మార్చు"</string> <string name="airplane_mode" msgid="2528005343938497866">"విమానం మోడ్"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"అప్డేట్కు సిద్ధం చేయడానికి పిన్ అవసరం"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"అప్డేట్కు సిద్ధం చేయడానికి ఆకృతి అవసరం"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"అప్డేట్కు సిద్ధం చేయడానికి పాస్వర్డ్ అవసరం"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"పరికరాన్ని పునఃప్రారంభించిన తర్వాత నమూనాను గీయాలి"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"డివైజ్ను పునఃప్రారంభించిన తర్వాత పిన్ నమోదు చేయాలి"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"పరికరాన్ని పునఃప్రారంభించిన తర్వాత పాస్వర్డ్ను నమోదు చేయాలి"</string> diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml index 48ae2ceb9fbd..e157be4ac18e 100644 --- a/packages/SystemUI/res-keyguard/values-th/strings.xml +++ b/packages/SystemUI/res-keyguard/values-th/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"ไม่มีบริการ"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"สลับวิธีการป้อนข้อมูล"</string> <string name="airplane_mode" msgid="2528005343938497866">"โหมดบนเครื่องบิน"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"ต้องใช้ PIN เพื่อเตรียมรับการอัปเดต"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"ต้องใช้รูปแบบเพื่อเตรียมรับการอัปเดต"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"ต้องใช้รหัสผ่านเพื่อเตรียมรับการอัปเดต"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ต้องวาดรูปแบบหลังจากอุปกรณ์รีสตาร์ท"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ต้องระบุ PIN หลังจากอุปกรณ์รีสตาร์ท"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ต้องป้อนรหัสผ่านหลังจากอุปกรณ์รีสตาร์ท"</string> diff --git a/packages/SystemUI/res-keyguard/values-tl/strings.xml b/packages/SystemUI/res-keyguard/values-tl/strings.xml index bd87b20a2ccb..7b7e17dc8dcb 100644 --- a/packages/SystemUI/res-keyguard/values-tl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-tl/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Walang serbisyo."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Magpalit ng pamamaraan ng pag-input"</string> <string name="airplane_mode" msgid="2528005343938497866">"Airplane mode"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Kinakailangan ang PIN para makapaghanda sa pag-update"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Kinakailangan ang pattern para makapaghanda sa pag-update"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Kinakailangan ang password para makapaghanda sa pag-update"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Kailangan ng pattern pagkatapos mag-restart ng device"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Kailangan ng PIN pagkatapos mag-restart ng device"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Kailangan ng password pagkatapos mag-restart ng device"</string> diff --git a/packages/SystemUI/res-keyguard/values-tr/strings.xml b/packages/SystemUI/res-keyguard/values-tr/strings.xml index cf37451a9ed8..8c0caead0bdb 100644 --- a/packages/SystemUI/res-keyguard/values-tr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-tr/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Hizmet yok."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Giriş yöntemini değiştir"</string> <string name="airplane_mode" msgid="2528005343938497866">"Uçak modu"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Güncellemenin hazırlanması için PIN gerekli"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Güncellemenin hazırlanması için desen gerekli"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Güncellemenin hazırlanması için şifre gerekli"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Cihaz yeniden başladıktan sonra desen gerekir"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Cihaz yeniden başladıktan sonra PIN gerekir"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Cihaz yeniden başladıktan sonra şifre gerekir"</string> diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml index 0ccd012c5221..6e5ce0f142dc 100644 --- a/packages/SystemUI/res-keyguard/values-uk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml @@ -107,9 +107,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Зв’язку немає."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Змінити метод введення"</string> <string name="airplane_mode" msgid="2528005343938497866">"Режим польоту"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Щоб підготуватися до оновлення, введіть PIN-код"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Щоб підготуватися до оновлення, введіть ключ"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Щоб підготуватися до оновлення, введіть пароль"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Після перезавантаження пристрою потрібно ввести ключ"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Після перезавантаження пристрою потрібно ввести PIN-код"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Після перезавантаження пристрою потрібно ввести пароль"</string> diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml index 22a477e3d63f..0fd5e17c953e 100644 --- a/packages/SystemUI/res-keyguard/values-ur/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"کوئی سروس نہیں ہے۔"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"اندراج کا طریقہ سوئچ کریں"</string> <string name="airplane_mode" msgid="2528005343938497866">"ہوائی جہاز وضع"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"اپ ڈیٹ تیار کرنے کے لیے PIN درکار ہے"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"اپ ڈیٹ تیار کرنے کے لیے پیٹرن درکار ہے"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"اپ ڈیٹ تیار کرنے کے لیے پاس ورڈ درکار ہے"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"آلہ دوبارہ چالو ہونے کے بعد پیٹرن درکار ہوتا ہے"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"آلہ دوبارہ چالو ہونے کے بعد PIN درکار ہوتا ہے"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"آلہ دوبارہ چالو ہونے کے بعد پاسورڈ درکار ہوتا ہے"</string> diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml index 72d4fae575b8..323fea5a608e 100644 --- a/packages/SystemUI/res-keyguard/values-uz/strings.xml +++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Aloqa yo‘q."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Matn kiritish usulini almashtirish"</string> <string name="airplane_mode" msgid="2528005343938497866">"Parvoz rejimi"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Yangilashga tayyorlash uchun PIN kod talab etiladi"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Yangilashga tayyorlash uchun grafik kalit talab etiladi"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Yangilashga tayyorlash uchun parol talab etiladi"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Qurilma o‘chirib yoqilgandan keyin grafik kalit talab qilinadi"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Qurilma o‘chirib yoqilgandan keyin PIN kod talab qilinadi"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Qurilma o‘chirib yoqilgandan keyin parol talab qilinadi"</string> diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml index de642f3cc27c..2ba5089c7ed9 100644 --- a/packages/SystemUI/res-keyguard/values-vi/strings.xml +++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Không có dịch vụ."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Chuyển phương thức nhập"</string> <string name="airplane_mode" msgid="2528005343938497866">"Chế độ trên máy bay"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Cần nhập mã PIN để chuẩn bị cập nhật"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Cần nhập hình mở khóa để chuẩn bị cập nhật"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Cần nhập mật khẩu để chuẩn bị cập nhật"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Yêu cầu hình mở khóa sau khi thiết bị khởi động lại"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Yêu cầu mã PIN sau khi thiết bị khởi động lại"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Yêu cầu mật khẩu sau khi thiết bị khởi động lại"</string> diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml index be162b0b5790..b4bff5fab6d6 100644 --- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"无服务。"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"切换输入法"</string> <string name="airplane_mode" msgid="2528005343938497866">"飞行模式"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"需要输入 PIN 码才能让设备做好更新准备"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"需要绘制解锁图案才能让设备做好更新准备"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"需要输入密码才能让设备做好更新准备"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"重启设备后需要绘制解锁图案"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"重启设备后需要输入 PIN 码"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"重启设备后需要输入密码"</string> diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml index 33e5b44ac31e..b3d387706fa5 100644 --- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"沒有服務。"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"轉換輸入方法"</string> <string name="airplane_mode" msgid="2528005343938497866">"飛行模式"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"必須提供 PIN 碼,才能準備進行更新"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"必須畫出上鎖圖案,才能準備進行更新"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"必須輸入密碼,才能準備進行更新"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"裝置重新啟動後,必須畫出上鎖圖案才能使用"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"裝置重新啟動後,必須輸入 PIN 碼才能使用"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"裝置重新啟動後,必須輸入密碼才能使用"</string> diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml index 763233cc2e15..03dec4852771 100644 --- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"沒有服務。"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"切換輸入法"</string> <string name="airplane_mode" msgid="2528005343938497866">"飛航模式"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"請輸入 PIN 碼,以便為更新作業進行準備"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"請畫出解鎖圖案,以便為更新作業進行準備"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"請輸入密碼,以便為更新作業進行準備"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"裝置重新啟動後需要畫出解鎖圖案"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"裝置重新啟動後需要輸入 PIN 碼"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"裝置重新啟動後需要輸入密碼"</string> diff --git a/packages/SystemUI/res-keyguard/values-zu/strings.xml b/packages/SystemUI/res-keyguard/values-zu/strings.xml index 397c868e6547..5ab567f706c3 100644 --- a/packages/SystemUI/res-keyguard/values-zu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zu/strings.xml @@ -101,9 +101,6 @@ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Ayikho isevisi"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Shintsha indlela yokufaka"</string> <string name="airplane_mode" msgid="2528005343938497866">"Imodi yendiza"</string> - <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Iphinikhodi iyadingeka ukuze kulungiselelwe isibuyekezo"</string> - <string name="kg_prompt_reason_prepare_for_update_pattern" msgid="4873394344883271519">"Iphethini iyadingeka ukuze kulungiselelwe isibuyekezo"</string> - <string name="kg_prompt_reason_prepare_for_update_password" msgid="5625446803865598337">"Iphasiwedi iyadingeka ukuze kulungiselelwe isibuyekezo"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Iphethini iyadingeka ngemuva kokuqala kabusha kwedivayisi"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Iphinikhodi iyadingeka ngemuva kokuqala kabusha kwedivayisi"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Iphasiwedi iyadingeka ngemuva kokuqala kabusha kwedivayisi"</string> diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml index 4d184d5758d3..f7e9fedd5f66 100644 --- a/packages/SystemUI/res-keyguard/values/strings.xml +++ b/packages/SystemUI/res-keyguard/values/strings.xml @@ -240,15 +240,6 @@ <!-- Description of airplane mode --> <string name="airplane_mode">Airplane mode</string> - <!-- An explanation text that the PIN needs to be entered to prepare for an operating system update. [CHAR LIMIT=80] --> - <string name="kg_prompt_reason_prepare_for_update_pin">PIN required to prepare for update</string> - - <!-- An explanation text that the pattern needs to be entered to prepare for an operating system update. [CHAR LIMIT=80] --> - <string name="kg_prompt_reason_prepare_for_update_pattern">Pattern required to prepare for update</string> - - <!-- An explanation text that the password needs to be entered to prepare for an operating system update. [CHAR LIMIT=80] --> - <string name="kg_prompt_reason_prepare_for_update_password">Password required to prepare for update</string> - <!-- An explanation text that the pattern needs to be solved since the device has just been restarted. [CHAR LIMIT=80] --> <string name="kg_prompt_reason_restart_pattern">Pattern required after device restarts</string> diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml index 5f2a946a1b6d..53eb2343d26a 100644 --- a/packages/SystemUI/res-keyguard/values/styles.xml +++ b/packages/SystemUI/res-keyguard/values/styles.xml @@ -23,10 +23,12 @@ <item name="android:textColor">?attr/wallpaperTextColorSecondary</item> <item name="android:textSize">@dimen/kg_status_line_font_size</item> </style> - <style name="Keyguard.TextView.EmergencyButton" parent="@android:style/DeviceDefault.ButtonBar"> + <style name="Keyguard.TextView.EmergencyButton" parent="Theme.SystemUI"> <item name="android:textColor">?attr/wallpaperTextColorSecondary</item> - <item name="android:textSize">@dimen/kg_status_line_font_size</item> - <item name="android:background">@null</item> + <item name="android:textSize">14dp</item> + <item name="android:background">@drawable/kg_emergency_button_background</item> + <item name="android:paddingLeft">12dp</item> + <item name="android:paddingRight">12dp</item> </style> <style name="Widget.TextView.NumPadKey" parent="@android:style/Widget.TextView"> <item name="android:singleLine">true</item> diff --git a/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml b/packages/SystemUI/res/drawable/ic_sysbar_rotate_button_ccw_start_0.xml index 3304c19b1ed8..ff5cb9ef6b67 100644 --- a/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml +++ b/packages/SystemUI/res/drawable/ic_sysbar_rotate_button_ccw_start_0.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - Copyright (C) 2017 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. @@ -23,7 +23,7 @@ android:viewportHeight="28.0"> <!-- Use scaleX to flip icon so arrows always point in the direction of motion --> <group android:name="icon" android:pivotX="14" android:pivotY="14" - android:scaleX="?attr/rotateButtonScaleX"> + android:scaleX="1"> <!-- Tint color to be set directly --> <path android:fillColor="#FFFFFFFF" android:pathData="M12.02,10.83L9.25,8.06l2.77,-2.77l1.12,1.12l-0.85,0.86h5.16c0.72,0 1.31,0.56 1.31,1.26v9.16l-1.58,-1.58V8.85h-4.89l0.86,0.86L12.02,10.83zM15.98,17.17l-1.12,1.12l0.85,0.86h-4.88v-7.26L9.25,10.3v9.17c0,0.7 0.59,1.26 1.31,1.26h5.16v0.01l-0.85,0.85l1.12,1.12l2.77,-2.77L15.98,17.17z"/> @@ -107,8 +107,8 @@ <objectAnimator android:propertyName="rotation" android:startOffset="100" android:duration="600" - android:valueFrom="?attr/rotateButtonStartAngle" - android:valueTo="?attr/rotateButtonEndAngle"> + android:valueFrom="0" + android:valueTo="-90"> <aapt:attr name="android:interpolator"> <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> </aapt:attr> @@ -118,14 +118,14 @@ <objectAnimator android:propertyName="rotation" android:startOffset="1300" android:duration="100" - android:valueFrom="?attr/rotateButtonStartAngle" - android:valueTo="?attr/rotateButtonStartAngle"/> + android:valueFrom="0" + android:valueTo="0"/> <!-- Icon rotation with start timing offset after fade in --> <objectAnimator android:propertyName="rotation" android:duration="600" - android:valueFrom="?attr/rotateButtonStartAngle" - android:valueTo="?attr/rotateButtonEndAngle"> + android:valueFrom="0" + android:valueTo="-90"> <aapt:attr name="android:interpolator"> <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> </aapt:attr> @@ -135,14 +135,14 @@ <objectAnimator android:propertyName="rotation" android:startOffset="1300" android:duration="100" - android:valueFrom="?attr/rotateButtonStartAngle" - android:valueTo="?attr/rotateButtonStartAngle"/> + android:valueFrom="0" + android:valueTo="0"/> <!-- Icon rotation with start timing offset after fade in --> <objectAnimator android:propertyName="rotation" android:duration="600" - android:valueFrom="?attr/rotateButtonStartAngle" - android:valueTo="?attr/rotateButtonEndAngle"> + android:valueFrom="0" + android:valueTo="-90"> <aapt:attr name="android:interpolator"> <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> </aapt:attr> @@ -152,14 +152,14 @@ <objectAnimator android:propertyName="rotation" android:startOffset="1300" android:duration="100" - android:valueFrom="?attr/rotateButtonStartAngle" - android:valueTo="?attr/rotateButtonStartAngle"/> + android:valueFrom="0" + android:valueTo="0"/> <!-- Icon rotation with start timing offset after fade in --> <objectAnimator android:propertyName="rotation" android:duration="600" - android:valueFrom="?attr/rotateButtonStartAngle" - android:valueTo="?attr/rotateButtonEndAngle"> + android:valueFrom="0" + android:valueTo="-90"> <aapt:attr name="android:interpolator"> <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> </aapt:attr> @@ -169,14 +169,14 @@ <objectAnimator android:propertyName="rotation" android:startOffset="1300" android:duration="100" - android:valueFrom="?attr/rotateButtonStartAngle" - android:valueTo="?attr/rotateButtonStartAngle"/> + android:valueFrom="0" + android:valueTo="0"/> <!-- Icon rotation with start timing offset after fade in --> <objectAnimator android:propertyName="rotation" android:duration="600" - android:valueFrom="?attr/rotateButtonStartAngle" - android:valueTo="?attr/rotateButtonEndAngle"> + android:valueFrom="0" + android:valueTo="-90"> <aapt:attr name="android:interpolator"> <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> </aapt:attr> diff --git a/packages/SystemUI/res/drawable/ic_sysbar_rotate_button_ccw_start_90.xml b/packages/SystemUI/res/drawable/ic_sysbar_rotate_button_ccw_start_90.xml new file mode 100644 index 000000000000..90fedb17ecf1 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_sysbar_rotate_button_ccw_start_90.xml @@ -0,0 +1,187 @@ +<?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. +--> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"> + <aapt:attr name="android:drawable"> + <vector android:name="root" + android:width="28dp" + android:height="28dp" + android:viewportWidth="28.0" + android:viewportHeight="28.0"> + <!-- Use scaleX to flip icon so arrows always point in the direction of motion --> + <group android:name="icon" android:pivotX="14" android:pivotY="14" + android:scaleX="1"> + <!-- Tint color to be set directly --> + <path android:fillColor="#FFFFFFFF" + android:pathData="M12.02,10.83L9.25,8.06l2.77,-2.77l1.12,1.12l-0.85,0.86h5.16c0.72,0 1.31,0.56 1.31,1.26v9.16l-1.58,-1.58V8.85h-4.89l0.86,0.86L12.02,10.83zM15.98,17.17l-1.12,1.12l0.85,0.86h-4.88v-7.26L9.25,10.3v9.17c0,0.7 0.59,1.26 1.31,1.26h5.16v0.01l-0.85,0.85l1.12,1.12l2.77,-2.77L15.98,17.17z"/> + </group> + </vector> + </aapt:attr> + + <!-- Repeat all animations 5 times but don't fade out at the end --> + <target android:name="root"> + <aapt:attr name="android:animation"> + <set android:ordering="sequentially"> + <!-- Linear fade in--> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:valueFrom="0" + android:valueTo="1" + android:interpolator="@android:anim/linear_interpolator" /> + <!-- Linear fade out --> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="1700" + android:valueFrom="1" + android:valueTo="0" + android:interpolator="@android:anim/linear_interpolator"/> + <!-- Linear fade in--> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="100" + android:valueFrom="0" + android:valueTo="1" + android:interpolator="@android:anim/linear_interpolator" /> + <!-- Linear fade out --> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="1700" + android:valueFrom="1" + android:valueTo="0" + android:interpolator="@android:anim/linear_interpolator"/> + <!-- Linear fade in--> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="100" + android:valueFrom="0" + android:valueTo="1" + android:interpolator="@android:anim/linear_interpolator" /> + <!-- Linear fade out --> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="1700" + android:valueFrom="1" + android:valueTo="0" + android:interpolator="@android:anim/linear_interpolator"/> + <!-- Linear fade in--> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="100" + android:valueFrom="0" + android:valueTo="1" + android:interpolator="@android:anim/linear_interpolator" /> + <!-- Linear fade out --> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="1700" + android:valueFrom="1" + android:valueTo="0" + android:interpolator="@android:anim/linear_interpolator"/> + <!-- Linear fade in--> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="100" + android:valueFrom="0" + android:valueTo="1" + android:interpolator="@android:anim/linear_interpolator" /> + </set> + </aapt:attr> + </target> + <target android:name="icon"> + <aapt:attr name="android:animation"> + <set android:ordering="sequentially"> + <!-- Icon rotation with start timing offset after fade in --> + <objectAnimator android:propertyName="rotation" + android:startOffset="100" + android:duration="600" + android:valueFrom="90" + android:valueTo="0"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + + <!-- Reset rotation position for fade in --> + <objectAnimator android:propertyName="rotation" + android:startOffset="1300" + android:duration="100" + android:valueFrom="90" + android:valueTo="90"/> + + <!-- Icon rotation with start timing offset after fade in --> + <objectAnimator android:propertyName="rotation" + android:duration="600" + android:valueFrom="90" + android:valueTo="0"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + + <!-- Reset rotation position for fade in --> + <objectAnimator android:propertyName="rotation" + android:startOffset="1300" + android:duration="100" + android:valueFrom="90" + android:valueTo="90"/> + + <!-- Icon rotation with start timing offset after fade in --> + <objectAnimator android:propertyName="rotation" + android:duration="600" + android:valueFrom="90" + android:valueTo="0"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + + <!-- Reset rotation position for fade in --> + <objectAnimator android:propertyName="rotation" + android:startOffset="1300" + android:duration="100" + android:valueFrom="90" + android:valueTo="90"/> + + <!-- Icon rotation with start timing offset after fade in --> + <objectAnimator android:propertyName="rotation" + android:duration="600" + android:valueFrom="90" + android:valueTo="0"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + + <!-- Reset rotation position for fade in --> + <objectAnimator android:propertyName="rotation" + android:startOffset="1300" + android:duration="100" + android:valueFrom="90" + android:valueTo="90"/> + + <!-- Icon rotation with start timing offset after fade in --> + <objectAnimator android:propertyName="rotation" + android:duration="600" + android:valueFrom="90" + android:valueTo="0"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> +</animated-vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_sysbar_rotate_button_cw_start_0.xml b/packages/SystemUI/res/drawable/ic_sysbar_rotate_button_cw_start_0.xml new file mode 100644 index 000000000000..a89e7a34ad26 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_sysbar_rotate_button_cw_start_0.xml @@ -0,0 +1,187 @@ +<?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. +--> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"> + <aapt:attr name="android:drawable"> + <vector android:name="root" + android:width="28dp" + android:height="28dp" + android:viewportWidth="28.0" + android:viewportHeight="28.0"> + <!-- Use scaleX to flip icon so arrows always point in the direction of motion --> + <group android:name="icon" android:pivotX="14" android:pivotY="14" + android:scaleX="-1"> + <!-- Tint color to be set directly --> + <path android:fillColor="#FFFFFFFF" + android:pathData="M12.02,10.83L9.25,8.06l2.77,-2.77l1.12,1.12l-0.85,0.86h5.16c0.72,0 1.31,0.56 1.31,1.26v9.16l-1.58,-1.58V8.85h-4.89l0.86,0.86L12.02,10.83zM15.98,17.17l-1.12,1.12l0.85,0.86h-4.88v-7.26L9.25,10.3v9.17c0,0.7 0.59,1.26 1.31,1.26h5.16v0.01l-0.85,0.85l1.12,1.12l2.77,-2.77L15.98,17.17z"/> + </group> + </vector> + </aapt:attr> + + <!-- Repeat all animations 5 times but don't fade out at the end --> + <target android:name="root"> + <aapt:attr name="android:animation"> + <set android:ordering="sequentially"> + <!-- Linear fade in--> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:valueFrom="0" + android:valueTo="1" + android:interpolator="@android:anim/linear_interpolator" /> + <!-- Linear fade out --> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="1700" + android:valueFrom="1" + android:valueTo="0" + android:interpolator="@android:anim/linear_interpolator"/> + <!-- Linear fade in--> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="100" + android:valueFrom="0" + android:valueTo="1" + android:interpolator="@android:anim/linear_interpolator" /> + <!-- Linear fade out --> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="1700" + android:valueFrom="1" + android:valueTo="0" + android:interpolator="@android:anim/linear_interpolator"/> + <!-- Linear fade in--> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="100" + android:valueFrom="0" + android:valueTo="1" + android:interpolator="@android:anim/linear_interpolator" /> + <!-- Linear fade out --> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="1700" + android:valueFrom="1" + android:valueTo="0" + android:interpolator="@android:anim/linear_interpolator"/> + <!-- Linear fade in--> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="100" + android:valueFrom="0" + android:valueTo="1" + android:interpolator="@android:anim/linear_interpolator" /> + <!-- Linear fade out --> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="1700" + android:valueFrom="1" + android:valueTo="0" + android:interpolator="@android:anim/linear_interpolator"/> + <!-- Linear fade in--> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="100" + android:valueFrom="0" + android:valueTo="1" + android:interpolator="@android:anim/linear_interpolator" /> + </set> + </aapt:attr> + </target> + <target android:name="icon"> + <aapt:attr name="android:animation"> + <set android:ordering="sequentially"> + <!-- Icon rotation with start timing offset after fade in --> + <objectAnimator android:propertyName="rotation" + android:startOffset="100" + android:duration="600" + android:valueFrom="0" + android:valueTo="90"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + + <!-- Reset rotation position for fade in --> + <objectAnimator android:propertyName="rotation" + android:startOffset="1300" + android:duration="100" + android:valueFrom="0" + android:valueTo="0"/> + + <!-- Icon rotation with start timing offset after fade in --> + <objectAnimator android:propertyName="rotation" + android:duration="600" + android:valueFrom="0" + android:valueTo="90"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + + <!-- Reset rotation position for fade in --> + <objectAnimator android:propertyName="rotation" + android:startOffset="1300" + android:duration="100" + android:valueFrom="0" + android:valueTo="0"/> + + <!-- Icon rotation with start timing offset after fade in --> + <objectAnimator android:propertyName="rotation" + android:duration="600" + android:valueFrom="0" + android:valueTo="90"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + + <!-- Reset rotation position for fade in --> + <objectAnimator android:propertyName="rotation" + android:startOffset="1300" + android:duration="100" + android:valueFrom="0" + android:valueTo="0"/> + + <!-- Icon rotation with start timing offset after fade in --> + <objectAnimator android:propertyName="rotation" + android:duration="600" + android:valueFrom="0" + android:valueTo="90"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + + <!-- Reset rotation position for fade in --> + <objectAnimator android:propertyName="rotation" + android:startOffset="1300" + android:duration="100" + android:valueFrom="0" + android:valueTo="0"/> + + <!-- Icon rotation with start timing offset after fade in --> + <objectAnimator android:propertyName="rotation" + android:duration="600" + android:valueFrom="0" + android:valueTo="90"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> +</animated-vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_sysbar_rotate_button_cw_start_90.xml b/packages/SystemUI/res/drawable/ic_sysbar_rotate_button_cw_start_90.xml new file mode 100644 index 000000000000..0dc67b0d22af --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_sysbar_rotate_button_cw_start_90.xml @@ -0,0 +1,187 @@ +<?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. +--> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"> + <aapt:attr name="android:drawable"> + <vector android:name="root" + android:width="28dp" + android:height="28dp" + android:viewportWidth="28.0" + android:viewportHeight="28.0"> + <!-- Use scaleX to flip icon so arrows always point in the direction of motion --> + <group android:name="icon" android:pivotX="14" android:pivotY="14" + android:scaleX="-1"> + <!-- Tint color to be set directly --> + <path android:fillColor="#FFFFFFFF" + android:pathData="M12.02,10.83L9.25,8.06l2.77,-2.77l1.12,1.12l-0.85,0.86h5.16c0.72,0 1.31,0.56 1.31,1.26v9.16l-1.58,-1.58V8.85h-4.89l0.86,0.86L12.02,10.83zM15.98,17.17l-1.12,1.12l0.85,0.86h-4.88v-7.26L9.25,10.3v9.17c0,0.7 0.59,1.26 1.31,1.26h5.16v0.01l-0.85,0.85l1.12,1.12l2.77,-2.77L15.98,17.17z"/> + </group> + </vector> + </aapt:attr> + + <!-- Repeat all animations 5 times but don't fade out at the end --> + <target android:name="root"> + <aapt:attr name="android:animation"> + <set android:ordering="sequentially"> + <!-- Linear fade in--> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:valueFrom="0" + android:valueTo="1" + android:interpolator="@android:anim/linear_interpolator" /> + <!-- Linear fade out --> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="1700" + android:valueFrom="1" + android:valueTo="0" + android:interpolator="@android:anim/linear_interpolator"/> + <!-- Linear fade in--> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="100" + android:valueFrom="0" + android:valueTo="1" + android:interpolator="@android:anim/linear_interpolator" /> + <!-- Linear fade out --> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="1700" + android:valueFrom="1" + android:valueTo="0" + android:interpolator="@android:anim/linear_interpolator"/> + <!-- Linear fade in--> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="100" + android:valueFrom="0" + android:valueTo="1" + android:interpolator="@android:anim/linear_interpolator" /> + <!-- Linear fade out --> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="1700" + android:valueFrom="1" + android:valueTo="0" + android:interpolator="@android:anim/linear_interpolator"/> + <!-- Linear fade in--> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="100" + android:valueFrom="0" + android:valueTo="1" + android:interpolator="@android:anim/linear_interpolator" /> + <!-- Linear fade out --> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="1700" + android:valueFrom="1" + android:valueTo="0" + android:interpolator="@android:anim/linear_interpolator"/> + <!-- Linear fade in--> + <objectAnimator android:propertyName="alpha" + android:duration="100" + android:startOffset="100" + android:valueFrom="0" + android:valueTo="1" + android:interpolator="@android:anim/linear_interpolator" /> + </set> + </aapt:attr> + </target> + <target android:name="icon"> + <aapt:attr name="android:animation"> + <set android:ordering="sequentially"> + <!-- Icon rotation with start timing offset after fade in --> + <objectAnimator android:propertyName="rotation" + android:startOffset="100" + android:duration="600" + android:valueFrom="90" + android:valueTo="180"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + + <!-- Reset rotation position for fade in --> + <objectAnimator android:propertyName="rotation" + android:startOffset="1300" + android:duration="100" + android:valueFrom="90" + android:valueTo="90"/> + + <!-- Icon rotation with start timing offset after fade in --> + <objectAnimator android:propertyName="rotation" + android:duration="600" + android:valueFrom="90" + android:valueTo="180"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + + <!-- Reset rotation position for fade in --> + <objectAnimator android:propertyName="rotation" + android:startOffset="1300" + android:duration="100" + android:valueFrom="90" + android:valueTo="90"/> + + <!-- Icon rotation with start timing offset after fade in --> + <objectAnimator android:propertyName="rotation" + android:duration="600" + android:valueFrom="90" + android:valueTo="180"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + + <!-- Reset rotation position for fade in --> + <objectAnimator android:propertyName="rotation" + android:startOffset="1300" + android:duration="100" + android:valueFrom="90" + android:valueTo="90"/> + + <!-- Icon rotation with start timing offset after fade in --> + <objectAnimator android:propertyName="rotation" + android:duration="600" + android:valueFrom="90" + android:valueTo="180"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + + <!-- Reset rotation position for fade in --> + <objectAnimator android:propertyName="rotation" + android:startOffset="1300" + android:duration="100" + android:valueFrom="90" + android:valueTo="90"/> + + <!-- Icon rotation with start timing offset after fade in --> + <objectAnimator android:propertyName="rotation" + android:duration="600" + android:valueFrom="90" + android:valueTo="180"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> +</animated-vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/privacy_chip_bg.xml b/packages/SystemUI/res/drawable/privacy_chip_bg.xml new file mode 100644 index 000000000000..827cf4a9d3b6 --- /dev/null +++ b/packages/SystemUI/res/drawable/privacy_chip_bg.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="#242424" /> <!-- 14% of white --> + <padding android:paddingTop="@dimen/ongoing_appops_chip_bg_padding" + android:paddingBottom="@dimen/ongoing_appops_chip_bg_padding" /> + <corners android:radius="@dimen/ongoing_appops_chip_bg_corner_radius" /> +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml new file mode 100644 index 000000000000..3c306322d21f --- /dev/null +++ b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml @@ -0,0 +1,40 @@ +<?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. +--> + + +<com.android.systemui.privacy.OngoingPrivacyChip + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/privacy_chip" + android:layout_height="match_parent" + android:layout_width="wrap_content" + android:layout_gravity="center_vertical|end" + android:focusable="true" > + + <FrameLayout + android:id="@+id/background" + android:layout_height="@dimen/ongoing_appops_chip_height" + android:layout_width="wrap_content" + android:minWidth="48dp" + android:layout_gravity="center_vertical"> + <LinearLayout + android:id="@+id/icons_container" + android:layout_height="match_parent" + android:layout_width="wrap_content" + android:gravity="center_vertical" + /> + </FrameLayout> +</com.android.systemui.privacy.OngoingPrivacyChip>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml index be86e5f5abc5..3c7480181877 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml @@ -14,7 +14,7 @@ ** See the License for the specific language governing permissions and ** limitations under the License. --> -<FrameLayout +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res-auto" android:id="@+id/quick_status_bar_system_icons" @@ -27,6 +27,13 @@ android:clickable="true" android:paddingTop="@dimen/status_bar_padding_top" > + <LinearLayout + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:orientation="horizontal" + android:gravity="center_vertical|start" > + <com.android.systemui.statusbar.policy.Clock android:id="@+id/clock" android:layout_width="wrap_content" @@ -38,5 +45,23 @@ android:singleLine="true" android:textAppearance="@style/TextAppearance.StatusBar.Clock" systemui:showDark="false" /> + </LinearLayout> + + <android.widget.Space + android:id="@+id/space" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_gravity="center_vertical|center_horizontal" + android:visibility="gone" /> + + <LinearLayout + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:orientation="horizontal" + android:gravity="center_vertical|end" > + + <include layout="@layout/ongoing_privacy_chip" /> -</FrameLayout> + </LinearLayout> +</LinearLayout> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 8e10230f2212..27bc3ab4aab0 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -1021,9 +1021,9 @@ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Параметрлер"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Ұлғайту терезесі"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Ұлғайту терезесінің басқару элементтері"</string> - <string name="quick_controls_title" msgid="6839108006171302273">"Құрылғы басқару виджеттері"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Құрылғыны басқару элементтері"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Жалғанған құрылғылар үшін басқару виджеттерін қосу"</string> - <string name="quick_controls_setup_title" msgid="8901436655997849822">"Құрылғы басқару виджеттерін реттеу"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Құрылғыны басқару элементтерін реттеу"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Басқару элементтерін шығару үшін қуат түймесін басып тұрыңыз."</string> <string name="controls_providers_title" msgid="6879775889857085056">"Басқару элементтері енгізілетін қолданбаны таңдаңыз"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1046,7 +1046,7 @@ <string name="controls_favorite_load_error" msgid="5126216176144877419">"Басқару элементтері жүктелмеді. Қолданба параметрлерінің өзгермегенін тексеру үшін <xliff:g id="APP">%s</xliff:g> қолданбасын қараңыз."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Үйлесімді басқару элементтері қолжетімді емес."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Басқа"</string> - <string name="controls_dialog_title" msgid="2343565267424406202">"Құрылғы басқару виджеттеріне қосу"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Құрылғы басқару элементтеріне қосу"</string> <string name="controls_dialog_ok" msgid="2770230012857881822">"Енгізу"</string> <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ұсынған"</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Басқару элементтері жаңартылды"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 6b8b674ea412..341efff0e4cd 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -811,7 +811,7 @@ <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Notificações"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Atalhos de teclado"</string> <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Alterar esquema de teclado"</string> - <string name="keyboard_shortcut_group_applications" msgid="7386239431100651266">"Aplicações"</string> + <string name="keyboard_shortcut_group_applications" msgid="7386239431100651266">"Apps"</string> <string name="keyboard_shortcut_group_applications_assist" msgid="771606231466098742">"Assistência"</string> <string name="keyboard_shortcut_group_applications_browser" msgid="2776211137869809251">"Navegador"</string> <string name="keyboard_shortcut_group_applications_contacts" msgid="2807268086386201060">"Contactos"</string> @@ -965,7 +965,7 @@ <string name="qs_dnd_until" msgid="7844269319043747955">"Até à(s) <xliff:g id="ID_1">%s</xliff:g>"</string> <string name="qs_dnd_keep" msgid="3829697305432866434">"Manter"</string> <string name="qs_dnd_replace" msgid="7712119051407052689">"Substituir"</string> - <string name="running_foreground_services_title" msgid="5137313173431186685">"Aplicações em execução em segundo plano"</string> + <string name="running_foreground_services_title" msgid="5137313173431186685">"Apps em execução em segundo plano"</string> <string name="running_foreground_services_msg" msgid="3009459259222695385">"Toque para obter detalhes acerca da utilização da bateria e dos dados"</string> <string name="mobile_data_disable_title" msgid="5366476131671617790">"Pretende desativar os dados móveis?"</string> <string name="mobile_data_disable_message" msgid="8604966027899770415">"Não terá acesso a dados ou à Internet através do operador <xliff:g id="CARRIER">%s</xliff:g>. A Internet estará disponível apenas por Wi-Fi."</string> diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml index 10c72102bba3..84dbd60b799d 100644 --- a/packages/SystemUI/res/values/attrs.xml +++ b/packages/SystemUI/res/values/attrs.xml @@ -133,11 +133,6 @@ <attr name="buttonStrokeWidth" format="dimension" /> </declare-styleable> - <!-- Used to style rotate suggestion button AVD animations --> - <attr name="rotateButtonStartAngle" format="float" /> - <attr name="rotateButtonEndAngle" format="float" /> - <attr name="rotateButtonScaleX" format="float" /> - <!-- Used to style charging animation AVD animation --> <attr name="chargingAnimColor" format="color" /> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 27db8cb5fb46..f407a8dcc57f 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -499,6 +499,8 @@ <item>com.android.systemui</item> </string-array> + <integer name="ongoing_appops_dialog_max_apps">5</integer> + <!-- Launcher package name for overlaying icons. --> <string name="launcher_overlayable_package" translatable="false">com.android.launcher3</string> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index ea855eb722b9..122fcb21a9f4 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1137,6 +1137,23 @@ <!-- How much into a DisplayCutout's bounds we can go, on each side --> <dimen name="display_cutout_margin_consumption">0px</dimen> + + <!-- Height of the Ongoing App Ops chip --> + <dimen name="ongoing_appops_chip_height">32dp</dimen> + <!-- Padding between background of Ongoing App Ops chip and content --> + <dimen name="ongoing_appops_chip_bg_padding">8dp</dimen> + <!-- Side padding between background of Ongoing App Ops chip and content --> + <dimen name="ongoing_appops_chip_side_padding">8dp</dimen> + <!-- Margin between icons of Ongoing App Ops chip when QQS--> + <dimen name="ongoing_appops_chip_icon_margin_collapsed">0dp</dimen> + <!-- Margin between icons of Ongoing App Ops chip when QS--> + <dimen name="ongoing_appops_chip_icon_margin_expanded">2dp</dimen> + <!-- Icon size of Ongoing App Ops chip --> + <dimen name="ongoing_appops_chip_icon_size">@dimen/status_bar_icon_drawing_size</dimen> + <!-- Radius of Ongoing App Ops chip corners --> + <dimen name="ongoing_appops_chip_bg_corner_radius">16dp</dimen> + + <!-- How much each bubble is elevated. --> <dimen name="bubble_elevation">1dp</dimen> <!-- How much the bubble flyout text container is elevated. --> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index d97aea7dab59..8b6543ac73bd 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2596,6 +2596,27 @@ app for debugging. Will not be seen by users. [CHAR LIMIT=20] --> <string name="heap_dump_tile_name">Dump SysUI Heap</string> + <!-- Content description for ongoing privacy chip. Use with a single app [CHAR LIMIT=NONE]--> + <string name="ongoing_privacy_chip_content_single_app"><xliff:g id="app" example="Example App">%1$s</xliff:g> is using your <xliff:g id="types_list" example="camera, location">%2$s</xliff:g>.</string> + + <!-- Content description for ongoing privacy chip. Use with multiple apps [CHAR LIMIT=NONE]--> + <string name="ongoing_privacy_chip_content_multiple_apps">Applications are using your <xliff:g id="types_list" example="camera, location">%s</xliff:g>.</string> + + <!-- Separator for types. Include spaces before and after if needed [CHAR LIMIT=10] --> + <string name="ongoing_privacy_dialog_separator">,\u0020</string> + + <!-- Separator for types, before last type. Include spaces before and after if needed [CHAR LIMIT=10] --> + <string name="ongoing_privacy_dialog_last_separator">\u0020and\u0020</string> + + <!-- Text for camera app op [CHAR LIMIT=20]--> + <string name="privacy_type_camera">camera</string> + + <!-- Text for location app op [CHAR LIMIT=20]--> + <string name="privacy_type_location">location</string> + + <!-- Text for microphone app op [CHAR LIMIT=20]--> + <string name="privacy_type_microphone">microphone</string> + <!-- Text for the quick setting tile for sensor privacy [CHAR LIMIT=30] --> <string name="sensor_privacy_mode">Sensors off</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 68c2a38f53c3..9e5b94ee855c 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -604,31 +604,6 @@ <item name="android:colorBackground">?android:attr/colorSecondary</item> </style> - <!-- Used to style rotate suggestion button AVD animations --> - <style name="RotateButtonCCWStart0"> - <item name="rotateButtonStartAngle">0</item> - <item name="rotateButtonEndAngle">-90</item> - <item name="rotateButtonScaleX">1</item> - </style> - - <style name="RotateButtonCCWStart90"> - <item name="rotateButtonStartAngle">90</item> - <item name="rotateButtonEndAngle">0</item> - <item name="rotateButtonScaleX">1</item> - </style> - - <style name="RotateButtonCWStart0"> - <item name="rotateButtonStartAngle">0</item> - <item name="rotateButtonEndAngle">90</item> - <item name="rotateButtonScaleX">-1</item> - </style> - - <style name="RotateButtonCWStart90"> - <item name="rotateButtonStartAngle">90</item> - <item name="rotateButtonEndAngle">180</item> - <item name="rotateButtonScaleX">-1</item> - </style> - <style name="MediaPlayer.Button" parent="@android:style/Widget.Material.Button.Borderless.Small"> <item name="android:background">@drawable/qs_media_light_source</item> <item name="android:tint">@android:color/white</item> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java index 65bf7e6e5025..97317cf5580f 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java @@ -138,7 +138,7 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView case PROMPT_REASON_USER_REQUEST: return R.string.kg_prompt_reason_user_request; case PROMPT_REASON_PREPARE_FOR_UPDATE: - return R.string.kg_prompt_reason_prepare_for_update_password; + return R.string.kg_prompt_reason_timeout_password; case PROMPT_REASON_NONE: return 0; default: diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java index ad92f8f623e4..c4a9fcb45284 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java @@ -440,8 +440,7 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_user_request); break; case PROMPT_REASON_PREPARE_FOR_UPDATE: - mSecurityMessageDisplay.setMessage( - R.string.kg_prompt_reason_prepare_for_update_pattern); + mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_timeout_pattern); break; case PROMPT_REASON_NONE: break; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java index 6d865ab525f3..c7f27cf8a71a 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java @@ -117,7 +117,7 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView case PROMPT_REASON_USER_REQUEST: return R.string.kg_prompt_reason_user_request; case PROMPT_REASON_PREPARE_FOR_UPDATE: - return R.string.kg_prompt_reason_prepare_for_update_pin; + return R.string.kg_prompt_reason_timeout_pin; case PROMPT_REASON_NONE: return 0; default: diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 8a36e7b127db..878947f6ba37 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -287,11 +287,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private final Executor mBackgroundExecutor; /** - * Short delay before restarting biometric authentication after a successful try - * This should be slightly longer than the time between on<biometric>Authenticated - * (e.g. onFingerprintAuthenticated) and setKeyguardGoingAway(true). + * Short delay before restarting fingerprint authentication after a successful try. This should + * be slightly longer than the time between onFingerprintAuthenticated and + * setKeyguardGoingAway(true). */ - private static final int BIOMETRIC_CONTINUE_DELAY_MS = 500; + private static final int FINGERPRINT_CONTINUE_DELAY_MS = 500; // If the HAL dies or is unable to authenticate, keyguard should retry after a short delay private int mHardwareFingerprintUnavailableRetryCount = 0; @@ -599,7 +599,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE), - BIOMETRIC_CONTINUE_DELAY_MS); + FINGERPRINT_CONTINUE_DELAY_MS); // Only authenticate fingerprint once when assistant is visible mAssistantVisible = false; @@ -782,9 +782,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } - mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE), - BIOMETRIC_CONTINUE_DELAY_MS); - // Only authenticate face once when assistant is visible mAssistantVisible = false; diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 02d2b8e4ef0f..4dbb92e1e37f 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -54,6 +54,7 @@ import com.android.systemui.plugins.VolumeDialogController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.power.EnhancedEstimates; import com.android.systemui.power.PowerUI; +import com.android.systemui.privacy.PrivacyItemController; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.recents.Recents; import com.android.systemui.screenrecord.RecordingController; @@ -122,9 +123,9 @@ import com.android.systemui.util.leak.GarbageMonitor; import com.android.systemui.util.leak.LeakDetector; import com.android.systemui.util.leak.LeakReporter; import com.android.systemui.util.sensors.AsyncSensorManager; -import com.android.systemui.wm.DisplayController; -import com.android.systemui.wm.DisplayImeController; -import com.android.systemui.wm.SystemWindows; +import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.DisplayImeController; +import com.android.wm.shell.common.SystemWindows; import java.util.function.Consumer; @@ -294,6 +295,7 @@ public class Dependency { @Inject Lazy<SensorPrivacyManager> mSensorPrivacyManager; @Inject Lazy<AutoHideController> mAutoHideController; @Inject Lazy<ForegroundServiceNotificationListener> mForegroundServiceNotificationListener; + @Inject Lazy<PrivacyItemController> mPrivacyItemController; @Inject @Background Lazy<Looper> mBgLooper; @Inject @Background Lazy<Handler> mBgHandler; @Inject @Main Lazy<Looper> mMainLooper; @@ -491,6 +493,7 @@ public class Dependency { mProviders.put(ForegroundServiceNotificationListener.class, mForegroundServiceNotificationListener::get); mProviders.put(ClockManager.class, mClockManager::get); + mProviders.put(PrivacyItemController.class, mPrivacyItemController::get); mProviders.put(ActivityManagerWrapper.class, mActivityManagerWrapper::get); mProviders.put(DevicePolicyManagerWrapper.class, mDevicePolicyManagerWrapper::get); mProviders.put(PackageManagerWrapper.class, mPackageManagerWrapper::get); diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java index 5fd7b53435cf..4df66602bb7e 100644 --- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java @@ -18,6 +18,7 @@ package com.android.systemui.appops; import android.app.AppOpsManager; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Handler; import android.os.Looper; import android.os.UserHandle; @@ -25,11 +26,14 @@ import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; +import androidx.annotation.WorkerThread; + import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dumpable; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dump.DumpManager; +import com.android.systemui.util.Assert; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -62,6 +66,7 @@ public class AppOpsControllerImpl implements AppOpsController, private H mBGHandler; private final List<AppOpsController.Callback> mCallbacks = new ArrayList<>(); private final SparseArray<Set<Callback>> mCallbacksByCode = new SparseArray<>(); + private final PermissionFlagsCache mFlagsCache; private boolean mListening; @GuardedBy("mActiveItems") @@ -82,8 +87,11 @@ public class AppOpsControllerImpl implements AppOpsController, public AppOpsControllerImpl( Context context, @Background Looper bgLooper, - DumpManager dumpManager) { + DumpManager dumpManager, + PermissionFlagsCache cache + ) { mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); + mFlagsCache = cache; mBGHandler = new H(bgLooper); final int numOps = OPS.length; for (int i = 0; i < numOps; i++) { @@ -230,10 +238,66 @@ public class AppOpsControllerImpl implements AppOpsController, } /** + * Does the app-op code refer to a user sensitive permission for the specified user id + * and package. Only user sensitive permission should be shown to the user by default. + * + * @param appOpCode The code of the app-op. + * @param uid The uid of the user. + * @param packageName The name of the package. + * + * @return {@code true} iff the app-op item is user sensitive + */ + private boolean isUserSensitive(int appOpCode, int uid, String packageName) { + String permission = AppOpsManager.opToPermission(appOpCode); + if (permission == null) { + return false; + } + int permFlags = mFlagsCache.getPermissionFlags(permission, + packageName, uid); + return (permFlags & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED) != 0; + } + + /** + * Does the app-op item refer to an operation that should be shown to the user. + * Only specficic ops (like SYSTEM_ALERT_WINDOW) or ops that refer to user sensitive + * permission should be shown to the user by default. + * + * @param item The item + * + * @return {@code true} iff the app-op item should be shown to the user + */ + private boolean isUserVisible(AppOpItem item) { + return isUserVisible(item.getCode(), item.getUid(), item.getPackageName()); + } + + + /** + * Does the app-op, uid and package name, refer to an operation that should be shown to the + * user. Only specficic ops (like {@link AppOpsManager.OP_SYSTEM_ALERT_WINDOW}) or + * ops that refer to user sensitive permission should be shown to the user by default. + * + * @param item The item + * + * @return {@code true} iff the app-op for should be shown to the user + */ + private boolean isUserVisible(int appOpCode, int uid, String packageName) { + // currently OP_SYSTEM_ALERT_WINDOW does not correspond to a platform permission + // which may be user senstive, so for now always show it to the user. + if (appOpCode == AppOpsManager.OP_SYSTEM_ALERT_WINDOW) { + return true; + } + + return isUserSensitive(appOpCode, uid, packageName); + } + + /** * Returns a copy of the list containing all the active AppOps that the controller tracks. * + * Call from a worker thread as it may perform long operations. + * * @return List of active AppOps information */ + @WorkerThread public List<AppOpItem> getActiveAppOps() { return getActiveAppOpsForUser(UserHandle.USER_ALL); } @@ -242,18 +306,23 @@ public class AppOpsControllerImpl implements AppOpsController, * Returns a copy of the list containing all the active AppOps that the controller tracks, for * a given user id. * + * Call from a worker thread as it may perform long operations. + * * @param userId User id to track, can be {@link UserHandle#USER_ALL} * * @return List of active AppOps information for that user id */ + @WorkerThread public List<AppOpItem> getActiveAppOpsForUser(int userId) { + Assert.isNotMainThread(); List<AppOpItem> list = new ArrayList<>(); synchronized (mActiveItems) { final int numActiveItems = mActiveItems.size(); for (int i = 0; i < numActiveItems; i++) { AppOpItem item = mActiveItems.get(i); if ((userId == UserHandle.USER_ALL - || UserHandle.getUserId(item.getUid()) == userId)) { + || UserHandle.getUserId(item.getUid()) == userId) + && isUserVisible(item)) { list.add(item); } } @@ -263,7 +332,8 @@ public class AppOpsControllerImpl implements AppOpsController, for (int i = 0; i < numNotedItems; i++) { AppOpItem item = mNotedItems.get(i); if ((userId == UserHandle.USER_ALL - || UserHandle.getUserId(item.getUid()) == userId)) { + || UserHandle.getUserId(item.getUid()) == userId) + && isUserVisible(item)) { list.add(item); } } @@ -311,7 +381,7 @@ public class AppOpsControllerImpl implements AppOpsController, } private void notifySuscribers(int code, int uid, String packageName, boolean active) { - if (mCallbacksByCode.contains(code)) { + if (mCallbacksByCode.contains(code) && isUserVisible(code, uid, packageName)) { if (DEBUG) Log.d(TAG, "Notifying of change in package " + packageName); for (Callback cb: mCallbacksByCode.get(code)) { cb.onActiveStateChanged(code, uid, packageName, active); diff --git a/packages/SystemUI/src/com/android/systemui/appops/PermissionFlagsCache.kt b/packages/SystemUI/src/com/android/systemui/appops/PermissionFlagsCache.kt new file mode 100644 index 000000000000..45ed78f750be --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/appops/PermissionFlagsCache.kt @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.appops + +import android.content.pm.PackageManager +import android.os.UserHandle +import androidx.annotation.WorkerThread +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.util.Assert +import java.util.concurrent.Executor +import javax.inject.Inject +import javax.inject.Singleton + +private data class PermissionFlagKey( + val permission: String, + val packageName: String, + val uid: Int +) + +/** + * Cache for PackageManager's PermissionFlags. + * + * After a specific `{permission, package, uid}` has been requested, updates to it will be tracked, + * and changes to the uid will trigger new requests (in the background). + */ +@Singleton +class PermissionFlagsCache @Inject constructor( + private val packageManager: PackageManager, + @Background private val executor: Executor +) : PackageManager.OnPermissionsChangedListener { + + private val permissionFlagsCache = + mutableMapOf<Int, MutableMap<PermissionFlagKey, Int>>() + private var listening = false + + override fun onPermissionsChanged(uid: Int) { + executor.execute { + // Only track those that we've seen before + val keys = permissionFlagsCache.get(uid) + if (keys != null) { + keys.mapValuesTo(keys) { + getFlags(it.key) + } + } + } + } + + /** + * Retrieve permission flags from cache or PackageManager. There parameters will be passed + * directly to [PackageManager]. + * + * Calls to this method should be done from a background thread (though it will only be + * enforced if the cache is not hit). + */ + @WorkerThread + fun getPermissionFlags(permission: String, packageName: String, uid: Int): Int { + if (!listening) { + listening = true + packageManager.addOnPermissionsChangeListener(this) + } + val key = PermissionFlagKey(permission, packageName, uid) + return permissionFlagsCache.getOrPut(uid, { mutableMapOf() }).get(key) ?: run { + getFlags(key).also { + Assert.isNotMainThread() + permissionFlagsCache.get(uid)?.put(key, it) + } + } + } + + private fun getFlags(key: PermissionFlagKey): Int { + return packageManager.getPermissionFlags(key.permission, key.packageName, + UserHandle.getUserHandleForUid(key.uid)) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java index ab7af43f91d2..f35322bd2a77 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java @@ -22,7 +22,6 @@ import android.content.Context; import android.hardware.SensorManager; import android.net.Uri; import android.provider.DeviceConfig; -import android.util.DisplayMetrics; import android.view.MotionEvent; import androidx.annotation.NonNull; @@ -62,7 +61,7 @@ public class FalsingManagerProxy implements FalsingManager, Dumpable { private static final String PROXIMITY_SENSOR_TAG = "FalsingManager"; private final ProximitySensor mProximitySensor; - private final DisplayMetrics mDisplayMetrics; + private final FalsingDataProvider mFalsingDataProvider; private FalsingManager mInternalFalsingManager; private DeviceConfig.OnPropertiesChangedListener mDeviceConfigListener; private final DeviceConfigProxy mDeviceConfig; @@ -74,18 +73,19 @@ public class FalsingManagerProxy implements FalsingManager, Dumpable { @Inject FalsingManagerProxy(Context context, PluginManager pluginManager, @Main Executor executor, - DisplayMetrics displayMetrics, ProximitySensor proximitySensor, + ProximitySensor proximitySensor, DeviceConfigProxy deviceConfig, DockManager dockManager, KeyguardUpdateMonitor keyguardUpdateMonitor, DumpManager dumpManager, @UiBackground Executor uiBgExecutor, - StatusBarStateController statusBarStateController) { - mDisplayMetrics = displayMetrics; + StatusBarStateController statusBarStateController, + FalsingDataProvider falsingDataProvider) { mProximitySensor = proximitySensor; mDockManager = dockManager; mKeyguardUpdateMonitor = keyguardUpdateMonitor; mUiBgExecutor = uiBgExecutor; mStatusBarStateController = statusBarStateController; + mFalsingDataProvider = falsingDataProvider; mProximitySensor.setTag(PROXIMITY_SENSOR_TAG); mProximitySensor.setDelay(SensorManager.SENSOR_DELAY_GAME); mDeviceConfig = deviceConfig; @@ -143,7 +143,7 @@ public class FalsingManagerProxy implements FalsingManager, Dumpable { mInternalFalsingManager = new FalsingManagerImpl(context, mUiBgExecutor); } else { mInternalFalsingManager = new BrightLineFalsingManager( - new FalsingDataProvider(mDisplayMetrics), + mFalsingDataProvider, mKeyguardUpdateMonitor, mProximitySensor, mDeviceConfig, diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java index 95d5ad9a7a94..a50f9ce9713b 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java @@ -132,7 +132,9 @@ public class BrightLineFalsingManager implements FalsingManager { } private void registerSensors() { - mProximitySensor.register(mSensorEventListener); + if (!mDataProvider.isWirelessCharging()) { + mProximitySensor.register(mSensorEventListener); + } } private void unregisterSensors() { diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingDataProvider.java index 5494c644c22c..ea46441c8fbe 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingDataProvider.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingDataProvider.java @@ -22,10 +22,13 @@ import android.view.MotionEvent.PointerCoords; import android.view.MotionEvent.PointerProperties; import com.android.systemui.classifier.Classifier; +import com.android.systemui.statusbar.policy.BatteryController; import java.util.ArrayList; import java.util.List; +import javax.inject.Inject; + /** * Acts as a cache and utility class for FalsingClassifiers. */ @@ -36,6 +39,7 @@ public class FalsingDataProvider { private final int mWidthPixels; private final int mHeightPixels; + private final BatteryController mBatteryController; private final float mXdpi; private final float mYdpi; @@ -50,11 +54,13 @@ public class FalsingDataProvider { private MotionEvent mFirstRecentMotionEvent; private MotionEvent mLastMotionEvent; - public FalsingDataProvider(DisplayMetrics displayMetrics) { + @Inject + public FalsingDataProvider(DisplayMetrics displayMetrics, BatteryController batteryController) { mXdpi = displayMetrics.xdpi; mYdpi = displayMetrics.ydpi; mWidthPixels = displayMetrics.widthPixels; mHeightPixels = displayMetrics.heightPixels; + mBatteryController = batteryController; FalsingClassifier.logInfo("xdpi, ydpi: " + getXdpi() + ", " + getYdpi()); FalsingClassifier.logInfo("width, height: " + getWidthPixels() + ", " + getHeightPixels()); @@ -177,6 +183,11 @@ public class FalsingDataProvider { return mLastMotionEvent.getY() < mFirstRecentMotionEvent.getY(); } + /** Returns true if phone is being charged without a cable. */ + boolean isWirelessCharging() { + return mBatteryController.isWirelessCharging(); + } + private void recalculateData() { if (!mDirty) { return; diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt index 58807f0f7025..aa3e193ddba2 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt @@ -49,6 +49,11 @@ open class ControlsBindingControllerImpl @Inject constructor( private const val SUGGESTED_STRUCTURES = 6L private const val SUGGESTED_CONTROLS_REQUEST = ControlsControllerImpl.SUGGESTED_CONTROLS_PER_STRUCTURE * SUGGESTED_STRUCTURES + + private val emptyCallback = object : ControlsBindingController.LoadCallback { + override fun accept(controls: List<Control>) {} + override fun error(message: String) {} + } } private var currentUser = UserHandle.of(ActivityManager.getCurrentUser()) @@ -283,7 +288,7 @@ open class ControlsBindingControllerImpl @Inject constructor( } private inner class LoadSubscriber( - val callback: ControlsBindingController.LoadCallback, + var callback: ControlsBindingController.LoadCallback, val requestLimit: Long ) : IControlsSubscriber.Stub() { val loadedControls = ArrayList<Control>() @@ -337,6 +342,10 @@ open class ControlsBindingControllerImpl @Inject constructor( if (isTerminated.get()) return _loadCancelInternal = {} + + // Reassign the callback to clear references to other areas of code. Binders such as + // this may not be GC'd right away, so do not hold onto these references. + callback = emptyCallback currentProvider?.cancelLoadTimeout() backgroundExecutor.execute { diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt index ec8bfc6fa2ae..977e46ac3b44 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt @@ -76,7 +76,8 @@ class ControlsProviderLifecycleManager( private const val LOAD_TIMEOUT_SECONDS = 20L // seconds private const val MAX_BIND_RETRIES = 5 private const val DEBUG = true - private val BIND_FLAGS = Context.BIND_AUTO_CREATE or Context.BIND_FOREGROUND_SERVICE + private val BIND_FLAGS = Context.BIND_AUTO_CREATE or Context.BIND_FOREGROUND_SERVICE or + Context.BIND_NOT_PERCEPTIBLE } private val intent = Intent().apply { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java index 56d0fa237b82..6e8d63b2c516 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java @@ -18,7 +18,9 @@ package com.android.systemui.dagger; import android.content.BroadcastReceiver; -import com.android.systemui.screenshot.GlobalScreenshot.ActionProxyReceiver; +import com.android.systemui.screenshot.ActionProxyReceiver; +import com.android.systemui.screenshot.DeleteScreenshotReceiver; +import com.android.systemui.screenshot.SmartActionsReceiver; import dagger.Binds; import dagger.Module; @@ -30,10 +32,31 @@ import dagger.multibindings.IntoMap; */ @Module public abstract class DefaultBroadcastReceiverBinder { - /** */ + /** + * + */ @Binds @IntoMap @ClassKey(ActionProxyReceiver.class) public abstract BroadcastReceiver bindActionProxyReceiver( ActionProxyReceiver broadcastReceiver); + + /** + * + */ + @Binds + @IntoMap + @ClassKey(DeleteScreenshotReceiver.class) + public abstract BroadcastReceiver bindDeleteScreenshotReceiver( + DeleteScreenshotReceiver broadcastReceiver); + + /** + * + */ + @Binds + @IntoMap + @ClassKey(SmartActionsReceiver.class) + public abstract BroadcastReceiver bindSmartActionsReceiver( + SmartActionsReceiver broadcastReceiver); + } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java index a30d9346c5ee..3d31070905d0 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java @@ -22,7 +22,6 @@ import android.app.INotificationManager; import android.content.Context; import android.content.SharedPreferences; import android.hardware.display.AmbientDisplayConfiguration; -import android.hardware.display.NightDisplayListener; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; @@ -78,7 +77,7 @@ import dagger.Provides; * * See SystemUI/docs/dagger.md */ -@Module +@Module(includes = {NightDisplayListenerModule.class}) public class DependencyProvider { @Singleton @@ -153,13 +152,6 @@ public class DependencyProvider { @Singleton @Provides - public NightDisplayListener provideNightDisplayListener(Context context, - @Background Handler bgHandler) { - return new NightDisplayListener(context, bgHandler); - } - - @Singleton - @Provides public PluginManager providePluginManager(Context context) { return new PluginManagerImpl(context, new PluginInitializerImpl()); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/NightDisplayListenerModule.java b/packages/SystemUI/src/com/android/systemui/dagger/NightDisplayListenerModule.java new file mode 100644 index 000000000000..7091105e63d2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dagger/NightDisplayListenerModule.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.dagger; + +import android.content.Context; +import android.hardware.display.NightDisplayListener; +import android.os.Handler; +import android.os.UserHandle; + +import com.android.systemui.dagger.qualifiers.Background; + +import javax.inject.Inject; + +import dagger.Module; +import dagger.Provides; + +/** + * Module for providing a {@link NightDisplayListener}. + */ +@Module +public class NightDisplayListenerModule { + + /** + * Provides a {@link NightDisplayListener}. + * + * The provided listener is associated with the user as returned by + * {@link android.app.ActivityManager#getCurrentUser}, making an IPC call on its creation. + * If the current user is known, prefer using a {@link Builder}. + */ + @Provides + public NightDisplayListener provideNightDisplayListener(Context context, + @Background Handler bgHandler) { + return new NightDisplayListener(context, bgHandler); + } + + /** + * Builder to create instances of {@link NightDisplayListener}. + * + * It uses {@link UserHandle#USER_SYSTEM} as the default user. + */ + public static class Builder { + private final Context mContext; + private final Handler mBgHandler; + private int mUserId = UserHandle.USER_SYSTEM; + + @Inject + public Builder(Context context, @Background Handler bgHandler) { + mContext = context; + mBgHandler = bgHandler; + } + + /** + * Set the userId for this builder + */ + public Builder setUser(int userId) { + mUserId = userId; + return this; + } + + /** + * Build a {@link NightDisplayListener} for the set user. + */ + public NightDisplayListener build() { + return new NightDisplayListener(mContext, mUserId, mBgHandler); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java index f683a639af10..251ce1304930 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java @@ -39,6 +39,7 @@ import android.content.pm.ShortcutManager; import android.content.res.Resources; import android.hardware.SensorManager; import android.hardware.SensorPrivacyManager; +import android.hardware.display.ColorDisplayManager; import android.hardware.display.DisplayManager; import android.media.AudioManager; import android.media.MediaRouter2Manager; @@ -106,6 +107,12 @@ public class SystemServicesModule { @Provides @Singleton + static ColorDisplayManager provideColorDisplayManager(Context context) { + return context.getSystemService(ColorDisplayManager.class); + } + + @Provides + @Singleton static ConnectivityManager provideConnectivityManagager(Context context) { return context.getSystemService(ConnectivityManager.class); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java index cd0ba290db46..803e56db8ff3 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java @@ -59,6 +59,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl; import com.android.systemui.statusbar.policy.HeadsUpManager; +import com.android.systemui.wmshell.WindowManagerShellModule; import javax.inject.Named; import javax.inject.Singleton; @@ -71,7 +72,7 @@ import dagger.Provides; * A dagger module for injecting default implementations of components of System UI that may be * overridden by the System UI implementation. */ -@Module(includes = {DividerModule.class, QSModule.class}) +@Module(includes = {DividerModule.class, QSModule.class, WindowManagerShellModule.class}) public abstract class SystemUIDefaultModule { @Singleton diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index 4bd046e23dab..fce545b421d5 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -45,6 +45,7 @@ import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.util.concurrency.ConcurrencyModule; import com.android.systemui.util.sensors.AsyncSensorManager; import com.android.systemui.util.sensors.SensorModule; +import com.android.systemui.util.settings.SettingsUtilModule; import com.android.systemui.util.time.SystemClock; import com.android.systemui.util.time.SystemClockImpl; @@ -65,7 +66,8 @@ import dagger.Provides; LogModule.class, PeopleHubModule.class, SensorModule.class, - SettingsModule.class + SettingsModule.class, + SettingsUtilModule.class }, subcomponents = {StatusBarComponent.class, NotificationRowComponent.class, diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java index b9d23ade2ee1..1ef806c8bd68 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java @@ -364,9 +364,6 @@ public class DozeMachine { Log.i(TAG, "Dropping pulse done because current state is already done: " + mState); return mState; } - if (requestedState == State.DOZE_AOD && mBatteryController.isAodPowerSave()) { - return State.DOZE; - } if (requestedState == State.DOZE_REQUEST_PULSE && !mState.canPulse()) { Log.i(TAG, "Dropping pulse request because current state can't pulse: " + mState); return mState; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index 37bdda8a06a1..524d9c8536b8 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -21,7 +21,6 @@ import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_ import android.annotation.AnyThread; import android.app.ActivityManager; -import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; import android.hardware.Sensor; @@ -49,6 +48,7 @@ import com.android.systemui.plugins.SensorManagerPlugin; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.util.sensors.AsyncSensorManager; import com.android.systemui.util.sensors.ProximitySensor; +import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.util.wakelock.WakeLock; import java.io.PrintWriter; @@ -64,10 +64,10 @@ public class DozeSensors { private final Context mContext; private final AsyncSensorManager mSensorManager; - private final ContentResolver mResolver; private final AmbientDisplayConfiguration mConfig; private final WakeLock mWakeLock; private final Consumer<Boolean> mProxCallback; + private final SecureSettings mSecureSettings; private final Callback mCallback; @VisibleForTesting protected TriggerSensor[] mSensors; @@ -98,13 +98,13 @@ public class DozeSensors { DozeSensors(Context context, AsyncSensorManager sensorManager, DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock, Callback callback, Consumer<Boolean> proxCallback, DozeLog dozeLog, - ProximitySensor proximitySensor) { + ProximitySensor proximitySensor, SecureSettings secureSettings) { mContext = context; mSensorManager = sensorManager; mConfig = config; mWakeLock = wakeLock; mProxCallback = proxCallback; - mResolver = mContext.getContentResolver(); + mSecureSettings = secureSettings; mCallback = callback; mProximitySensor = proximitySensor; @@ -241,7 +241,7 @@ public class DozeSensors { } if (!anyListening) { - mResolver.unregisterContentObserver(mSettingsObserver); + mSecureSettings.unregisterContentObserver(mSettingsObserver); } else if (!mSettingRegistered) { for (TriggerSensor s : mSensors) { s.registerSettingsObserver(mSettingsObserver); @@ -400,7 +400,7 @@ public class DozeSensors { } else if (TextUtils.isEmpty(mSetting)) { return true; } - return Settings.Secure.getIntForUser(mResolver, mSetting, mSettingDefault ? 1 : 0, + return mSecureSettings.getIntForUser(mSetting, mSettingDefault ? 1 : 0, UserHandle.USER_CURRENT) != 0; } @@ -444,9 +444,8 @@ public class DozeSensors { public void registerSettingsObserver(ContentObserver settingsObserver) { if (mConfigured && !TextUtils.isEmpty(mSetting)) { - mResolver.registerContentObserver( - Settings.Secure.getUriFor(mSetting), false /* descendants */, - mSettingsObserver, UserHandle.USER_ALL); + mSecureSettings.registerContentObserverForUser( + mSetting, mSettingsObserver, UserHandle.USER_ALL); } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index 0800a201bd92..e38dce05a32e 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -46,6 +46,7 @@ import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.util.Assert; import com.android.systemui.util.sensors.AsyncSensorManager; import com.android.systemui.util.sensors.ProximitySensor; +import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.util.wakelock.WakeLock; import java.io.PrintWriter; @@ -163,7 +164,8 @@ public class DozeTriggers implements DozeMachine.Part { DozeParameters dozeParameters, AsyncSensorManager sensorManager, WakeLock wakeLock, DockManager dockManager, ProximitySensor proximitySensor, ProximitySensor.ProximityCheck proxCheck, - DozeLog dozeLog, BroadcastDispatcher broadcastDispatcher) { + DozeLog dozeLog, BroadcastDispatcher broadcastDispatcher, + SecureSettings secureSettings) { mContext = context; mDozeHost = dozeHost; mConfig = config; @@ -172,7 +174,8 @@ public class DozeTriggers implements DozeMachine.Part { mWakeLock = wakeLock; mAllowPulseTriggers = true; mDozeSensors = new DozeSensors(context, mSensorManager, dozeParameters, - config, wakeLock, this::onSensor, this::onProximityFar, dozeLog, proximitySensor); + config, wakeLock, this::onSensor, this::onProximityFar, dozeLog, proximitySensor, + secureSettings); mUiModeManager = mContext.getSystemService(UiModeManager.class); mDockManager = dockManager; mProxCheck = proxCheck; @@ -408,10 +411,13 @@ public class DozeTriggers implements DozeMachine.Part { break; case DOZE_PULSING: case DOZE_PULSING_BRIGHT: - case DOZE_AOD_DOCKED: mWantProx = true; mWantTouchScreenSensors = false; break; + case DOZE_AOD_DOCKED: + mWantProx = false; + mWantTouchScreenSensors = false; + break; case DOZE_PULSE_DONE: mDozeSensors.requestTemporaryDisable(); // A pulse will temporarily disable sensors that require a touch screen. diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt index e12b7dd259a5..075318b3f1f7 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt @@ -306,7 +306,7 @@ class MediaCarouselController @Inject constructor( private fun updatePageIndicator() { val numPages = mediaContent.getChildCount() - pageIndicator.setNumPages(numPages, Color.WHITE) + pageIndicator.setNumPages(numPages) if (numPages == 1) { pageIndicator.setLocation(0f) } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index 299ae5b50aa9..b3277737f397 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -316,18 +316,13 @@ class MediaDataManager( as MediaSession.Token? val metadata = mediaControllerFactory.create(token).metadata - if (metadata == null) { - // TODO: handle this better, removing media notification - return - } - // Foreground and Background colors computed from album art val notif: Notification = sbn.notification - var artworkBitmap = metadata.getBitmap(MediaMetadata.METADATA_KEY_ART) + var artworkBitmap = metadata?.getBitmap(MediaMetadata.METADATA_KEY_ART) if (artworkBitmap == null) { - artworkBitmap = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART) + artworkBitmap = metadata?.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART) } - if (artworkBitmap == null) { + if (artworkBitmap == null && metadata != null) { artworkBitmap = loadBitmapFromUri(metadata) } val artWorkIcon = if (artworkBitmap == null) { @@ -363,16 +358,16 @@ class MediaDataManager( val smallIconDrawable: Drawable = sbn.notification.smallIcon.loadDrawable(context) // Song name - var song: CharSequence? = metadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE) + var song: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE) if (song == null) { - song = metadata.getString(MediaMetadata.METADATA_KEY_TITLE) + song = metadata?.getString(MediaMetadata.METADATA_KEY_TITLE) } if (song == null) { song = HybridGroupManager.resolveTitle(notif) } // Artist name - var artist: CharSequence? = metadata.getString(MediaMetadata.METADATA_KEY_ARTIST) + var artist: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_ARTIST) if (artist == null) { artist = HybridGroupManager.resolveText(notif) } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt index 143f8496e7aa..ae7f66b5ac48 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt @@ -19,8 +19,12 @@ package com.android.systemui.media import android.content.Context import android.media.MediaRouter2Manager import android.media.session.MediaController +import androidx.annotation.AnyThread +import androidx.annotation.MainThread +import androidx.annotation.WorkerThread import com.android.settingslib.media.LocalMediaManager import com.android.settingslib.media.MediaDevice +import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.Dumpable import com.android.systemui.dump.DumpManager @@ -39,11 +43,12 @@ class MediaDeviceManager @Inject constructor( private val localMediaManagerFactory: LocalMediaManagerFactory, private val mr2manager: MediaRouter2Manager, @Main private val fgExecutor: Executor, + @Background private val bgExecutor: Executor, private val mediaDataManager: MediaDataManager, private val dumpManager: DumpManager ) : MediaDataManager.Listener, Dumpable { private val listeners: MutableSet<Listener> = mutableSetOf() - private val entries: MutableMap<String, Token> = mutableMapOf() + private val entries: MutableMap<String, Entry> = mutableMapOf() init { mediaDataManager.addListener(this) @@ -71,7 +76,7 @@ class MediaDeviceManager @Inject constructor( val controller = data.token?.let { MediaController(context, it) } - entry = Token(key, oldKey, controller, + entry = Entry(key, oldKey, controller, localMediaManagerFactory.create(data.packageName)) entries[key] = entry entry.start() @@ -99,6 +104,7 @@ class MediaDeviceManager @Inject constructor( } } + @MainThread private fun processDevice(key: String, oldKey: String?, device: MediaDevice?) { val enabled = device != null val data = MediaDeviceData(enabled, device?.iconWithoutBackground, device?.name) @@ -114,12 +120,13 @@ class MediaDeviceManager @Inject constructor( fun onKeyRemoved(key: String) } - private inner class Token( + private inner class Entry( val key: String, val oldKey: String?, val controller: MediaController?, val localMediaManager: LocalMediaManager ) : LocalMediaManager.DeviceCallback { + val token get() = controller?.sessionToken private var started = false @@ -127,20 +134,27 @@ class MediaDeviceManager @Inject constructor( set(value) { if (!started || value != field) { field = value - processDevice(key, oldKey, value) + fgExecutor.execute { + processDevice(key, oldKey, value) + } } } - fun start() { + + @AnyThread + fun start() = bgExecutor.execute { localMediaManager.registerCallback(this) localMediaManager.startScan() updateCurrent() started = true } - fun stop() { + + @AnyThread + fun stop() = bgExecutor.execute { started = false localMediaManager.stopScan() localMediaManager.unregisterCallback(this) } + fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) { val route = controller?.let { mr2manager.getRoutingSessionForMediaController(it) @@ -152,14 +166,18 @@ class MediaDeviceManager @Inject constructor( println(" route=$route") } } - override fun onDeviceListUpdate(devices: List<MediaDevice>?) = fgExecutor.execute { + + override fun onDeviceListUpdate(devices: List<MediaDevice>?) = bgExecutor.execute { updateCurrent() } + override fun onSelectedDeviceStateChanged(device: MediaDevice, state: Int) { - fgExecutor.execute { + bgExecutor.execute { updateCurrent() } } + + @WorkerThread private fun updateCurrent() { val device = localMediaManager.getCurrentConnectedDevice() controller?.let { diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt index 1dca3f1297b1..9e326aaec3c1 100644 --- a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt @@ -71,7 +71,7 @@ private fun PlaybackState.computePosition(duration: Long): Long { /** ViewModel for seek bar in QS media player. */ class SeekBarViewModel @Inject constructor(@Background private val bgExecutor: RepeatableExecutor) { - private var _data = Progress(false, false, null, null) + private var _data = Progress(false, false, null, 0) set(value) { field = value _progress.postValue(value) @@ -186,10 +186,10 @@ class SeekBarViewModel @Inject constructor(@Background private val bgExecutor: R val mediaMetadata = controller?.metadata val seekAvailable = ((playbackState?.actions ?: 0L) and PlaybackState.ACTION_SEEK_TO) != 0L val position = playbackState?.position?.toInt() - val duration = mediaMetadata?.getLong(MediaMetadata.METADATA_KEY_DURATION)?.toInt() + val duration = mediaMetadata?.getLong(MediaMetadata.METADATA_KEY_DURATION)?.toInt() ?: 0 val enabled = if (playbackState == null || playbackState?.getState() == PlaybackState.STATE_NONE || - (duration != null && duration <= 0)) false else true + (duration <= 0)) false else true _data = Progress(enabled, seekAvailable, position, duration) checkIfPollingNeeded() } @@ -408,6 +408,6 @@ class SeekBarViewModel @Inject constructor(@Background private val bgExecutor: R val enabled: Boolean, val seekAvailable: Boolean, val elapsedTime: Int?, - val duration: Int? + val duration: Int ) } diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java index 16e05f1e3f26..c0b9258f39fd 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java @@ -27,7 +27,6 @@ import android.graphics.Rect; import android.os.Handler; import android.os.Looper; import android.util.Log; -import android.view.Surface; import android.view.SurfaceControl; import android.window.DisplayAreaInfo; import android.window.DisplayAreaOrganizer; @@ -39,7 +38,7 @@ import androidx.annotation.VisibleForTesting; import com.android.internal.os.SomeArgs; import com.android.systemui.Dumpable; -import com.android.systemui.wm.DisplayController; +import com.android.wm.shell.common.DisplayController; import java.io.FileDescriptor; import java.io.PrintWriter; diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java index f995bf9eb2a1..71c5f8020330 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java @@ -41,8 +41,8 @@ import androidx.annotation.VisibleForTesting; import com.android.systemui.R; import com.android.systemui.statusbar.phone.NavigationModeController; -import com.android.systemui.wm.DisplayChangeController; -import com.android.systemui.wm.DisplayController; +import com.android.wm.shell.common.DisplayChangeController; +import com.android.wm.shell.common.DisplayController; import javax.inject.Inject; import javax.inject.Singleton; diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java index 586761b0fc3d..70a81aaed249 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java @@ -33,8 +33,8 @@ import com.android.systemui.R; import com.android.systemui.model.SysUiState; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.TaskStackChangeListener; -import com.android.systemui.wm.DisplayChangeController; -import com.android.systemui.wm.DisplayController; +import com.android.wm.shell.common.DisplayChangeController; +import com.android.wm.shell.common.DisplayController; import java.io.FileDescriptor; import java.io.PrintWriter; diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java index 665b90e29976..df3aeadaacd6 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java @@ -39,8 +39,8 @@ import android.view.DisplayInfo; import android.view.Gravity; import android.window.WindowContainerTransaction; -import com.android.systemui.wm.DisplayController; -import com.android.systemui.wm.DisplayLayout; +import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.DisplayLayout; import java.io.PrintWriter; diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java index 35e56ee87967..312d6d62128f 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java @@ -58,8 +58,8 @@ import android.window.WindowOrganizer; import com.android.internal.os.SomeArgs; import com.android.systemui.pip.phone.PipUpdateThread; import com.android.systemui.stackdivider.Divider; -import com.android.systemui.wm.DisplayController; import com.android.wm.shell.R; +import com.android.wm.shell.common.DisplayController; import java.io.PrintWriter; import java.util.ArrayList; diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index 02bf475d5744..582cd046f9e0 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -56,9 +56,8 @@ import com.android.systemui.shared.system.WindowManagerWrapper; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.FloatingContentCoordinator; -import com.android.systemui.wm.DisplayChangeController; -import com.android.systemui.wm.DisplayController; -import com.android.systemui.wm.DisplayLayout; +import com.android.wm.shell.common.DisplayChangeController; +import com.android.wm.shell.common.DisplayController; import java.io.PrintWriter; @@ -79,7 +78,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio private final DisplayInfo mTmpDisplayInfo = new DisplayInfo(); private final Rect mTmpInsetBounds = new Rect(); private final Rect mTmpNormalBounds = new Rect(); - private final Rect mReentryBounds = new Rect(); + protected final Rect mReentryBounds = new Rect(); private PipBoundsHandler mPipBoundsHandler; private InputConsumerController mInputConsumerController; diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java index 05b9b0ec3957..361aafacdf76 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java @@ -36,9 +36,9 @@ import android.media.session.PlaybackState; import android.os.UserHandle; import com.android.systemui.Dependency; +import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.statusbar.policy.UserInfoController; -import com.android.wm.shell.R; import java.util.ArrayList; import java.util.Collections; diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index bd9ddc57ca19..5434b62e19b8 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -56,6 +56,7 @@ import androidx.dynamicanimation.animation.SpringForce; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.logging.MetricsLoggerWrapper; +import com.android.systemui.R; import com.android.systemui.model.SysUiState; import com.android.systemui.pip.PipAnimationController; import com.android.systemui.pip.PipBoundsHandler; @@ -67,7 +68,6 @@ import com.android.systemui.util.DismissCircleView; import com.android.systemui.util.FloatingContentCoordinator; import com.android.systemui.util.animation.PhysicsAnimator; import com.android.systemui.util.magnetictarget.MagnetizedObject; -import com.android.wm.shell.R; import java.io.PrintWriter; diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java index 3a3d629e89f4..2138f092b790 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -46,6 +46,7 @@ import android.util.Log; import android.view.DisplayInfo; import com.android.systemui.Dependency; +import com.android.systemui.R; import com.android.systemui.UiOffloadThread; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.pip.BasePipManager; @@ -57,7 +58,6 @@ import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedSta import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.WindowManagerWrapper; import com.android.systemui.stackdivider.Divider; -import com.android.wm.shell.R; import java.util.ArrayList; import java.util.List; diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt new file mode 100644 index 000000000000..870e714ee24c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.privacy + +import android.content.Context +import android.util.AttributeSet +import android.view.Gravity +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.ImageView +import android.widget.LinearLayout +import com.android.systemui.R + +class OngoingPrivacyChip @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttrs: Int = 0, + defStyleRes: Int = 0 +) : FrameLayout(context, attrs, defStyleAttrs, defStyleRes) { + + private val iconMarginExpanded = context.resources.getDimensionPixelSize( + R.dimen.ongoing_appops_chip_icon_margin_expanded) + private val iconMarginCollapsed = context.resources.getDimensionPixelSize( + R.dimen.ongoing_appops_chip_icon_margin_collapsed) + private val iconSize = + context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_size) + private val iconColor = context.resources.getColor( + R.color.status_bar_clock_color, context.theme) + private val sidePadding = + context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_side_padding) + private val backgroundDrawable = context.getDrawable(R.drawable.privacy_chip_bg) + private lateinit var iconsContainer: LinearLayout + private lateinit var back: FrameLayout + var expanded = false + set(value) { + if (value != field) { + field = value + updateView(PrivacyChipBuilder(context, privacyList)) + } + } + + var privacyList = emptyList<PrivacyItem>() + set(value) { + field = value + updateView(PrivacyChipBuilder(context, field)) + } + + override fun onFinishInflate() { + super.onFinishInflate() + + back = requireViewById(R.id.background) + iconsContainer = requireViewById(R.id.icons_container) + } + + // Should only be called if the builder icons or app changed + private fun updateView(builder: PrivacyChipBuilder) { + back.background = if (expanded) backgroundDrawable else null + val padding = if (expanded) sidePadding else 0 + back.setPaddingRelative(padding, 0, padding, 0) + fun setIcons(chipBuilder: PrivacyChipBuilder, iconsContainer: ViewGroup) { + iconsContainer.removeAllViews() + chipBuilder.generateIcons().forEachIndexed { i, it -> + it.mutate() + it.setTint(iconColor) + val image = ImageView(context).apply { + setImageDrawable(it) + scaleType = ImageView.ScaleType.CENTER_INSIDE + } + iconsContainer.addView(image, iconSize, iconSize) + if (i != 0) { + val lp = image.layoutParams as MarginLayoutParams + lp.marginStart = if (expanded) iconMarginExpanded else iconMarginCollapsed + image.layoutParams = lp + } + } + } + + if (!privacyList.isEmpty()) { + generateContentDescription(builder) + setIcons(builder, iconsContainer) + val lp = iconsContainer.layoutParams as FrameLayout.LayoutParams + lp.gravity = Gravity.CENTER_VERTICAL or + (if (expanded) Gravity.CENTER_HORIZONTAL else Gravity.END) + iconsContainer.layoutParams = lp + } else { + iconsContainer.removeAllViews() + } + requestLayout() + } + + private fun generateContentDescription(builder: PrivacyChipBuilder) { + val typesText = builder.joinTypes() + contentDescription = context.getString( + R.string.ongoing_privacy_chip_content_multiple_apps, typesText) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipBuilder.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipBuilder.kt new file mode 100644 index 000000000000..1d2e74703b42 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipBuilder.kt @@ -0,0 +1,51 @@ +/* + * 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.privacy + +import android.content.Context +import com.android.systemui.R + +class PrivacyChipBuilder(private val context: Context, itemsList: List<PrivacyItem>) { + + val appsAndTypes: List<Pair<PrivacyApplication, List<PrivacyType>>> + val types: List<PrivacyType> + private val separator = context.getString(R.string.ongoing_privacy_dialog_separator) + private val lastSeparator = context.getString(R.string.ongoing_privacy_dialog_last_separator) + + init { + appsAndTypes = itemsList.groupBy({ it.application }, { it.privacyType }) + .toList() + .sortedWith(compareBy({ -it.second.size }, // Sort by number of AppOps + { it.second.min() })) // Sort by "smallest" AppOpp (Location is largest) + types = itemsList.map { it.privacyType }.distinct().sorted() + } + + fun generateIcons() = types.map { it.getIcon(context) } + + private fun <T> List<T>.joinWithAnd(): StringBuilder { + return subList(0, size - 1).joinTo(StringBuilder(), separator = separator).apply { + append(lastSeparator) + append(this@joinWithAnd.last()) + } + } + + fun joinTypes(): String { + return when (types.size) { + 0 -> "" + 1 -> types[0].getName(context) + else -> types.map { it.getName(context) }.joinWithAnd().toString() + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipEvent.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipEvent.kt new file mode 100644 index 000000000000..1f24fde1377e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipEvent.kt @@ -0,0 +1,30 @@ +/* + * 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.privacy + +import com.android.internal.logging.UiEvent +import com.android.internal.logging.UiEventLogger + +enum class PrivacyChipEvent(private val _id: Int) : UiEventLogger.UiEventEnum { + @UiEvent(doc = "Privacy chip is viewed by the user. Logged at most once per time QS is visible") + ONGOING_INDICATORS_CHIP_VIEW(601), + + @UiEvent(doc = "Privacy chip is clicked") + ONGOING_INDICATORS_CHIP_CLICK(602); + + override fun getId() = _id +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt new file mode 100644 index 000000000000..3da1363f2a56 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.privacy + +import android.content.Context +import com.android.systemui.R + +typealias Privacy = PrivacyType + +enum class PrivacyType(val nameId: Int, val iconId: Int) { + // This is uses the icons used by the corresponding permission groups in the AndroidManifest + TYPE_CAMERA(R.string.privacy_type_camera, + com.android.internal.R.drawable.perm_group_camera), + TYPE_MICROPHONE(R.string.privacy_type_microphone, + com.android.internal.R.drawable.perm_group_microphone), + TYPE_LOCATION(R.string.privacy_type_location, + com.android.internal.R.drawable.perm_group_location); + + fun getName(context: Context) = context.resources.getString(nameId) + + fun getIcon(context: Context) = context.resources.getDrawable(iconId, context.theme) +} + +data class PrivacyItem(val privacyType: PrivacyType, val application: PrivacyApplication) + +data class PrivacyApplication(val packageName: String, val uid: Int) diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt new file mode 100644 index 000000000000..d5a14f7bef2f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt @@ -0,0 +1,296 @@ +/* + * 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.privacy + +import android.app.ActivityManager +import android.app.AppOpsManager +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.os.UserHandle +import android.os.UserManager +import android.provider.DeviceConfig +import com.android.internal.annotations.VisibleForTesting +import com.android.internal.config.sysui.SystemUiDeviceConfigFlags +import com.android.systemui.Dumpable +import com.android.systemui.appops.AppOpItem +import com.android.systemui.appops.AppOpsController +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.dump.DumpManager +import com.android.systemui.util.DeviceConfigProxy +import com.android.systemui.util.concurrency.DelayableExecutor +import java.io.FileDescriptor +import java.io.PrintWriter +import java.lang.ref.WeakReference +import java.util.concurrent.Executor +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class PrivacyItemController @Inject constructor( + context: Context, + private val appOpsController: AppOpsController, + @Main uiExecutor: DelayableExecutor, + @Background private val bgExecutor: Executor, + private val broadcastDispatcher: BroadcastDispatcher, + private val deviceConfigProxy: DeviceConfigProxy, + private val userManager: UserManager, + dumpManager: DumpManager +) : Dumpable { + + @VisibleForTesting + internal companion object { + val OPS = intArrayOf(AppOpsManager.OP_CAMERA, + AppOpsManager.OP_RECORD_AUDIO, + AppOpsManager.OP_COARSE_LOCATION, + AppOpsManager.OP_FINE_LOCATION) + val intentFilter = IntentFilter().apply { + addAction(Intent.ACTION_USER_SWITCHED) + addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE) + addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE) + } + const val TAG = "PrivacyItemController" + } + + @VisibleForTesting + internal var privacyList = emptyList<PrivacyItem>() + @Synchronized get() = field.toList() // Returns a shallow copy of the list + @Synchronized set + + private fun isPermissionsHubEnabled(): Boolean { + return deviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, + SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, false) + } + + private var currentUserIds = emptyList<Int>() + private var listening = false + private val callbacks = mutableListOf<WeakReference<Callback>>() + private val internalUiExecutor = MyExecutor(uiExecutor) + + private val notifyChanges = Runnable { + val list = privacyList + callbacks.forEach { it.get()?.onPrivacyItemsChanged(list) } + } + + private val updateListAndNotifyChanges = Runnable { + updatePrivacyList() + uiExecutor.execute(notifyChanges) + } + + var indicatorsAvailable = isPermissionsHubEnabled() + private set + @VisibleForTesting + internal val devicePropertiesChangedListener = + object : DeviceConfig.OnPropertiesChangedListener { + override fun onPropertiesChanged(properties: DeviceConfig.Properties) { + if (DeviceConfig.NAMESPACE_PRIVACY.equals(properties.getNamespace()) && + properties.getKeyset().contains( + SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED)) { + val flag = properties.getBoolean( + SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, false) + if (indicatorsAvailable != flag) { + // This is happening already in the UI executor, so we can iterate in the + indicatorsAvailable = flag + callbacks.forEach { it.get()?.onFlagChanged(flag) } + } + + internalUiExecutor.updateListeningState() + } + } + } + + private val cb = object : AppOpsController.Callback { + override fun onActiveStateChanged( + code: Int, + uid: Int, + packageName: String, + active: Boolean + ) { + val userId = UserHandle.getUserId(uid) + if (userId in currentUserIds) { + update(false) + } + } + } + + @VisibleForTesting + internal var userSwitcherReceiver = Receiver() + set(value) { + unregisterReceiver() + field = value + if (listening) registerReceiver() + } + + init { + deviceConfigProxy.addOnPropertiesChangedListener( + DeviceConfig.NAMESPACE_PRIVACY, + uiExecutor, + devicePropertiesChangedListener) + dumpManager.registerDumpable(TAG, this) + } + + private fun unregisterReceiver() { + broadcastDispatcher.unregisterReceiver(userSwitcherReceiver) + } + + private fun registerReceiver() { + broadcastDispatcher.registerReceiver(userSwitcherReceiver, intentFilter, + null /* handler */, UserHandle.ALL) + } + + private fun update(updateUsers: Boolean) { + bgExecutor.execute { + if (updateUsers) { + val currentUser = ActivityManager.getCurrentUser() + currentUserIds = userManager.getProfiles(currentUser).map { it.id } + } + updateListAndNotifyChanges.run() + } + } + + /** + * Updates listening status based on whether there are callbacks and the indicators are enabled + * + * This is only called from private (add/remove)Callback and from the config listener, all in + * main thread. + */ + private fun setListeningState() { + val listen = !callbacks.isEmpty() and indicatorsAvailable + if (listening == listen) return + listening = listen + if (listening) { + appOpsController.addCallback(OPS, cb) + registerReceiver() + update(true) + } else { + appOpsController.removeCallback(OPS, cb) + unregisterReceiver() + // Make sure that we remove all indicators and notify listeners if we are not + // listening anymore due to indicators being disabled + update(false) + } + } + + private fun addCallback(callback: WeakReference<Callback>) { + callbacks.add(callback) + if (callbacks.isNotEmpty() && !listening) { + internalUiExecutor.updateListeningState() + } + // Notify this callback if we didn't set to listening + else if (listening) { + internalUiExecutor.execute(NotifyChangesToCallback(callback.get(), privacyList)) + } + } + + private fun removeCallback(callback: WeakReference<Callback>) { + // Removes also if the callback is null + callbacks.removeIf { it.get()?.equals(callback.get()) ?: true } + if (callbacks.isEmpty()) { + internalUiExecutor.updateListeningState() + } + } + + fun addCallback(callback: Callback) { + addCallback(WeakReference(callback)) + } + + fun removeCallback(callback: Callback) { + removeCallback(WeakReference(callback)) + } + + private fun updatePrivacyList() { + if (!listening) { + privacyList = emptyList() + return + } + val list = currentUserIds.flatMap { appOpsController.getActiveAppOpsForUser(it) } + .mapNotNull { toPrivacyItem(it) }.distinct() + privacyList = list + } + + private fun toPrivacyItem(appOpItem: AppOpItem): PrivacyItem? { + val type: PrivacyType = when (appOpItem.code) { + AppOpsManager.OP_CAMERA -> PrivacyType.TYPE_CAMERA + AppOpsManager.OP_COARSE_LOCATION -> PrivacyType.TYPE_LOCATION + AppOpsManager.OP_FINE_LOCATION -> PrivacyType.TYPE_LOCATION + AppOpsManager.OP_RECORD_AUDIO -> PrivacyType.TYPE_MICROPHONE + else -> return null + } + val app = PrivacyApplication(appOpItem.packageName, appOpItem.uid) + return PrivacyItem(type, app) + } + + interface Callback { + fun onPrivacyItemsChanged(privacyItems: List<PrivacyItem>) + @JvmDefault + fun onFlagChanged(flag: Boolean) {} + } + + internal inner class Receiver : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + if (intentFilter.hasAction(intent.action)) { + update(true) + } + } + } + + private class NotifyChangesToCallback( + private val callback: Callback?, + private val list: List<PrivacyItem> + ) : Runnable { + override fun run() { + callback?.onPrivacyItemsChanged(list) + } + } + + override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) { + pw.println("PrivacyItemController state:") + pw.println(" Listening: $listening") + pw.println(" Current user ids: $currentUserIds") + pw.println(" Privacy Items:") + privacyList.forEach { + pw.print(" ") + pw.println(it.toString()) + } + pw.println(" Callbacks:") + callbacks.forEach { + it.get()?.let { + pw.print(" ") + pw.println(it.toString()) + } + } + } + + private inner class MyExecutor( + private val delegate: DelayableExecutor + ) : Executor { + + private var listeningCanceller: Runnable? = null + + override fun execute(command: Runnable) { + delegate.execute(command) + } + + fun updateListeningState() { + listeningCanceller?.run() + listeningCanceller = delegate.executeDelayed({ setListeningState() }, 0L) + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java index 2c76d70fb3cc..f8655cc44d2a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java @@ -10,10 +10,18 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; +import androidx.annotation.NonNull; + +import com.android.settingslib.Utils; import com.android.systemui.R; import java.util.ArrayList; +/** + * Page indicator for using with pageable layouts + * + * Supports {@code android.R.attr.tint}. If missing, it will use the current accent color. + */ public class PageIndicator extends ViewGroup { private static final String TAG = "PageIndicator"; @@ -31,12 +39,22 @@ public class PageIndicator extends ViewGroup { private final int mPageIndicatorWidth; private final int mPageIndicatorHeight; private final int mPageDotWidth; + private @NonNull ColorStateList mTint; private int mPosition = -1; private boolean mAnimating; public PageIndicator(Context context, AttributeSet attrs) { super(context, attrs); + + TypedArray array = context.obtainStyledAttributes(attrs, new int[]{android.R.attr.tint}); + if (array.hasValue(0)) { + mTint = array.getColorStateList(0); + } else { + mTint = Utils.getColorAccent(context); + } + array.recycle(); + mPageIndicatorWidth = (int) mContext.getResources().getDimension(R.dimen.qs_page_indicator_width); mPageIndicatorHeight = @@ -45,15 +63,6 @@ public class PageIndicator extends ViewGroup { } public void setNumPages(int numPages) { - TypedArray array = getContext().obtainStyledAttributes( - new int[]{android.R.attr.colorControlActivated}); - int color = array.getColor(0, 0); - array.recycle(); - setNumPages(numPages, color); - } - - /** Overload of setNumPages that allows the indicator color to be specified.*/ - public void setNumPages(int numPages, int color) { setVisibility(numPages > 1 ? View.VISIBLE : View.GONE); if (numPages == getChildCount()) { return; @@ -67,13 +76,41 @@ public class PageIndicator extends ViewGroup { while (numPages > getChildCount()) { ImageView v = new ImageView(mContext); v.setImageResource(R.drawable.minor_a_b); - v.setImageTintList(ColorStateList.valueOf(color)); + v.setImageTintList(mTint); addView(v, new LayoutParams(mPageIndicatorWidth, mPageIndicatorHeight)); } // Refresh state. setIndex(mPosition >> 1); } + /** + * @return the current tint list for this view. + */ + @NonNull + public ColorStateList getTintList() { + return mTint; + } + + /** + * Set the color for this view. + * <br> + * Calling this will change the color of the current view and any new dots that are added to it. + * @param color the new color + */ + public void setTintList(@NonNull ColorStateList color) { + if (color.equals(mTint)) { + return; + } + mTint = color; + final int N = getChildCount(); + for (int i = 0; i < N; i++) { + View v = getChildAt(i); + if (v instanceof ImageView) { + ((ImageView) v).setImageTintList(mTint); + } + } + } + public void setLocation(float location) { int index = (int) location; setContentDescription(getContext().getString(R.string.accessibility_quick_settings_page, diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java index 3eed8ad89075..560998b5d1d8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java @@ -508,7 +508,6 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { mPageListener.onPageChanged(isLayoutRtl() ? position == mPages.size() - 1 : position == 0); } - } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java index 1e8c4d86da36..290ab8594fc0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java @@ -20,7 +20,6 @@ import com.android.internal.logging.InstanceId; import com.android.internal.logging.UiEventLogger; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.qs.external.TileServices; -import com.android.systemui.qs.logging.QSLogger; import java.util.Collection; @@ -31,7 +30,6 @@ public interface QSHost { void openPanels(); Context getContext(); Context getUserContext(); - QSLogger getQSLogger(); UiEventLogger getUiEventLogger(); Collection<QSTile> getTiles(); void addCallback(Callback callback); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java index 1f3967c03a41..3b16a4ec1c38 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java @@ -179,10 +179,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D onTuningChanged(TILES_SETTING, value); } - public QSLogger getQSLogger() { - return mQSLogger; - } - @Override public UiEventLogger getUiEventLogger() { return mUiEventLogger; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index b07b1a9561ff..2dc82dd853d4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -31,6 +31,7 @@ import android.graphics.Color; import android.graphics.Rect; import android.media.AudioManager; import android.os.Handler; +import android.os.Looper; import android.provider.AlarmClock; import android.provider.Settings; import android.service.notification.ZenModeConfig; @@ -46,7 +47,9 @@ import android.view.ViewGroup; import android.view.WindowInsets; import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.RelativeLayout; +import android.widget.Space; import android.widget.TextView; import androidx.annotation.NonNull; @@ -55,6 +58,7 @@ import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LifecycleRegistry; +import com.android.internal.logging.UiEventLogger; import com.android.settingslib.Utils; import com.android.systemui.BatteryMeterView; import com.android.systemui.DualToneHandler; @@ -63,6 +67,10 @@ import com.android.systemui.R; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; +import com.android.systemui.privacy.OngoingPrivacyChip; +import com.android.systemui.privacy.PrivacyChipEvent; +import com.android.systemui.privacy.PrivacyItem; +import com.android.systemui.privacy.PrivacyItemController; import com.android.systemui.qs.QSDetail.Callback; import com.android.systemui.qs.carrier.QSCarrierGroup; import com.android.systemui.statusbar.CommandQueue; @@ -101,7 +109,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements private static final int TOOLTIP_NOT_YET_SHOWN_COUNT = 0; public static final int MAX_TOOLTIP_SHOWN_COUNT = 2; - private final Handler mHandler = new Handler(); private final NextAlarmController mAlarmController; private final ZenModeController mZenController; private final StatusBarIconController mStatusBarIconController; @@ -140,9 +147,14 @@ public class QuickStatusBarHeader extends RelativeLayout implements private View mRingerContainer; private Clock mClockView; private DateView mDateView; + private OngoingPrivacyChip mPrivacyChip; + private Space mSpace; private BatteryMeterView mBatteryRemainingIcon; private RingerModeTracker mRingerModeTracker; + private boolean mPermissionsHubEnabled; + private PrivacyItemController mPrivacyItemController; + private final UiEventLogger mUiEventLogger; // Used for RingerModeTracker private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this); @@ -156,22 +168,43 @@ public class QuickStatusBarHeader extends RelativeLayout implements private int mCutOutPaddingRight; private float mExpandedHeaderAlpha = 1.0f; private float mKeyguardExpansionFraction; + private boolean mPrivacyChipLogged = false; + + private PrivacyItemController.Callback mPICCallback = new PrivacyItemController.Callback() { + @Override + public void onPrivacyItemsChanged(List<PrivacyItem> privacyItems) { + mPrivacyChip.setPrivacyList(privacyItems); + setChipVisibility(!privacyItems.isEmpty()); + } + + @Override + public void onFlagChanged(boolean flag) { + if (mPermissionsHubEnabled != flag) { + StatusIconContainer iconContainer = requireViewById(R.id.statusIcons); + iconContainer.setIgnoredSlots(getIgnoredIconSlots()); + setChipVisibility(!mPrivacyChip.getPrivacyList().isEmpty()); + } + } + }; @Inject public QuickStatusBarHeader(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs, NextAlarmController nextAlarmController, ZenModeController zenModeController, StatusBarIconController statusBarIconController, - ActivityStarter activityStarter, - CommandQueue commandQueue, RingerModeTracker ringerModeTracker) { + ActivityStarter activityStarter, PrivacyItemController privacyItemController, + CommandQueue commandQueue, RingerModeTracker ringerModeTracker, + UiEventLogger uiEventLogger) { super(context, attrs); mAlarmController = nextAlarmController; mZenController = zenModeController; mStatusBarIconController = statusBarIconController; mActivityStarter = activityStarter; + mPrivacyItemController = privacyItemController; mDualToneHandler = new DualToneHandler( new ContextThemeWrapper(context, R.style.QSHeaderTheme)); mCommandQueue = commandQueue; mRingerModeTracker = ringerModeTracker; + mUiEventLogger = uiEventLogger; } @Override @@ -198,8 +231,11 @@ public class QuickStatusBarHeader extends RelativeLayout implements mRingerModeTextView = findViewById(R.id.ringer_mode_text); mRingerContainer = findViewById(R.id.ringer_container); mRingerContainer.setOnClickListener(this::onClick); + mPrivacyChip = findViewById(R.id.privacy_chip); + mPrivacyChip.setOnClickListener(this::onClick); mCarrierGroup = findViewById(R.id.carrier_group); + updateResources(); Rect tintArea = new Rect(0, 0, 0, 0); @@ -219,6 +255,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements mClockView = findViewById(R.id.clock); mClockView.setOnClickListener(this); mDateView = findViewById(R.id.date); + mSpace = findViewById(R.id.space); // Tint for the battery icons are handled in setupHost() mBatteryRemainingIcon = findViewById(R.id.batteryRemainingIcon); @@ -229,6 +266,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE); mRingerModeTextView.setSelected(true); mNextAlarmTextView.setSelected(true); + + mPermissionsHubEnabled = mPrivacyItemController.getIndicatorsAvailable(); } public QuickQSPanel getHeaderQsPanel() { @@ -241,6 +280,10 @@ public class QuickStatusBarHeader extends RelativeLayout implements com.android.internal.R.string.status_bar_camera)); ignored.add(mContext.getResources().getString( com.android.internal.R.string.status_bar_microphone)); + if (mPermissionsHubEnabled) { + ignored.add(mContext.getResources().getString( + com.android.internal.R.string.status_bar_location)); + } return ignored; } @@ -256,6 +299,20 @@ public class QuickStatusBarHeader extends RelativeLayout implements } } + private void setChipVisibility(boolean chipVisible) { + if (chipVisible && mPermissionsHubEnabled) { + mPrivacyChip.setVisibility(View.VISIBLE); + // Makes sure that the chip is logged as viewed at most once each time QS is opened + // mListening makes sure that the callback didn't return after the user closed QS + if (!mPrivacyChipLogged && mListening) { + mPrivacyChipLogged = true; + mUiEventLogger.log(PrivacyChipEvent.ONGOING_INDICATORS_CHIP_VIEW); + } + } else { + mPrivacyChip.setVisibility(View.GONE); + } + } + private boolean updateRingerStatus() { boolean isOriginalVisible = mRingerModeTextView.getVisibility() == View.VISIBLE; CharSequence originalRingerText = mRingerModeTextView.getText(); @@ -363,6 +420,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements updateStatusIconAlphaAnimator(); updateHeaderTextContainerAlphaAnimator(); + updatePrivacyChipAlphaAnimator(); } private void updateStatusIconAlphaAnimator() { @@ -377,6 +435,12 @@ public class QuickStatusBarHeader extends RelativeLayout implements .build(); } + private void updatePrivacyChipAlphaAnimator() { + mPrivacyChipAlphaAnimator = new TouchAnimator.Builder() + .addFloat(mPrivacyChip, "alpha", 1, 0, 1) + .build(); + } + public void setExpanded(boolean expanded) { if (mExpanded == expanded) return; mExpanded = expanded; @@ -415,6 +479,10 @@ public class QuickStatusBarHeader extends RelativeLayout implements mHeaderTextContainerView.setVisibility(INVISIBLE); } } + if (mPrivacyChipAlphaAnimator != null) { + mPrivacyChip.setExpanded(expansionFraction > 0.5); + mPrivacyChipAlphaAnimator.setPosition(keyguardExpansionFraction); + } if (expansionFraction < 1 && expansionFraction > 0.99) { if (mHeaderQsPanel.switchTileLayout()) { updateResources(); @@ -453,6 +521,31 @@ public class QuickStatusBarHeader extends RelativeLayout implements Pair<Integer, Integer> padding = StatusBarWindowView.paddingNeededForCutoutAndRoundedCorner( cutout, cornerCutoutPadding, -1); + if (padding == null) { + mSystemIconsView.setPaddingRelative( + getResources().getDimensionPixelSize(R.dimen.status_bar_padding_start), 0, + getResources().getDimensionPixelSize(R.dimen.status_bar_padding_end), 0); + } else { + mSystemIconsView.setPadding(padding.first, 0, padding.second, 0); + + } + LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mSpace.getLayoutParams(); + boolean cornerCutout = cornerCutoutPadding != null + && (cornerCutoutPadding.first == 0 || cornerCutoutPadding.second == 0); + if (cutout != null) { + Rect topCutout = cutout.getBoundingRectTop(); + if (topCutout.isEmpty() || cornerCutout) { + mHasTopCutout = false; + lp.width = 0; + mSpace.setVisibility(View.GONE); + } else { + mHasTopCutout = true; + lp.width = topCutout.width(); + mSpace.setVisibility(View.VISIBLE); + } + } + mSpace.setLayoutParams(lp); + setChipVisibility(mPrivacyChip.getVisibility() == View.VISIBLE); mCutOutPaddingLeft = padding.first; mCutOutPaddingRight = padding.second; mWaterfallTopInset = cutout == null ? 0 : cutout.getWaterfallInsets().top; @@ -513,10 +606,15 @@ public class QuickStatusBarHeader extends RelativeLayout implements mZenController.addCallback(this); mAlarmController.addCallback(this); mLifecycle.setCurrentState(Lifecycle.State.RESUMED); + // Get the most up to date info + mPermissionsHubEnabled = mPrivacyItemController.getIndicatorsAvailable(); + mPrivacyItemController.addCallback(mPICCallback); } else { mZenController.removeCallback(this); mAlarmController.removeCallback(this); mLifecycle.setCurrentState(Lifecycle.State.CREATED); + mPrivacyItemController.removeCallback(mPICCallback); + mPrivacyChipLogged = false; } } @@ -534,6 +632,15 @@ public class QuickStatusBarHeader extends RelativeLayout implements mActivityStarter.postStartActivityDismissingKeyguard(new Intent( AlarmClock.ACTION_SHOW_ALARMS), 0); } + } else if (v == mPrivacyChip) { + // If the privacy chip is visible, it means there were some indicators + Handler mUiHandler = new Handler(Looper.getMainLooper()); + mUiEventLogger.log(PrivacyChipEvent.ONGOING_INDICATORS_CHIP_CLICK); + mUiHandler.post(() -> { + mActivityStarter.postStartActivityDismissingKeyguard( + new Intent(Intent.ACTION_REVIEW_ONGOING_PERMISSION_USAGE), 0); + mHost.collapsePanels(); + }); } else if (v == mRingerContainer && mRingerContainer.isVisibleToUser()) { mActivityStarter.postStartActivityDismissingKeyguard(new Intent( Settings.ACTION_SOUND_SETTINGS), 0); 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 30e0a766de37..19c7b6cefc5d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java @@ -29,7 +29,9 @@ import android.graphics.drawable.Drawable; import android.metrics.LogMaker; import android.net.Uri; import android.os.Binder; +import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.os.RemoteException; import android.provider.Settings; import android.service.quicksettings.IQSTileService; @@ -42,16 +44,27 @@ import android.view.IWindowManager; import android.view.WindowManagerGlobal; import android.widget.Switch; +import androidx.annotation.NonNull; + +import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.Dependency; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile.State; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import java.util.Objects; +import javax.inject.Inject; + +import dagger.Lazy; + public class CustomTile extends QSTileImpl<State> implements TileChangeListener { public static final String PREFIX = "custom("; @@ -79,8 +92,19 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener private boolean mIsTokenGranted; private boolean mIsShowingDialog; - private CustomTile(QSHost host, String action, Context userContext) { - super(host); + private CustomTile( + QSHost host, + Looper backgroundLooper, + Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + String action, + Context userContext + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); mWindowManager = WindowManagerGlobal.getWindowManagerService(); mComponent = ComponentName.unflattenFromString(action); mTile = new Tile(); @@ -397,7 +421,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener return ComponentName.unflattenFromString(action); } - public static CustomTile create(QSHost host, String spec, Context userContext) { + private static String getAction(String spec) { if (spec == null || !spec.startsWith(PREFIX) || !spec.endsWith(")")) { throw new IllegalArgumentException("Bad custom tile spec: " + spec); } @@ -405,6 +429,81 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener if (action.isEmpty()) { throw new IllegalArgumentException("Empty custom tile spec action"); } - return new CustomTile(host, action, userContext); + return action; + } + + /** + * Create a {@link CustomTile} for a given spec and user. + * + * @param builder including injected common dependencies. + * @param spec as provided by {@link CustomTile#toSpec} + * @param userContext context for the user that is creating this tile. + * @return a new {@link CustomTile} + */ + public static CustomTile create(Builder builder, String spec, Context userContext) { + return builder + .setSpec(spec) + .setUserContext(userContext) + .build(); + } + + public static class Builder { + final Lazy<QSHost> mQSHostLazy; + final Looper mBackgroundLooper; + final Handler mMainHandler; + final MetricsLogger mMetricsLogger; + final StatusBarStateController mStatusBarStateController; + final ActivityStarter mActivityStarter; + final QSLogger mQSLogger; + + Context mUserContext; + String mSpec = ""; + + @Inject + public Builder( + Lazy<QSHost> hostLazy, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger + ) { + mQSHostLazy = hostLazy; + mBackgroundLooper = backgroundLooper; + mMainHandler = mainHandler; + mMetricsLogger = metricsLogger; + mStatusBarStateController = statusBarStateController; + mActivityStarter = activityStarter; + mQSLogger = qsLogger; + } + + Builder setSpec(@NonNull String spec) { + mSpec = spec; + return this; + } + + Builder setUserContext(@NonNull Context userContext) { + mUserContext = userContext; + return this; + } + + CustomTile build() { + if (mUserContext == null) { + throw new NullPointerException("UserContext cannot be null"); + } + String action = getAction(mSpec); + return new CustomTile( + mQSHostLazy.get(), + mBackgroundLooper, + mMainHandler, + mMetricsLogger, + mStatusBarStateController, + mActivityStarter, + mQSLogger, + action, + mUserContext + ); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java index c182a58a28c4..69a6fe1075c2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java @@ -80,9 +80,12 @@ public class QSFactoryImpl implements QSFactory { private final Provider<ScreenRecordTile> mScreenRecordTileProvider; private final Lazy<QSHost> mQsHostLazy; + private final Provider<CustomTile.Builder> mCustomTileBuilderProvider; @Inject - public QSFactoryImpl(Lazy<QSHost> qsHostLazy, + public QSFactoryImpl( + Lazy<QSHost> qsHostLazy, + Provider<CustomTile.Builder> customTileBuilderProvider, Provider<WifiTile> wifiTileProvider, Provider<BluetoothTile> bluetoothTileProvider, Provider<CellularTile> cellularTileProvider, @@ -104,6 +107,8 @@ public class QSFactoryImpl implements QSFactory { Provider<UiModeNightTile> uiModeNightTileProvider, Provider<ScreenRecordTile> screenRecordTileProvider) { mQsHostLazy = qsHostLazy; + mCustomTileBuilderProvider = customTileBuilderProvider; + mWifiTileProvider = wifiTileProvider; mBluetoothTileProvider = bluetoothTileProvider; mCellularTileProvider = cellularTileProvider; @@ -179,8 +184,8 @@ public class QSFactoryImpl implements QSFactory { // Custom tiles if (tileSpec.startsWith(CustomTile.PREFIX)) { - return CustomTile.create(mQsHostLazy.get(), tileSpec, - mQsHostLazy.get().getUserContext()); + return CustomTile.create( + mCustomTileBuilderProvider.get(), tileSpec, mQsHostLazy.get().getUserContext()); } // Debug tiles. diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java index d11079294a85..8c485a6a950f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java @@ -55,7 +55,6 @@ import com.android.internal.logging.UiEventLogger; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.Utils; -import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.Prefs; import com.android.systemui.plugins.ActivityStarter; @@ -93,12 +92,12 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy protected final QSHost mHost; protected final Context mContext; // @NonFinalForTesting - protected H mHandler = new H(Dependency.get(Dependency.BG_LOOPER)); - protected final Handler mUiHandler = new Handler(Looper.getMainLooper()); + protected final H mHandler; + protected final Handler mUiHandler; private final ArraySet<Object> mListeners = new ArraySet<>(); - private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class); - private final StatusBarStateController - mStatusBarStateController = Dependency.get(StatusBarStateController.class); + private final MetricsLogger mMetricsLogger; + private final StatusBarStateController mStatusBarStateController; + protected final ActivityStarter mActivityStarter; private final UiEventLogger mUiEventLogger; private final QSLogger mQSLogger; @@ -151,14 +150,29 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy */ abstract public int getMetricsCategory(); - protected QSTileImpl(QSHost host) { + protected QSTileImpl( + QSHost host, + Looper backgroundLooper, + Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger + ) { mHost = host; mContext = host.getContext(); mInstanceId = host.getNewInstanceId(); + mUiEventLogger = host.getUiEventLogger(); + + mUiHandler = mainHandler; + mHandler = new H(backgroundLooper); + mQSLogger = qsLogger; + mMetricsLogger = metricsLogger; + mStatusBarStateController = statusBarStateController; + mActivityStarter = activityStarter; + mState = newTileState(); mTmpState = newTileState(); - mQSLogger = host.getQSLogger(); - mUiEventLogger = host.getUiEventLogger(); } protected final void resetStates() { @@ -358,8 +372,7 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy * {@link QSTileImpl#getLongClickIntent} */ protected void handleLongClick() { - Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard( - getLongClickIntent(), 0); + mActivityStarter.postStartActivityDismissingKeyguard(getLongClickIntent(), 0); } /** @@ -533,7 +546,8 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy private static final int REMOVE_CALLBACKS = 11; private static final int REMOVE_CALLBACK = 12; private static final int SET_LISTENING = 13; - private static final int STALE = 14; + @VisibleForTesting + protected static final int STALE = 14; @VisibleForTesting protected H(Looper looper) { @@ -558,8 +572,7 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy if (mState.disabledByPolicy) { Intent intent = RestrictedLockUtils.getShowAdminSupportDetailsIntent( mContext, mEnforcedAdmin); - Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard( - intent, 0); + mActivityStarter.postStartActivityDismissingKeyguard(intent, 0); } else { handleClick(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java index b24fdbfc562f..b8485907c519 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java @@ -21,6 +21,8 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; +import android.os.Handler; +import android.os.Looper; import android.os.UserManager; import android.provider.Settings; import android.provider.Settings.Global; @@ -33,33 +35,50 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile.BooleanState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.GlobalSetting; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import javax.inject.Inject; +import dagger.Lazy; + /** Quick settings tile: Airplane mode **/ public class AirplaneModeTile extends QSTileImpl<BooleanState> { private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_airplane); private final GlobalSetting mSetting; - private final ActivityStarter mActivityStarter; private final BroadcastDispatcher mBroadcastDispatcher; + private final Lazy<ConnectivityManager> mLazyConnectivityManager; private boolean mListening; @Inject - public AirplaneModeTile(QSHost host, ActivityStarter activityStarter, - BroadcastDispatcher broadcastDispatcher) { - super(host); - mActivityStarter = activityStarter; + public AirplaneModeTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + BroadcastDispatcher broadcastDispatcher, + Lazy<ConnectivityManager> lazyConnectivityManager + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); mBroadcastDispatcher = broadcastDispatcher; + mLazyConnectivityManager = lazyConnectivityManager; mSetting = new GlobalSetting(mContext, mHandler, Global.AIRPLANE_MODE_ON) { @Override protected void handleValueChanged(int value) { + // mHandler is the background handler so calling this is OK handleRefreshState(value); } }; @@ -83,9 +102,7 @@ public class AirplaneModeTile extends QSTileImpl<BooleanState> { } private void setEnabled(boolean enabled) { - final ConnectivityManager mgr = - (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); - mgr.setAirplaneMode(enabled); + mLazyConnectivityManager.get().setAirplaneMode(enabled); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java index f2495048bf26..eb794a8b4378 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java @@ -16,16 +16,24 @@ package com.android.systemui.qs.tiles; import android.content.Intent; +import android.os.Handler; +import android.os.Looper; import android.provider.Settings.Secure; import android.service.quicksettings.Tile; import android.widget.Switch; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile.BooleanState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.SecureSetting; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.BatteryController; @@ -46,8 +54,18 @@ public class BatterySaverTile extends QSTileImpl<BooleanState> implements private Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_battery_saver); @Inject - public BatterySaverTile(QSHost host, BatteryController batteryController) { - super(host); + public BatterySaverTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + BatteryController batteryController + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); mBatteryController = batteryController; mBatteryController.observe(getLifecycle(), this); int currentUser = host.getUserContext().getUserId(); @@ -55,6 +73,7 @@ public class BatterySaverTile extends QSTileImpl<BooleanState> implements currentUser) { @Override protected void handleValueChanged(int value, boolean observedChange) { + // mHandler is the background handler so calling this is OK handleRefreshState(null); } }; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java index c67ece060b02..1424244b6729 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -24,6 +24,8 @@ import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.Intent; import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.Looper; import android.provider.Settings; import android.service.quicksettings.Tile; import android.text.TextUtils; @@ -37,12 +39,16 @@ import com.android.settingslib.Utils; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.graph.BluetoothDeviceLayerDrawable; import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSTile.BooleanState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSDetailItems; import com.android.systemui.qs.QSDetailItems.Item; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.BluetoothController; @@ -58,15 +64,21 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { private final BluetoothController mController; private final BluetoothDetailAdapter mDetailAdapter; - private final ActivityStarter mActivityStarter; @Inject - public BluetoothTile(QSHost host, - BluetoothController bluetoothController, - ActivityStarter activityStarter) { - super(host); + public BluetoothTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + BluetoothController bluetoothController + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); mController = bluetoothController; - mActivityStarter = activityStarter; mDetailAdapter = (BluetoothDetailAdapter) createDetailAdapter(); mController.observe(getLifecycle(), mCallback); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java index 4b53ae2c6379..56b939df383f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java @@ -22,6 +22,8 @@ import android.app.Dialog; import android.content.Context; import android.content.Intent; import android.media.MediaRouter.RouteInfo; +import android.os.Handler; +import android.os.Looper; import android.provider.Settings; import android.service.quicksettings.Tile; import android.util.Log; @@ -35,12 +37,16 @@ import com.android.internal.app.MediaRouteDialogPresenter; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSTile.BooleanState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSDetailItems; import com.android.systemui.qs.QSDetailItems.Item; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.CastController; @@ -64,20 +70,28 @@ public class CastTile extends QSTileImpl<BooleanState> { private final KeyguardStateController mKeyguard; private final NetworkController mNetworkController; private final Callback mCallback = new Callback(); - private final ActivityStarter mActivityStarter; private Dialog mDialog; private boolean mWifiConnected; @Inject - public CastTile(QSHost host, CastController castController, - KeyguardStateController keyguardStateController, NetworkController networkController, - ActivityStarter activityStarter) { - super(host); + public CastTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + CastController castController, + KeyguardStateController keyguardStateController, + NetworkController networkController + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); mController = castController; mDetailAdapter = new CastDetailAdapter(); mKeyguard = keyguardStateController; mNetworkController = networkController; - mActivityStarter = activityStarter; mController.observe(this, mCallback); mKeyguard.observe(this, mCallback); mNetworkController.observe(this, mSignalCallback); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java index bc03ca617dea..b4f1fe72f944 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -23,6 +23,8 @@ import android.app.AlertDialog.Builder; import android.content.Context; import android.content.Intent; import android.content.res.Resources; +import android.os.Handler; +import android.os.Looper; import android.provider.Settings; import android.service.quicksettings.Tile; import android.telephony.SubscriptionManager; @@ -39,12 +41,16 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.net.DataUsageController; import com.android.systemui.Prefs; import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSIconView; import com.android.systemui.plugins.qs.QSTile.SignalState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.SignalTileView; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.NetworkController; @@ -62,14 +68,21 @@ public class CellularTile extends QSTileImpl<SignalState> { private final CellularDetailAdapter mDetailAdapter; private final CellSignalCallback mSignalCallback = new CellSignalCallback(); - private final ActivityStarter mActivityStarter; @Inject - public CellularTile(QSHost host, NetworkController networkController, - ActivityStarter activityStarter) { - super(host); + public CellularTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + NetworkController networkController + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); mController = networkController; - mActivityStarter = activityStarter; mDataController = mController.getMobileDataController(); mDetailAdapter = new CellularDetailAdapter(); mController.observe(getLifecycle(), mSignalCallback); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java index 9c0030d528e7..347ef45824c9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java @@ -17,17 +17,26 @@ package com.android.systemui.qs.tiles; import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.provider.Settings; import android.provider.Settings.Secure; import android.service.quicksettings.Tile; import android.widget.Switch; +import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; import com.android.systemui.R.drawable; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile.BooleanState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.SecureSetting; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import javax.inject.Inject; @@ -35,19 +44,33 @@ import javax.inject.Inject; /** Quick settings tile: Invert colors **/ public class ColorInversionTile extends QSTileImpl<BooleanState> { + private static final String EXTRA_FRAGMENT_ARGS_KEY = ":settings:fragment_args_key"; + private static final String EXTRA_SHOW_FRAGMENT_ARGS_KEY = ":settings:show_fragment_args"; + private static final String COLOR_INVERSION_PREFERENCE_KEY = "toggle_inversion_preference"; + private final Icon mIcon = ResourceIcon.get(drawable.ic_invert_colors); private final SecureSetting mSetting; private boolean mListening; @Inject - public ColorInversionTile(QSHost host) { - super(host); - - mSetting = new SecureSetting(mContext, mHandler, + public ColorInversionTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); + + mSetting = new SecureSetting(mContext, mainHandler, Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED) { @Override protected void handleValueChanged(int value, boolean observedChange) { + // mHandler is the background handler so calling this is OK handleRefreshState(value); } }; @@ -78,7 +101,11 @@ public class ColorInversionTile extends QSTileImpl<BooleanState> { @Override public Intent getLongClickIntent() { - return new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); + Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); + Bundle bundle = new Bundle(); + bundle.putString(EXTRA_FRAGMENT_ARGS_KEY, COLOR_INVERSION_PREFERENCE_KEY); + intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGS_KEY, bundle); + return intent; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java index 7ae8fbc928a6..85f12458c33a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java @@ -16,19 +16,26 @@ package com.android.systemui.qs.tiles; import android.content.DialogInterface.OnClickListener; import android.content.Intent; +import android.os.Handler; +import android.os.Looper; import android.provider.Settings; import android.service.quicksettings.Tile; import android.widget.Switch; +import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.Prefs; import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile.BooleanState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.DataSaverController; -import com.android.systemui.statusbar.policy.NetworkController; import javax.inject.Inject; @@ -38,9 +45,19 @@ public class DataSaverTile extends QSTileImpl<BooleanState> implements private final DataSaverController mDataSaverController; @Inject - public DataSaverTile(QSHost host, NetworkController networkController) { - super(host); - mDataSaverController = networkController.getDataSaverController(); + public DataSaverTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + DataSaverController dataSaverController + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); + mDataSaverController = dataSaverController; mDataSaverController.observe(getLifecycle(), this); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java index 9f7b84aa62c1..ec8b1435e201 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java @@ -30,6 +30,8 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.net.Uri; +import android.os.Handler; +import android.os.Looper; import android.os.UserManager; import android.provider.Settings; import android.provider.Settings.Global; @@ -53,11 +55,14 @@ import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.SysUIToast; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSTile.BooleanState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.ZenModeController; @@ -79,7 +84,6 @@ public class DndTile extends QSTileImpl<BooleanState> { private final ZenModeController mController; private final DndDetailAdapter mDetailAdapter; - private final ActivityStarter mActivityStarter; private final SharedPreferences mSharedPreferences; private final BroadcastDispatcher mBroadcastDispatcher; @@ -88,12 +92,21 @@ public class DndTile extends QSTileImpl<BooleanState> { private boolean mReceiverRegistered; @Inject - public DndTile(QSHost host, ZenModeController zenModeController, - ActivityStarter activityStarter, BroadcastDispatcher broadcastDispatcher, - @Main SharedPreferences sharedPreferences) { - super(host); + public DndTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + ZenModeController zenModeController, + BroadcastDispatcher broadcastDispatcher, + @Main SharedPreferences sharedPreferences + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); mController = zenModeController; - mActivityStarter = activityStarter; mSharedPreferences = sharedPreferences; mDetailAdapter = new DndDetailAdapter(); mBroadcastDispatcher = broadcastDispatcher; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java index 27ccd7cab226..cd45082458f2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java @@ -18,14 +18,22 @@ package com.android.systemui.qs.tiles; import android.app.ActivityManager; import android.content.Intent; +import android.os.Handler; +import android.os.Looper; import android.provider.MediaStore; import android.service.quicksettings.Tile; import android.widget.Switch; +import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile.BooleanState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.FlashlightController; @@ -39,8 +47,18 @@ public class FlashlightTile extends QSTileImpl<BooleanState> implements private final FlashlightController mFlashlightController; @Inject - public FlashlightTile(QSHost host, FlashlightController flashlightController) { - super(host); + public FlashlightTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + FlashlightController flashlightController + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); mFlashlightController = flashlightController; mFlashlightController.observe(getLifecycle(), this); } 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 1ab77f3f7524..a45d94ace425 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java @@ -18,16 +18,24 @@ package com.android.systemui.qs.tiles; import android.annotation.Nullable; import android.content.Intent; +import android.os.Handler; +import android.os.Looper; import android.os.UserManager; import android.provider.Settings; import android.service.quicksettings.Tile; import android.util.Log; import android.widget.Switch; +import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile.BooleanState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.DataSaverController; import com.android.systemui.statusbar.policy.HotspotController; @@ -45,9 +53,19 @@ public class HotspotTile extends QSTileImpl<BooleanState> { private boolean mListening; @Inject - public HotspotTile(QSHost host, HotspotController hotspotController, - DataSaverController dataSaverController) { - super(host); + public HotspotTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + HotspotController hotspotController, + DataSaverController dataSaverController + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); mHotspotController = hotspotController; mDataSaverController = dataSaverController; mHotspotController.observe(this, mCallbacks); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java index 02f364bd3a7e..d502d06efceb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java @@ -17,16 +17,23 @@ package com.android.systemui.qs.tiles; import android.content.Intent; +import android.os.Handler; +import android.os.Looper; import android.os.UserManager; import android.provider.Settings; import android.service.quicksettings.Tile; import android.widget.Switch; +import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile.BooleanState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.LocationController; @@ -41,16 +48,24 @@ public class LocationTile extends QSTileImpl<BooleanState> { private final LocationController mController; private final KeyguardStateController mKeyguard; - private final ActivityStarter mActivityStarter; private final Callback mCallback = new Callback(); @Inject - public LocationTile(QSHost host, LocationController locationController, - KeyguardStateController keyguardStateController, ActivityStarter activityStarter) { - super(host); + public LocationTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + LocationController locationController, + KeyguardStateController keyguardStateController + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); mController = locationController; mKeyguard = keyguardStateController; - mActivityStarter = activityStarter; mController.observe(this, mCallback); mKeyguard.observe(this, mCallback); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java index 7da913592286..fb281169b2f1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java @@ -23,15 +23,23 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.nfc.NfcAdapter; +import android.os.Handler; +import android.os.Looper; import android.provider.Settings; import android.service.quicksettings.Tile; import android.widget.Switch; +import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile.BooleanState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import javax.inject.Inject; @@ -47,8 +55,18 @@ public class NfcTile extends QSTileImpl<BooleanState> { private boolean mListening; @Inject - public NfcTile(QSHost host, BroadcastDispatcher broadcastDispatcher) { - super(host); + public NfcTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + BroadcastDispatcher broadcastDispatcher + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); mBroadcastDispatcher = broadcastDispatcher; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java index 2f582727c766..3264429a1723 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java @@ -33,10 +33,17 @@ import android.widget.Switch; import androidx.annotation.StringRes; +import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; +import com.android.systemui.dagger.NightDisplayListenerModule; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile.BooleanState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.LocationController; @@ -62,15 +69,29 @@ public class NightDisplayTile extends QSTileImpl<BooleanState> implements private final ColorDisplayManager mManager; private final LocationController mLocationController; + private final NightDisplayListenerModule.Builder mNightDisplayListenerBuilder; private NightDisplayListener mListener; private boolean mIsListening; @Inject - public NightDisplayTile(QSHost host, LocationController locationController) { - super(host); + public NightDisplayTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + LocationController locationController, + ColorDisplayManager colorDisplayManager, + NightDisplayListenerModule.Builder nightDisplayListenerBuilder + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); mLocationController = locationController; - mManager = mContext.getSystemService(ColorDisplayManager.class); - mListener = new NightDisplayListener(mContext, new Handler(Looper.myLooper())); + mManager = colorDisplayManager; + mNightDisplayListenerBuilder = nightDisplayListenerBuilder; + mListener = mNightDisplayListenerBuilder.setUser(host.getUserContext().getUserId()).build(); } @Override @@ -106,7 +127,7 @@ public class NightDisplayTile extends QSTileImpl<BooleanState> implements } // Make a new controller for the new user. - mListener = new NightDisplayListener(mContext, newUserId, new Handler(Looper.myLooper())); + mListener = mNightDisplayListenerBuilder.setUser(newUserId).build(); if (mIsListening) { mListener.setCallback(this); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java index 5dcb4e3b1fb9..4bf27e2aa4b8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java @@ -19,14 +19,22 @@ package com.android.systemui.qs.tiles; import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; +import android.os.Handler; +import android.os.Looper; import android.provider.Settings; import android.service.quicksettings.Tile; import android.widget.Switch; +import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile.BooleanState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.RotationLockController; import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback; @@ -40,8 +48,18 @@ public class RotationLockTile extends QSTileImpl<BooleanState> { private final RotationLockController mController; @Inject - public RotationLockTile(QSHost host, RotationLockController rotationLockController) { - super(host); + public RotationLockTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + RotationLockController rotationLockController + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); mController = rotationLockController; mController.observe(this, mCallback); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java index 0c34b27d348e..d7a2975a4b04 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java @@ -17,15 +17,22 @@ package com.android.systemui.qs.tiles; import android.content.Intent; +import android.os.Handler; +import android.os.Looper; import android.service.quicksettings.Tile; import android.text.TextUtils; import android.util.Log; import android.widget.Switch; +import com.android.internal.logging.MetricsLogger; import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.screenrecord.RecordingController; import com.android.systemui.statusbar.phone.KeyguardDismissUtil; @@ -44,9 +51,19 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState> private Callback mCallback = new Callback(); @Inject - public ScreenRecordTile(QSHost host, RecordingController controller, - KeyguardDismissUtil keyguardDismissUtil) { - super(host); + public ScreenRecordTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + RecordingController controller, + KeyguardDismissUtil keyguardDismissUtil + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); mController = controller; mController.observe(this, mCallback); mKeyguardDismissUtil = keyguardDismissUtil; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java index 7b83c20d4b86..07b841ffb6f7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java @@ -19,15 +19,23 @@ package com.android.systemui.qs.tiles; import android.app.UiModeManager; import android.content.Intent; import android.content.res.Configuration; +import android.os.Handler; +import android.os.Looper; import android.provider.Settings; import android.service.quicksettings.Tile; import android.text.TextUtils; import android.widget.Switch; +import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -55,9 +63,20 @@ public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements private final LocationController mLocationController; @Inject - public UiModeNightTile(QSHost host, ConfigurationController configurationController, - BatteryController batteryController, LocationController locationController) { - super(host); + public UiModeNightTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + ConfigurationController configurationController, + BatteryController batteryController, + LocationController locationController + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); mBatteryController = batteryController; mUiModeManager = mContext.getSystemService(UiModeManager.class); mLocationController = locationController; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java index aab30d499e08..26adfdcd8539 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java @@ -18,14 +18,22 @@ package com.android.systemui.qs.tiles; import android.content.Context; import android.content.Intent; import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.Looper; import android.provider.Settings; import android.util.Pair; +import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTile.State; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.UserInfoController; import com.android.systemui.statusbar.policy.UserSwitcherController; @@ -39,9 +47,19 @@ public class UserTile extends QSTileImpl<State> implements UserInfoController.On private Pair<String, Drawable> mLastUpdate; @Inject - public UserTile(QSHost host, UserSwitcherController userSwitcherController, - UserInfoController userInfoController) { - super(host); + public UserTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + UserSwitcherController userSwitcherController, + UserInfoController userInfoController + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); mUserSwitcherController = userSwitcherController; mUserInfoController = userInfoController; mUserInfoController.observe(getLifecycle(), this); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java index 1279d42eb64d..4d89dea7cb70 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -20,6 +20,8 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; +import android.os.Handler; +import android.os.Looper; import android.provider.Settings; import android.service.quicksettings.Tile; import android.text.TextUtils; @@ -32,15 +34,19 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.wifi.AccessPoint; import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSIconView; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTile.SignalState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.AlphaControlledSignalTileView; import com.android.systemui.qs.QSDetailItems; import com.android.systemui.qs.QSDetailItems.Item; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSIconViewImpl; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.NetworkController; @@ -63,17 +69,24 @@ public class WifiTile extends QSTileImpl<SignalState> { private final QSTile.SignalState mStateBeforeClick = newTileState(); protected final WifiSignalCallback mSignalCallback = new WifiSignalCallback(); - private final ActivityStarter mActivityStarter; private boolean mExpectDisabled; @Inject - public WifiTile(QSHost host, NetworkController networkController, - ActivityStarter activityStarter) { - super(host); + public WifiTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + NetworkController networkController + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); mController = networkController; mWifiController = mController.getAccessPointController(); mDetailAdapter = (WifiDetailAdapter) createDetailAdapter(); - mActivityStarter = activityStarter; mController.observe(getLifecycle(), mSignalCallback); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java index 318c0c4660cb..5235b6d5a0bb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java @@ -17,14 +17,22 @@ package com.android.systemui.qs.tiles; import android.content.Intent; +import android.os.Handler; +import android.os.Looper; import android.provider.Settings; import android.service.quicksettings.Tile; import android.widget.Switch; +import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile.BooleanState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.phone.ManagedProfileController; @@ -38,8 +46,18 @@ public class WorkModeTile extends QSTileImpl<BooleanState> implements private final ManagedProfileController mProfileController; @Inject - public WorkModeTile(QSHost host, ManagedProfileController managedProfileController) { - super(host); + public WorkModeTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + ManagedProfileController managedProfileController + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); mProfileController = managedProfileController; mProfileController.observe(getLifecycle(), this); } diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java index 476ec798a35f..469c4a7b4c57 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java @@ -42,6 +42,7 @@ import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.LongRunning; import com.android.systemui.settings.CurrentUserContextTracker; +import com.android.systemui.statusbar.phone.KeyguardDismissUtil; import java.io.IOException; import java.util.concurrent.Executor; @@ -72,7 +73,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis private static final String ACTION_DELETE = "com.android.systemui.screenrecord.DELETE"; private final RecordingController mController; - + private final KeyguardDismissUtil mKeyguardDismissUtil; private ScreenRecordingAudioSource mAudioSource; private boolean mShowTaps; private boolean mOriginalShowTaps; @@ -85,12 +86,13 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis @Inject public RecordingService(RecordingController controller, @LongRunning Executor executor, UiEventLogger uiEventLogger, NotificationManager notificationManager, - CurrentUserContextTracker userContextTracker) { + CurrentUserContextTracker userContextTracker, KeyguardDismissUtil keyguardDismissUtil) { mController = controller; mLongExecutor = executor; mUiEventLogger = uiEventLogger; mNotificationManager = notificationManager; mUserContextTracker = userContextTracker; + mKeyguardDismissUtil = keyguardDismissUtil; } /** @@ -170,33 +172,36 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis Intent shareIntent = new Intent(Intent.ACTION_SEND) .setType("video/mp4") .putExtra(Intent.EXTRA_STREAM, shareUri); - String shareLabel = getResources().getString(R.string.screenrecord_share_label); + mKeyguardDismissUtil.executeWhenUnlocked(() -> { + String shareLabel = getResources().getString(R.string.screenrecord_share_label); + startActivity(Intent.createChooser(shareIntent, shareLabel) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + // Remove notification + mNotificationManager.cancelAsUser(null, NOTIFICATION_VIEW_ID, currentUser); + return false; + }, false); // Close quick shade sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); - - // Remove notification - mNotificationManager.cancelAsUser(null, NOTIFICATION_VIEW_ID, currentUser); - - startActivity(Intent.createChooser(shareIntent, shareLabel) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); break; case ACTION_DELETE: - // Close quick shade - sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); - - ContentResolver resolver = getContentResolver(); - Uri uri = Uri.parse(intent.getStringExtra(EXTRA_PATH)); - resolver.delete(uri, null, null); - - Toast.makeText( - this, - R.string.screenrecord_delete_description, - Toast.LENGTH_LONG).show(); - - // Remove notification - mNotificationManager.cancelAsUser(null, NOTIFICATION_VIEW_ID, currentUser); - Log.d(TAG, "Deleted recording " + uri); + mKeyguardDismissUtil.executeWhenUnlocked(() -> { + // Close quick shade + sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); + ContentResolver resolver = getContentResolver(); + Uri uri = Uri.parse(intent.getStringExtra(EXTRA_PATH)); + resolver.delete(uri, null, null); + + Toast.makeText( + this, + R.string.screenrecord_delete_description, + Toast.LENGTH_LONG).show(); + Log.d(TAG, "Deleted recording " + uri); + + // Remove notification + mNotificationManager.cancelAsUser(null, NOTIFICATION_VIEW_ID, currentUser); + return false; + }, false); break; } return Service.START_STICKY; diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java new file mode 100644 index 000000000000..3fd7f94514f3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java @@ -0,0 +1,105 @@ +/* + * 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.screenshot; + +import static com.android.systemui.screenshot.GlobalScreenshot.ACTION_TYPE_EDIT; +import static com.android.systemui.screenshot.GlobalScreenshot.ACTION_TYPE_SHARE; +import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_ACTION_INTENT; +import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_DISALLOW_ENTER_PIP; +import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_ID; +import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED; +import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_SCREENSHOT; + +import android.app.ActivityOptions; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.statusbar.phone.StatusBar; + +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import javax.inject.Inject; + +/** + * Receiver to proxy the share or edit intent, used to clean up the notification and send + * appropriate signals to the system (ie. to dismiss the keyguard if necessary). + */ +public class ActionProxyReceiver extends BroadcastReceiver { + private static final String TAG = "ActionProxyReceiver"; + + private static final int CLOSE_WINDOWS_TIMEOUT_MILLIS = 3000; + private final StatusBar mStatusBar; + private final ActivityManagerWrapper mActivityManagerWrapper; + private final ScreenshotSmartActions mScreenshotSmartActions; + + @Inject + public ActionProxyReceiver(Optional<StatusBar> statusBar, + ActivityManagerWrapper activityManagerWrapper, + ScreenshotSmartActions screenshotSmartActions) { + mStatusBar = statusBar.orElse(null); + mActivityManagerWrapper = activityManagerWrapper; + mScreenshotSmartActions = screenshotSmartActions; + } + + @Override + public void onReceive(Context context, final Intent intent) { + Runnable startActivityRunnable = () -> { + try { + mActivityManagerWrapper.closeSystemWindows( + SYSTEM_DIALOG_REASON_SCREENSHOT).get( + CLOSE_WINDOWS_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); + } catch (TimeoutException | InterruptedException | ExecutionException e) { + Log.e(TAG, "Unable to share screenshot", e); + return; + } + + PendingIntent actionIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT); + ActivityOptions opts = ActivityOptions.makeBasic(); + opts.setDisallowEnterPictureInPictureWhileLaunching( + intent.getBooleanExtra(EXTRA_DISALLOW_ENTER_PIP, false)); + try { + actionIntent.send(context, 0, null, null, null, null, opts.toBundle()); + } catch (PendingIntent.CanceledException e) { + Log.e(TAG, "Pending intent canceled", e); + } + + }; + + if (mStatusBar != null) { + mStatusBar.executeRunnableDismissingKeyguard(startActivityRunnable, null, + true /* dismissShade */, true /* afterKeyguardGone */, + true /* deferred */); + } else { + startActivityRunnable.run(); + } + + if (intent.getBooleanExtra(EXTRA_SMART_ACTIONS_ENABLED, false)) { + String actionType = Intent.ACTION_EDIT.equals(intent.getAction()) + ? ACTION_TYPE_EDIT + : ACTION_TYPE_SHARE; + mScreenshotSmartActions.notifyScreenshotAction( + context, intent.getStringExtra(EXTRA_ID), actionType, false); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/DeleteImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/DeleteImageInBackgroundTask.java deleted file mode 100644 index 8c4865510ed1..000000000000 --- a/packages/SystemUI/src/com/android/systemui/screenshot/DeleteImageInBackgroundTask.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.screenshot; - -import android.content.ContentResolver; -import android.content.Context; -import android.net.Uri; -import android.os.AsyncTask; - -/** - * An AsyncTask that deletes an image from the media store in the background. - */ -class DeleteImageInBackgroundTask extends AsyncTask<Uri, Void, Void> { - private Context mContext; - - DeleteImageInBackgroundTask(Context context) { - mContext = context; - } - - @Override - protected Void doInBackground(Uri... params) { - if (params.length != 1) return null; - - Uri screenshotUri = params[0]; - ContentResolver resolver = mContext.getContentResolver(); - resolver.delete(screenshotUri, null, null); - return null; - } -} diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/DeleteScreenshotReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/DeleteScreenshotReceiver.java new file mode 100644 index 000000000000..9028bb57c8e5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/screenshot/DeleteScreenshotReceiver.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.screenshot; + +import static com.android.systemui.screenshot.GlobalScreenshot.ACTION_TYPE_DELETE; +import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_ID; +import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED; +import static com.android.systemui.screenshot.GlobalScreenshot.SCREENSHOT_URI_ID; + +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; + +import com.android.systemui.dagger.qualifiers.Background; + +import java.util.concurrent.Executor; + +import javax.inject.Inject; + +/** + * Removes the file at a provided URI. + */ +public class DeleteScreenshotReceiver extends BroadcastReceiver { + + private final ScreenshotSmartActions mScreenshotSmartActions; + private final Executor mBackgroundExecutor; + + @Inject + public DeleteScreenshotReceiver(ScreenshotSmartActions screenshotSmartActions, + @Background Executor backgroundExecutor) { + mScreenshotSmartActions = screenshotSmartActions; + mBackgroundExecutor = backgroundExecutor; + } + + @Override + public void onReceive(Context context, Intent intent) { + if (!intent.hasExtra(SCREENSHOT_URI_ID)) { + return; + } + + // And delete the image from the media store + final Uri uri = Uri.parse(intent.getStringExtra(SCREENSHOT_URI_ID)); + mBackgroundExecutor.execute(() -> { + ContentResolver resolver = context.getContentResolver(); + resolver.delete(uri, null, null); + }); + if (intent.getBooleanExtra(EXTRA_SMART_ACTIONS_ENABLED, false)) { + mScreenshotSmartActions.notifyScreenshotAction( + context, intent.getStringExtra(EXTRA_ID), ACTION_TYPE_DELETE, false); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index 85444303490d..e69319ee6829 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -21,8 +21,6 @@ import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; -import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_SCREENSHOT; - import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; @@ -30,13 +28,10 @@ import android.animation.ValueAnimator; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.app.ActivityManager; -import android.app.ActivityOptions; import android.app.Notification; import android.app.PendingIntent; -import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; -import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; @@ -57,13 +52,11 @@ import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.os.PowerManager; import android.os.RemoteException; import android.provider.Settings; import android.util.DisplayMetrics; import android.util.Log; import android.util.MathUtils; -import android.util.Slog; import android.view.Display; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -88,23 +81,15 @@ import android.widget.Toast; import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.QuickStepContract; -import com.android.systemui.statusbar.phone.StatusBar; import java.util.ArrayList; import java.util.List; -import java.util.Optional; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.function.Consumer; import javax.inject.Inject; import javax.inject.Singleton; -import dagger.Lazy; - /** * Class for handling device screen shots */ @@ -193,6 +178,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset private final UiEventLogger mUiEventLogger; private final Context mContext; + private final ScreenshotSmartActions mScreenshotSmartActions; private final WindowManager mWindowManager; private final WindowManager.LayoutParams mWindowLayoutParams; private final Display mDisplay; @@ -248,9 +234,11 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset @Inject public GlobalScreenshot( Context context, @Main Resources resources, + ScreenshotSmartActions screenshotSmartActions, ScreenshotNotificationsController screenshotNotificationsController, UiEventLogger uiEventLogger) { mContext = context; + mScreenshotSmartActions = screenshotSmartActions; mNotificationsController = screenshotNotificationsController; mUiEventLogger = uiEventLogger; @@ -648,14 +636,6 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset */ private void startAnimation(final Consumer<Uri> finisher, Rect screenRect, Insets screenInsets, boolean showFlash) { - - // If power save is on, show a toast so there is some visual indication that a - // screenshot has been taken. - PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); - if (powerManager.isPowerSaveMode()) { - Toast.makeText(mContext, R.string.screenshot_saved_title, Toast.LENGTH_SHORT).show(); - } - mScreenshotHandler.post(() -> { if (!mScreenshotLayout.isAttachedToWindow()) { mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams); @@ -713,7 +693,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset }); } - mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data); + mSaveInBgTask = new SaveImageInBackgroundTask(mContext, mScreenshotSmartActions, data); mSaveInBgTask.execute(); } @@ -1033,6 +1013,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset mScreenshotPreview.setLayerType(View.LAYER_TYPE_NONE, null); mScreenshotPreview.setContentDescription( mContext.getResources().getString(R.string.screenshot_preview_description)); + mScreenshotPreview.setOnClickListener(null); mScreenshotLayout.setAlpha(1); mDismissButton.setTranslationY(0); mActionsContainer.setTranslationY(0); @@ -1125,119 +1106,4 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset return insetDrawable; } } - - /** - * Receiver to proxy the share or edit intent, used to clean up the notification and send - * appropriate signals to the system (ie. to dismiss the keyguard if necessary). - */ - public static class ActionProxyReceiver extends BroadcastReceiver { - static final int CLOSE_WINDOWS_TIMEOUT_MILLIS = 3000; - private final StatusBar mStatusBar; - - @Inject - public ActionProxyReceiver(Optional<Lazy<StatusBar>> statusBarLazy) { - Lazy<StatusBar> statusBar = statusBarLazy.orElse(null); - mStatusBar = statusBar != null ? statusBar.get() : null; - } - - @Override - public void onReceive(Context context, final Intent intent) { - Runnable startActivityRunnable = () -> { - try { - ActivityManagerWrapper.getInstance().closeSystemWindows( - SYSTEM_DIALOG_REASON_SCREENSHOT).get( - CLOSE_WINDOWS_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); - } catch (TimeoutException | InterruptedException | ExecutionException e) { - Slog.e(TAG, "Unable to share screenshot", e); - return; - } - - PendingIntent actionIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT); - if (intent.getBooleanExtra(EXTRA_CANCEL_NOTIFICATION, false)) { - ScreenshotNotificationsController.cancelScreenshotNotification(context); - } - ActivityOptions opts = ActivityOptions.makeBasic(); - opts.setDisallowEnterPictureInPictureWhileLaunching( - intent.getBooleanExtra(EXTRA_DISALLOW_ENTER_PIP, false)); - try { - actionIntent.send(context, 0, null, null, null, null, opts.toBundle()); - } catch (PendingIntent.CanceledException e) { - Log.e(TAG, "Pending intent canceled", e); - } - - }; - - if (mStatusBar != null) { - mStatusBar.executeRunnableDismissingKeyguard(startActivityRunnable, null, - true /* dismissShade */, true /* afterKeyguardGone */, - true /* deferred */); - } else { - startActivityRunnable.run(); - } - - if (intent.getBooleanExtra(EXTRA_SMART_ACTIONS_ENABLED, false)) { - String actionType = Intent.ACTION_EDIT.equals(intent.getAction()) - ? ACTION_TYPE_EDIT - : ACTION_TYPE_SHARE; - ScreenshotSmartActions.notifyScreenshotAction( - context, intent.getStringExtra(EXTRA_ID), actionType, false); - } - } - } - - /** - * Removes the notification for a screenshot after a share target is chosen. - */ - public static class TargetChosenReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - // Clear the notification only after the user has chosen a share action - ScreenshotNotificationsController.cancelScreenshotNotification(context); - } - } - - /** - * Removes the last screenshot. - */ - public static class DeleteScreenshotReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - if (!intent.hasExtra(SCREENSHOT_URI_ID)) { - return; - } - - // Clear the notification when the image is deleted - ScreenshotNotificationsController.cancelScreenshotNotification(context); - - // And delete the image from the media store - final Uri uri = Uri.parse(intent.getStringExtra(SCREENSHOT_URI_ID)); - new DeleteImageInBackgroundTask(context).execute(uri); - if (intent.getBooleanExtra(EXTRA_SMART_ACTIONS_ENABLED, false)) { - ScreenshotSmartActions.notifyScreenshotAction( - context, intent.getStringExtra(EXTRA_ID), ACTION_TYPE_DELETE, false); - } - } - } - - /** - * Executes the smart action tapped by the user in the notification. - */ - public static class SmartActionsReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - PendingIntent pendingIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT); - String actionType = intent.getStringExtra(EXTRA_ACTION_TYPE); - Slog.d(TAG, "Executing smart action [" + actionType + "]:" + pendingIntent.getIntent()); - ActivityOptions opts = ActivityOptions.makeBasic(); - - try { - pendingIntent.send(context, 0, null, null, null, null, opts.toBundle()); - } catch (PendingIntent.CanceledException e) { - Log.e(TAG, "Pending intent canceled", e); - } - - ScreenshotSmartActions.notifyScreenshotAction( - context, intent.getStringExtra(EXTRA_ID), actionType, true); - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java index 468b9b16addb..df1d78953f46 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java @@ -81,6 +81,7 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { private static final String SCREENSHOT_SHARE_SUBJECT_TEMPLATE = "Screenshot (%s)"; private final Context mContext; + private final ScreenshotSmartActions mScreenshotSmartActions; private final GlobalScreenshot.SaveImageInBackgroundData mParams; private final GlobalScreenshot.SavedImageData mImageData; private final String mImageFileName; @@ -90,8 +91,10 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { private final boolean mSmartActionsEnabled; private final Random mRandom = new Random(); - SaveImageInBackgroundTask(Context context, GlobalScreenshot.SaveImageInBackgroundData data) { + SaveImageInBackgroundTask(Context context, ScreenshotSmartActions screenshotSmartActions, + GlobalScreenshot.SaveImageInBackgroundData data) { mContext = context; + mScreenshotSmartActions = screenshotSmartActions; mImageData = new GlobalScreenshot.SavedImageData(); // Prepare all the output metadata @@ -141,7 +144,7 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { final Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); CompletableFuture<List<Notification.Action>> smartActionsFuture = - ScreenshotSmartActions.getSmartActionsFuture( + mScreenshotSmartActions.getSmartActionsFuture( mScreenshotId, uri, image, mSmartActionsProvider, mSmartActionsEnabled, getUserHandle(mContext)); @@ -199,7 +202,7 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { SystemUiDeviceConfigFlags.SCREENSHOT_NOTIFICATION_SMART_ACTIONS_TIMEOUT_MS, 1000); smartActions.addAll(buildSmartActions( - ScreenshotSmartActions.getSmartActions( + mScreenshotSmartActions.getSmartActions( mScreenshotId, smartActionsFuture, timeoutMs, mSmartActionsProvider), mContext)); @@ -274,11 +277,8 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { // by setting the (otherwise unused) request code to the current user id. int requestCode = context.getUserId(); - PendingIntent chooserAction = PendingIntent.getBroadcast(context, requestCode, - new Intent(context, GlobalScreenshot.TargetChosenReceiver.class), - PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT); Intent sharingChooserIntent = - Intent.createChooser(sharingIntent, null, chooserAction.getIntentSender()) + Intent.createChooser(sharingIntent, null) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK) .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); @@ -288,7 +288,7 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { // Create a share action for the notification PendingIntent shareAction = PendingIntent.getBroadcastAsUser(context, requestCode, - new Intent(context, GlobalScreenshot.ActionProxyReceiver.class) + new Intent(context, ActionProxyReceiver.class) .putExtra(GlobalScreenshot.EXTRA_ACTION_INTENT, pendingIntent) .putExtra(GlobalScreenshot.EXTRA_DISALLOW_ENTER_PIP, true) .putExtra(GlobalScreenshot.EXTRA_ID, mScreenshotId) @@ -333,10 +333,8 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { // Create a edit action PendingIntent editAction = PendingIntent.getBroadcastAsUser(context, requestCode, - new Intent(context, GlobalScreenshot.ActionProxyReceiver.class) + new Intent(context, ActionProxyReceiver.class) .putExtra(GlobalScreenshot.EXTRA_ACTION_INTENT, pendingIntent) - .putExtra(GlobalScreenshot.EXTRA_CANCEL_NOTIFICATION, - editIntent.getComponent() != null) .putExtra(GlobalScreenshot.EXTRA_ID, mScreenshotId) .putExtra(GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED, mSmartActionsEnabled) @@ -358,7 +356,7 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { // Create a delete action for the notification PendingIntent deleteAction = PendingIntent.getBroadcast(context, requestCode, - new Intent(context, GlobalScreenshot.DeleteScreenshotReceiver.class) + new Intent(context, DeleteScreenshotReceiver.class) .putExtra(GlobalScreenshot.SCREENSHOT_URI_ID, uri.toString()) .putExtra(GlobalScreenshot.EXTRA_ID, mScreenshotId) .putExtra(GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED, @@ -398,7 +396,7 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { String actionType = extras.getString( ScreenshotNotificationSmartActionsProvider.ACTION_TYPE, ScreenshotNotificationSmartActionsProvider.DEFAULT_ACTION_TYPE); - Intent intent = new Intent(context, GlobalScreenshot.SmartActionsReceiver.class) + Intent intent = new Intent(context, SmartActionsReceiver.class) .putExtra(GlobalScreenshot.EXTRA_ACTION_INTENT, action.actionIntent) .addFlags(Intent.FLAG_RECEIVER_FOREGROUND); addIntentExtras(mScreenshotId, intent, actionType, mSmartActionsEnabled); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java index 442b373b31be..633cdd6ca5ca 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java @@ -39,14 +39,21 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import javax.inject.Inject; +import javax.inject.Singleton; + /** * Collects the static functions for retrieving and acting on smart actions. */ +@Singleton public class ScreenshotSmartActions { private static final String TAG = "ScreenshotSmartActions"; + @Inject + public ScreenshotSmartActions() {} + @VisibleForTesting - static CompletableFuture<List<Notification.Action>> getSmartActionsFuture( + CompletableFuture<List<Notification.Action>> getSmartActionsFuture( String screenshotId, Uri screenshotUri, Bitmap image, ScreenshotNotificationSmartActionsProvider smartActionsProvider, boolean smartActionsEnabled, UserHandle userHandle) { @@ -86,7 +93,7 @@ public class ScreenshotSmartActions { } @VisibleForTesting - static List<Notification.Action> getSmartActions(String screenshotId, + List<Notification.Action> getSmartActions(String screenshotId, CompletableFuture<List<Notification.Action>> smartActionsFuture, int timeoutMs, ScreenshotNotificationSmartActionsProvider smartActionsProvider) { long startTimeMs = SystemClock.uptimeMillis(); @@ -116,7 +123,7 @@ public class ScreenshotSmartActions { } } - static void notifyScreenshotOp(String screenshotId, + void notifyScreenshotOp(String screenshotId, ScreenshotNotificationSmartActionsProvider smartActionsProvider, ScreenshotNotificationSmartActionsProvider.ScreenshotOp op, ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus status, long durationMs) { @@ -127,7 +134,7 @@ public class ScreenshotSmartActions { } } - static void notifyScreenshotAction(Context context, String screenshotId, String action, + void notifyScreenshotAction(Context context, String screenshotId, String action, boolean isSmartAction) { try { ScreenshotNotificationSmartActionsProvider provider = diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java new file mode 100644 index 000000000000..217235b16ecf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.screenshot; + +import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_ACTION_INTENT; +import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_ACTION_TYPE; +import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_ID; + +import android.app.ActivityOptions; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; +import android.util.Slog; + +import javax.inject.Inject; + + +/** + * Executes the smart action tapped by the user in the notification. + */ +public class SmartActionsReceiver extends BroadcastReceiver { + private static final String TAG = "SmartActionsReceiver"; + + private final ScreenshotSmartActions mScreenshotSmartActions; + + @Inject + SmartActionsReceiver(ScreenshotSmartActions screenshotSmartActions) { + mScreenshotSmartActions = screenshotSmartActions; + } + + @Override + public void onReceive(Context context, Intent intent) { + PendingIntent pendingIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT); + String actionType = intent.getStringExtra(EXTRA_ACTION_TYPE); + Slog.d(TAG, "Executing smart action [" + actionType + "]:" + pendingIntent.getIntent()); + ActivityOptions opts = ActivityOptions.makeBasic(); + + try { + pendingIntent.send(context, 0, null, null, null, null, opts.toBundle()); + } catch (PendingIntent.CanceledException e) { + Log.e(TAG, "Pending intent canceled", e); + } + + mScreenshotSmartActions.notifyScreenshotAction( + context, intent.getStringExtra(EXTRA_ID), actionType, true); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java index 570a4bb3cd12..eb7231211ea8 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java @@ -39,16 +39,16 @@ import android.window.WindowOrganizer; import com.android.internal.policy.DividerSnapAlgorithm; import com.android.systemui.R; import com.android.systemui.SystemUI; -import com.android.systemui.TransactionPool; import com.android.systemui.recents.Recents; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.wm.DisplayChangeController; -import com.android.systemui.wm.DisplayController; -import com.android.systemui.wm.DisplayImeController; -import com.android.systemui.wm.DisplayLayout; -import com.android.systemui.wm.SystemWindows; +import com.android.wm.shell.common.DisplayChangeController; +import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.DisplayImeController; +import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.common.SystemWindows; +import com.android.wm.shell.common.TransactionPool; import java.io.FileDescriptor; import java.io.PrintWriter; diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java index 5aeca5e07bdd..84ec38744e98 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java @@ -33,8 +33,8 @@ import android.window.WindowOrganizer; import androidx.annotation.Nullable; -import com.android.systemui.TransactionPool; -import com.android.systemui.wm.DisplayImeController; +import com.android.wm.shell.common.DisplayImeController; +import com.android.wm.shell.common.TransactionPool; class DividerImeController implements DisplayImeController.ImePositionProcessor { private static final String TAG = "DividerImeController"; diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java index 3b7f3152ec76..c24431c22d62 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java @@ -19,13 +19,13 @@ package com.android.systemui.stackdivider; import android.content.Context; import android.os.Handler; -import com.android.systemui.TransactionPool; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.recents.Recents; import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.wm.DisplayController; -import com.android.systemui.wm.DisplayImeController; -import com.android.systemui.wm.SystemWindows; +import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.DisplayImeController; +import com.android.wm.shell.common.SystemWindows; +import com.android.wm.shell.common.TransactionPool; import java.util.Optional; diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java index 6ea3132ac942..d869333e11a7 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java @@ -32,7 +32,7 @@ import android.os.Binder; import android.view.View; import android.view.WindowManager; -import com.android.systemui.wm.SystemWindows; +import com.android.wm.shell.common.SystemWindows; /** * Manages the window parameters of the docked stack divider. diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java index 69095f7538c5..a34e85517953 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java @@ -34,7 +34,7 @@ import android.window.WindowContainerTransaction; import com.android.internal.policy.DividerSnapAlgorithm; import com.android.internal.policy.DockedDividerUtils; -import com.android.systemui.wm.DisplayLayout; +import com.android.wm.shell.common.DisplayLayout; /** * Handles split-screen related internal display layout. In general, this represents the diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java index 1ff404677ea6..6812f62422a7 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java @@ -25,7 +25,7 @@ import android.window.WindowOrganizer; import androidx.annotation.NonNull; -import com.android.systemui.TransactionPool; +import com.android.wm.shell.common.TransactionPool; import java.util.ArrayList; diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java index 410e3dd39a0b..2b3681281064 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java @@ -40,7 +40,7 @@ import android.window.WindowContainerTransaction; import android.window.WindowOrganizer; import com.android.internal.annotations.GuardedBy; -import com.android.systemui.TransactionPool; +import com.android.wm.shell.common.TransactionPool; import java.util.ArrayList; import java.util.List; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index 9abc66056452..aba9e1005559 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -24,18 +24,24 @@ import static com.android.systemui.statusbar.notification.row.NotificationRowCon import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Notification; +import android.content.Context; +import android.os.RemoteException; +import android.os.ServiceManager; import android.os.SystemClock; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.NotificationListenerService.RankingMap; +import android.service.notification.NotificationStats; import android.service.notification.StatusBarNotification; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.Dumpable; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationLifetimeExtender; import com.android.systemui.statusbar.NotificationListener; @@ -52,6 +58,7 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.No import com.android.systemui.statusbar.notification.dagger.NotificationsModule; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.phone.NotificationGroupManager; +import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.util.Assert; import com.android.systemui.util.leak.LeakDetector; @@ -127,6 +134,8 @@ public class NotificationEntryManager implements private final NotificationEntryManagerLogger mLogger; + private final IStatusBarService mStatusBarService; + // Lazily retrieved dependencies private final Lazy<NotificationRowBinder> mNotificationRowBinderLazy; private final Lazy<NotificationRemoteInputManager> mRemoteInputManagerLazy; @@ -138,6 +147,8 @@ public class NotificationEntryManager implements private final NotificationRankingManager mRankingManager; private final FeatureFlags mFeatureFlags; private final ForegroundServiceDismissalFeatureController mFgsFeatureController; + private final HeadsUpManager mHeadsUpManager; + private final StatusBarStateController mStatusBarStateController; private NotificationPresenter mPresenter; private RankingMap mLatestRankingMap; @@ -201,7 +212,10 @@ public class NotificationEntryManager implements Lazy<NotificationRowBinder> notificationRowBinderLazy, Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy, LeakDetector leakDetector, - ForegroundServiceDismissalFeatureController fgsFeatureController) { + ForegroundServiceDismissalFeatureController fgsFeatureController, + HeadsUpManager headsUpManager, + StatusBarStateController statusBarStateController + ) { mLogger = logger; mGroupManager = groupManager; mRankingManager = rankingManager; @@ -211,6 +225,11 @@ public class NotificationEntryManager implements mRemoteInputManagerLazy = notificationRemoteInputManagerLazy; mLeakDetector = leakDetector; mFgsFeatureController = fgsFeatureController; + mHeadsUpManager = headsUpManager; + mStatusBarStateController = statusBarStateController; + + mStatusBarService = IStatusBarService.Stub.asInterface( + ServiceManager.checkService(Context.STATUS_BAR_SERVICE)); } /** Once called, the NEM will start processing notification events from system server. */ @@ -496,6 +515,9 @@ public class NotificationEntryManager implements removedByUser |= entryDismissed; mLogger.logNotifRemoved(entry.getKey(), removedByUser); + if (removedByUser && visibility != null) { + sendNotificationRemovalToServer(entry.getKey(), entry.getSbn(), visibility); + } for (NotificationEntryListener listener : mNotificationEntryListeners) { listener.onEntryRemoved(entry, visibility, removedByUser, reason); } @@ -511,6 +533,36 @@ public class NotificationEntryManager implements } } + private void sendNotificationRemovalToServer( + String key, + StatusBarNotification notification, + NotificationVisibility nv) { + final String pkg = notification.getPackageName(); + final String tag = notification.getTag(); + final int id = notification.getId(); + final int userId = notification.getUser().getIdentifier(); + try { + int dismissalSurface = NotificationStats.DISMISSAL_SHADE; + if (mHeadsUpManager.isAlerting(key)) { + dismissalSurface = NotificationStats.DISMISSAL_PEEK; + } else if (mStatusBarStateController.isDozing()) { + dismissalSurface = NotificationStats.DISMISSAL_AOD; + } + int dismissalSentiment = NotificationStats.DISMISS_SENTIMENT_NEUTRAL; + mStatusBarService.onNotificationClear( + pkg, + tag, + id, + userId, + notification.getKey(), + dismissalSurface, + dismissalSentiment, + nv); + } catch (RemoteException ex) { + // system process is dead if we're here. + } + } + /** * Ensures that the group children are cancelled immediately when the group summary is cancelled * instead of waiting for the notification manager to send all cancels. Otherwise this could diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt index 27476964b9af..f982cf05de97 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt @@ -382,7 +382,7 @@ class NotificationWakeUpCoordinator @Inject constructor( } private fun shouldAnimateVisibility() = - dozeParameters.getAlwaysOn() && !dozeParameters.getDisplayNeedsBlanking() + dozeParameters.alwaysOn && !dozeParameters.displayNeedsBlanking interface WakeUpListener { /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java index 9d81d3563ebb..a86ab41141a6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java @@ -842,7 +842,7 @@ public class ShadeListBuilder implements Dumpable { } private static final NotifSection sDefaultSection = - new NotifSection("DefaultSection") { + new NotifSection("UnknownSection") { @Override public boolean isInSection(ListEntry entry) { return true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java index 4b244bb18975..68ec6b620a53 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification.collection.coordinator; +import static android.app.NotificationManager.IMPORTANCE_MIN; + import android.app.Notification; import android.os.UserHandle; import android.service.notification.StatusBarNotification; @@ -24,9 +26,11 @@ import android.util.ArraySet; import com.android.systemui.ForegroundServiceController; import com.android.systemui.appops.AppOpsController; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.statusbar.notification.collection.ListEntry; 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.listbuilder.pluggable.NotifSection; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; import com.android.systemui.util.Assert; @@ -43,6 +47,8 @@ import javax.inject.Singleton; * Tags notifications with appOps * Lifetime extends notifications associated with an ongoing ForegroundService. * Filters out notifications that represent foreground services that are no longer running + * Puts foreground service notifications into the FGS section. See {@link NotifCoordinators} for + * section ordering priority. * * Previously this logic lived in * frameworks/base/packages/SystemUI/src/com/android/systemui/ForegroundServiceController @@ -86,6 +92,10 @@ public class AppOpsCoordinator implements Coordinator { mAppOpsController.addCallback(ForegroundServiceController.APP_OPS, this::onAppOpsChanged); } + public NotifSection getSection() { + return mNotifSection; + } + /** * Filters out notifications that represent foreground services that are no longer running or * that already have an app notification with the appOps tagged to @@ -204,6 +214,23 @@ public class AppOpsCoordinator implements Coordinator { } }; + /** + * Puts foreground service notifications into its own section. + */ + private final NotifSection mNotifSection = new NotifSection("ForegroundService") { + @Override + public boolean isInSection(ListEntry entry) { + NotificationEntry notificationEntry = entry.getRepresentativeEntry(); + if (notificationEntry != null) { + Notification notification = notificationEntry.getSbn().getNotification(); + return notification.isForegroundService() + && notification.isColorized() + && entry.getRepresentativeEntry().getImportance() > IMPORTANCE_MIN; + } + return false; + } + }; + private void onAppOpsChanged(int code, int uid, String packageName, boolean active) { mMainExecutor.execute(() -> handleAppOpsChanged(code, uid, packageName, active)); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt index 1bac938a9fca..1a9de8829faf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt @@ -16,17 +16,25 @@ package com.android.systemui.statusbar.notification.collection.coordinator +import com.android.systemui.statusbar.notification.collection.ListEntry 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.NotifPromoter +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection +import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier +import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON import javax.inject.Inject import javax.inject.Singleton /** - * A coordinator that elevates important conversation notifications + * A Conversation/People Coordinator that: + * - Elevates important conversation notifications + * - Puts conversations into its own people section. @see [NotifCoordinators] for section ordering. */ @Singleton -class ConversationCoordinator @Inject constructor() : Coordinator { +class ConversationCoordinator @Inject constructor( + private val peopleNotificationIdentifier: PeopleNotificationIdentifier +) : Coordinator { private val notificationPromoter = object : NotifPromoter(TAG) { override fun shouldPromoteToTopLevel(entry: NotificationEntry): Boolean { @@ -34,10 +42,24 @@ class ConversationCoordinator @Inject constructor() : Coordinator { } } + private val mNotifSection: NotifSection = object : NotifSection("People") { + override fun isInSection(entry: ListEntry): Boolean { + return isConversation(entry.representativeEntry!!) + } + } + override fun attach(pipeline: NotifPipeline) { pipeline.addPromoter(notificationPromoter) } + fun getSection(): NotifSection { + return mNotifSection + } + + private fun isConversation(entry: NotificationEntry): Boolean = + peopleNotificationIdentifier.getPeopleNotificationType(entry.sbn, entry.ranking) != + TYPE_NON_PERSON + companion object { private const val TAG = "ConversationCoordinator" } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/Coordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/Coordinator.java index d8b2e4089f30..c1a11b2f64c8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/Coordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/Coordinator.java @@ -17,7 +17,6 @@ package com.android.systemui.statusbar.notification.collection.coordinator; import com.android.systemui.statusbar.notification.collection.NotifPipeline; -import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable; /** @@ -29,8 +28,4 @@ public interface Coordinator { * Coordinators should register their listeners and {@link Pluggable}s to the pipeline. */ void attach(NotifPipeline pipeline); - - default NotifSection getSection() { - return null; - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java index 3fde2ed249d9..72597afc3b90 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java @@ -88,7 +88,6 @@ public class HeadsUpCoordinator implements Coordinator { pipeline.addNotificationLifetimeExtender(mLifetimeExtender); } - @Override public NotifSection getSection() { return mNotifSection; } @@ -192,7 +191,7 @@ public class HeadsUpCoordinator implements Coordinator { } }; - private final NotifSection mNotifSection = new NotifSection(TAG) { + private final NotifSection mNotifSection = new NotifSection("HeadsUp") { @Override public boolean isInSection(ListEntry entry) { return isCurrentlyShowingHun(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 99e822c66a8f..a09c6509e65e 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 @@ -60,6 +60,7 @@ public class NotifCoordinators implements Dumpable { PreparationCoordinator preparationCoordinator, MediaCoordinator mediaCoordinator) { dumpManager.registerDumpable(TAG, this); + mCoordinators.add(new HideLocallyDismissedNotifsCoordinator()); mCoordinators.add(hideNotifsForOtherUsersCoordinator); mCoordinators.add(keyguardCoordinator); @@ -67,20 +68,22 @@ public class NotifCoordinators implements Dumpable { mCoordinators.add(appOpsCoordinator); mCoordinators.add(deviceProvisionedCoordinator); mCoordinators.add(bubbleCoordinator); + mCoordinators.add(mediaCoordinator); + mCoordinators.add(conversationCoordinator); if (featureFlags.isNewNotifPipelineRenderingEnabled()) { - mCoordinators.add(conversationCoordinator); mCoordinators.add(headsUpCoordinator); mCoordinators.add(preparationCoordinator); } - // TODO: add new Coordinators here! (b/112656837) - mCoordinators.add(mediaCoordinator); - // TODO: add the sections in a particular ORDER (HeadsUp < People < Alerting) - for (Coordinator c : mCoordinators) { - if (c.getSection() != null) { - mOrderedSections.add(c.getSection()); - } + // Manually add Ordered Sections + // HeadsUp > FGS > People > Alerting > Silent > Unknown/Default + if (featureFlags.isNewNotifPipelineRenderingEnabled()) { + mOrderedSections.add(headsUpCoordinator.getSection()); // HeadsUp } + mOrderedSections.add(appOpsCoordinator.getSection()); // ForegroundService + mOrderedSections.add(conversationCoordinator.getSection()); // People + mOrderedSections.add(rankingCoordinator.getAlertingSection()); // Alerting + mOrderedSections.add(rankingCoordinator.getSilentSection()); // Silent } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java index e9cbf32ee052..0d2f9da77db7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java @@ -17,15 +17,19 @@ package com.android.systemui.statusbar.notification.collection.coordinator; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.notification.collection.ListEntry; 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.listbuilder.pluggable.NotifSection; +import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; import javax.inject.Inject; import javax.inject.Singleton; /** * Filters out NotificationEntries based on its Ranking and dozing state. + * Assigns alerting / silent section based on the importance of the notification entry. * We check the NotificationEntry's Ranking for: * - whether the notification's app is suspended or hiding its notifications * - whether DND settings are hiding notifications from ambient display or the notification list @@ -35,10 +39,14 @@ public class RankingCoordinator implements Coordinator { private static final String TAG = "RankingNotificationCoordinator"; private final StatusBarStateController mStatusBarStateController; + private final HighPriorityProvider mHighPriorityProvider; @Inject - public RankingCoordinator(StatusBarStateController statusBarStateController) { + public RankingCoordinator( + StatusBarStateController statusBarStateController, + HighPriorityProvider highPriorityProvider) { mStatusBarStateController = statusBarStateController; + mHighPriorityProvider = highPriorityProvider; } @Override @@ -49,6 +57,28 @@ public class RankingCoordinator implements Coordinator { pipeline.addPreGroupFilter(mDozingFilter); } + public NotifSection getAlertingSection() { + return mAlertingNotifSection; + } + + public NotifSection getSilentSection() { + return mSilentNotifSection; + } + + private final NotifSection mAlertingNotifSection = new NotifSection("Alerting") { + @Override + public boolean isInSection(ListEntry entry) { + return mHighPriorityProvider.isHighPriority(entry); + } + }; + + private final NotifSection mSilentNotifSection = new NotifSection("Silent") { + @Override + public boolean isInSection(ListEntry entry) { + return !mHighPriorityProvider.isHighPriority(entry); + } + }; + /** * Checks whether to filter out the given notification based the notification's Ranking object. * NotifListBuilder invalidates the notification list each time the ranking is updated, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index d2c202cb485f..d661b5e2b7cf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -59,6 +59,7 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.PriorityOnboardingDialogController; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.util.leak.LeakDetector; import java.util.concurrent.Executor; @@ -88,7 +89,9 @@ public interface NotificationsModule { Lazy<NotificationRowBinder> notificationRowBinderLazy, Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy, LeakDetector leakDetector, - ForegroundServiceDismissalFeatureController fgsFeatureController) { + ForegroundServiceDismissalFeatureController fgsFeatureController, + HeadsUpManager headsUpManager, + StatusBarStateController statusBarStateController) { return new NotificationEntryManager( logger, groupManager, @@ -98,7 +101,9 @@ public interface NotificationsModule { notificationRowBinderLazy, notificationRemoteInputManagerLazy, leakDetector, - fgsFeatureController); + fgsFeatureController, + headsUpManager, + statusBarStateController); } /** Provides an instance of {@link NotificationGutsManager} */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java index bd0d0b31e4dc..4441270f895b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java @@ -21,7 +21,6 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.service.notification.NotificationListenerService; -import android.service.notification.NotificationStats; import android.service.notification.StatusBarNotification; import android.util.ArrayMap; import android.util.ArraySet; @@ -44,7 +43,6 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.dagger.NotificationsModule; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; -import com.android.systemui.statusbar.policy.HeadsUpManager; import java.util.Collection; import java.util.Collections; @@ -74,7 +72,6 @@ public class NotificationLogger implements StateListener { private final Executor mUiBgExecutor; private final NotificationEntryManager mEntryManager; private final NotificationPanelLogger mNotificationPanelLogger; - private HeadsUpManager mHeadsUpManager; private final ExpansionStateLogger mExpansionStateLogger; protected Handler mHandler = new Handler(); @@ -226,9 +223,6 @@ public class NotificationLogger implements StateListener { NotificationVisibility visibility, boolean removedByUser, int reason) { - if (removedByUser && visibility != null) { - logNotificationClear(entry.getKey(), entry.getSbn(), visibility); - } mExpansionStateLogger.onEntryRemoved(entry.getKey()); } @@ -250,10 +244,6 @@ public class NotificationLogger implements StateListener { mListContainer = listContainer; } - public void setHeadsUpManager(HeadsUpManager headsUpManager) { - mHeadsUpManager = headsUpManager; - } - public void stopNotificationLogging() { if (mLogging) { mLogging = false; @@ -296,30 +286,6 @@ public class NotificationLogger implements StateListener { } } - // TODO: This method has side effects, it is NOT just logging that a notification - // was cleared, it also actually removes the notification - private void logNotificationClear(String key, StatusBarNotification notification, - NotificationVisibility nv) { - final String pkg = notification.getPackageName(); - final String tag = notification.getTag(); - final int id = notification.getId(); - final int userId = notification.getUserId(); - try { - int dismissalSurface = NotificationStats.DISMISSAL_SHADE; - if (mHeadsUpManager.isAlerting(key)) { - dismissalSurface = NotificationStats.DISMISSAL_PEEK; - } else if (mListContainer.hasPulsingNotifications()) { - dismissalSurface = NotificationStats.DISMISSAL_AOD; - } - int dismissalSentiment = NotificationStats.DISMISS_SENTIMENT_NEUTRAL; - mBarService.onNotificationClear(pkg, tag, id, userId, notification.getKey(), - dismissalSurface, - dismissalSentiment, nv); - } catch (RemoteException ex) { - // system process is dead if we're here. - } - } - /** * Logs Notification inflation error */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java index d7d09e05c238..d3b8a8cd2093 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java @@ -34,6 +34,8 @@ import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; +import java.lang.ref.WeakReference; + class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeActionHelper { @VisibleForTesting @@ -47,7 +49,11 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc private static final long SWIPE_MENU_TIMING = 200; - private NotificationMenuRowPlugin mCurrMenuRow; + // Hold a weak ref to the menu row so that it isn't accidentally retained in memory. The + // lifetime of the row should be the same as the ActivatableView, which is owned by the + // NotificationStackScrollLayout. If the notification isn't in the notification shade, then it + // isn't possible to swipe it and, so, this class doesn't need to "help." + private WeakReference<NotificationMenuRowPlugin> mCurrMenuRowRef; private boolean mIsExpanded; private boolean mPulsing; @@ -82,11 +88,17 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc return mMenuExposedView; } - public void setCurrentMenuRow(NotificationMenuRowPlugin menuRow) { - mCurrMenuRow = menuRow; + @VisibleForTesting + void setCurrentMenuRow(NotificationMenuRowPlugin menuRow) { + mCurrMenuRowRef = menuRow != null ? new WeakReference(menuRow) : null; } - public NotificationMenuRowPlugin getCurrentMenuRow() { return mCurrMenuRow; } + public NotificationMenuRowPlugin getCurrentMenuRow() { + if (mCurrMenuRowRef == null) { + return null; + } + return mCurrMenuRowRef.get(); + } @VisibleForTesting protected Handler getHandler() { return mHandler; } @@ -102,8 +114,9 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc @Override protected void onChildSnappedBack(View animView, float targetLeft) { - if (mCurrMenuRow != null && targetLeft == 0) { - mCurrMenuRow.resetMenu(); + final NotificationMenuRowPlugin menuRow = getCurrentMenuRow(); + if (menuRow != null && targetLeft == 0) { + menuRow.resetMenu(); clearCurrentMenuRow(); } } @@ -129,10 +142,11 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc @VisibleForTesting protected void initializeRow(SwipeableView row) { if (row.hasFinishedInitialization()) { - mCurrMenuRow = row.createMenu(); - if (mCurrMenuRow != null) { - mCurrMenuRow.setMenuClickListener(mMenuListener); - mCurrMenuRow.onTouchStart(); + final NotificationMenuRowPlugin menuRow = row.createMenu(); + setCurrentMenuRow(menuRow); + if (menuRow != null) { + menuRow.setMenuClickListener(mMenuListener); + menuRow.onTouchStart(); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java index 5bc17f5bc2c6..53b369c3543e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java @@ -50,12 +50,12 @@ public class ContextualButton extends ButtonDispatcher { /** * Reload the drawable from resource id, should reapply the previous dark intensity. */ - public void updateIcon() { + public void updateIcon(int lightIconColor, int darkIconColor) { if (getCurrentView() == null || !getCurrentView().isAttachedToWindow() || mIconResId == 0) { return; } final KeyButtonDrawable currentDrawable = getImageDrawable(); - KeyButtonDrawable drawable = getNewDrawable(); + KeyButtonDrawable drawable = getNewDrawable(lightIconColor, darkIconColor); if (currentDrawable != null) { drawable.setDarkIntensity(currentDrawable.getDarkIntensity()); } @@ -116,9 +116,9 @@ public class ContextualButton extends ButtonDispatcher { mGroup = group; } - protected KeyButtonDrawable getNewDrawable() { - return KeyButtonDrawable.create(getContext().getApplicationContext(), mIconResId, - false /* shadow */); + protected KeyButtonDrawable getNewDrawable(int lightIconColor, int darkIconColor) { + return KeyButtonDrawable.create(getContext().getApplicationContext(), lightIconColor, + darkIconColor, mIconResId, false /* shadow */, null /* ovalBackground */); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java index 9e843f93d00e..c1017f4def0f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java @@ -111,9 +111,9 @@ public class ContextualButtonGroup extends ButtonDispatcher { * Update all the icons that are attached to this group. This will get all the buttons to update * their icons for their buttons. */ - public void updateIcons() { + public void updateIcons(int lightIconColor, int darkIconColor) { for (ButtonData data : mButtonData) { - data.button.updateIcon(); + data.button.updateIcon(lightIconColor, darkIconColor); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java index f5ea1c880a41..5fab4bea9a04 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -28,6 +28,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.doze.AlwaysOnDisplayPolicy; import com.android.systemui.doze.DozeScreenState; +import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.tuner.TunerService; import java.io.PrintWriter; @@ -52,6 +53,7 @@ public class DozeParameters implements TunerService.Tunable, private final AlwaysOnDisplayPolicy mAlwaysOnPolicy; private final Resources mResources; + private final BatteryController mBatteryController; private boolean mDozeAlwaysOn; private boolean mControlScreenOffAnimation; @@ -62,10 +64,12 @@ public class DozeParameters implements TunerService.Tunable, AmbientDisplayConfiguration ambientDisplayConfiguration, AlwaysOnDisplayPolicy alwaysOnDisplayPolicy, PowerManager powerManager, + BatteryController batteryController, TunerService tunerService) { mResources = resources; mAmbientDisplayConfiguration = ambientDisplayConfiguration; mAlwaysOnPolicy = alwaysOnDisplayPolicy; + mBatteryController = batteryController; mControlScreenOffAnimation = !getDisplayNeedsBlanking(); mPowerManager = powerManager; @@ -164,7 +168,7 @@ public class DozeParameters implements TunerService.Tunable, * @return {@code true} if enabled and available. */ public boolean getAlwaysOn() { - return mDozeAlwaysOn; + return mDozeAlwaysOn && !mBatteryController.isAodPowerSave(); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java index 16b5a2389ec6..687f5f15a78c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java @@ -16,19 +16,16 @@ package com.android.systemui.statusbar.phone; -import android.annotation.ColorInt; import android.content.Context; import android.content.res.Resources; import android.graphics.Color; import android.graphics.PixelFormat; -import android.view.ContextThemeWrapper; import android.view.Gravity; import android.view.LayoutInflater; import android.view.Surface; import android.view.View; import android.view.WindowManager; -import com.android.settingslib.Utils; import com.android.systemui.R; import com.android.systemui.statusbar.policy.KeyButtonDrawable; import com.android.systemui.statusbar.policy.KeyButtonView; @@ -65,6 +62,8 @@ public class FloatingRotationButton implements RotationButton { @Override public void setRotationButtonController(RotationButtonController rotationButtonController) { mRotationButtonController = rotationButtonController; + updateIcon(mRotationButtonController.getLightIconColor(), + mRotationButtonController.getDarkIconColor()); } @Override @@ -101,7 +100,6 @@ public class FloatingRotationButton implements RotationButton { default: break; } - updateIcon(); mWindowManager.addView(mKeyButtonView, lp); if (mKeyButtonDrawable != null && mKeyButtonDrawable.canAnimate()) { mKeyButtonDrawable.resetAnimation(); @@ -126,17 +124,13 @@ public class FloatingRotationButton implements RotationButton { } @Override - public void updateIcon() { - if (!mIsShowing) { - return; - } - mKeyButtonDrawable = getImageDrawable(); + public void updateIcon(int lightIconColor, int darkIconColor) { + Color ovalBackgroundColor = Color.valueOf(Color.red(darkIconColor), + Color.green(darkIconColor), Color.blue(darkIconColor), BACKGROUND_ALPHA); + mKeyButtonDrawable = KeyButtonDrawable.create(mRotationButtonController.getContext(), + lightIconColor, darkIconColor, mRotationButtonController.getIconResId(), + false /* shadow */, ovalBackgroundColor); mKeyButtonView.setImageDrawable(mKeyButtonDrawable); - mKeyButtonDrawable.setCallback(mKeyButtonView); - if (mKeyButtonDrawable != null && mKeyButtonDrawable.canAnimate()) { - mKeyButtonDrawable.resetAnimation(); - mKeyButtonDrawable.startAnimation(); - } } @Override @@ -151,20 +145,7 @@ public class FloatingRotationButton implements RotationButton { @Override public KeyButtonDrawable getImageDrawable() { - Context context = new ContextThemeWrapper(mContext.getApplicationContext(), - mRotationButtonController.getStyleRes()); - final int dualToneDarkTheme = Utils.getThemeAttr(context, R.attr.darkIconTheme); - final int dualToneLightTheme = Utils.getThemeAttr(context, R.attr.lightIconTheme); - Context lightContext = new ContextThemeWrapper(context, dualToneLightTheme); - Context darkContext = new ContextThemeWrapper(context, dualToneDarkTheme); - @ColorInt int darkColor = Utils.getColorAttrDefaultColor(darkContext, - R.attr.singleToneColor); - Color ovalBackgroundColor = Color.valueOf(Color.red(darkColor), Color.green(darkColor), - Color.blue(darkColor), BACKGROUND_ALPHA); - - return KeyButtonDrawable.create(lightContext, - Utils.getColorAttrDefaultColor(lightContext, R.attr.singleToneColor), darkColor, - R.drawable.ic_sysbar_rotate_button, false /* shadow */, ovalBackgroundColor); + return mKeyButtonDrawable; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index 1eab427b4155..7936e533f76d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -48,6 +48,7 @@ import android.os.Bundle; import android.util.AttributeSet; import android.util.Log; import android.util.SparseArray; +import android.view.ContextThemeWrapper; import android.view.Display; import android.view.MotionEvent; import android.view.Surface; @@ -63,6 +64,7 @@ import android.view.inputmethod.InputMethodManager; import android.widget.FrameLayout; import com.android.internal.annotations.VisibleForTesting; +import com.android.settingslib.Utils; import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; @@ -124,6 +126,9 @@ public class NavigationBarView extends FrameLayout implements private KeyButtonDrawable mHomeDefaultIcon; private KeyButtonDrawable mRecentIcon; private KeyButtonDrawable mDockedIcon; + private Context mLightContext; + private int mLightIconColor; + private int mDarkIconColor; private EdgeBackGestureHandler mEdgeBackGestureHandler; private final DeadZone mDeadZone; @@ -278,6 +283,12 @@ public class NavigationBarView extends FrameLayout implements public NavigationBarView(Context context, AttributeSet attrs) { super(context, attrs); + final Context darkContext = new ContextThemeWrapper(context, + Utils.getThemeAttr(context, R.attr.darkIconTheme)); + mLightContext = new ContextThemeWrapper(context, + Utils.getThemeAttr(context, R.attr.lightIconTheme)); + mLightIconColor = Utils.getColorAttrDefaultColor(mLightContext, R.attr.singleToneColor); + mDarkIconColor = Utils.getColorAttrDefaultColor(darkContext, R.attr.singleToneColor); mIsVertical = false; mLongClickableAccessibilityButton = false; mNavBarMode = Dependency.get(NavigationModeController.class).addListener(this); @@ -290,7 +301,7 @@ public class NavigationBarView extends FrameLayout implements final ContextualButton imeSwitcherButton = new ContextualButton(R.id.ime_switcher, R.drawable.ic_ime_switcher_default); final RotationContextButton rotateSuggestionButton = new RotationContextButton( - R.id.rotate_suggestion, R.drawable.ic_sysbar_rotate_button); + R.id.rotate_suggestion, R.drawable.ic_sysbar_rotate_button_ccw_start_0); final ContextualButton accessibilityButton = new ContextualButton(R.id.accessibility_button, R.drawable.ic_sysbar_accessibility_button); @@ -303,8 +314,8 @@ public class NavigationBarView extends FrameLayout implements mOverviewProxyService = Dependency.get(OverviewProxyService.class); mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService); mFloatingRotationButton = new FloatingRotationButton(context); - mRotationButtonController = new RotationButtonController(context, - R.style.RotateButtonCCWStart90, + mRotationButtonController = new RotationButtonController(mLightContext, + mLightIconColor, mDarkIconColor, isGesturalMode ? mFloatingRotationButton : rotateSuggestionButton); mConfiguration = new Configuration(); @@ -501,7 +512,7 @@ public class NavigationBarView extends FrameLayout implements } if (densityChange || dirChange) { mRecentIcon = getDrawable(R.drawable.ic_sysbar_recent); - mContextualButtonGroup.updateIcons(); + mContextualButtonGroup.updateIcons(mLightIconColor, mDarkIconColor); } if (orientationChange || densityChange || dirChange) { mBackIcon = getBackDrawable(); @@ -559,11 +570,6 @@ public class NavigationBarView extends FrameLayout implements drawable.setRotation(mIsVertical ? 90 : 0); } - private KeyButtonDrawable chooseNavigationIconDrawable(@DrawableRes int icon, - @DrawableRes int quickStepIcon) { - return getDrawable(chooseNavigationIconDrawableRes(icon, quickStepIcon)); - } - private @DrawableRes int chooseNavigationIconDrawableRes(@DrawableRes int icon, @DrawableRes int quickStepIcon) { final boolean quickStepEnabled = mOverviewProxyService.shouldShowSwipeUpUI(); @@ -571,11 +577,8 @@ public class NavigationBarView extends FrameLayout implements } private KeyButtonDrawable getDrawable(@DrawableRes int icon) { - return KeyButtonDrawable.create(mContext, icon, true /* hasShadow */); - } - - private KeyButtonDrawable getDrawable(@DrawableRes int icon, boolean hasShadow) { - return KeyButtonDrawable.create(mContext, icon, hasShadow); + return KeyButtonDrawable.create(mLightContext, mLightIconColor, mDarkIconColor, icon, + true /* hasShadow */, null /* ovalBackgroundColor */); } /** To be called when screen lock/unlock state changes */ @@ -861,7 +864,6 @@ public class NavigationBarView extends FrameLayout implements mBarTransitions.onNavigationModeChanged(mNavBarMode); mEdgeBackGestureHandler.onNavigationModeChanged(mNavBarMode); mRecentsOnboarding.onNavigationModeChanged(mNavBarMode); - getRotateSuggestionButton().onNavigationModeChanged(mNavBarMode); if (isGesturalMode(mNavBarMode)) { mRegionSamplingHelper.start(mSamplingBounds); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index 5bb8fab8a62e..b2cfceae2cf6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -47,6 +47,9 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.DisplayId; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.UiBackground; +import com.android.systemui.privacy.PrivacyItem; +import com.android.systemui.privacy.PrivacyItemController; +import com.android.systemui.privacy.PrivacyType; import com.android.systemui.qs.tiles.DndTile; import com.android.systemui.qs.tiles.RotationLockTile; import com.android.systemui.screenrecord.RecordingController; @@ -70,6 +73,9 @@ import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.util.RingerModeTracker; import com.android.systemui.util.time.DateFormatUtil; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.List; import java.util.Locale; import java.util.concurrent.Executor; @@ -87,13 +93,13 @@ public class PhoneStatusBarPolicy ZenModeController.Callback, DeviceProvisionedListener, KeyguardStateController.Callback, + PrivacyItemController.Callback, LocationController.LocationChangeCallback, RecordingController.RecordingStateChangeCallback { private static final String TAG = "PhoneStatusBarPolicy"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - static final int LOCATION_STATUS_ICON_ID = - com.android.internal.R.drawable.perm_group_location; + static final int LOCATION_STATUS_ICON_ID = PrivacyType.TYPE_LOCATION.getIconId(); private final String mSlotCast; private final String mSlotHotspot; @@ -107,6 +113,8 @@ public class PhoneStatusBarPolicy private final String mSlotHeadset; private final String mSlotDataSaver; private final String mSlotLocation; + private final String mSlotMicrophone; + private final String mSlotCamera; private final String mSlotSensorsOff; private final String mSlotScreenRecord; private final int mDisplayId; @@ -132,6 +140,7 @@ public class PhoneStatusBarPolicy private final DeviceProvisionedController mProvisionedController; private final KeyguardStateController mKeyguardStateController; private final LocationController mLocationController; + private final PrivacyItemController mPrivacyItemController; private final Executor mUiBgExecutor; private final SensorPrivacyController mSensorPrivacyController; private final RecordingController mRecordingController; @@ -162,7 +171,8 @@ public class PhoneStatusBarPolicy RecordingController recordingController, @Nullable TelecomManager telecomManager, @DisplayId int displayId, @Main SharedPreferences sharedPreferences, DateFormatUtil dateFormatUtil, - RingerModeTracker ringerModeTracker) { + RingerModeTracker ringerModeTracker, + PrivacyItemController privacyItemController) { mIconController = iconController; mCommandQueue = commandQueue; mBroadcastDispatcher = broadcastDispatcher; @@ -181,6 +191,7 @@ public class PhoneStatusBarPolicy mProvisionedController = deviceProvisionedController; mKeyguardStateController = keyguardStateController; mLocationController = locationController; + mPrivacyItemController = privacyItemController; mSensorPrivacyController = sensorPrivacyController; mRecordingController = recordingController; mUiBgExecutor = uiBgExecutor; @@ -200,6 +211,8 @@ public class PhoneStatusBarPolicy mSlotHeadset = resources.getString(com.android.internal.R.string.status_bar_headset); mSlotDataSaver = resources.getString(com.android.internal.R.string.status_bar_data_saver); mSlotLocation = resources.getString(com.android.internal.R.string.status_bar_location); + mSlotMicrophone = resources.getString(com.android.internal.R.string.status_bar_microphone); + mSlotCamera = resources.getString(com.android.internal.R.string.status_bar_camera); mSlotSensorsOff = resources.getString(com.android.internal.R.string.status_bar_sensors_off); mSlotScreenRecord = resources.getString( com.android.internal.R.string.status_bar_screen_record); @@ -271,6 +284,13 @@ public class PhoneStatusBarPolicy mResources.getString(R.string.accessibility_data_saver_on)); mIconController.setIconVisibility(mSlotDataSaver, false); + // privacy items + mIconController.setIcon(mSlotMicrophone, PrivacyType.TYPE_MICROPHONE.getIconId(), + mResources.getString(PrivacyType.TYPE_MICROPHONE.getNameId())); + mIconController.setIconVisibility(mSlotMicrophone, false); + mIconController.setIcon(mSlotCamera, PrivacyType.TYPE_CAMERA.getIconId(), + mResources.getString(PrivacyType.TYPE_CAMERA.getNameId())); + mIconController.setIconVisibility(mSlotCamera, false); mIconController.setIcon(mSlotLocation, LOCATION_STATUS_ICON_ID, mResources.getString(R.string.accessibility_location_active)); mIconController.setIconVisibility(mSlotLocation, false); @@ -294,6 +314,7 @@ public class PhoneStatusBarPolicy mNextAlarmController.addCallback(mNextAlarmCallback); mDataSaver.addCallback(this); mKeyguardStateController.addCallback(this); + mPrivacyItemController.addCallback(this); mSensorPrivacyController.addCallback(mSensorPrivacyListener); mLocationController.addCallback(this); mRecordingController.addCallback(this); @@ -609,9 +630,44 @@ public class PhoneStatusBarPolicy mIconController.setIconVisibility(mSlotDataSaver, isDataSaving); } + @Override // PrivacyItemController.Callback + public void onPrivacyItemsChanged(List<PrivacyItem> privacyItems) { + updatePrivacyItems(privacyItems); + } + + private void updatePrivacyItems(List<PrivacyItem> items) { + boolean showCamera = false; + boolean showMicrophone = false; + boolean showLocation = false; + for (PrivacyItem item : items) { + if (item == null /* b/124234367 */) { + Log.e(TAG, "updatePrivacyItems - null item found"); + StringWriter out = new StringWriter(); + mPrivacyItemController.dump(null, new PrintWriter(out), null); + // Throw so we can look into this + throw new NullPointerException(out.toString()); + } + switch (item.getPrivacyType()) { + case TYPE_CAMERA: + showCamera = true; + break; + case TYPE_LOCATION: + showLocation = true; + break; + case TYPE_MICROPHONE: + showMicrophone = true; + break; + } + } + + mIconController.setIconVisibility(mSlotCamera, showCamera); + mIconController.setIconVisibility(mSlotMicrophone, showMicrophone); + mIconController.setIconVisibility(mSlotLocation, showLocation); + } + @Override public void onLocationActiveChanged(boolean active) { - updateLocation(); + if (!mPrivacyItemController.getIndicatorsAvailable()) updateLocation(); } // Updates the status view based on the current state of location requests. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButton.java index 2580c0e77013..687efd34ee30 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButton.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButton.java @@ -27,7 +27,7 @@ interface RotationButton { boolean show(); boolean hide(); boolean isVisible(); - void updateIcon(); + void updateIcon(int lightIconColor, int darkIconColor); void setOnClickListener(View.OnClickListener onClickListener); void setOnHoverListener(View.OnHoverListener onHoverListener); KeyButtonDrawable getImageDrawable(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java index 59b10e416b03..f83cdd488c04 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java @@ -21,6 +21,8 @@ import static com.android.internal.view.RotationPolicy.NATURAL_ROTATION; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; +import android.annotation.ColorInt; +import android.annotation.DrawableRes; import android.annotation.StyleRes; import android.app.StatusBarManager; import android.content.ContentResolver; @@ -30,6 +32,7 @@ import android.os.Looper; import android.os.RemoteException; import android.provider.Settings; import android.util.Log; +import android.view.ContextThemeWrapper; import android.view.IRotationWatcher.Stub; import android.view.MotionEvent; import android.view.Surface; @@ -40,6 +43,7 @@ import android.view.accessibility.AccessibilityManager; import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.UiEventLoggerImpl; +import com.android.settingslib.Utils; import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; @@ -61,10 +65,12 @@ public class RotationButtonController { private static final int NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION = 3; + private final Context mContext; + private final RotationButton mRotationButton; + private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); private final UiEventLogger mUiEventLogger = new UiEventLoggerImpl(); private final ViewRippler mViewRippler = new ViewRippler(); - private @StyleRes int mStyleRes; private int mLastRotationSuggestion; private boolean mPendingRotationSuggestion; private boolean mHoveringRotationSuggestion; @@ -75,6 +81,9 @@ public class RotationButtonController { private boolean mListenersRegistered = false; private boolean mIsNavigationBarShowing; private boolean mSkipOverrideUserLockPrefsOnce; + private int mLightIconColor; + private int mDarkIconColor; + private int mIconResId = R.drawable.ic_sysbar_rotate_button_ccw_start_90; private final Runnable mRemoveRotationProposal = () -> setRotateSuggestionButtonState(false /* visible */); @@ -82,9 +91,6 @@ public class RotationButtonController { () -> mPendingRotationSuggestion = false; private Animator mRotateHideAnimator; - private final Context mContext; - private final RotationButton mRotationButton; - private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); private final Stub mRotationWatcher = new Stub() { @Override @@ -117,12 +123,14 @@ public class RotationButtonController { return (disable2Flags & StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS) != 0; } - RotationButtonController(Context context, @StyleRes int style, RotationButton rotationButton) { + RotationButtonController(Context context, @ColorInt int lightIconColor, + @ColorInt int darkIconColor, RotationButton rotationButton) { mContext = context; + mLightIconColor = lightIconColor; + mDarkIconColor = darkIconColor; mRotationButton = rotationButton; mRotationButton.setRotationButtonController(this); - mStyleRes = style; mIsNavigationBarShowing = true; mRotationLockController = Dependency.get(RotationLockController.class); mAccessibilityManagerWrapper = Dependency.get(AccessibilityManagerWrapper.class); @@ -275,17 +283,20 @@ public class RotationButtonController { return; } + // TODO: Remove styles? // Prepare to show the navbar icon by updating the icon style to change anim params mLastRotationSuggestion = rotation; // Remember rotation for click final boolean rotationCCW = isRotationAnimationCCW(windowRotation, rotation); - int style; if (windowRotation == Surface.ROTATION_0 || windowRotation == Surface.ROTATION_180) { - style = rotationCCW ? R.style.RotateButtonCCWStart90 : R.style.RotateButtonCWStart90; + mIconResId = rotationCCW + ? R.drawable.ic_sysbar_rotate_button_ccw_start_90 + : R.drawable.ic_sysbar_rotate_button_cw_start_90; } else { // 90 or 270 - style = rotationCCW ? R.style.RotateButtonCCWStart0 : R.style.RotateButtonCWStart0; + mIconResId = rotationCCW + ? R.drawable.ic_sysbar_rotate_button_ccw_start_0 + : R.drawable.ic_sysbar_rotate_button_ccw_start_0; } - mStyleRes = style; - mRotationButton.updateIcon(); + mRotationButton.updateIcon(mLightIconColor, mDarkIconColor); if (mIsNavigationBarShowing) { // The navbar is visible so show the icon right away @@ -316,14 +327,26 @@ public class RotationButtonController { } } - @StyleRes int getStyleRes() { - return mStyleRes; + Context getContext() { + return mContext; } RotationButton getRotationButton() { return mRotationButton; } + @DrawableRes int getIconResId() { + return mIconResId; + } + + @ColorInt int getLightIconColor() { + return mLightIconColor; + } + + @ColorInt int getDarkIconColor() { + return mDarkIconColor; + } + private void onRotateSuggestionClick(View v) { mUiEventLogger.log(RotationButtonEvent.ROTATION_SUGGESTION_ACCEPTED); incrementNumAcceptedRotationSuggestionsIfNeeded(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java index bd9675280b0b..d7e95e43ea8f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java @@ -16,22 +16,16 @@ package com.android.systemui.statusbar.phone; -import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; - import android.annotation.DrawableRes; import android.annotation.IdRes; -import android.content.Context; -import android.view.ContextThemeWrapper; import android.view.View; import com.android.systemui.statusbar.policy.KeyButtonDrawable; /** Containing logic for the rotation button in nav bar. */ -public class RotationContextButton extends ContextualButton implements - NavigationModeController.ModeChangedListener, RotationButton { +public class RotationContextButton extends ContextualButton implements RotationButton { public static final boolean DEBUG_ROTATION = false; - private int mNavBarMode = NAV_BAR_MODE_3BUTTON; private RotationButtonController mRotationButtonController; public RotationContextButton(@IdRes int buttonResId, @DrawableRes int iconResId) { @@ -56,16 +50,10 @@ public class RotationContextButton extends ContextualButton implements } @Override - protected KeyButtonDrawable getNewDrawable() { - Context context = new ContextThemeWrapper(getContext().getApplicationContext(), - mRotationButtonController.getStyleRes()); - return KeyButtonDrawable.create(context, mIconResId, false /* shadow */, - null /* ovalBackgroundColor */); - } - - @Override - public void onNavigationModeChanged(int mode) { - mNavBarMode = mode; + protected KeyButtonDrawable getNewDrawable(int lightIconColor, int darkIconColor) { + return KeyButtonDrawable.create(mRotationButtonController.getContext(), + lightIconColor, darkIconColor, mRotationButtonController.getIconResId(), + false /* shadow */, null /* ovalBackgroundColor */); } @Override 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 c5acd9bd0f06..1f2a2c652331 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -1101,7 +1101,6 @@ public class StatusBar extends SystemUI implements DemoMode, mHeadsUpManager.addListener(mNotificationPanelViewController.getOnHeadsUpChangedListener()); mHeadsUpManager.addListener(mVisualStabilityManager); mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager); - mNotificationLogger.setHeadsUpManager(mHeadsUpManager); createNavigationBar(result); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java index 6dd96f92b344..95601955ec04 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java @@ -23,6 +23,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.res.TypedArray; import android.graphics.Rect; +import android.icu.text.DateTimePatternGenerator; import android.os.Bundle; import android.os.Handler; import android.os.Parcelable; @@ -53,8 +54,6 @@ import com.android.systemui.statusbar.policy.ConfigurationController.Configurati import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; -import libcore.icu.LocaleData; - import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Locale; @@ -391,15 +390,16 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C private final CharSequence getSmallTime() { Context context = getContext(); boolean is24 = DateFormat.is24HourFormat(context, mCurrentUserId); - LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale); + DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance( + context.getResources().getConfiguration().locale); final char MAGIC1 = '\uEF00'; final char MAGIC2 = '\uEF01'; SimpleDateFormat sdf; String format = mShowSeconds - ? is24 ? d.timeFormat_Hms : d.timeFormat_hms - : is24 ? d.timeFormat_Hm : d.timeFormat_hm; + ? is24 ? dtpg.getBestPattern("Hms") : dtpg.getBestPattern("hms") + : is24 ? dtpg.getBestPattern("Hm") : dtpg.getBestPattern("hm"); if (!format.equals(mClockFormatString)) { mContentDescriptionFormat = new SimpleDateFormat(format); /* diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java index 23d03a4b225a..755938863b5e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java @@ -37,7 +37,6 @@ import android.graphics.Rect; import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.Drawable; import android.util.FloatProperty; -import android.view.ContextThemeWrapper; import android.view.View; import com.android.settingslib.Utils; @@ -439,34 +438,6 @@ public class KeyButtonDrawable extends Drawable { } /** - * Creates a KeyButtonDrawable with a shadow given its icon. The tint applied to the drawable - * is determined by the dark and light theme given by the context. - * @param ctx Context to get the drawable and determine the dark and light theme - * @param icon the icon resource id - * @param hasShadow if a shadow will appear with the drawable - * @param ovalBackgroundColor the color of the oval bg that will be drawn - * @return KeyButtonDrawable - */ - public static KeyButtonDrawable create(@NonNull Context ctx, @DrawableRes int icon, - boolean hasShadow, Color ovalBackgroundColor) { - final int dualToneDarkTheme = Utils.getThemeAttr(ctx, R.attr.darkIconTheme); - final int dualToneLightTheme = Utils.getThemeAttr(ctx, R.attr.lightIconTheme); - Context lightContext = new ContextThemeWrapper(ctx, dualToneLightTheme); - Context darkContext = new ContextThemeWrapper(ctx, dualToneDarkTheme); - return KeyButtonDrawable.create(lightContext, darkContext, icon, hasShadow, - ovalBackgroundColor); - } - - /** - * Creates a KeyButtonDrawable with a shadow given its icon. For more information, see - * {@link #create(Context, int, boolean, boolean)}. - */ - public static KeyButtonDrawable create(@NonNull Context ctx, @DrawableRes int icon, - boolean hasShadow) { - return create(ctx, icon, hasShadow, null /* ovalBackgroundColor */); - } - - /** * Creates a KeyButtonDrawable with a shadow given its icon. For more information, see * {@link #create(Context, int, boolean, boolean)}. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java index 251693e162d0..adfc14e1d72b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java @@ -39,6 +39,7 @@ import com.android.systemui.BootCompleteCache; import com.android.systemui.appops.AppOpItem; import com.android.systemui.appops.AppOpsController; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.util.Utils; @@ -65,8 +66,8 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio @Inject public LocationControllerImpl(Context context, AppOpsController appOpsController, - @Main Looper mainLooper, BroadcastDispatcher broadcastDispatcher, - BootCompleteCache bootCompleteCache) { + @Main Looper mainLooper, @Background Handler backgroundHandler, + BroadcastDispatcher broadcastDispatcher, BootCompleteCache bootCompleteCache) { mContext = context; mAppOpsController = appOpsController; mBootCompleteCache = bootCompleteCache; @@ -80,7 +81,7 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio mAppOpsController.addCallback(new int[]{OP_MONITOR_HIGH_POWER_LOCATION}, this); // Examine the current location state and initialize the status view. - updateActiveLocationRequests(); + backgroundHandler.post(this::updateActiveLocationRequests); } /** diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java index b12224bf583d..d1805af06434 100644 --- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java @@ -44,13 +44,17 @@ import android.text.format.DateUtils; import android.util.Log; import android.util.LongSparseArray; +import com.android.internal.logging.MetricsLogger; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.SystemUI; import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import java.io.FileDescriptor; @@ -396,15 +400,23 @@ public class GarbageMonitor implements Dumpable { public static final String TILE_SPEC = "dbg:mem"; private final GarbageMonitor gm; - private final ActivityStarter mActivityStarter; private ProcessMemInfo pmi; private boolean dumpInProgress; @Inject - public MemoryTile(QSHost host, GarbageMonitor monitor, ActivityStarter starter) { - super(host); + public MemoryTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + GarbageMonitor monitor + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); gm = monitor; - mActivityStarter = starter; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettings.java b/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettings.java new file mode 100644 index 000000000000..84ab66b66a7c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettings.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.util.settings; + +/** + * Public interface that can be injected to interact with Settings.Global. + * + * See {@link SettingsProxy} for details. + */ +public interface GlobalSettings extends SettingsProxy { +} diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java b/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java new file mode 100644 index 000000000000..1a30b0a8d8bf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.util.settings; + +import android.content.ContentResolver; +import android.net.Uri; +import android.provider.Settings; + +import javax.inject.Inject; + +class GlobalSettingsImpl implements GlobalSettings { + private final ContentResolver mContentResolver; + + @Inject + GlobalSettingsImpl(ContentResolver contentResolver) { + mContentResolver = contentResolver; + } + + @Override + public ContentResolver getContentResolver() { + return mContentResolver; + } + + @Override + public Uri getUriFor(String name) { + return Settings.Global.getUriFor(name); + } + + @Override + public String getStringForUser(String name, int userHandle) { + return Settings.Global.getStringForUser(mContentResolver, name, userHandle); + } + + @Override + public boolean putString(String name, String value, boolean overrideableByRestore) { + throw new UnsupportedOperationException( + "This method only exists publicly for Settings.System and Settings.Secure"); + } + + @Override + public boolean putStringForUser(String name, String value, int userHandle) { + return Settings.Global.putStringForUser(mContentResolver, name, value, userHandle); + } + + @Override + public boolean putStringForUser(String name, String value, String tag, boolean makeDefault, + int userHandle, boolean overrideableByRestore) { + return Settings.Global.putStringForUser( + mContentResolver, name, value, tag, makeDefault, userHandle, overrideableByRestore); + } + + @Override + public boolean putString(String name, String value, String tag, boolean makeDefault) { + return Settings.Global.putString(mContentResolver, name, value, tag, makeDefault); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettings.java b/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettings.java new file mode 100644 index 000000000000..798033e841d5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettings.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.util.settings; + +/** + * Public interface that can be injected to interact with Settings.Secure. + * + * See {@link SettingsProxy} for details. + */ + +public interface SecureSettings extends SettingsProxy { +} diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java b/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java new file mode 100644 index 000000000000..020c234191e0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.util.settings; + +import android.content.ContentResolver; +import android.net.Uri; +import android.provider.Settings; + +import javax.inject.Inject; + +class SecureSettingsImpl implements SecureSettings { + private final ContentResolver mContentResolver; + + @Inject + SecureSettingsImpl(ContentResolver contentResolver) { + mContentResolver = contentResolver; + } + + @Override + public ContentResolver getContentResolver() { + return mContentResolver; + } + + @Override + public Uri getUriFor(String name) { + return Settings.Secure.getUriFor(name); + } + + @Override + public String getStringForUser(String name, int userHandle) { + return Settings.Secure.getStringForUser(mContentResolver, name, userHandle); + } + + @Override + public boolean putString(String name, String value, boolean overrideableByRestore) { + return Settings.Secure.putString(mContentResolver, name, value, overrideableByRestore); + } + + @Override + public boolean putStringForUser(String name, String value, int userHandle) { + return Settings.Secure.putStringForUser(mContentResolver, name, value, userHandle); + } + + @Override + public boolean putStringForUser(String name, String value, String tag, boolean makeDefault, + int userHandle, boolean overrideableByRestore) { + return Settings.Secure.putStringForUser( + mContentResolver, name, value, tag, makeDefault, userHandle, overrideableByRestore); + } + + @Override + public boolean putString(String name, String value, String tag, boolean makeDefault) { + return Settings.Secure.putString(mContentResolver, name, value, tag, makeDefault); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java new file mode 100644 index 000000000000..5c37f797b678 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java @@ -0,0 +1,412 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.util.settings; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.content.ContentResolver; +import android.database.ContentObserver; +import android.net.Uri; +import android.provider.Settings; + +/** + * Used to interact with Settings.Secure, Settings.Global, and Settings.System. + * + * This interface can be implemented to give instance method (instead of static method) versions + * of Settings.Secure, Settings.Global, and Settings.System. It can be injected into class + * constructors and then faked or mocked as needed in tests. + * + * You can ask for {@link SecureSettings}, {@link GlobalSettings}, or {@link SystemSettings} to be + * injected as needed. + * + * This class also provides {@link #registerContentObserver(String, ContentObserver)} methods, + * normally found on {@link ContentResolver} instances, unifying setting related actions in one + * place. + */ +public interface SettingsProxy { + + /** + * Returns the {@link ContentResolver} this instance was constructed with. + */ + ContentResolver getContentResolver(); + + /** + * Returns the user id for the associated {@link ContentResolver}. + */ + default int getUserId() { + return getContentResolver().getUserId(); + } + + /** + * Construct the content URI for a particular name/value pair, + * useful for monitoring changes with a ContentObserver. + * @param name to look up in the table + * @return the corresponding content URI, or null if not present + */ + Uri getUriFor(String name); + + /** + * Convenience wrapper around + * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.' + * + * Implicitly calls {@link #getUriFor(String)} on the passed in name. + */ + default void registerContentObserver(String name, ContentObserver settingsObserver) { + registerContentObserverForUser(name, settingsObserver, getUserId()); + } + + /** + * Convenience wrapper around + * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)} + * + * Implicitly calls {@link #getUriFor(String)} on the passed in name. + */ + default void registerContentObserverForUser( + String name, ContentObserver settingsObserver, int userHandle) { + getContentResolver().registerContentObserver( + getUriFor(name), false, settingsObserver, userHandle); + } + + /** See {@link ContentResolver#unregisterContentObserver(ContentObserver)}. */ + default void unregisterContentObserver(ContentObserver settingsObserver) { + getContentResolver().unregisterContentObserver(settingsObserver); + } + + /** + * Look up a name in the database. + * @param name to look up in the table + * @return the corresponding value, or null if not present + */ + default String getString(String name) { + return getStringForUser(name, getUserId()); + } + + /**See {@link #getString(String)}. */ + String getStringForUser(String name, int userHandle); + + /** + * Store a name/value pair into the database. Values written by this method will be + * overridden if a restore happens in the future. + * + * @param name to store + * @param value to associate with the name + * @return true if the value was set, false on database errors + */ + boolean putString(String name, String value, boolean overrideableByRestore); + + /** + * Store a name/value pair into the database. + * @param name to store + * @param value to associate with the name + * @return true if the value was set, false on database errors + */ + default boolean putString(String name, String value) { + return putStringForUser(name, value, getUserId()); + } + + /** See {@link #putString(String, String)}. */ + boolean putStringForUser(String name, String value, int userHandle); + + /** See {@link #putString(String, String)}. */ + boolean putStringForUser(@NonNull String name, @Nullable String value, @Nullable String tag, + boolean makeDefault, @UserIdInt int userHandle, boolean overrideableByRestore); + + /** + * Store a name/value pair into the database. + * <p> + * The method takes an optional tag to associate with the setting + * which can be used to clear only settings made by your package and + * associated with this tag by passing the tag to {@link + * #resetToDefaults(String)}. Anyone can override + * the current tag. Also if another package changes the setting + * then the tag will be set to the one specified in the set call + * which can be null. Also any of the settings setters that do not + * take a tag as an argument effectively clears the tag. + * </p><p> + * For example, if you set settings A and B with tags T1 and T2 and + * another app changes setting A (potentially to the same value), it + * can assign to it a tag T3 (note that now the package that changed + * the setting is not yours). Now if you reset your changes for T1 and + * T2 only setting B will be reset and A not (as it was changed by + * another package) but since A did not change you are in the desired + * initial state. Now if the other app changes the value of A (assuming + * you registered an observer in the beginning) you would detect that + * the setting was changed by another app and handle this appropriately + * (ignore, set back to some value, etc). + * </p><p> + * Also the method takes an argument whether to make the value the + * default for this setting. If the system already specified a default + * value, then the one passed in here will <strong>not</strong> + * be set as the default. + * </p> + * + * @param name to store. + * @param value to associate with the name. + * @param tag to associate with the setting. + * @param makeDefault whether to make the value the default one. + * @return true if the value was set, false on database errors. + * + * @see #resetToDefaults(String) + * + */ + boolean putString(@NonNull String name, @Nullable String value, @Nullable String tag, + boolean makeDefault); + + /** + * Convenience function for retrieving a single secure settings value + * as an integer. Note that internally setting values are always + * stored as strings; this function converts the string to an integer + * for you. The default value will be returned if the setting is + * not defined or not an integer. + * + * @param name The name of the setting to retrieve. + * @param def Value to return if the setting is not defined. + * + * @return The setting's current value, or 'def' if it is not defined + * or not a valid integer. + */ + default int getInt(String name, int def) { + return getIntForUser(name, def, getUserId()); + } + + /** See {@link #getInt(String, int)}. */ + default int getIntForUser(String name, int def, int userHandle) { + String v = getStringForUser(name, userHandle); + try { + return v != null ? Integer.parseInt(v) : def; + } catch (NumberFormatException e) { + return def; + } + } + + /** + * Convenience function for retrieving a single secure settings value + * as an integer. Note that internally setting values are always + * stored as strings; this function converts the string to an integer + * for you. + * <p> + * This version does not take a default value. If the setting has not + * been set, or the string value is not a number, + * it throws {@link Settings.SettingNotFoundException}. + * + * @param name The name of the setting to retrieve. + * + * @throws Settings.SettingNotFoundException Thrown if a setting by the given + * name can't be found or the setting value is not an integer. + * + * @return The setting's current value. + */ + default int getInt(String name) throws Settings.SettingNotFoundException { + return getIntForUser(name, getUserId()); + } + + /** See {@link #getInt(String)}. */ + default int getIntForUser(String name, int userHandle) + throws Settings.SettingNotFoundException { + String v = getStringForUser(name, userHandle); + try { + return Integer.parseInt(v); + } catch (NumberFormatException e) { + throw new Settings.SettingNotFoundException(name); + } + } + + /** + * Convenience function for updating a single settings value as an + * integer. This will either create a new entry in the table if the + * given name does not exist, or modify the value of the existing row + * with that name. Note that internally setting values are always + * stored as strings, so this function converts the given value to a + * string before storing it. + * + * @param name The name of the setting to modify. + * @param value The new value for the setting. + * @return true if the value was set, false on database errors + */ + default boolean putInt(String name, int value) { + return putIntForUser(name, value, getUserId()); + } + /** See {@link #putInt(String, int)}. */ + default boolean putIntForUser(String name, int value, int userHandle) { + return putStringForUser(name, Integer.toString(value), userHandle); + } + + /** + * Convenience function for retrieving a single secure settings value + * as a {@code long}. Note that internally setting values are always + * stored as strings; this function converts the string to a {@code long} + * for you. The default value will be returned if the setting is + * not defined or not a {@code long}. + * + * @param name The name of the setting to retrieve. + * @param def Value to return if the setting is not defined. + * + * @return The setting's current value, or 'def' if it is not defined + * or not a valid {@code long}. + */ + default long getLong(String name, long def) { + return getLongForUser(name, def, getUserId()); + } + + /** See {@link #getLong(String, long)}. */ + default long getLongForUser(String name, long def, int userHandle) { + String valString = getStringForUser(name, userHandle); + long value; + try { + value = valString != null ? Long.parseLong(valString) : def; + } catch (NumberFormatException e) { + value = def; + } + return value; + } + + /** + * Convenience function for retrieving a single secure settings value + * as a {@code long}. Note that internally setting values are always + * stored as strings; this function converts the string to a {@code long} + * for you. + * <p> + * This version does not take a default value. If the setting has not + * been set, or the string value is not a number, + * it throws {@link Settings.SettingNotFoundException}. + * + * @param name The name of the setting to retrieve. + * + * @return The setting's current value. + * @throws Settings.SettingNotFoundException Thrown if a setting by the given + * name can't be found or the setting value is not an integer. + */ + default long getLong(String name) throws Settings.SettingNotFoundException { + return getLongForUser(name, getUserId()); + } + + /** See {@link #getLong(String)}. */ + default long getLongForUser(String name, int userHandle) + throws Settings.SettingNotFoundException { + String valString = getStringForUser(name, userHandle); + try { + return Long.parseLong(valString); + } catch (NumberFormatException e) { + throw new Settings.SettingNotFoundException(name); + } + } + + /** + * Convenience function for updating a secure settings value as a long + * integer. This will either create a new entry in the table if the + * given name does not exist, or modify the value of the existing row + * with that name. Note that internally setting values are always + * stored as strings, so this function converts the given value to a + * string before storing it. + * + * @param name The name of the setting to modify. + * @param value The new value for the setting. + * @return true if the value was set, false on database errors + */ + default boolean putLong(String name, long value) { + return putLongForUser(name, value, getUserId()); + } + + /** See {@link #putLong(String, long)}. */ + default boolean putLongForUser(String name, long value, int userHandle) { + return putStringForUser(name, Long.toString(value), userHandle); + } + + /** + * Convenience function for retrieving a single secure settings value + * as a floating point number. Note that internally setting values are + * always stored as strings; this function converts the string to an + * float for you. The default value will be returned if the setting + * is not defined or not a valid float. + * + * @param name The name of the setting to retrieve. + * @param def Value to return if the setting is not defined. + * + * @return The setting's current value, or 'def' if it is not defined + * or not a valid float. + */ + default float getFloat(String name, float def) { + return getFloatForUser(name, def, getUserId()); + } + + /** See {@link #getFloat(String)}. */ + default float getFloatForUser(String name, float def, int userHandle) { + String v = getStringForUser(name, userHandle); + try { + return v != null ? Float.parseFloat(v) : def; + } catch (NumberFormatException e) { + return def; + } + } + + /** + * Convenience function for retrieving a single secure settings value + * as a float. Note that internally setting values are always + * stored as strings; this function converts the string to a float + * for you. + * <p> + * This version does not take a default value. If the setting has not + * been set, or the string value is not a number, + * it throws {@link Settings.SettingNotFoundException}. + * + * @param name The name of the setting to retrieve. + * + * @throws Settings.SettingNotFoundException Thrown if a setting by the given + * name can't be found or the setting value is not a float. + * + * @return The setting's current value. + */ + default float getFloat(String name) throws Settings.SettingNotFoundException { + return getFloatForUser(name, getUserId()); + } + + /** See {@link #getFloat(String, float)}. */ + default float getFloatForUser(String name, int userHandle) + throws Settings.SettingNotFoundException { + String v = getStringForUser(name, userHandle); + if (v == null) { + throw new Settings.SettingNotFoundException(name); + } + try { + return Float.parseFloat(v); + } catch (NumberFormatException e) { + throw new Settings.SettingNotFoundException(name); + } + } + + /** + * Convenience function for updating a single settings value as a + * floating point number. This will either create a new entry in the + * table if the given name does not exist, or modify the value of the + * existing row with that name. Note that internally setting values + * are always stored as strings, so this function converts the given + * value to a string before storing it. + * + * @param name The name of the setting to modify. + * @param value The new value for the setting. + * @return true if the value was set, false on database errors + */ + default boolean putFloat(String name, float value) { + return putFloatForUser(name, value, getUserId()); + } + + /** See {@link #putFloat(String, float)} */ + default boolean putFloatForUser(String name, float value, int userHandle) { + return putStringForUser(name, Float.toString(value), userHandle); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsUtilModule.java b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsUtilModule.java new file mode 100644 index 000000000000..f36c335e0f44 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsUtilModule.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.util.settings; + +import dagger.Binds; +import dagger.Module; + +/** + * Dagger Module for classes within com.android.systemui.util.settings. + */ +@Module +public interface SettingsUtilModule { + + /** Bind SecureSettingsImpl to SecureSettings. */ + @Binds + SecureSettings bindsSecureSettings(SecureSettingsImpl impl); + + /** Bind SystemSettingsImpl to SystemSettings. */ + @Binds + SystemSettings bindsSystemSettings(SystemSettingsImpl impl); + + /** Bind GlobalSettingsImpl to GlobalSettings. */ + @Binds + GlobalSettings bindsGlobalSettings(GlobalSettingsImpl impl); +} diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettings.java b/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettings.java new file mode 100644 index 000000000000..d57d7496381c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettings.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.util.settings; + +/** + * Public interface that can be injected to interact with Settings.System. + * + * See {@link SettingsProxy} for details. + */ +public interface SystemSettings extends SettingsProxy { +} diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java b/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java new file mode 100644 index 000000000000..0dbb76f8f758 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.util.settings; + +import android.content.ContentResolver; +import android.net.Uri; +import android.provider.Settings; + +import javax.inject.Inject; + +class SystemSettingsImpl implements SystemSettings { + private final ContentResolver mContentResolver; + + @Inject + SystemSettingsImpl(ContentResolver contentResolver) { + mContentResolver = contentResolver; + } + + @Override + public ContentResolver getContentResolver() { + return mContentResolver; + } + + @Override + public Uri getUriFor(String name) { + return Settings.System.getUriFor(name); + } + + @Override + public String getStringForUser(String name, int userHandle) { + return Settings.System.getStringForUser(mContentResolver, name, userHandle); + } + + @Override + public boolean putString(String name, String value, boolean overrideableByRestore) { + return Settings.System.putString(mContentResolver, name, value, overrideableByRestore); + } + + @Override + public boolean putStringForUser(String name, String value, int userHandle) { + return Settings.System.putStringForUser(mContentResolver, name, value, userHandle); + } + + @Override + public boolean putStringForUser(String name, String value, String tag, boolean makeDefault, + int userHandle, boolean overrideableByRestore) { + throw new UnsupportedOperationException( + "This method only exists publicly for Settings.Secure and Settings.Global"); + } + + @Override + public boolean putString(String name, String value, String tag, boolean makeDefault) { + throw new UnsupportedOperationException( + "This method only exists publicly for Settings.Secure and Settings.Global"); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellModule.java new file mode 100644 index 000000000000..fbc167683a2a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellModule.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.wmshell; + +import android.content.Context; +import android.os.Handler; +import android.view.IWindowManager; + +import com.android.systemui.dagger.qualifiers.Main; +import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.DisplayImeController; +import com.android.wm.shell.common.SystemWindows; +import com.android.wm.shell.common.TransactionPool; + +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +/** + * Provides dependencies from {@link com.android.wm.shell}. + */ +@Module +// TODO(b/161116823) Clean up dependencies after wm shell migration finished. +public class WindowManagerShellModule { + @Singleton + @Provides + static TransactionPool provideTransactionPool() { + return new TransactionPool(); + } + + @Singleton + @Provides + static DisplayController provideDisplayController(Context context, @Main Handler handler, + IWindowManager wmService) { + return new DisplayController(context, handler, wmService); + } + + @Singleton + @Provides + static SystemWindows provideSystemWindows(DisplayController displayController, + IWindowManager wmService) { + return new SystemWindows(displayController, wmService); + } + + @Singleton + @Provides + static DisplayImeController provideDisplayImeController( + IWindowManager wmService, DisplayController displayController, + @Main Handler mainHandler, TransactionPool transactionPool) { + return new DisplayImeController(wmService, displayController, mainHandler, transactionPool); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java index dd3a7858fd1f..b6cc2ee03f38 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java +++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java @@ -140,6 +140,10 @@ public abstract class SysuiTestCase { return null; } + protected FakeBroadcastDispatcher getFakeBroadcastDispatcher() { + return mFakeBroadcastDispatcher; + } + public SysuiTestableContext getContext() { return mContext; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java index e0049d1349f1..4fdc06e64e2c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java @@ -26,11 +26,14 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; 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.AppOpsManager; +import android.content.pm.PackageManager; import android.os.Looper; import android.os.UserHandle; import android.testing.AndroidTestingRunner; @@ -56,6 +59,7 @@ public class AppOpsControllerTest extends SysuiTestCase { private static final String TEST_PACKAGE_NAME = "test"; private static final int TEST_UID = UserHandle.getUid(0, 0); private static final int TEST_UID_OTHER = UserHandle.getUid(1, 0); + private static final int TEST_UID_NON_USER_SENSITIVE = UserHandle.getUid(2, 0); @Mock private AppOpsManager mAppOpsManager; @@ -65,6 +69,10 @@ public class AppOpsControllerTest extends SysuiTestCase { private AppOpsControllerImpl.H mMockHandler; @Mock private DumpManager mDumpManager; + @Mock + private PermissionFlagsCache mFlagsCache; + @Mock + private PackageManager mPackageManager; private AppOpsControllerImpl mController; private TestableLooper mTestableLooper; @@ -76,8 +84,22 @@ public class AppOpsControllerTest extends SysuiTestCase { getContext().addMockSystemService(AppOpsManager.class, mAppOpsManager); - mController = - new AppOpsControllerImpl(mContext, mTestableLooper.getLooper(), mDumpManager); + // All permissions of TEST_UID and TEST_UID_OTHER are user sensitive. None of + // TEST_UID_NON_USER_SENSITIVE are user sensitive. + getContext().setMockPackageManager(mPackageManager); + when(mFlagsCache.getPermissionFlags(anyString(), anyString(), eq(TEST_UID))).thenReturn( + PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED); + when(mFlagsCache.getPermissionFlags(anyString(), anyString(), eq(TEST_UID_OTHER))) + .thenReturn(PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED); + when(mFlagsCache.getPermissionFlags(anyString(), anyString(), + eq(TEST_UID_NON_USER_SENSITIVE))).thenReturn(0); + + mController = new AppOpsControllerImpl( + mContext, + mTestableLooper.getLooper(), + mDumpManager, + mFlagsCache + ); } @Test @@ -173,6 +195,26 @@ public class AppOpsControllerTest extends SysuiTestCase { } @Test + public void nonUserSensitiveOpsAreIgnored() { + mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO, + TEST_UID_NON_USER_SENSITIVE, TEST_PACKAGE_NAME, true); + assertEquals(0, mController.getActiveAppOpsForUser( + UserHandle.getUserId(TEST_UID_NON_USER_SENSITIVE)).size()); + } + + @Test + public void nonUserSensitiveOpsNotNotified() { + mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); + mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO, + TEST_UID_NON_USER_SENSITIVE, TEST_PACKAGE_NAME, true); + + mTestableLooper.processAllMessages(); + + verify(mCallback, never()) + .onActiveStateChanged(anyInt(), anyInt(), anyString(), anyBoolean()); + } + + @Test public void opNotedScheduledForRemoval() { mController.setBGHandler(mMockHandler); mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/PermissionFlagsCacheTest.kt b/packages/SystemUI/tests/src/com/android/systemui/appops/PermissionFlagsCacheTest.kt new file mode 100644 index 000000000000..0fb0ce087ee3 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/appops/PermissionFlagsCacheTest.kt @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.appops + +import android.content.pm.PackageManager +import android.os.UserHandle +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.time.FakeSystemClock +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotEquals +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyString +import org.mockito.Mock +import org.mockito.Mockito.`when` +import org.mockito.Mockito.never +import org.mockito.Mockito.times +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class PermissionFlagsCacheTest : SysuiTestCase() { + + companion object { + const val TEST_PERMISSION = "test_permission" + const val TEST_PACKAGE = "test_package" + const val TEST_UID1 = 1000 + const val TEST_UID2 = UserHandle.PER_USER_RANGE + 1000 + } + + @Mock + private lateinit var packageManager: PackageManager + + private lateinit var executor: FakeExecutor + private lateinit var flagsCache: PermissionFlagsCache + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + executor = FakeExecutor(FakeSystemClock()) + + flagsCache = PermissionFlagsCache(packageManager, executor) + executor.runAllReady() + } + + @Test + fun testNotListeningByDefault() { + verify(packageManager, never()).addOnPermissionsChangeListener(any()) + } + + @Test + fun testGetCorrectFlags() { + `when`(packageManager.getPermissionFlags(anyString(), anyString(), any())).thenReturn(0) + `when`(packageManager.getPermissionFlags( + TEST_PERMISSION, + TEST_PACKAGE, + UserHandle.getUserHandleForUid(TEST_UID1)) + ).thenReturn(1) + + assertEquals(1, flagsCache.getPermissionFlags(TEST_PERMISSION, TEST_PACKAGE, TEST_UID1)) + assertNotEquals(1, flagsCache.getPermissionFlags(TEST_PERMISSION, TEST_PACKAGE, TEST_UID2)) + } + + @Test + fun testFlagIsCached() { + flagsCache.getPermissionFlags(TEST_PERMISSION, TEST_PACKAGE, TEST_UID1) + + flagsCache.getPermissionFlags(TEST_PERMISSION, TEST_PACKAGE, TEST_UID1) + + verify(packageManager, times(1)).getPermissionFlags( + TEST_PERMISSION, + TEST_PACKAGE, + UserHandle.getUserHandleForUid(TEST_UID1) + ) + } + + @Test + fun testListeningAfterFirstRequest() { + flagsCache.getPermissionFlags(TEST_PERMISSION, TEST_PACKAGE, TEST_UID1) + + verify(packageManager).addOnPermissionsChangeListener(any()) + } + + @Test + fun testListeningOnlyOnce() { + flagsCache.getPermissionFlags(TEST_PERMISSION, TEST_PACKAGE, TEST_UID1) + + flagsCache.getPermissionFlags(TEST_PERMISSION, TEST_PACKAGE, TEST_UID2) + + verify(packageManager, times(1)).addOnPermissionsChangeListener(any()) + } + + @Test + fun testUpdateFlag() { + assertEquals(0, flagsCache.getPermissionFlags(TEST_PERMISSION, TEST_PACKAGE, TEST_UID1)) + + `when`(packageManager.getPermissionFlags( + TEST_PERMISSION, + TEST_PACKAGE, + UserHandle.getUserHandleForUid(TEST_UID1)) + ).thenReturn(1) + + flagsCache.onPermissionsChanged(TEST_UID1) + + executor.runAllReady() + + assertEquals(1, flagsCache.getPermissionFlags(TEST_PERMISSION, TEST_PACKAGE, TEST_UID1)) + } + + @Test + fun testUpdateFlag_notUpdatedIfUidHasNotBeenRequestedBefore() { + flagsCache.getPermissionFlags(TEST_PERMISSION, TEST_PACKAGE, TEST_UID1) + + flagsCache.onPermissionsChanged(TEST_UID2) + + executor.runAllReady() + + verify(packageManager, never()).getPermissionFlags( + TEST_PERMISSION, + TEST_PACKAGE, + UserHandle.getUserHandleForUid(TEST_UID2) + ) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java index ae7387996322..c3c9ecc23d59 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java @@ -29,8 +29,8 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.brightline.BrightLineFalsingManager; +import com.android.systemui.classifier.brightline.FalsingDataProvider; import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManagerFake; import com.android.systemui.dump.DumpManager; @@ -42,6 +42,8 @@ import com.android.systemui.util.DeviceConfigProxyFake; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.sensors.ProximitySensor; import com.android.systemui.util.time.FakeSystemClock; +import com.android.systemui.utils.leaks.FakeBatteryController; +import com.android.systemui.utils.leaks.LeakCheckedTest; import org.junit.After; import org.junit.Before; @@ -52,7 +54,7 @@ import org.mockito.MockitoAnnotations; @SmallTest @RunWith(AndroidTestingRunner.class) -public class FalsingManagerProxyTest extends SysuiTestCase { +public class FalsingManagerProxyTest extends LeakCheckedTest { @Mock(stubOnly = true) PluginManager mPluginManager; @Mock(stubOnly = true) @@ -62,7 +64,7 @@ public class FalsingManagerProxyTest extends SysuiTestCase { @Mock DumpManager mDumpManager; private FalsingManagerProxy mProxy; private DeviceConfigProxy mDeviceConfig; - private DisplayMetrics mDisplayMetrics = new DisplayMetrics(); + private FalsingDataProvider mFalsingDataProvider; private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); private DockManager mDockManager = new DockManagerFake(); @@ -75,6 +77,8 @@ public class FalsingManagerProxyTest extends SysuiTestCase { mDeviceConfig = new DeviceConfigProxyFake(); mDeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, BRIGHTLINE_FALSING_MANAGER_ENABLED, "false", false); + mFalsingDataProvider = new FalsingDataProvider( + new DisplayMetrics(), new FakeBatteryController(getLeakCheck())); } @After @@ -86,9 +90,9 @@ public class FalsingManagerProxyTest extends SysuiTestCase { @Test public void test_brightLineFalsingManagerDisabled() { - mProxy = new FalsingManagerProxy(getContext(), mPluginManager, mExecutor, mDisplayMetrics, + mProxy = new FalsingManagerProxy(getContext(), mPluginManager, mExecutor, mProximitySensor, mDeviceConfig, mDockManager, mKeyguardUpdateMonitor, - mDumpManager, mUiBgExecutor, mStatusBarStateController); + mDumpManager, mUiBgExecutor, mStatusBarStateController, mFalsingDataProvider); assertThat(mProxy.getInternalFalsingManager(), instanceOf(FalsingManagerImpl.class)); } @@ -97,17 +101,17 @@ public class FalsingManagerProxyTest extends SysuiTestCase { mDeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, BRIGHTLINE_FALSING_MANAGER_ENABLED, "true", false); mExecutor.runAllReady(); - mProxy = new FalsingManagerProxy(getContext(), mPluginManager, mExecutor, mDisplayMetrics, + mProxy = new FalsingManagerProxy(getContext(), mPluginManager, mExecutor, mProximitySensor, mDeviceConfig, mDockManager, mKeyguardUpdateMonitor, - mDumpManager, mUiBgExecutor, mStatusBarStateController); + mDumpManager, mUiBgExecutor, mStatusBarStateController, mFalsingDataProvider); assertThat(mProxy.getInternalFalsingManager(), instanceOf(BrightLineFalsingManager.class)); } @Test public void test_brightLineFalsingManagerToggled() throws InterruptedException { - mProxy = new FalsingManagerProxy(getContext(), mPluginManager, mExecutor, mDisplayMetrics, + mProxy = new FalsingManagerProxy(getContext(), mPluginManager, mExecutor, mProximitySensor, mDeviceConfig, mDockManager, mKeyguardUpdateMonitor, - mDumpManager, mUiBgExecutor, mStatusBarStateController); + mDumpManager, mUiBgExecutor, mStatusBarStateController, mFalsingDataProvider); assertThat(mProxy.getInternalFalsingManager(), instanceOf(FalsingManagerImpl.class)); mDeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java index 2f05f0b4c69b..061664b4f6d4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java @@ -17,6 +17,7 @@ package com.android.systemui.classifier.brightline; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; @@ -27,7 +28,6 @@ import android.util.DisplayMetrics; import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.systemui.SysuiTestCase; import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManagerFake; import com.android.systemui.statusbar.StatusBarState; @@ -37,6 +37,8 @@ import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.DeviceConfigProxyFake; import com.android.systemui.util.sensors.ProximitySensor; import com.android.systemui.util.sensors.ThresholdSensor; +import com.android.systemui.utils.leaks.FakeBatteryController; +import com.android.systemui.utils.leaks.LeakCheckedTest; import org.junit.Before; import org.junit.Test; @@ -47,7 +49,7 @@ import org.mockito.MockitoAnnotations; @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper -public class BrightLineFalsingManagerTest extends SysuiTestCase { +public class BrightLineFalsingManagerTest extends LeakCheckedTest { @Mock @@ -55,23 +57,26 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase { @Mock private ProximitySensor mProximitySensor; private SysuiStatusBarStateController mStatusBarStateController; + private FalsingDataProvider mFalsingDataProvider; + private FakeBatteryController mFakeBatteryController; private BrightLineFalsingManager mFalsingManager; @Before public void setup() { MockitoAnnotations.initMocks(this); + mFakeBatteryController = new FakeBatteryController(getLeakCheck()); DisplayMetrics dm = new DisplayMetrics(); dm.xdpi = 100; dm.ydpi = 100; dm.widthPixels = 100; dm.heightPixels = 100; - FalsingDataProvider falsingDataProvider = new FalsingDataProvider(dm); + mFalsingDataProvider = new FalsingDataProvider(dm, mFakeBatteryController); DeviceConfigProxy deviceConfigProxy = new DeviceConfigProxyFake(); DockManager dockManager = new DockManagerFake(); mStatusBarStateController = new StatusBarStateControllerImpl(new UiEventLoggerFake()); mStatusBarStateController.setState(StatusBarState.KEYGUARD); - mFalsingManager = new BrightLineFalsingManager(falsingDataProvider, + mFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider, mKeyguardUpdateMonitor, mProximitySensor, deviceConfigProxy, dockManager, mStatusBarStateController); } @@ -83,6 +88,13 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase { } @Test + public void testNoProximityWhenWirelessCharging() { + mFakeBatteryController.setWirelessCharging(true); + mFalsingManager.onScreenTurningOn(); + verify(mProximitySensor, never()).register(any(ThresholdSensor.Listener.class)); + } + + @Test public void testUnregisterSensor() { mFalsingManager.onScreenTurningOn(); reset(mProximitySensor); diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ClassifierTest.java index 3ba5d1ac79ea..a4d198a14541 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ClassifierTest.java @@ -21,29 +21,30 @@ import static com.android.systemui.classifier.Classifier.UNLOCK; import android.util.DisplayMetrics; import android.view.MotionEvent; -import com.android.systemui.SysuiTestCase; +import com.android.systemui.utils.leaks.FakeBatteryController; +import com.android.systemui.utils.leaks.LeakCheckedTest; import org.junit.After; -import org.junit.Before; import java.util.ArrayList; import java.util.List; -public class ClassifierTest extends SysuiTestCase { +public class ClassifierTest extends LeakCheckedTest { private FalsingDataProvider mDataProvider; private List<MotionEvent> mMotionEvents = new ArrayList<>(); private float mOffsetX = 0; private float mOffsetY = 0; + private FakeBatteryController mFakeBatteryController; - @Before public void setup() { DisplayMetrics displayMetrics = new DisplayMetrics(); displayMetrics.xdpi = 100; displayMetrics.ydpi = 100; displayMetrics.widthPixels = 1000; displayMetrics.heightPixels = 1000; - mDataProvider = new FalsingDataProvider(displayMetrics); + mFakeBatteryController = new FakeBatteryController(getLeakCheck()); + mDataProvider = new FalsingDataProvider(displayMetrics, mFakeBatteryController); mDataProvider.setInteractionType(UNLOCK); } @@ -56,6 +57,10 @@ public class ClassifierTest extends SysuiTestCase { return mDataProvider; } + FakeBatteryController getFakeBatteryController() { + return mFakeBatteryController; + } + void setOffsetX(float offsetX) { mOffsetX = offsetX; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/FalsingDataProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/FalsingDataProviderTest.java index 448c2f7b33ad..f13bc7379436 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/FalsingDataProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/FalsingDataProviderTest.java @@ -26,6 +26,8 @@ import android.view.MotionEvent; import androidx.test.filters.SmallTest; +import com.android.systemui.utils.leaks.FakeBatteryController; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -37,17 +39,19 @@ import java.util.List; @RunWith(AndroidTestingRunner.class) public class FalsingDataProviderTest extends ClassifierTest { + private FakeBatteryController mFakeBatteryController; private FalsingDataProvider mDataProvider; @Before public void setup() { super.setup(); + mFakeBatteryController = new FakeBatteryController(getLeakCheck()); DisplayMetrics displayMetrics = new DisplayMetrics(); displayMetrics.xdpi = 100; displayMetrics.ydpi = 100; displayMetrics.widthPixels = 1000; displayMetrics.heightPixels = 1000; - mDataProvider = new FalsingDataProvider(displayMetrics); + mDataProvider = new FalsingDataProvider(displayMetrics, mFakeBatteryController); } @After @@ -246,4 +250,12 @@ public class FalsingDataProviderTest extends ClassifierTest { assertThat(mDataProvider.isUp(), is(false)); mDataProvider.onSessionEnd(); } + + @Test + public void test_isWirelessCharging() { + assertThat(mDataProvider.isWirelessCharging(), is(false)); + + mFakeBatteryController.setWirelessCharging(true); + assertThat(mDataProvider.isWirelessCharging(), is(true)); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java index 7ebead8a33fa..4f0ff4242b6a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java @@ -47,6 +47,7 @@ import com.android.systemui.plugins.SensorManagerPlugin; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.util.sensors.AsyncSensorManager; import com.android.systemui.util.sensors.ProximitySensor; +import com.android.systemui.util.settings.FakeSettings; import com.android.systemui.util.wakelock.WakeLock; import org.junit.Before; @@ -84,6 +85,7 @@ public class DozeSensorsTest extends SysuiTestCase { private DozeLog mDozeLog; @Mock private ProximitySensor mProximitySensor; + private FakeSettings mFakeSettings = new FakeSettings(); private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener; private TestableLooper mTestableLooper; private DozeSensors mDozeSensors; @@ -154,7 +156,7 @@ public class DozeSensorsTest extends SysuiTestCase { TestableDozeSensors() { super(getContext(), mSensorManager, mDozeParameters, mAmbientDisplayConfiguration, mWakeLock, mCallback, mProxCallback, mDozeLog, - mProximitySensor); + mProximitySensor, mFakeSettings); for (TriggerSensor sensor : mSensors) { if (sensor instanceof PluginSensor && ((PluginSensor) sensor).mPluginSensor.getType() diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java index d3af835873e2..1ed58714fb9f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java @@ -47,6 +47,7 @@ import com.android.systemui.util.sensors.FakeProximitySensor; import com.android.systemui.util.sensors.FakeSensorManager; import com.android.systemui.util.sensors.FakeThresholdSensor; import com.android.systemui.util.sensors.ProximitySensor; +import com.android.systemui.util.settings.FakeSettings; import com.android.systemui.util.time.FakeSystemClock; import com.android.systemui.util.wakelock.WakeLock; import com.android.systemui.util.wakelock.WakeLockFake; @@ -99,7 +100,7 @@ public class DozeTriggersTest extends SysuiTestCase { mTriggers = new DozeTriggers(mContext, mHost, mAlarmManager, config, parameters, asyncSensorManager, wakeLock, mDockManager, mProximitySensor, - mProximityCheck, mock(DozeLog.class), mBroadcastDispatcher); + mProximityCheck, mock(DozeLog.class), mBroadcastDispatcher, new FakeSettings()); mTriggers.setDozeMachine(mMachine); waitForSensorManager(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt index 3c6e19f0ec6f..7bc15dd46cd6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt @@ -72,7 +72,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() { @Mock private lateinit var lmmFactory: LocalMediaManagerFactory @Mock private lateinit var lmm: LocalMediaManager @Mock private lateinit var mr2: MediaRouter2Manager - private lateinit var fakeExecutor: FakeExecutor + private lateinit var fakeFgExecutor: FakeExecutor + private lateinit var fakeBgExecutor: FakeExecutor @Mock private lateinit var dumpster: DumpManager @Mock private lateinit var listener: MediaDeviceManager.Listener @Mock private lateinit var device: MediaDevice @@ -87,9 +88,10 @@ public class MediaDeviceManagerTest : SysuiTestCase() { @Before fun setUp() { - fakeExecutor = FakeExecutor(FakeSystemClock()) - manager = MediaDeviceManager(context, lmmFactory, mr2, fakeExecutor, mediaDataManager, - dumpster) + fakeFgExecutor = FakeExecutor(FakeSystemClock()) + fakeBgExecutor = FakeExecutor(FakeSystemClock()) + manager = MediaDeviceManager(context, lmmFactory, mr2, fakeFgExecutor, fakeBgExecutor, + mediaDataManager, dumpster) manager.addListener(listener) // Configure mocks. @@ -144,13 +146,15 @@ public class MediaDeviceManagerTest : SysuiTestCase() { fun loadAndRemoveMediaData() { manager.onMediaDataLoaded(KEY, null, mediaData) manager.onMediaDataRemoved(KEY) + fakeBgExecutor.runAllReady() verify(lmm).unregisterCallback(any()) } @Test fun loadMediaDataWithNullToken() { manager.onMediaDataLoaded(KEY, null, mediaData.copy(token = null)) - fakeExecutor.runAllReady() + fakeBgExecutor.runAllReady() + fakeFgExecutor.runAllReady() val data = captureDeviceData(KEY) assertThat(data.enabled).isTrue() assertThat(data.name).isEqualTo(DEVICE_NAME) @@ -163,6 +167,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() { reset(listener) // WHEN data is loaded with a new key manager.onMediaDataLoaded(KEY, KEY_OLD, mediaData) + fakeBgExecutor.runAllReady() + fakeFgExecutor.runAllReady() // THEN the listener for the old key should removed. verify(lmm).unregisterCallback(any()) // AND a new device event emitted @@ -186,6 +192,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() { fun unknownOldKey() { val oldKey = "unknown" manager.onMediaDataLoaded(KEY, oldKey, mediaData) + fakeBgExecutor.runAllReady() + fakeFgExecutor.runAllReady() verify(listener).onMediaDeviceChanged(eq(KEY), eq(oldKey), any()) } @@ -193,13 +201,16 @@ public class MediaDeviceManagerTest : SysuiTestCase() { fun updateToSessionTokenWithNullRoute() { // GIVEN that media data has been loaded with a null token manager.onMediaDataLoaded(KEY, null, mediaData.copy(token = null)) + fakeBgExecutor.runAllReady() + fakeFgExecutor.runAllReady() + reset(listener) // WHEN media data is loaded with a different token // AND that token results in a null route - reset(listener) whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null) manager.onMediaDataLoaded(KEY, null, mediaData) + fakeBgExecutor.runAllReady() + fakeFgExecutor.runAllReady() // THEN the device should be disabled - fakeExecutor.runAllReady() val data = captureDeviceData(KEY) assertThat(data.enabled).isFalse() assertThat(data.name).isNull() @@ -210,7 +221,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() { fun deviceEventOnAddNotification() { // WHEN a notification is added manager.onMediaDataLoaded(KEY, null, mediaData) - val deviceCallback = captureCallback() + fakeBgExecutor.runAllReady() + fakeFgExecutor.runAllReady() // THEN the update is dispatched to the listener val data = captureDeviceData(KEY) assertThat(data.enabled).isTrue() @@ -230,10 +242,12 @@ public class MediaDeviceManagerTest : SysuiTestCase() { @Test fun deviceListUpdate() { manager.onMediaDataLoaded(KEY, null, mediaData) + fakeBgExecutor.runAllReady() val deviceCallback = captureCallback() // WHEN the device list changes deviceCallback.onDeviceListUpdate(mutableListOf(device)) - assertThat(fakeExecutor.runAllReady()).isEqualTo(1) + assertThat(fakeBgExecutor.runAllReady()).isEqualTo(1) + assertThat(fakeFgExecutor.runAllReady()).isEqualTo(1) // THEN the update is dispatched to the listener val data = captureDeviceData(KEY) assertThat(data.enabled).isTrue() @@ -244,10 +258,12 @@ public class MediaDeviceManagerTest : SysuiTestCase() { @Test fun selectedDeviceStateChanged() { manager.onMediaDataLoaded(KEY, null, mediaData) + fakeBgExecutor.runAllReady() val deviceCallback = captureCallback() // WHEN the selected device changes state deviceCallback.onSelectedDeviceStateChanged(device, 1) - assertThat(fakeExecutor.runAllReady()).isEqualTo(1) + assertThat(fakeBgExecutor.runAllReady()).isEqualTo(1) + assertThat(fakeFgExecutor.runAllReady()).isEqualTo(1) // THEN the update is dispatched to the listener val data = captureDeviceData(KEY) assertThat(data.enabled).isTrue() @@ -270,6 +286,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() { whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null) // WHEN a notification is added manager.onMediaDataLoaded(KEY, null, mediaData) + fakeBgExecutor.runAllReady() + fakeFgExecutor.runAllReady() // THEN the device is disabled val data = captureDeviceData(KEY) assertThat(data.enabled).isFalse() @@ -281,13 +299,16 @@ public class MediaDeviceManagerTest : SysuiTestCase() { fun deviceDisabledWhenMR2ReturnsNullRouteInfoOnDeviceChanged() { // GIVEN a notif is added manager.onMediaDataLoaded(KEY, null, mediaData) + fakeBgExecutor.runAllReady() + fakeFgExecutor.runAllReady() reset(listener) // AND MR2Manager returns null for routing session whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null) // WHEN the selected device changes state val deviceCallback = captureCallback() deviceCallback.onSelectedDeviceStateChanged(device, 1) - fakeExecutor.runAllReady() + fakeBgExecutor.runAllReady() + fakeFgExecutor.runAllReady() // THEN the device is disabled val data = captureDeviceData(KEY) assertThat(data.enabled).isFalse() @@ -299,13 +320,16 @@ public class MediaDeviceManagerTest : SysuiTestCase() { fun deviceDisabledWhenMR2ReturnsNullRouteInfoOnDeviceListUpdate() { // GIVEN a notif is added manager.onMediaDataLoaded(KEY, null, mediaData) + fakeBgExecutor.runAllReady() + fakeFgExecutor.runAllReady() reset(listener) // GIVEN that MR2Manager returns null for routing session whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null) // WHEN the selected device changes state val deviceCallback = captureCallback() deviceCallback.onDeviceListUpdate(mutableListOf(device)) - fakeExecutor.runAllReady() + fakeBgExecutor.runAllReady() + fakeFgExecutor.runAllReady() // THEN the device is disabled val data = captureDeviceData(KEY) assertThat(data.enabled).isFalse() diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt index e9a0a40fe8ae..71554608f04b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt @@ -69,7 +69,7 @@ public class SeekBarObserverTest : SysuiTestCase() { fun seekBarGone() { // WHEN seek bar is disabled val isEnabled = false - val data = SeekBarViewModel.Progress(isEnabled, false, null, null) + val data = SeekBarViewModel.Progress(isEnabled, false, null, 0) observer.onChanged(data) // THEN seek bar shows just a thin line with no text assertThat(seekBarView.isEnabled()).isFalse() diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt index c8ef9fbf06e5..b81ab74458ce 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt @@ -204,6 +204,22 @@ public class SeekBarViewModelTest : SysuiTestCase() { } @Test + fun updateDurationNoMetadata() { + // GIVEN that the metadata is null + whenever(mockController.getMetadata()).thenReturn(null) + // AND a valid playback state (ie. media session is not destroyed) + val state = PlaybackState.Builder().run { + setState(PlaybackState.STATE_PLAYING, 200L, 1f) + build() + } + whenever(mockController.getPlaybackState()).thenReturn(state) + // WHEN the controller is updated + viewModel.updateController(mockController) + // THEN the seek bar is disabled + assertThat(viewModel.progress.value!!.enabled).isFalse() + } + + @Test fun updateElapsedTime() { // GIVEN that the PlaybackState contains the current position val position = 200L diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java index 84a261b6e7d2..3231b2852e7c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java @@ -41,7 +41,7 @@ import android.window.WindowContainerToken; import androidx.test.filters.SmallTest; -import com.android.systemui.wm.DisplayController; +import com.android.wm.shell.common.DisplayController; import org.junit.Before; import org.junit.Ignore; diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java index 180c4507bd09..3b284b14c36f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java @@ -33,7 +33,7 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.systemui.model.SysUiState; import com.android.systemui.statusbar.phone.NavigationModeController; -import com.android.systemui.wm.DisplayController; +import com.android.wm.shell.common.DisplayController; import org.junit.Before; import org.junit.Test; diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java index b6b2217837b2..55bec54eacb8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java @@ -33,7 +33,7 @@ import android.view.Display; import androidx.test.filters.SmallTest; import com.android.systemui.model.SysUiState; -import com.android.systemui.wm.DisplayController; +import com.android.wm.shell.common.DisplayController; import org.junit.Before; import org.junit.Test; diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java index 80fe0f095020..3a4ba6a213dc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java @@ -31,7 +31,7 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.systemui.model.SysUiState; import com.android.systemui.statusbar.phone.NavigationModeController; -import com.android.systemui.wm.DisplayController; +import com.android.wm.shell.common.DisplayController; import org.junit.Before; import org.junit.Test; diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java index 70c2bba040a0..e9d2b73182e0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java @@ -33,7 +33,7 @@ import android.view.Gravity; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; -import com.android.systemui.wm.DisplayController; +import com.android.wm.shell.common.DisplayController; import org.junit.Before; import org.junit.Test; diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyChipBuilderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyChipBuilderTest.kt new file mode 100644 index 000000000000..dcee5a716ceb --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyChipBuilderTest.kt @@ -0,0 +1,77 @@ +/* + * 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.privacy + +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import com.android.systemui.SysuiTestCase +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +@SmallTest +class PrivacyChipBuilderTest : SysuiTestCase() { + + companion object { + val TEST_UID = 1 + } + + @Test + fun testGenerateAppsList() { + val bar2 = PrivacyItem(Privacy.TYPE_CAMERA, PrivacyApplication( + "Bar", TEST_UID)) + val bar3 = PrivacyItem(Privacy.TYPE_LOCATION, PrivacyApplication( + "Bar", TEST_UID)) + val foo0 = PrivacyItem(Privacy.TYPE_MICROPHONE, PrivacyApplication( + "Foo", TEST_UID)) + val baz1 = PrivacyItem(Privacy.TYPE_CAMERA, PrivacyApplication( + "Baz", TEST_UID)) + + val items = listOf(bar2, foo0, baz1, bar3) + + val textBuilder = PrivacyChipBuilder(context, items) + + val list = textBuilder.appsAndTypes + assertEquals(3, list.size) + val appsList = list.map { it.first } + val typesList = list.map { it.second } + // List is sorted by number of types and then by types + assertEquals(listOf("Bar", "Baz", "Foo"), appsList.map { it.packageName }) + assertEquals(listOf(Privacy.TYPE_CAMERA, Privacy.TYPE_LOCATION), typesList[0]) + assertEquals(listOf(Privacy.TYPE_CAMERA), typesList[1]) + assertEquals(listOf(Privacy.TYPE_MICROPHONE), typesList[2]) + } + + @Test + fun testOrder() { + // We want location to always go last, so it will go in the "+ other apps" + val appCamera = PrivacyItem(PrivacyType.TYPE_CAMERA, + PrivacyApplication("Camera", TEST_UID)) + val appMicrophone = + PrivacyItem(PrivacyType.TYPE_MICROPHONE, + PrivacyApplication("Microphone", TEST_UID)) + val appLocation = + PrivacyItem(PrivacyType.TYPE_LOCATION, + PrivacyApplication("Location", TEST_UID)) + + val items = listOf(appLocation, appMicrophone, appCamera) + val textBuilder = PrivacyChipBuilder(context, items) + val appList = textBuilder.appsAndTypes.map { it.first }.map { it.packageName } + assertEquals(listOf("Camera", "Microphone", "Location"), appList) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt new file mode 100644 index 000000000000..dddc35072315 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.privacy + +import android.app.ActivityManager +import android.app.AppOpsManager +import android.content.Context +import android.content.Intent +import android.content.pm.UserInfo +import android.os.UserHandle +import android.os.UserManager +import android.provider.DeviceConfig +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper.RunWithLooper +import androidx.test.filters.SmallTest +import com.android.internal.config.sysui.SystemUiDeviceConfigFlags +import com.android.systemui.SysuiTestCase +import com.android.systemui.appops.AppOpItem +import com.android.systemui.appops.AppOpsController +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.dump.DumpManager +import com.android.systemui.util.DeviceConfigProxy +import com.android.systemui.util.DeviceConfigProxyFake +import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.time.FakeSystemClock +import org.hamcrest.Matchers.hasItem +import org.hamcrest.Matchers.not +import org.hamcrest.Matchers.nullValue +import org.junit.Assert.assertEquals +import org.junit.Assert.assertThat +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.anyList +import org.mockito.Captor +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.Mockito.atLeastOnce +import org.mockito.Mockito.doReturn +import org.mockito.Mockito.mock +import org.mockito.Mockito.never +import org.mockito.Mockito.reset +import org.mockito.Mockito.verify +import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.MockitoAnnotations + +@RunWith(AndroidTestingRunner::class) +@SmallTest +@RunWithLooper +class PrivacyItemControllerTest : SysuiTestCase() { + + companion object { + val CURRENT_USER_ID = ActivityManager.getCurrentUser() + val TEST_UID = CURRENT_USER_ID * UserHandle.PER_USER_RANGE + const val SYSTEM_UID = 1000 + const val TEST_PACKAGE_NAME = "test" + const val DEVICE_SERVICES_STRING = "Device services" + const val TAG = "PrivacyItemControllerTest" + fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture() + fun <T> eq(value: T): T = Mockito.eq(value) ?: value + fun <T> any(): T = Mockito.any<T>() + } + + @Mock + private lateinit var appOpsController: AppOpsController + @Mock + private lateinit var callback: PrivacyItemController.Callback + @Mock + private lateinit var userManager: UserManager + @Mock + private lateinit var broadcastDispatcher: BroadcastDispatcher + @Mock + private lateinit var dumpManager: DumpManager + @Captor + private lateinit var argCaptor: ArgumentCaptor<List<PrivacyItem>> + @Captor + private lateinit var argCaptorCallback: ArgumentCaptor<AppOpsController.Callback> + + private lateinit var privacyItemController: PrivacyItemController + private lateinit var executor: FakeExecutor + private lateinit var deviceConfigProxy: DeviceConfigProxy + + fun PrivacyItemController(context: Context): PrivacyItemController { + return PrivacyItemController( + context, + appOpsController, + executor, + executor, + broadcastDispatcher, + deviceConfigProxy, + userManager, + dumpManager + ) + } + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + executor = FakeExecutor(FakeSystemClock()) + deviceConfigProxy = DeviceConfigProxyFake() + + appOpsController = mDependency.injectMockDependency(AppOpsController::class.java) + + deviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_PRIVACY, + SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, + "true", false) + + doReturn(listOf(object : UserInfo() { + init { + id = CURRENT_USER_ID + } + })).`when`(userManager).getProfiles(anyInt()) + + privacyItemController = PrivacyItemController(mContext) + } + + @Test + fun testSetListeningTrueByAddingCallback() { + privacyItemController.addCallback(callback) + executor.runAllReady() + verify(appOpsController).addCallback(eq(PrivacyItemController.OPS), + any()) + verify(callback).onPrivacyItemsChanged(anyList()) + } + + @Test + fun testSetListeningFalseByRemovingLastCallback() { + privacyItemController.addCallback(callback) + executor.runAllReady() + verify(appOpsController, never()).removeCallback(any(), + any()) + privacyItemController.removeCallback(callback) + executor.runAllReady() + verify(appOpsController).removeCallback(eq(PrivacyItemController.OPS), + any()) + verify(callback).onPrivacyItemsChanged(emptyList()) + } + + @Test + fun testDistinctItems() { + doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 0), + AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 1))) + .`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + + privacyItemController.addCallback(callback) + executor.runAllReady() + verify(callback).onPrivacyItemsChanged(capture(argCaptor)) + assertEquals(1, argCaptor.value.size) + } + + @Test + fun testRegisterReceiver_allUsers() { + privacyItemController.addCallback(callback) + executor.runAllReady() + verify(broadcastDispatcher, atLeastOnce()).registerReceiver( + eq(privacyItemController.userSwitcherReceiver), any(), eq(null), eq(UserHandle.ALL)) + verify(broadcastDispatcher, never()) + .unregisterReceiver(eq(privacyItemController.userSwitcherReceiver)) + } + + @Test + fun testReceiver_ACTION_USER_FOREGROUND() { + privacyItemController.userSwitcherReceiver.onReceive(context, + Intent(Intent.ACTION_USER_SWITCHED)) + executor.runAllReady() + verify(userManager).getProfiles(anyInt()) + } + + @Test + fun testReceiver_ACTION_MANAGED_PROFILE_ADDED() { + privacyItemController.userSwitcherReceiver.onReceive(context, + Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)) + executor.runAllReady() + verify(userManager).getProfiles(anyInt()) + } + + @Test + fun testReceiver_ACTION_MANAGED_PROFILE_REMOVED() { + privacyItemController.userSwitcherReceiver.onReceive(context, + Intent(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) + executor.runAllReady() + verify(userManager).getProfiles(anyInt()) + } + + @Test + fun testAddMultipleCallbacks() { + val otherCallback = mock(PrivacyItemController.Callback::class.java) + privacyItemController.addCallback(callback) + executor.runAllReady() + verify(callback).onPrivacyItemsChanged(anyList()) + + privacyItemController.addCallback(otherCallback) + executor.runAllReady() + verify(otherCallback).onPrivacyItemsChanged(anyList()) + // Adding a callback should not unnecessarily call previous ones + verifyNoMoreInteractions(callback) + } + + @Test + fun testMultipleCallbacksAreUpdated() { + doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + + val otherCallback = mock(PrivacyItemController.Callback::class.java) + privacyItemController.addCallback(callback) + privacyItemController.addCallback(otherCallback) + executor.runAllReady() + reset(callback) + reset(otherCallback) + + verify(appOpsController).addCallback(any(), capture(argCaptorCallback)) + argCaptorCallback.value.onActiveStateChanged(0, TEST_UID, "", true) + executor.runAllReady() + verify(callback).onPrivacyItemsChanged(anyList()) + verify(otherCallback).onPrivacyItemsChanged(anyList()) + } + + @Test + fun testRemoveCallback() { + doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + val otherCallback = mock(PrivacyItemController.Callback::class.java) + privacyItemController.addCallback(callback) + privacyItemController.addCallback(otherCallback) + executor.runAllReady() + executor.runAllReady() + reset(callback) + reset(otherCallback) + + verify(appOpsController).addCallback(any(), capture(argCaptorCallback)) + privacyItemController.removeCallback(callback) + argCaptorCallback.value.onActiveStateChanged(0, TEST_UID, "", true) + executor.runAllReady() + verify(callback, never()).onPrivacyItemsChanged(anyList()) + verify(otherCallback).onPrivacyItemsChanged(anyList()) + } + + @Test + fun testListShouldNotHaveNull() { + doReturn(listOf(AppOpItem(AppOpsManager.OP_ACTIVATE_VPN, TEST_UID, "", 0), + AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, "", 0))) + .`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + privacyItemController.addCallback(callback) + executor.runAllReady() + executor.runAllReady() + + verify(callback).onPrivacyItemsChanged(capture(argCaptor)) + assertEquals(1, argCaptor.value.size) + assertThat(argCaptor.value, not(hasItem(nullValue()))) + } + + @Test + fun testListShouldBeCopy() { + val list = listOf(PrivacyItem(PrivacyType.TYPE_CAMERA, + PrivacyApplication("", TEST_UID))) + privacyItemController.privacyList = list + val privacyList = privacyItemController.privacyList + assertEquals(list, privacyList) + assertTrue(list !== privacyList) + } + + @Test + fun testNotListeningWhenIndicatorsDisabled() { + deviceConfigProxy.setProperty( + DeviceConfig.NAMESPACE_PRIVACY, + SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, + "false", + false + ) + privacyItemController.addCallback(callback) + executor.runAllReady() + verify(appOpsController, never()).addCallback(eq(PrivacyItemController.OPS), + any()) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java index 5d4ef550b36c..bdb7166f5db1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java @@ -41,14 +41,17 @@ import android.testing.TestableLooper.RunWithLooper; import androidx.test.filters.SmallTest; +import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; import com.android.internal.util.CollectionUtils; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSFactory; import com.android.systemui.plugins.qs.QSTile; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.external.CustomTile; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; @@ -331,7 +334,15 @@ public class QSTileHostTest extends SysuiTestCase { private class TestTile extends QSTileImpl<QSTile.State> { protected TestTile(QSHost host) { - super(host); + super( + host, + mLooper.getLooper(), + new Handler(mLooper.getLooper()), + mock(MetricsLogger.class), + mock(StatusBarStateController.class), + mock(ActivityStarter.class), + mQSLogger + ); } @Override 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 953198c42d66..c2579dd46e78 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 @@ -23,17 +23,23 @@ import android.content.pm.PackageManager import android.content.pm.ServiceInfo import android.graphics.drawable.Drawable import android.graphics.drawable.Icon +import android.os.Handler import android.service.quicksettings.IQSTileService import android.service.quicksettings.Tile import android.test.suitebuilder.annotation.SmallTest +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper import android.view.IWindowManager -import androidx.test.runner.AndroidJUnit4 +import com.android.internal.logging.MetricsLogger import com.android.systemui.SysuiTestCase +import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.qs.QSTile +import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost -import junit.framework.Assert.assertFalse -import junit.framework.Assert.assertTrue +import com.android.systemui.qs.logging.QSLogger import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -46,7 +52,8 @@ import org.mockito.Mockito.mock import org.mockito.MockitoAnnotations @SmallTest -@RunWith(AndroidJUnit4::class) +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper class CustomTileTest : SysuiTestCase() { companion object { @@ -56,36 +63,53 @@ class CustomTileTest : SysuiTestCase() { val TILE_SPEC = CustomTile.toSpec(componentName) } - @Mock private lateinit var mTileHost: QSHost - @Mock private lateinit var mTileService: IQSTileService - @Mock private lateinit var mTileServices: TileServices - @Mock private lateinit var mTileServiceManager: TileServiceManager - @Mock private lateinit var mWindowService: IWindowManager - @Mock private lateinit var mPackageManager: PackageManager - @Mock private lateinit var mApplicationInfo: ApplicationInfo - @Mock private lateinit var mServiceInfo: ServiceInfo + @Mock private lateinit var tileHost: QSHost + @Mock private lateinit var metricsLogger: MetricsLogger + @Mock private lateinit var statusBarStateController: StatusBarStateController + @Mock private lateinit var activityStarter: ActivityStarter + @Mock private lateinit var qsLogger: QSLogger + @Mock private lateinit var tileService: IQSTileService + @Mock private lateinit var tileServices: TileServices + @Mock private lateinit var tileServiceManager: TileServiceManager + @Mock private lateinit var windowService: IWindowManager + @Mock private lateinit var packageManager: PackageManager + @Mock private lateinit var applicationInfo: ApplicationInfo + @Mock private lateinit var serviceInfo: ServiceInfo private lateinit var customTile: CustomTile + private lateinit var testableLooper: TestableLooper + private lateinit var customTileBuilder: CustomTile.Builder @Before fun setUp() { MockitoAnnotations.initMocks(this) - - mContext.addMockSystemService("window", mWindowService) - mContext.setMockPackageManager(mPackageManager) - `when`(mTileHost.tileServices).thenReturn(mTileServices) - `when`(mTileHost.context).thenReturn(mContext) - `when`(mTileServices.getTileWrapper(any(CustomTile::class.java))) - .thenReturn(mTileServiceManager) - `when`(mTileServiceManager.tileService).thenReturn(mTileService) - `when`(mPackageManager.getApplicationInfo(anyString(), anyInt())) - .thenReturn(mApplicationInfo) - - `when`(mPackageManager.getServiceInfo(any(ComponentName::class.java), anyInt())) - .thenReturn(mServiceInfo) - mServiceInfo.applicationInfo = mApplicationInfo - - customTile = CustomTile.create(mTileHost, TILE_SPEC, mContext) + testableLooper = TestableLooper.get(this) + + mContext.addMockSystemService("window", windowService) + mContext.setMockPackageManager(packageManager) + `when`(tileHost.tileServices).thenReturn(tileServices) + `when`(tileHost.context).thenReturn(mContext) + `when`(tileServices.getTileWrapper(any(CustomTile::class.java))) + .thenReturn(tileServiceManager) + `when`(tileServiceManager.tileService).thenReturn(tileService) + `when`(packageManager.getApplicationInfo(anyString(), anyInt())) + .thenReturn(applicationInfo) + + `when`(packageManager.getServiceInfo(any(ComponentName::class.java), anyInt())) + .thenReturn(serviceInfo) + serviceInfo.applicationInfo = applicationInfo + + customTileBuilder = CustomTile.Builder( + { tileHost }, + testableLooper.looper, + Handler(testableLooper.looper), + metricsLogger, + statusBarStateController, + activityStarter, + qsLogger + ) + + customTile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext) } @Test @@ -93,18 +117,18 @@ class CustomTileTest : SysuiTestCase() { assertEquals(0, customTile.user) val userContext = mock(Context::class.java) - `when`(userContext.packageManager).thenReturn(mPackageManager) + `when`(userContext.packageManager).thenReturn(packageManager) `when`(userContext.userId).thenReturn(10) - val tile = CustomTile.create(mTileHost, TILE_SPEC, userContext) + val tile = CustomTile.create(customTileBuilder, TILE_SPEC, userContext) assertEquals(10, tile.user) } @Test fun testToggleableTileHasBooleanState() { - `when`(mTileServiceManager.isToggleableTile).thenReturn(true) - customTile = CustomTile.create(mTileHost, TILE_SPEC, mContext) + `when`(tileServiceManager.isToggleableTile).thenReturn(true) + customTile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext) assertTrue(customTile.state is QSTile.BooleanState) assertTrue(customTile.newTileState() is QSTile.BooleanState) @@ -118,8 +142,8 @@ class CustomTileTest : SysuiTestCase() { @Test fun testValueUpdatedInBooleanTile() { - `when`(mTileServiceManager.isToggleableTile).thenReturn(true) - customTile = CustomTile.create(mTileHost, TILE_SPEC, mContext) + `when`(tileServiceManager.isToggleableTile).thenReturn(true) + customTile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext) customTile.qsTile.icon = mock(Icon::class.java) `when`(customTile.qsTile.icon.loadDrawable(any(Context::class.java))) .thenReturn(mock(Drawable::class.java)) diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java index 20f13bb02435..103e5586f395 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java @@ -35,17 +35,14 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Matchers.argThat; -import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static java.lang.Thread.sleep; - import android.content.Intent; import android.metrics.LogMaker; +import android.os.Handler; +import android.os.Looper; import android.service.quicksettings.Tile; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -57,7 +54,6 @@ import com.android.internal.logging.InstanceId; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.testing.UiEventLoggerFake; -import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile; @@ -69,7 +65,6 @@ import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.statusbar.StatusBarState; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -91,9 +86,14 @@ public class QSTileImplTest extends SysuiTestCase { private TestableLooper mTestableLooper; private TileImpl mTile; + @Mock private QSTileHost mHost; + @Mock private MetricsLogger mMetricsLogger; + @Mock private StatusBarStateController mStatusBarStateController; + @Mock + private ActivityStarter mActivityStarter; private UiEventLoggerFake mUiEventLoggerFake; private InstanceId mInstanceId = InstanceId.fakeInstanceId(5); @@ -104,21 +104,16 @@ public class QSTileImplTest extends SysuiTestCase { public void setup() throws Exception { MockitoAnnotations.initMocks(this); mTestableLooper = TestableLooper.get(this); - mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper()); - mDependency.injectMockDependency(ActivityStarter.class); - mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class); mUiEventLoggerFake = new UiEventLoggerFake(); - mStatusBarStateController = - mDependency.injectMockDependency(StatusBarStateController.class); - mHost = mock(QSTileHost.class); when(mHost.indexOf(SPEC)).thenReturn(POSITION); when(mHost.getContext()).thenReturn(mContext.getBaseContext()); - when(mHost.getQSLogger()).thenReturn(mQsLogger); when(mHost.getUiEventLogger()).thenReturn(mUiEventLoggerFake); when(mHost.getNewInstanceId()).thenReturn(mInstanceId); - mTile = spy(new TileImpl(mHost)); - mTile.mHandler = mTile.new H(mTestableLooper.getLooper()); + Handler mainHandler = new Handler(mTestableLooper.getLooper()); + + mTile = new TileImpl(mHost, mTestableLooper.getLooper(), mainHandler, + mMetricsLogger, mStatusBarStateController, mActivityStarter, mQsLogger); mTile.setTileSpec(SPEC); } @@ -223,40 +218,25 @@ public class QSTileImplTest extends SysuiTestCase { verify(maker).addTaggedData(eq(FIELD_QS_POSITION), eq(POSITION)); } - @Test - @Ignore("flaky") - public void testStaleTimeout() throws InterruptedException { - when(mTile.getStaleTimeout()).thenReturn(5l); - clearInvocations(mTile); - - mTile.handleRefreshState(null); - mTestableLooper.processAllMessages(); - verify(mTile, never()).handleStale(); - - sleep(10); - mTestableLooper.processAllMessages(); - verify(mTile).handleStale(); - } + //TODO(b/161799397) Bring back testStaleTimeout when we can use FakeExecutor @Test public void testStaleListening() { mTile.handleStale(); mTestableLooper.processAllMessages(); - verify(mTile).handleSetListening(eq(true)); + verify(mQsLogger).logTileChangeListening(SPEC, true); mTile.handleRefreshState(null); mTestableLooper.processAllMessages(); - verify(mTile).handleSetListening(eq(false)); + verify(mQsLogger).logTileChangeListening(SPEC, false); } @Test public void testHandleDestroyClearsHandlerQueue() { - when(mTile.getStaleTimeout()).thenReturn(0L); mTile.handleRefreshState(null); // this will add a delayed H.STALE message mTile.handleDestroy(); - mTestableLooper.processAllMessages(); - verify(mTile, never()).handleStale(); + assertFalse(mTile.mHandler.hasMessages(QSTileImpl.H.STALE)); } @Test @@ -359,8 +339,17 @@ public class QSTileImplTest extends SysuiTestCase { } private static class TileImpl extends QSTileImpl<QSTile.BooleanState> { - protected TileImpl(QSHost host) { - super(host); + protected TileImpl( + QSHost host, + Looper backgroundLooper, + Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); getState().state = Tile.STATE_ACTIVE; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt index 31992875df07..f70106a64968 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt @@ -17,13 +17,17 @@ package com.android.systemui.qs.tiles import android.content.Context +import android.os.Handler import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest -import com.android.systemui.Dependency +import com.android.internal.logging.MetricsLogger import com.android.systemui.SysuiTestCase +import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost +import com.android.systemui.qs.logging.QSLogger import com.android.systemui.statusbar.policy.BatteryController import org.junit.Assert.assertEquals import org.junit.Before @@ -47,6 +51,14 @@ class BatterySaverTileTest : SysuiTestCase() { @Mock private lateinit var qsHost: QSHost @Mock + private lateinit var metricsLogger: MetricsLogger + @Mock + private lateinit var statusBarStateController: StatusBarStateController + @Mock + private lateinit var activityStarter: ActivityStarter + @Mock + private lateinit var qsLogger: QSLogger + @Mock private lateinit var batteryController: BatteryController private lateinit var testableLooper: TestableLooper private lateinit var tile: BatterySaverTile @@ -55,11 +67,18 @@ class BatterySaverTileTest : SysuiTestCase() { fun setUp() { MockitoAnnotations.initMocks(this) testableLooper = TestableLooper.get(this) - mDependency.injectTestDependency(Dependency.BG_LOOPER, testableLooper.looper) `when`(qsHost.userContext).thenReturn(userContext) `when`(userContext.userId).thenReturn(USER) - tile = BatterySaverTile(qsHost, batteryController) + tile = BatterySaverTile( + qsHost, + testableLooper.looper, + Handler(testableLooper.looper), + metricsLogger, + statusBarStateController, + activityStarter, + qsLogger, + batteryController) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java index 853b2dbbc485..8ece62281f77 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.when; import android.media.MediaRouter; import android.media.MediaRouter.RouteInfo; import android.media.projection.MediaProjectionInfo; +import android.os.Handler; import android.service.quicksettings.Tile; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -34,10 +35,12 @@ import android.testing.TestableLooper; import androidx.lifecycle.LifecycleOwner; import androidx.test.filters.SmallTest; -import com.android.systemui.Dependency; +import com.android.internal.logging.MetricsLogger; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSTileHost; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.statusbar.policy.CastController; import com.android.systemui.statusbar.policy.CastController.CastDevice; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -71,6 +74,12 @@ public class CastTileTest extends SysuiTestCase { private QSTileHost mHost; @Mock NetworkController.SignalCallback mCallback; + @Mock + private MetricsLogger mMetricsLogger; + @Mock + private StatusBarStateController mStatusBarStateController; + @Mock + private QSLogger mQSLogger; private TestableLooper mTestableLooper; private CastTile mCastTile; @@ -80,16 +89,20 @@ public class CastTileTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); mTestableLooper = TestableLooper.get(this); - mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper()); - mController = mDependency.injectMockDependency(CastController.class); - mActivityStarter = mDependency.injectMockDependency(ActivityStarter.class); - mKeyguard = mDependency.injectMockDependency(KeyguardStateController.class); - mNetworkController = mDependency.injectMockDependency(NetworkController.class); - when(mHost.getContext()).thenReturn(mContext); - mCastTile = new CastTile(mHost, mController, mKeyguard, mNetworkController, - mActivityStarter); + mCastTile = new CastTile( + mHost, + mTestableLooper.getLooper(), + new Handler(mTestableLooper.getLooper()), + mMetricsLogger, + mStatusBarStateController, + mActivityStarter, + mQSLogger, + mController, + mKeyguard, + mNetworkController + ); // We are not setting the mocks to listening, so we trigger a first refresh state to // set the initial state diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java index 5a6823879942..2d276bb876f3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java @@ -23,16 +23,20 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.os.Handler; import android.service.quicksettings.Tile; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import androidx.test.filters.SmallTest; -import com.android.systemui.Dependency; +import com.android.internal.logging.MetricsLogger; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSTileHost; +import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.screenrecord.RecordingController; import com.android.systemui.statusbar.phone.KeyguardDismissUtil; @@ -43,7 +47,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; @RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper(setAsMainLooper = true) +@TestableLooper.RunWithLooper() @SmallTest public class ScreenRecordTileTest extends SysuiTestCase { @@ -53,6 +57,14 @@ public class ScreenRecordTileTest extends SysuiTestCase { private QSTileHost mHost; @Mock private KeyguardDismissUtil mKeyguardDismissUtil; + @Mock + private MetricsLogger mMetricsLogger; + @Mock + private StatusBarStateController mStatusBarStateController; + @Mock + private ActivityStarter mActivityStarter; + @Mock + private QSLogger mQSLogger; private TestableLooper mTestableLooper; private ScreenRecordTile mTile; @@ -62,12 +74,20 @@ public class ScreenRecordTileTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); mTestableLooper = TestableLooper.get(this); - mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper()); - mController = mDependency.injectMockDependency(RecordingController.class); when(mHost.getContext()).thenReturn(mContext); - mTile = new ScreenRecordTile(mHost, mController, mKeyguardDismissUtil); + mTile = new ScreenRecordTile( + mHost, + mTestableLooper.getLooper(), + new Handler(mTestableLooper.getLooper()), + mMetricsLogger, + mStatusBarStateController, + mActivityStarter, + mQSLogger, + mController, + mKeyguardDismissUtil + ); } // Test that the tile is inactive and labeled correctly when the controller is neither starting diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java index e98b6b69ee76..4c9e141c45cc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java @@ -32,7 +32,9 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.UiEventLogger; import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.settings.CurrentUserContextTracker; +import com.android.systemui.statusbar.phone.KeyguardDismissUtil; import org.junit.Before; import org.junit.Test; @@ -61,6 +63,12 @@ public class RecordingServiceTest extends SysuiTestCase { private Executor mExecutor; @Mock private CurrentUserContextTracker mUserContextTracker; + private KeyguardDismissUtil mKeyguardDismissUtil = new KeyguardDismissUtil() { + public void executeWhenUnlocked(ActivityStarter.OnDismissAction action, + boolean requiresShadeOpen) { + action.onDismiss(); + } + }; private RecordingService mRecordingService; @@ -68,7 +76,7 @@ public class RecordingServiceTest extends SysuiTestCase { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mRecordingService = Mockito.spy(new RecordingService(mController, mExecutor, mUiEventLogger, - mNotificationManager, mUserContextTracker)); + mNotificationManager, mUserContextTracker, mKeyguardDismissUtil)); // Return actual context info doReturn(mContext).when(mRecordingService).getApplicationContext(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java new file mode 100644 index 000000000000..4aaafbdaec1d --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.screenshot; + +import static com.android.systemui.screenshot.GlobalScreenshot.ACTION_TYPE_SHARE; +import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_ID; +import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED; +import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_SCREENSHOT; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.statusbar.phone.StatusBar; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.stubbing.Answer; + +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +@RunWith(AndroidTestingRunner.class) +@SmallTest +public class ActionProxyReceiverTest extends SysuiTestCase { + + @Mock + private StatusBar mMockStatusBar; + @Mock + private ActivityManagerWrapper mMockActivityManagerWrapper; + @Mock + private Future mMockFuture; + @Mock + private ScreenshotSmartActions mMockScreenshotSmartActions; + @Mock + private PendingIntent mMockPendingIntent; + + private Intent mIntent; + + @Before + public void setup() throws InterruptedException, ExecutionException, TimeoutException { + MockitoAnnotations.initMocks(this); + mIntent = new Intent(mContext, ActionProxyReceiver.class) + .putExtra(GlobalScreenshot.EXTRA_ACTION_INTENT, mMockPendingIntent); + + when(mMockActivityManagerWrapper.closeSystemWindows(anyString())).thenReturn(mMockFuture); + when(mMockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(null); + } + + @Test + public void testPendingIntentSentWithoutStatusBar() throws PendingIntent.CanceledException { + ActionProxyReceiver actionProxyReceiver = constructActionProxyReceiver(false); + + actionProxyReceiver.onReceive(mContext, mIntent); + + verify(mMockActivityManagerWrapper).closeSystemWindows(SYSTEM_DIALOG_REASON_SCREENSHOT); + verify(mMockStatusBar, never()).executeRunnableDismissingKeyguard( + any(Runnable.class), any(Runnable.class), anyBoolean(), anyBoolean(), anyBoolean()); + verify(mMockPendingIntent).send( + eq(mContext), anyInt(), isNull(), isNull(), isNull(), isNull(), any(Bundle.class)); + } + + @Test + public void testPendingIntentSentWithStatusBar() throws PendingIntent.CanceledException { + ActionProxyReceiver actionProxyReceiver = constructActionProxyReceiver(true); + // ensure that the pending intent call is passed through + doAnswer((Answer<Object>) invocation -> { + ((Runnable) invocation.getArgument(0)).run(); + return null; + }).when(mMockStatusBar).executeRunnableDismissingKeyguard( + any(Runnable.class), isNull(), anyBoolean(), anyBoolean(), anyBoolean()); + + actionProxyReceiver.onReceive(mContext, mIntent); + + verify(mMockActivityManagerWrapper).closeSystemWindows(SYSTEM_DIALOG_REASON_SCREENSHOT); + verify(mMockStatusBar).executeRunnableDismissingKeyguard( + any(Runnable.class), isNull(), eq(true), eq(true), eq(true)); + verify(mMockPendingIntent).send( + eq(mContext), anyInt(), isNull(), isNull(), isNull(), isNull(), any(Bundle.class)); + } + + @Test + public void testSmartActionsNotNotifiedByDefault() { + ActionProxyReceiver actionProxyReceiver = constructActionProxyReceiver(true); + + actionProxyReceiver.onReceive(mContext, mIntent); + + verify(mMockScreenshotSmartActions, never()) + .notifyScreenshotAction(any(Context.class), anyString(), anyString(), anyBoolean()); + } + + @Test + public void testSmartActionsNotifiedIfEnabled() { + ActionProxyReceiver actionProxyReceiver = constructActionProxyReceiver(true); + mIntent.putExtra(EXTRA_SMART_ACTIONS_ENABLED, true); + String testId = "testID"; + mIntent.putExtra(EXTRA_ID, testId); + + actionProxyReceiver.onReceive(mContext, mIntent); + + verify(mMockScreenshotSmartActions).notifyScreenshotAction( + mContext, testId, ACTION_TYPE_SHARE, false); + } + + private ActionProxyReceiver constructActionProxyReceiver(boolean withStatusBar) { + if (withStatusBar) { + return new ActionProxyReceiver( + Optional.of(mMockStatusBar), mMockActivityManagerWrapper, + mMockScreenshotSmartActions); + } else { + return new ActionProxyReceiver( + Optional.empty(), mMockActivityManagerWrapper, mMockScreenshotSmartActions); + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/DeleteScreenshotReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DeleteScreenshotReceiverTest.java new file mode 100644 index 000000000000..b9249131c191 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DeleteScreenshotReceiverTest.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.screenshot; + +import static com.android.systemui.screenshot.GlobalScreenshot.ACTION_TYPE_DELETE; +import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_ID; +import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED; +import static com.android.systemui.screenshot.GlobalScreenshot.SCREENSHOT_URI_ID; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.os.Environment; +import android.provider.MediaStore; +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.File; +import java.util.concurrent.Executor; + +@RunWith(AndroidTestingRunner.class) +@SmallTest +public class DeleteScreenshotReceiverTest extends SysuiTestCase { + + @Mock + private ScreenshotSmartActions mMockScreenshotSmartActions; + @Mock + private Executor mMockExecutor; + + private DeleteScreenshotReceiver mDeleteScreenshotReceiver; + private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock()); + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mDeleteScreenshotReceiver = + new DeleteScreenshotReceiver(mMockScreenshotSmartActions, mMockExecutor); + } + + @Test + public void testNoUriProvided() { + Intent intent = new Intent(mContext, DeleteScreenshotReceiver.class); + + mDeleteScreenshotReceiver.onReceive(mContext, intent); + + verify(mMockExecutor, never()).execute(any(Runnable.class)); + verify(mMockScreenshotSmartActions, never()).notifyScreenshotAction( + any(Context.class), any(String.class), any(String.class), anyBoolean()); + } + + @Test + public void testFileDeleted() { + DeleteScreenshotReceiver deleteScreenshotReceiver = + new DeleteScreenshotReceiver(mMockScreenshotSmartActions, mFakeExecutor); + ContentResolver contentResolver = mContext.getContentResolver(); + final Uri testUri = contentResolver.insert( + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, getFakeContentValues()); + assertNotNull(testUri); + + try { + Cursor cursor = + contentResolver.query(testUri, null, null, null, null); + assertEquals(1, cursor.getCount()); + Intent intent = new Intent(mContext, DeleteScreenshotReceiver.class) + .putExtra(SCREENSHOT_URI_ID, testUri.toString()); + + deleteScreenshotReceiver.onReceive(mContext, intent); + int runCount = mFakeExecutor.runAllReady(); + + assertEquals(1, runCount); + cursor = + contentResolver.query(testUri, null, null, null, null); + assertEquals(0, cursor.getCount()); + } finally { + contentResolver.delete(testUri, null, null); + } + + // ensure smart actions not called by default + verify(mMockScreenshotSmartActions, never()).notifyScreenshotAction( + any(Context.class), any(String.class), any(String.class), anyBoolean()); + } + + @Test + public void testNotifyScreenshotAction() { + Intent intent = new Intent(mContext, DeleteScreenshotReceiver.class); + String uriString = "testUri"; + String testId = "testID"; + intent.putExtra(SCREENSHOT_URI_ID, uriString); + intent.putExtra(EXTRA_ID, testId); + intent.putExtra(EXTRA_SMART_ACTIONS_ENABLED, true); + + mDeleteScreenshotReceiver.onReceive(mContext, intent); + + verify(mMockExecutor).execute(any(Runnable.class)); + verify(mMockScreenshotSmartActions).notifyScreenshotAction( + mContext, testId, ACTION_TYPE_DELETE, false); + } + + private static ContentValues getFakeContentValues() { + final ContentValues values = new ContentValues(); + values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + + File.separator + Environment.DIRECTORY_SCREENSHOTS); + values.put(MediaStore.MediaColumns.DISPLAY_NAME, "test_screenshot"); + values.put(MediaStore.MediaColumns.MIME_TYPE, "image/png"); + values.put(MediaStore.MediaColumns.DATE_ADDED, 0); + values.put(MediaStore.MediaColumns.DATE_MODIFIED, 0); + return values; + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java index d3b33992d017..184329ec6e5f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java @@ -61,12 +61,14 @@ import java.util.concurrent.TimeUnit; */ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { private ScreenshotNotificationSmartActionsProvider mSmartActionsProvider; + private ScreenshotSmartActions mScreenshotSmartActions; private Handler mHandler; @Before public void setup() { mSmartActionsProvider = mock( ScreenshotNotificationSmartActionsProvider.class); + mScreenshotSmartActions = new ScreenshotSmartActions(); mHandler = mock(Handler.class); } @@ -82,7 +84,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { when(smartActionsProvider.getActions(any(), any(), any(), any(), any())) .thenThrow(RuntimeException.class); CompletableFuture<List<Notification.Action>> smartActionsFuture = - ScreenshotSmartActions.getSmartActionsFuture( + mScreenshotSmartActions.getSmartActionsFuture( "", Uri.parse("content://authority/data"), bitmap, smartActionsProvider, true, UserHandle.getUserHandleForUid(UserHandle.myUserId())); assertNotNull(smartActionsFuture); @@ -100,7 +102,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { int timeoutMs = 1000; when(smartActionsFuture.get(timeoutMs, TimeUnit.MILLISECONDS)).thenThrow( RuntimeException.class); - List<Notification.Action> actions = ScreenshotSmartActions.getSmartActions( + List<Notification.Action> actions = mScreenshotSmartActions.getSmartActions( "", smartActionsFuture, timeoutMs, mSmartActionsProvider); assertEquals(Collections.emptyList(), actions); } @@ -111,7 +113,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { throws Exception { doThrow(RuntimeException.class).when(mSmartActionsProvider).notifyOp(any(), any(), any(), anyLong()); - ScreenshotSmartActions.notifyScreenshotOp(null, mSmartActionsProvider, null, null, -1); + mScreenshotSmartActions.notifyScreenshotOp(null, mSmartActionsProvider, null, null, -1); } // Tests for a non-hardware bitmap, ScreenshotNotificationSmartActionsProvider is never invoked @@ -122,7 +124,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { Bitmap bitmap = mock(Bitmap.class); when(bitmap.getConfig()).thenReturn(Bitmap.Config.RGB_565); CompletableFuture<List<Notification.Action>> smartActionsFuture = - ScreenshotSmartActions.getSmartActionsFuture( + mScreenshotSmartActions.getSmartActionsFuture( "", Uri.parse("content://autority/data"), bitmap, mSmartActionsProvider, true, UserHandle.getUserHandleForUid(UserHandle.myUserId())); verify(mSmartActionsProvider, never()).getActions(any(), any(), any(), any(), any()); @@ -136,7 +138,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { public void testScreenshotNotificationSmartActionsProviderInvokedOnce() { Bitmap bitmap = mock(Bitmap.class); when(bitmap.getConfig()).thenReturn(Bitmap.Config.HARDWARE); - ScreenshotSmartActions.getSmartActionsFuture( + mScreenshotSmartActions.getSmartActionsFuture( "", Uri.parse("content://autority/data"), bitmap, mSmartActionsProvider, true, UserHandle.getUserHandleForUid(UserHandle.myUserId())); verify(mSmartActionsProvider, times(1)).getActions(any(), any(), any(), any(), any()); @@ -152,7 +154,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { SystemUIFactory.getInstance().createScreenshotNotificationSmartActionsProvider( mContext, null, mHandler); CompletableFuture<List<Notification.Action>> smartActionsFuture = - ScreenshotSmartActions.getSmartActionsFuture("", null, bitmap, + mScreenshotSmartActions.getSmartActionsFuture("", null, bitmap, actionsProvider, true, UserHandle.getUserHandleForUid(UserHandle.myUserId())); assertNotNull(smartActionsFuture); @@ -172,7 +174,8 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { data.image = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); data.finisher = null; data.mActionsReadyListener = null; - SaveImageInBackgroundTask task = new SaveImageInBackgroundTask(mContext, data); + SaveImageInBackgroundTask task = + new SaveImageInBackgroundTask(mContext, mScreenshotSmartActions, data); Notification.Action shareAction = task.createShareAction(mContext, mContext.getResources(), Uri.parse("Screenshot_123.png")); @@ -198,7 +201,8 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { data.image = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); data.finisher = null; data.mActionsReadyListener = null; - SaveImageInBackgroundTask task = new SaveImageInBackgroundTask(mContext, data); + SaveImageInBackgroundTask task = + new SaveImageInBackgroundTask(mContext, mScreenshotSmartActions, data); Notification.Action editAction = task.createEditAction(mContext, mContext.getResources(), Uri.parse("Screenshot_123.png")); @@ -224,7 +228,8 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { data.image = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); data.finisher = null; data.mActionsReadyListener = null; - SaveImageInBackgroundTask task = new SaveImageInBackgroundTask(mContext, data); + SaveImageInBackgroundTask task = + new SaveImageInBackgroundTask(mContext, mScreenshotSmartActions, data); Notification.Action deleteAction = task.createDeleteAction(mContext, mContext.getResources(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java new file mode 100644 index 000000000000..ce6f0736ec33 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.screenshot; + +import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_ACTION_TYPE; +import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_ID; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.verify; + +import android.app.PendingIntent; +import android.content.Intent; +import android.os.Bundle; +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidTestingRunner.class) +@SmallTest +public class SmartActionsReceiverTest extends SysuiTestCase { + + @Mock + private ScreenshotSmartActions mMockScreenshotSmartActions; + @Mock + private PendingIntent mMockPendingIntent; + + private SmartActionsReceiver mSmartActionsReceiver; + private Intent mIntent; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mSmartActionsReceiver = new SmartActionsReceiver(mMockScreenshotSmartActions); + mIntent = new Intent(mContext, SmartActionsReceiver.class) + .putExtra(GlobalScreenshot.EXTRA_ACTION_INTENT, mMockPendingIntent); + } + + @Test + public void testSmartActionIntent() throws PendingIntent.CanceledException { + String testId = "testID"; + String testActionType = "testActionType"; + mIntent.putExtra(EXTRA_ID, testId); + mIntent.putExtra(EXTRA_ACTION_TYPE, testActionType); + + mSmartActionsReceiver.onReceive(mContext, mIntent); + + verify(mMockPendingIntent).send( + eq(mContext), eq(0), isNull(), isNull(), isNull(), isNull(), any(Bundle.class)); + verify(mMockScreenshotSmartActions).notifyScreenshotAction( + mContext, testId, testActionType, true); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java index aefea57155bc..8a49326add25 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java @@ -61,6 +61,7 @@ import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationLifetimeExtender; import com.android.systemui.statusbar.NotificationMediaManager; @@ -200,7 +201,9 @@ public class NotificationEntryManagerTest extends SysuiTestCase { () -> mNotificationRowBinder, () -> mRemoteInputManager, mLeakDetector, - mock(ForegroundServiceDismissalFeatureController.class) + mock(ForegroundServiceDismissalFeatureController.class), + mock(HeadsUpManager.class), + mock(StatusBarStateController.class) ); mEntryManager.setUpWithPresenter(mPresenter); mEntryManager.addNotificationEntryListener(mEntryListener); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java index 314b19140e7a..960ea79f36b4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java @@ -16,6 +16,11 @@ package com.android.systemui.statusbar.notification.collection.coordinator; +import static android.app.Notification.FLAG_FOREGROUND_SERVICE; +import static android.app.NotificationManager.IMPORTANCE_DEFAULT; +import static android.app.NotificationManager.IMPORTANCE_HIGH; +import static android.app.NotificationManager.IMPORTANCE_MIN; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; @@ -43,6 +48,7 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; import com.android.systemui.util.concurrency.FakeExecutor; @@ -68,13 +74,13 @@ public class AppOpsCoordinatorTest extends SysuiTestCase { @Mock private AppOpsController mAppOpsController; @Mock private NotifPipeline mNotifPipeline; - private NotificationEntry mEntry; - private Notification mNotification; + private NotificationEntryBuilder mEntryBuilder; private AppOpsCoordinator mAppOpsCoordinator; private NotifFilter mForegroundFilter; private NotifCollectionListener mNotifCollectionListener; private AppOpsController.Callback mAppOpsCallback; private NotifLifetimeExtender mForegroundNotifLifetimeExtender; + private NotifSection mFgsSection; private FakeSystemClock mClock = new FakeSystemClock(); private FakeExecutor mExecutor = new FakeExecutor(mClock); @@ -90,11 +96,8 @@ public class AppOpsCoordinatorTest extends SysuiTestCase { mAppOpsController, mExecutor); - mNotification = new Notification(); - mEntry = new NotificationEntryBuilder() - .setUser(new UserHandle(NOTIF_USER_ID)) - .setNotification(mNotification) - .build(); + mEntryBuilder = new NotificationEntryBuilder() + .setUser(new UserHandle(NOTIF_USER_ID)); mAppOpsCoordinator.attach(mNotifPipeline); @@ -122,11 +125,14 @@ public class AppOpsCoordinatorTest extends SysuiTestCase { ArgumentCaptor.forClass(AppOpsController.Callback.class); verify(mAppOpsController).addCallback(any(int[].class), appOpsCaptor.capture()); mAppOpsCallback = appOpsCaptor.getValue(); + + mFgsSection = mAppOpsCoordinator.getSection(); } @Test public void filterTest_disclosureUnnecessary() { - StatusBarNotification sbn = mEntry.getSbn(); + NotificationEntry entry = mEntryBuilder.build(); + StatusBarNotification sbn = entry.getSbn(); // GIVEN the notification is a disclosure notification when(mForegroundServiceController.isDisclosureNotification(sbn)).thenReturn(true); @@ -136,84 +142,91 @@ public class AppOpsCoordinatorTest extends SysuiTestCase { .thenReturn(false); // THEN filter out the notification - assertTrue(mForegroundFilter.shouldFilterOut(mEntry, 0)); + assertTrue(mForegroundFilter.shouldFilterOut(entry, 0)); } @Test public void filterTest_systemAlertNotificationUnnecessary() { - StatusBarNotification sbn = mEntry.getSbn(); - - // GIVEN the notification is a system alert notification + not a disclosure notification - when(mForegroundServiceController.isSystemAlertNotification(sbn)).thenReturn(true); - when(mForegroundServiceController.isDisclosureNotification(sbn)).thenReturn(false); - // GIVEN the alert notification isn't needed for this user final Bundle extras = new Bundle(); extras.putStringArray(Notification.EXTRA_FOREGROUND_APPS, new String[]{TEST_PKG}); - mNotification.extras = extras; + mEntryBuilder.modifyNotification(mContext) + .setExtras(extras); + NotificationEntry entry = mEntryBuilder.build(); + StatusBarNotification sbn = entry.getSbn(); when(mForegroundServiceController.isSystemAlertWarningNeeded(sbn.getUserId(), TEST_PKG)) .thenReturn(false); + // GIVEN the notification is a system alert notification + not a disclosure notification + when(mForegroundServiceController.isSystemAlertNotification(sbn)).thenReturn(true); + when(mForegroundServiceController.isDisclosureNotification(sbn)).thenReturn(false); + + // THEN filter out the notification - assertTrue(mForegroundFilter.shouldFilterOut(mEntry, 0)); + assertTrue(mForegroundFilter.shouldFilterOut(entry, 0)); } @Test public void filterTest_doNotFilter() { - StatusBarNotification sbn = mEntry.getSbn(); + NotificationEntry entry = mEntryBuilder.build(); + StatusBarNotification sbn = entry.getSbn(); // GIVEN the notification isn't a system alert notification nor a disclosure notification when(mForegroundServiceController.isSystemAlertNotification(sbn)).thenReturn(false); when(mForegroundServiceController.isDisclosureNotification(sbn)).thenReturn(false); // THEN don't filter out the notification - assertFalse(mForegroundFilter.shouldFilterOut(mEntry, 0)); + assertFalse(mForegroundFilter.shouldFilterOut(entry, 0)); } @Test public void extendLifetimeText_notForeground() { // GIVEN the notification doesn't represent a foreground service - mNotification.flags = 0; + mEntryBuilder.modifyNotification(mContext) + .setFlag(FLAG_FOREGROUND_SERVICE, false); // THEN don't extend the lifetime assertFalse(mForegroundNotifLifetimeExtender - .shouldExtendLifetime(mEntry, NotificationListenerService.REASON_CLICK)); + .shouldExtendLifetime(mEntryBuilder.build(), + NotificationListenerService.REASON_CLICK)); } @Test public void extendLifetimeText_foregroundNotifRecentlyPosted() { // GIVEN the notification represents a foreground service that was just posted - mNotification.flags |= Notification.FLAG_FOREGROUND_SERVICE; - mEntry = new NotificationEntryBuilder() - .setUser(new UserHandle(NOTIF_USER_ID)) + Notification notification = new Notification.Builder(mContext, "test_channel") + .setFlag(FLAG_FOREGROUND_SERVICE, true) + .build(); + NotificationEntry entry = mEntryBuilder .setSbn(new StatusBarNotification(TEST_PKG, TEST_PKG, NOTIF_USER_ID, "", - NOTIF_USER_ID, NOTIF_USER_ID, mNotification, + NOTIF_USER_ID, NOTIF_USER_ID, notification, new UserHandle(NOTIF_USER_ID), "", System.currentTimeMillis())) - .setNotification(mNotification) + .setNotification(notification) .build(); // THEN extend the lifetime assertTrue(mForegroundNotifLifetimeExtender - .shouldExtendLifetime(mEntry, NotificationListenerService.REASON_CLICK)); + .shouldExtendLifetime(entry, NotificationListenerService.REASON_CLICK)); } @Test public void extendLifetimeText_foregroundNotifOld() { // GIVEN the notification represents a foreground service that was posted 10 seconds ago - mNotification.flags |= Notification.FLAG_FOREGROUND_SERVICE; - mEntry = new NotificationEntryBuilder() - .setUser(new UserHandle(NOTIF_USER_ID)) + Notification notification = new Notification.Builder(mContext, "test_channel") + .setFlag(FLAG_FOREGROUND_SERVICE, true) + .build(); + NotificationEntry entry = mEntryBuilder .setSbn(new StatusBarNotification(TEST_PKG, TEST_PKG, NOTIF_USER_ID, "", - NOTIF_USER_ID, NOTIF_USER_ID, mNotification, + NOTIF_USER_ID, NOTIF_USER_ID, notification, new UserHandle(NOTIF_USER_ID), "", System.currentTimeMillis() - 10000)) - .setNotification(mNotification) + .setNotification(notification) .build(); // THEN don't extend the lifetime because the extended time exceeds MIN_FGS_TIME_MS assertFalse(mForegroundNotifLifetimeExtender - .shouldExtendLifetime(mEntry, NotificationListenerService.REASON_CLICK)); + .shouldExtendLifetime(entry, NotificationListenerService.REASON_CLICK)); } @Test @@ -345,4 +358,41 @@ public class AppOpsCoordinatorTest extends SysuiTestCase { // THEN the entry's active app ops is updated to empty assertTrue(entry.mActiveAppOps.isEmpty()); } + + @Test + public void testIncludeFGSInSection_importanceDefault() { + // GIVEN the notification represents a colorized foreground service with > min importance + mEntryBuilder + .setFlag(mContext, FLAG_FOREGROUND_SERVICE, true) + .setImportance(IMPORTANCE_DEFAULT) + .modifyNotification(mContext).setColorized(true); + + // THEN the entry is in the fgs section + assertTrue(mFgsSection.isInSection(mEntryBuilder.build())); + } + + @Test + public void testDiscludeFGSInSection_importanceMin() { + // GIVEN the notification represents a colorized foreground service with min importance + mEntryBuilder + .setFlag(mContext, FLAG_FOREGROUND_SERVICE, true) + .setImportance(IMPORTANCE_MIN) + .modifyNotification(mContext).setColorized(true); + + // THEN the entry is NOT in the fgs section + assertFalse(mFgsSection.isInSection(mEntryBuilder.build())); + } + + @Test + public void testDiscludeNonFGSInSection() { + // GIVEN the notification represents a colorized notification with high importance that + // is NOT a foreground service + mEntryBuilder + .setImportance(IMPORTANCE_HIGH) + .setFlag(mContext, FLAG_FOREGROUND_SERVICE, false) + .modifyNotification(mContext).setColorized(false); + + // THEN the entry is NOT in the fgs section + assertFalse(mFgsSection.isInSection(mEntryBuilder.build())); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt index dfc627e14d8c..be5c8a846afb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt @@ -25,6 +25,9 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection +import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier +import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before @@ -40,38 +43,52 @@ import org.mockito.Mockito.`when` as whenever @RunWith(AndroidTestingRunner::class) @TestableLooper.RunWithLooper class ConversationCoordinatorTest : SysuiTestCase() { - - private var coordinator: ConversationCoordinator = ConversationCoordinator() - // captured listeners and pluggables: - private var promoter: NotifPromoter? = null + private lateinit var promoter: NotifPromoter + private lateinit var peopleSection: NotifSection @Mock - private val pipeline: NotifPipeline? = null + private lateinit var pipeline: NotifPipeline + @Mock + private lateinit var peopleNotificationIdentifier: PeopleNotificationIdentifier @Mock - private val channel: NotificationChannel? = null - private var entry: NotificationEntry? = null + private lateinit var channel: NotificationChannel + private lateinit var entry: NotificationEntry + + private lateinit var coordinator: ConversationCoordinator @Before fun setUp() { MockitoAnnotations.initMocks(this) - whenever(channel!!.isImportantConversation).thenReturn(true) + coordinator = ConversationCoordinator(peopleNotificationIdentifier) + whenever(channel.isImportantConversation).thenReturn(true) - coordinator.attach(pipeline!!) + coordinator.attach(pipeline) // capture arguments: val notifPromoterCaptor = ArgumentCaptor.forClass(NotifPromoter::class.java) verify(pipeline).addPromoter(notifPromoterCaptor.capture()) promoter = notifPromoterCaptor.value + peopleSection = coordinator.getSection() + entry = NotificationEntryBuilder().setChannel(channel).build() } @Test - fun testPromotesCurrentHUN() { - + fun testPromotesImportantConversations() { // only promote important conversations - assertTrue(promoter!!.shouldPromoteToTopLevel(entry)) - assertFalse(promoter!!.shouldPromoteToTopLevel(NotificationEntryBuilder().build())) + assertTrue(promoter.shouldPromoteToTopLevel(entry)) + assertFalse(promoter.shouldPromoteToTopLevel(NotificationEntryBuilder().build())) + } + + @Test + fun testInPeopleSection() { + whenever(peopleNotificationIdentifier.getPeopleNotificationType( + entry.sbn, entry.ranking)).thenReturn(TYPE_PERSON) + + // only put people notifications in this section + assertTrue(peopleSection.isInSection(entry)) + assertFalse(peopleSection.isInSection(NotificationEntryBuilder().build())) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java index 85acbe6d440b..5f10f38b2ee8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java @@ -36,6 +36,8 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection; +import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; import org.junit.Before; import org.junit.Test; @@ -50,6 +52,7 @@ import org.mockito.MockitoAnnotations; public class RankingCoordinatorTest extends SysuiTestCase { @Mock private StatusBarStateController mStatusBarStateController; + @Mock private HighPriorityProvider mHighPriorityProvider; @Mock private NotifPipeline mNotifPipeline; @Captor private ArgumentCaptor<NotifFilter> mNotifFilterCaptor; @@ -58,16 +61,23 @@ public class RankingCoordinatorTest extends SysuiTestCase { private NotifFilter mCapturedSuspendedFilter; private NotifFilter mCapturedDozingFilter; + private NotifSection mAlertingSection; + private NotifSection mSilentSection; + @Before public void setup() { MockitoAnnotations.initMocks(this); - RankingCoordinator rankingCoordinator = new RankingCoordinator(mStatusBarStateController); + RankingCoordinator rankingCoordinator = + new RankingCoordinator(mStatusBarStateController, mHighPriorityProvider); mEntry = new NotificationEntryBuilder().build(); rankingCoordinator.attach(mNotifPipeline); verify(mNotifPipeline, times(2)).addPreGroupFilter(mNotifFilterCaptor.capture()); mCapturedSuspendedFilter = mNotifFilterCaptor.getAllValues().get(0); mCapturedDozingFilter = mNotifFilterCaptor.getAllValues().get(1); + + mAlertingSection = rankingCoordinator.getAlertingSection(); + mSilentSection = rankingCoordinator.getSilentSection(); } @Test @@ -130,6 +140,26 @@ public class RankingCoordinatorTest extends SysuiTestCase { assertTrue(mCapturedDozingFilter.shouldFilterOut(mEntry, 0)); } + @Test + public void testIncludeInSectionAlerting() { + // GIVEN the entry is high priority + when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(true); + + // THEN entry is in the alerting section + assertTrue(mAlertingSection.isInSection(mEntry)); + assertFalse(mSilentSection.isInSection(mEntry)); + } + + @Test + public void testIncludeInSectionSilent() { + // GIVEN the entry isn't high priority + when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false); + + // THEN entry is in the silent section + assertFalse(mAlertingSection.isInSection(mEntry)); + assertTrue(mSilentSection.isInSection(mEntry)); + } + private RankingBuilder getRankingForUnfilteredNotif() { return new RankingBuilder() .setKey(mEntry.getKey()) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java index c5374b2eb049..601df2cb4fc7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java @@ -184,7 +184,9 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { () -> mRowBinder, () -> mRemoteInputManager, mLeakDetector, - mock(ForegroundServiceDismissalFeatureController.class) + mock(ForegroundServiceDismissalFeatureController.class), + mock(HeadsUpManager.class), + mock(StatusBarStateController.class) ); NotifRemoteViewCache cache = new NotifRemoteViewCacheImpl(mEntryManager); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index b286f9486e13..6d411333b220 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -55,6 +55,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.media.KeyguardMediaController; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.EmptyShadeView; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationLockscreenUserManager; @@ -92,6 +93,7 @@ import com.android.systemui.statusbar.phone.NotificationIconAreaController; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.util.leak.LeakDetector; @@ -190,7 +192,9 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { () -> mock(NotificationRowBinder.class), () -> mRemoteInputManager, mock(LeakDetector.class), - mock(ForegroundServiceDismissalFeatureController.class) + mock(ForegroundServiceDismissalFeatureController.class), + mock(HeadsUpManager.class), + mock(StatusBarStateController.class) ); mEntryManager.setUpWithPresenter(mock(NotificationPresenter.class)); when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java index debc840394b5..fa253e62ef0a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java @@ -16,13 +16,18 @@ package com.android.systemui.statusbar.phone; +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.content.res.Resources; import android.hardware.display.AmbientDisplayConfiguration; import android.os.PowerManager; +import android.provider.Settings; import android.test.suitebuilder.annotation.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -30,6 +35,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.systemui.SysuiTestCase; import com.android.systemui.doze.AlwaysOnDisplayPolicy; import com.android.systemui.doze.DozeScreenState; +import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.tuner.TunerService; import org.junit.Assert; @@ -50,6 +56,7 @@ public class DozeParametersTest extends SysuiTestCase { @Mock private AlwaysOnDisplayPolicy mAlwaysOnDisplayPolicy; @Mock private PowerManager mPowerManager; @Mock private TunerService mTunerService; + @Mock private BatteryController mBatteryController; @Before public void setup() { @@ -59,11 +66,12 @@ public class DozeParametersTest extends SysuiTestCase { mAmbientDisplayConfiguration, mAlwaysOnDisplayPolicy, mPowerManager, + mBatteryController, mTunerService ); } @Test - public void test_setControlScreenOffAnimation_setsDozeAfterScreenOff_false() { + public void testSetControlScreenOffAnimation_setsDozeAfterScreenOff_false() { mDozeParameters.setControlScreenOffAnimation(true); reset(mPowerManager); mDozeParameters.setControlScreenOffAnimation(false); @@ -71,7 +79,7 @@ public class DozeParametersTest extends SysuiTestCase { } @Test - public void test_setControlScreenOffAnimation_setsDozeAfterScreenOff_true() { + public void testSetControlScreenOffAnimation_setsDozeAfterScreenOff_true() { mDozeParameters.setControlScreenOffAnimation(false); reset(mPowerManager); mDozeParameters.setControlScreenOffAnimation(true); @@ -79,11 +87,28 @@ public class DozeParametersTest extends SysuiTestCase { } @Test - public void test_getWallpaperAodDuration_when_shouldControlScreenOff() { + public void testGetWallpaperAodDuration_when_shouldControlScreenOff() { mDozeParameters.setControlScreenOffAnimation(true); Assert.assertEquals( "wallpaper hides faster when controlling screen off", mDozeParameters.getWallpaperAodDuration(), DozeScreenState.ENTER_DOZE_HIDE_WALLPAPER_DELAY); } + + @Test + public void testGetAlwaysOn() { + when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true); + mDozeParameters.onTuningChanged(Settings.Secure.DOZE_ALWAYS_ON, "1"); + + assertThat(mDozeParameters.getAlwaysOn()).isTrue(); + } + + @Test + public void testGetAlwaysOn_whenBatterySaver() { + when(mBatteryController.isAodPowerSave()).thenReturn(true); + when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true); + mDozeParameters.onTuningChanged(Settings.Secure.DOZE_ALWAYS_ON, "1"); + + assertThat(mDozeParameters.getAlwaysOn()).isFalse(); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java index 6433376cd2a9..b5060ee416f7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertNotEquals; 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 static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; @@ -190,13 +191,13 @@ public class NavigationBarContextTest extends SysuiTestCase { kbd2.setDarkIntensity(0f); // Update icon returns the drawable intensity to half - doReturn(kbd1).when(button).getNewDrawable(); - button.updateIcon(); + doReturn(kbd1).when(button).getNewDrawable(anyInt(), anyInt()); + button.updateIcon(0, 0); assertEquals(TEST_DARK_INTENSITY, kbd1.getDarkIntensity(), DARK_INTENSITY_ERR); // Return old dark intensity on new drawable after update icon - doReturn(kbd2).when(button).getNewDrawable(); - button.updateIcon(); + doReturn(kbd2).when(button).getNewDrawable(anyInt(), anyInt()); + button.updateIcon(0, 0); assertEquals(TEST_DARK_INTENSITY, kbd2.getDarkIntensity(), DARK_INTENSITY_ERR); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarRotationContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarRotationContextTest.java index d6b38ff4936f..f21235c12cde 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarRotationContextTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarRotationContextTest.java @@ -59,8 +59,8 @@ public class NavigationBarRotationContextTest extends SysuiTestCase { final View view = new View(mContext); mRotationButton = mock(RotationButton.class); - mRotationButtonController = spy( - new RotationButtonController(mContext, RES_UNDEF, mRotationButton)); + mRotationButtonController = spy(new RotationButtonController(mContext, 0, 0, + mRotationButton)); final KeyButtonDrawable kbd = mock(KeyButtonDrawable.class); doReturn(view).when(mRotationButton).getCurrentView(); doReturn(true).when(mRotationButton).acceptRotationProposal(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java index 4d6922c02c41..0c2361a9f6b9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java @@ -24,6 +24,7 @@ import static org.mockito.Mockito.verify; import android.app.AppOpsManager; import android.content.Intent; import android.location.LocationManager; +import android.os.Handler; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; @@ -60,8 +61,11 @@ public class LocationControllerImplTest extends SysuiTestCase { mLocationController = spy(new LocationControllerImpl(mContext, mAppOpsController, mTestableLooper.getLooper(), + new Handler(mTestableLooper.getLooper()), mock(BroadcastDispatcher.class), mock(BootCompleteCache.class))); + + mTestableLooper.processAllMessages(); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java new file mode 100644 index 000000000000..8cb5f3e65a5e --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.util.settings; + +import android.content.ContentResolver; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.UserHandle; +import android.util.Pair; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class FakeSettings implements SecureSettings, GlobalSettings, SystemSettings { + private final Map<SettingsKey, String> mValues = new HashMap<>(); + private final Map<SettingsKey, List<ContentObserver>> mContentObservers = + new HashMap<>(); + + public static final Uri CONTENT_URI = Uri.parse("content://settings/fake"); + + public FakeSettings() { + } + + public FakeSettings(String initialKey, String initialValue) { + putString(initialKey, initialValue); + } + + public FakeSettings(Map<String, String> initialValues) { + for (Map.Entry<String, String> kv : initialValues.entrySet()) { + putString(kv.getKey(), kv.getValue()); + } + } + + @Override + public ContentResolver getContentResolver() { + return null; + } + + @Override + public void registerContentObserverForUser(String name, ContentObserver settingsObserver, + int userHandle) { + SettingsKey key = new SettingsKey(userHandle, name); + mContentObservers.putIfAbsent(key, new ArrayList<>()); + List<ContentObserver> observers = mContentObservers.get(key); + observers.add(settingsObserver); + } + + @Override + public void unregisterContentObserver(ContentObserver settingsObserver) { + for (SettingsKey key : mContentObservers.keySet()) { + List<ContentObserver> observers = mContentObservers.get(key); + observers.remove(settingsObserver); + } + } + + @Override + public Uri getUriFor(String name) { + return Uri.withAppendedPath(CONTENT_URI, name); + } + + @Override + public int getUserId() { + return UserHandle.USER_CURRENT; + } + + @Override + public String getString(String name) { + return getStringForUser(name, getUserId()); + } + + @Override + public String getStringForUser(String name, int userHandle) { + return mValues.get(new SettingsKey(userHandle, name)); + } + + @Override + public boolean putString(String name, String value, boolean overrideableByRestore) { + return putStringForUser(name, value, null, false, getUserId(), overrideableByRestore); + } + + @Override + public boolean putString(String name, String value) { + return putString(name, value, false); + } + + @Override + public boolean putStringForUser(String name, String value, int userHandle) { + return putStringForUser(name, value, null, false, userHandle, false); + } + + @Override + public boolean putStringForUser(String name, String value, String tag, boolean makeDefault, + int userHandle, boolean overrideableByRestore) { + SettingsKey key = new SettingsKey(userHandle, name); + mValues.put(key, value); + + Uri uri = getUriFor(name); + for (ContentObserver observer : mContentObservers.getOrDefault(key, new ArrayList<>())) { + observer.dispatchChange(false, List.of(uri), userHandle); + } + return true; + } + + @Override + public boolean putString(String name, String value, String tag, boolean makeDefault) { + return putString(name, value); + } + + private static class SettingsKey extends Pair<Integer, String> { + SettingsKey(Integer first, String second) { + super(first, second); + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java new file mode 100644 index 000000000000..0d560f237a07 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.util.settings; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import android.database.ContentObserver; +import android.provider.Settings; +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Collection; +import java.util.Map; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class FakeSettingsTest extends SysuiTestCase { + @Mock + ContentObserver mContentObserver; + + private FakeSettings mFakeSettings; + + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mFakeSettings = new FakeSettings(); + } + + /** + * Test FakeExecutor that receives non-delayed items to execute. + */ + @Test + public void testPutAndGet() throws Settings.SettingNotFoundException { + mFakeSettings.putInt("foobar", 1); + assertThat(mFakeSettings.getInt("foobar")).isEqualTo(1); + } + + @Test + public void testInitialize() { + mFakeSettings = new FakeSettings("abra", "cadabra"); + assertThat(mFakeSettings.getString("abra")).isEqualTo("cadabra"); + } + + @Test + public void testInitializeWithMap() { + mFakeSettings = new FakeSettings(Map.of("one fish", "two fish", "red fish", "blue fish")); + assertThat(mFakeSettings.getString("red fish")).isEqualTo("blue fish"); + assertThat(mFakeSettings.getString("one fish")).isEqualTo("two fish"); + } + + @Test + public void testRegisterContentObserver() { + mFakeSettings.registerContentObserver("cat", mContentObserver); + + mFakeSettings.putString("cat", "hat"); + + verify(mContentObserver).dispatchChange(anyBoolean(), any(Collection.class), anyInt()); + } + + @Test + public void testUnregisterContentObserver() { + mFakeSettings.registerContentObserver("cat", mContentObserver); + mFakeSettings.unregisterContentObserver(mContentObserver); + + mFakeSettings.putString("cat", "hat"); + + verify(mContentObserver, never()).dispatchChange( + anyBoolean(), any(Collection.class), anyInt()); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBatteryController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBatteryController.java index 8ec4cb8b927b..50c1e73f6aac 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBatteryController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBatteryController.java @@ -25,6 +25,8 @@ import java.io.PrintWriter; public class FakeBatteryController extends BaseLeakChecker<BatteryStateChangeCallback> implements BatteryController { + private boolean mWirelessCharging; + public FakeBatteryController(LeakCheck test) { super(test, "battery"); } @@ -58,4 +60,13 @@ public class FakeBatteryController extends BaseLeakChecker<BatteryStateChangeCal public boolean isAodPowerSave() { return false; } + + @Override + public boolean isWirelessCharging() { + return mWirelessCharging; + } + + public void setWirelessCharging(boolean wirelessCharging) { + mWirelessCharging = wirelessCharging; + } } diff --git a/services/Android.bp b/services/Android.bp index 8c251e9867f8..f0144ac1c695 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -154,7 +154,14 @@ droidstubs { java_library { name: "android_system_server_stubs_current", + defaults: ["android_stubs_dists_default"], srcs: [":services-stubs.sources"], installable: false, static_libs: ["android_module_lib_stubs_current"], + sdk_version: "none", + system_modules: "none", + java_version: "1.8", + dist: { + dir: "apistubs/android/system-server", + }, } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index c92571ce31b0..2cd4c6939fa9 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -56,6 +56,8 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.database.ContentObserver; +import android.graphics.Point; +import android.graphics.Rect; import android.graphics.Region; import android.hardware.display.DisplayManager; import android.hardware.fingerprint.IFingerprintService; @@ -194,6 +196,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private final SimpleStringSplitter mStringColonSplitter = new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR); + private final Rect mTempRect = new Rect(); + private final Rect mTempRect1 = new Rect(); + private final PackageManager mPackageManager; private final PowerManager mPowerManager; @@ -251,6 +256,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub //TODO: Remove this hack private boolean mInitialized; + private Point mTempPoint = new Point(); private boolean mIsAccessibilityButtonShown; private AccessibilityUserState getCurrentUserStateLocked() { @@ -1086,6 +1092,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } /** + * Gets a point within the accessibility focused node where we can send down + * and up events to perform a click. + * + * @param outPoint The click point to populate. + * @return Whether accessibility a click point was found and set. + */ + // TODO: (multi-display) Make sure this works for multiple displays. + public boolean getAccessibilityFocusClickPointInScreen(Point outPoint) { + return getInteractionBridge().getAccessibilityFocusClickPointInScreenNotLocked(outPoint); + } + + /** * Perform an accessibility action on the view that currently has accessibility focus. * Has no effect if no item has accessibility focus, if the item with accessibility * focus does not expose the specified action, or if the action fails. @@ -1099,6 +1117,32 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return getInteractionBridge().performActionOnAccessibilityFocusedItemNotLocked(action); } + /** + * Returns true if accessibility focus is confined to the active window. + */ + public boolean accessibilityFocusOnlyInActiveWindow() { + synchronized (mLock) { + return mA11yWindowManager.isTrackingWindowsLocked(); + } + } + + /** + * Gets the bounds of a window. + * + * @param outBounds The output to which to write the bounds. + */ + boolean getWindowBounds(int windowId, Rect outBounds) { + IBinder token; + synchronized (mLock) { + token = getWindowToken(windowId, mCurrentUserId); + } + mWindowManagerService.getWindowFrame(token, outBounds); + if (!outBounds.isEmpty()) { + return true; + } + return false; + } + public int getActiveWindowId() { return mA11yWindowManager.getActiveWindowId(mCurrentUserId); } @@ -1877,9 +1921,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub for (int i = 0; !observingWindows && (i < boundServiceCount); i++) { AccessibilityServiceConnection boundService = boundServices.get(i); if (boundService.canRetrieveInteractiveWindowsLocked()) { + userState.setAccessibilityFocusOnlyInActiveWindow(false); observingWindows = true; } } + userState.setAccessibilityFocusOnlyInActiveWindow(true); // Gets all valid displays and start tracking windows of each display if there is at least // one bound service that can retrieve window content. @@ -2997,6 +3043,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } /** + * Gets a point within the accessibility focused node where we can send down and up events + * to perform a click. + * + * @param outPoint The click point to populate. + * @return Whether accessibility a click point was found and set. + */ + // TODO: (multi-display) Make sure this works for multiple displays. + boolean getAccessibilityFocusClickPointInScreen(Point outPoint) { + return getInteractionBridge() + .getAccessibilityFocusClickPointInScreenNotLocked(outPoint); + } + + /** * Perform an accessibility action on the view that currently has accessibility focus. * Has no effect if no item has accessibility focus, if the item with accessibility * focus does not expose the specified action, or if the action fails. @@ -3014,6 +3073,43 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return focus.performAction(action.getId()); } + public boolean getAccessibilityFocusClickPointInScreenNotLocked(Point outPoint) { + AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked(); + if (focus == null) { + return false; + } + + synchronized (mLock) { + Rect boundsInScreen = mTempRect; + focus.getBoundsInScreen(boundsInScreen); + + // Apply magnification if needed. + MagnificationSpec spec = getCompatibleMagnificationSpecLocked(focus.getWindowId()); + if (spec != null && !spec.isNop()) { + boundsInScreen.offset((int) -spec.offsetX, (int) -spec.offsetY); + boundsInScreen.scale(1 / spec.scale); + } + + // Clip to the window bounds. + Rect windowBounds = mTempRect1; + getWindowBounds(focus.getWindowId(), windowBounds); + if (!boundsInScreen.intersect(windowBounds)) { + return false; + } + + // Clip to the screen bounds. + Point screenSize = mTempPoint; + mDefaultDisplay.getRealSize(screenSize); + if (!boundsInScreen.intersect(0, 0, screenSize.x, screenSize.y)) { + return false; + } + + outPoint.set(boundsInScreen.centerX(), boundsInScreen.centerY()); + } + + return true; + } + private AccessibilityNodeInfo getAccessibilityFocusNotLocked() { final int focusedWindowId; synchronized (mLock) { diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java index e54b0f9fb413..f865aa7d6e37 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java @@ -105,6 +105,7 @@ class AccessibilityUserState { private boolean mIsDisplayMagnificationEnabled; private boolean mIsFilterKeyEventsEnabled; private boolean mIsPerformGesturesEnabled; + private boolean mAccessibilityFocusOnlyInActiveWindow; private boolean mIsTextHighContrastEnabled; private boolean mIsTouchExplorationEnabled; private boolean mServiceHandlesDoubleTap; @@ -742,6 +743,13 @@ class AccessibilityUserState { mIsPerformGesturesEnabled = enabled; } + public boolean isAccessibilityFocusOnlyInActiveWindow() { + return mAccessibilityFocusOnlyInActiveWindow; + } + + public void setAccessibilityFocusOnlyInActiveWindow(boolean enabled) { + mAccessibilityFocusOnlyInActiveWindow = enabled; + } public ComponentName getServiceChangingSoftKeyboardModeLocked() { return mServiceChangingSoftKeyboardMode; } diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java index 667364c9c901..070626be9f80 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java @@ -21,8 +21,11 @@ import static com.android.server.accessibility.gestures.TouchState.ALL_POINTER_I import static com.android.server.accessibility.gestures.TouchState.MAX_POINTER_COUNT; import android.content.Context; +import android.graphics.Point; import android.util.Slog; import android.view.MotionEvent; +import android.view.MotionEvent.PointerCoords; +import android.view.MotionEvent.PointerProperties; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; @@ -37,19 +40,27 @@ import com.android.server.policy.WindowManagerPolicy; */ class EventDispatcher { private static final String LOG_TAG = "EventDispatcher"; + private static final int CLICK_LOCATION_NONE = 0; + private static final int CLICK_LOCATION_ACCESSIBILITY_FOCUS = 1; + private static final int CLICK_LOCATION_LAST_TOUCH_EXPLORED = 2; private final AccessibilityManagerService mAms; private Context mContext; // The receiver of motion events. private EventStreamTransformation mReceiver; - // Keep track of which pointers sent to the system are down. - private int mInjectedPointersDown; - // The time of the last injected down. - private long mLastInjectedDownEventTime; + // The long pressing pointer id if coordinate remapping is needed for double tap and hold + private int mLongPressingPointerId = -1; + + // The long pressing pointer X if coordinate remapping is needed for double tap and hold. + private int mLongPressingPointerDeltaX; + + // The long pressing pointer Y if coordinate remapping is needed for double tap and hold. + private int mLongPressingPointerDeltaY; + + // Temporary point to avoid instantiation. + private final Point mTempPoint = new Point(); - // The last injected hover event. - private MotionEvent mLastInjectedHoverEvent; private TouchState mState; EventDispatcher( @@ -98,8 +109,18 @@ class EventDispatcher { if (action == MotionEvent.ACTION_DOWN) { event.setDownTime(event.getEventTime()); } else { - event.setDownTime(getLastInjectedDownEventTime()); + event.setDownTime(mState.getLastInjectedDownEventTime()); + } + // If the user is long pressing but the long pressing pointer + // was not exactly over the accessibility focused item we need + // to remap the location of that pointer so the user does not + // have to explicitly touch explore something to be able to + // long press it, or even worse to avoid the user long pressing + // on the wrong item since click and long press behave differently. + if (mLongPressingPointerId >= 0) { + event = offsetEvent(event, -mLongPressingPointerDeltaX, -mLongPressingPointerDeltaY); } + if (DEBUG) { Slog.d( LOG_TAG, @@ -116,7 +137,7 @@ class EventDispatcher { } else { Slog.e(LOG_TAG, "Error sending event: no receiver specified."); } - updateState(event); + mState.onInjectedMotionEvent(event); if (event != prototype) { event.recycle(); @@ -145,87 +166,15 @@ class EventDispatcher { mState.onInjectedAccessibilityEvent(type); } - /** - * Processes an injected {@link MotionEvent} event. - * - * @param event The event to process. - */ - void updateState(MotionEvent event) { - final int action = event.getActionMasked(); - final int pointerId = event.getPointerId(event.getActionIndex()); - final int pointerFlag = (1 << pointerId); - switch (action) { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_POINTER_DOWN: - mInjectedPointersDown |= pointerFlag; - mLastInjectedDownEventTime = event.getDownTime(); - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_POINTER_UP: - mInjectedPointersDown &= ~pointerFlag; - if (mInjectedPointersDown == 0) { - mLastInjectedDownEventTime = 0; - } - break; - case MotionEvent.ACTION_HOVER_ENTER: - case MotionEvent.ACTION_HOVER_MOVE: - case MotionEvent.ACTION_HOVER_EXIT: - if (mLastInjectedHoverEvent != null) { - mLastInjectedHoverEvent.recycle(); - } - mLastInjectedHoverEvent = MotionEvent.obtain(event); - break; - } - if (DEBUG) { - Slog.i(LOG_TAG, "Injected pointer:\n" + toString()); - } - } - - /** Clears the internals state. */ - public void clear() { - mInjectedPointersDown = 0; - } - - /** @return The time of the last injected down event. */ - public long getLastInjectedDownEventTime() { - return mLastInjectedDownEventTime; - } - - /** @return The number of down pointers injected to the view hierarchy. */ - public int getInjectedPointerDownCount() { - return Integer.bitCount(mInjectedPointersDown); - } - - /** @return The bits of the injected pointers that are down. */ - public int getInjectedPointersDown() { - return mInjectedPointersDown; - } - - /** - * Whether an injected pointer is down. - * - * @param pointerId The unique pointer id. - * @return True if the pointer is down. - */ - public boolean isInjectedPointerDown(int pointerId) { - final int pointerFlag = (1 << pointerId); - return (mInjectedPointersDown & pointerFlag) != 0; - } - - /** @return The the last injected hover event. */ - public MotionEvent getLastInjectedHoverEvent() { - return mLastInjectedHoverEvent; - } - @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("========================="); builder.append("\nDown pointers #"); - builder.append(Integer.bitCount(mInjectedPointersDown)); + builder.append(Integer.bitCount(mState.getInjectedPointersDown())); builder.append(" [ "); for (int i = 0; i < MAX_POINTER_COUNT; i++) { - if ((mInjectedPointersDown & i) != 0) { + if (mState.isInjectedPointerDown(i)) { builder.append(i); builder.append(" "); } @@ -236,6 +185,48 @@ class EventDispatcher { } /** + * /** Offsets all pointers in the given event by adding the specified X and Y offsets. + * + * @param event The event to offset. + * @param offsetX The X offset. + * @param offsetY The Y offset. + * @return An event with the offset pointers or the original event if both offsets are zero. + */ + private MotionEvent offsetEvent(MotionEvent event, int offsetX, int offsetY) { + if (offsetX == 0 && offsetY == 0) { + return event; + } + final int remappedIndex = event.findPointerIndex(mLongPressingPointerId); + final int pointerCount = event.getPointerCount(); + PointerProperties[] props = PointerProperties.createArray(pointerCount); + PointerCoords[] coords = PointerCoords.createArray(pointerCount); + for (int i = 0; i < pointerCount; i++) { + event.getPointerProperties(i, props[i]); + event.getPointerCoords(i, coords[i]); + if (i == remappedIndex) { + coords[i].x += offsetX; + coords[i].y += offsetY; + } + } + return MotionEvent.obtain( + event.getDownTime(), + event.getEventTime(), + event.getAction(), + event.getPointerCount(), + props, + coords, + event.getMetaState(), + event.getButtonState(), + 1.0f, + 1.0f, + event.getDeviceId(), + event.getEdgeFlags(), + event.getSource(), + event.getDisplayId(), + event.getFlags()); + } + + /** * Computes the action for an injected event based on a masked action and a pointer index. * * @param actionMasked The masked action. @@ -247,7 +238,7 @@ class EventDispatcher { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_POINTER_DOWN: // Compute the action based on how many down pointers are injected. - if (getInjectedPointerDownCount() == 0) { + if (mState.getInjectedPointerDownCount() == 0) { return MotionEvent.ACTION_DOWN; } else { return (pointerIndex << MotionEvent.ACTION_POINTER_INDEX_SHIFT) @@ -255,7 +246,7 @@ class EventDispatcher { } case MotionEvent.ACTION_POINTER_UP: // Compute the action based on how many down pointers are injected. - if (getInjectedPointerDownCount() == 1) { + if (mState.getInjectedPointerDownCount() == 1) { return MotionEvent.ACTION_UP; } else { return (pointerIndex << MotionEvent.ACTION_POINTER_INDEX_SHIFT) @@ -280,7 +271,7 @@ class EventDispatcher { for (int i = 0; i < pointerCount; i++) { final int pointerId = prototype.getPointerId(i); // Do not send event for already delivered pointers. - if (!isInjectedPointerDown(pointerId)) { + if (!mState.isInjectedPointerDown(pointerId)) { pointerIdBits |= (1 << pointerId); final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, i); sendMotionEvent( @@ -306,7 +297,7 @@ class EventDispatcher { for (int i = 0; i < pointerCount; i++) { final int pointerId = prototype.getPointerId(i); // Skip non injected down pointers. - if (!isInjectedPointerDown(pointerId)) { + if (!mState.isInjectedPointerDown(pointerId)) { continue; } final int action = computeInjectionAction(MotionEvent.ACTION_POINTER_UP, i); @@ -315,4 +306,103 @@ class EventDispatcher { pointerIdBits &= ~(1 << pointerId); } } + + public boolean longPressWithTouchEvents(MotionEvent event, int policyFlags) { + final int pointerIndex = event.getActionIndex(); + final int pointerId = event.getPointerId(pointerIndex); + Point clickLocation = mTempPoint; + final int result = computeClickLocation(clickLocation); + if (result == CLICK_LOCATION_NONE) { + return false; + } + mLongPressingPointerId = pointerId; + mLongPressingPointerDeltaX = (int) event.getX(pointerIndex) - clickLocation.x; + mLongPressingPointerDeltaY = (int) event.getY(pointerIndex) - clickLocation.y; + sendDownForAllNotInjectedPointers(event, policyFlags); + return true; + } + + void clear() { + mLongPressingPointerId = -1; + mLongPressingPointerDeltaX = 0; + mLongPressingPointerDeltaY = 0; + } + + public void clickWithTouchEvents(MotionEvent event, MotionEvent rawEvent, int policyFlags) { + final int pointerIndex = event.getActionIndex(); + final int pointerId = event.getPointerId(pointerIndex); + Point clickLocation = mTempPoint; + final int result = computeClickLocation(clickLocation); + if (result == CLICK_LOCATION_NONE) { + Slog.e(LOG_TAG, "Unable to compute click location."); + // We can't send a click to no location, but the gesture was still + // consumed. + return; + } + // Do the click. + PointerProperties[] properties = new PointerProperties[1]; + properties[0] = new PointerProperties(); + event.getPointerProperties(pointerIndex, properties[0]); + PointerCoords[] coords = new PointerCoords[1]; + coords[0] = new PointerCoords(); + coords[0].x = clickLocation.x; + coords[0].y = clickLocation.y; + MotionEvent clickEvent = + MotionEvent.obtain( + event.getDownTime(), + event.getEventTime(), + MotionEvent.ACTION_DOWN, + 1, + properties, + coords, + 0, + 0, + 1.0f, + 1.0f, + event.getDeviceId(), + 0, + event.getSource(), + event.getDisplayId(), + event.getFlags()); + final boolean targetAccessibilityFocus = (result == CLICK_LOCATION_ACCESSIBILITY_FOCUS); + sendActionDownAndUp(clickEvent, rawEvent, policyFlags, targetAccessibilityFocus); + clickEvent.recycle(); + } + + private int computeClickLocation(Point outLocation) { + if (mState.getLastInjectedHoverEventForClick() != null) { + final int lastExplorePointerIndex = + mState.getLastInjectedHoverEventForClick().getActionIndex(); + outLocation.x = + (int) mState.getLastInjectedHoverEventForClick().getX(lastExplorePointerIndex); + outLocation.y = + (int) mState.getLastInjectedHoverEventForClick().getY(lastExplorePointerIndex); + if (!mAms.accessibilityFocusOnlyInActiveWindow() + || mState.getLastTouchedWindowId() == mAms.getActiveWindowId()) { + if (mAms.getAccessibilityFocusClickPointInScreen(outLocation)) { + return CLICK_LOCATION_ACCESSIBILITY_FOCUS; + } else { + return CLICK_LOCATION_LAST_TOUCH_EXPLORED; + } + } + } + if (mAms.getAccessibilityFocusClickPointInScreen(outLocation)) { + return CLICK_LOCATION_ACCESSIBILITY_FOCUS; + } + return CLICK_LOCATION_NONE; + } + + private void sendActionDownAndUp( + MotionEvent prototype, + MotionEvent rawEvent, + int policyFlags, + boolean targetAccessibilityFocus) { + // Tap with the pointer that last explored. + final int pointerId = prototype.getPointerId(prototype.getActionIndex()); + final int pointerIdBits = (1 << pointerId); + prototype.setTargetAccessibilityFocus(targetAccessibilityFocus); + sendMotionEvent(prototype, MotionEvent.ACTION_DOWN, rawEvent, pointerIdBits, policyFlags); + prototype.setTargetAccessibilityFocus(targetAccessibilityFocus); + sendMotionEvent(prototype, MotionEvent.ACTION_UP, rawEvent, pointerIdBits, policyFlags); + } } diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java index 6d0f069e51ac..e9c70c60a322 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java @@ -104,6 +104,7 @@ class GestureManifold implements GestureMatcher.StateChangeListener { mHandler = new Handler(context.getMainLooper()); mListener = listener; mState = state; + mMultiFingerGesturesEnabled = false; // Set up gestures. // Start with double tap. mGestures.add(new MultiTap(context, 2, GESTURE_DOUBLE_TAP, this)); @@ -247,7 +248,7 @@ class GestureManifold implements GestureMatcher.StateChangeListener { * and hold is dispatched via onGestureCompleted. Otherwise, this method is called when the * user has performed a double tap and then held down the second tap. */ - void onDoubleTapAndHold(); + void onDoubleTapAndHold(MotionEvent event, MotionEvent rawEvent, int policyFlags); /** * When FLAG_SERVICE_HANDLES_DOUBLE_TAP is enabled, this method is not called; double-tap is @@ -256,7 +257,7 @@ class GestureManifold implements GestureMatcher.StateChangeListener { * * @return true if the event is consumed, else false */ - boolean onDoubleTap(); + boolean onDoubleTap(MotionEvent event, MotionEvent rawEvent, int policyFlags); /** * Called when the system has decided the event stream is a potential gesture. @@ -322,7 +323,7 @@ class GestureManifold implements GestureMatcher.StateChangeListener { new AccessibilityGestureEvent(gestureId, event.getDisplayId()); mListener.onGestureCompleted(gestureEvent); } else { - mListener.onDoubleTap(); + mListener.onDoubleTap(event, rawEvent, policyFlags); } clear(); break; @@ -332,7 +333,7 @@ class GestureManifold implements GestureMatcher.StateChangeListener { new AccessibilityGestureEvent(gestureId, event.getDisplayId()); mListener.onGestureCompleted(gestureEvent); } else { - mListener.onDoubleTapAndHold(); + mListener.onDoubleTapAndHold(event, rawEvent, policyFlags); } clear(); break; diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index 7b5180d7041b..696702fad730 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -39,7 +39,6 @@ import static com.android.server.accessibility.gestures.TouchState.ALL_POINTER_I import android.accessibilityservice.AccessibilityGestureEvent; import android.annotation.NonNull; import android.content.Context; -import android.graphics.Point; import android.graphics.Region; import android.os.Handler; import android.util.Slog; @@ -133,8 +132,6 @@ public class TouchExplorer extends BaseEventStreamTransformation // Handle to the accessibility manager service. private final AccessibilityManagerService mAms; - // Temporary point to avoid instantiation. - private final Point mTempPoint = new Point(); // Context in which this explorer operates. private final Context mContext; @@ -301,6 +298,7 @@ public class TouchExplorer extends BaseEventStreamTransformation if (eventType == TYPE_VIEW_HOVER_EXIT) { sendsPendingA11yEventsIfNeeded(); } + mState.onReceivedAccessibilityEvent(event); super.onAccessibilityEvent(event); } @@ -332,16 +330,15 @@ public class TouchExplorer extends BaseEventStreamTransformation } @Override - public void onDoubleTapAndHold() { - // Try to use the standard accessibility API to long click - if (!mAms.performActionOnAccessibilityFocusedItem( - AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK)) { - Slog.e(LOG_TAG, "ACTION_LONG_CLICK failed."); + public void onDoubleTapAndHold(MotionEvent event, MotionEvent rawEvent, int policyFlags) { + if (mDispatcher.longPressWithTouchEvents(event, policyFlags)) { + sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags); + mState.startDelegating(); } } @Override - public boolean onDoubleTap() { + public boolean onDoubleTap(MotionEvent event, MotionEvent rawEvent, int policyFlags) { mAms.onTouchInteractionEnd(); // Remove pending event deliveries. mSendHoverEnterAndMoveDelayed.cancel(); @@ -357,7 +354,10 @@ public class TouchExplorer extends BaseEventStreamTransformation // Try to use the standard accessibility API to click if (!mAms.performActionOnAccessibilityFocusedItem( AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK)) { - Slog.e(LOG_TAG, "ACTION_CLICK failed."); + Slog.e(LOG_TAG, "ACTION_CLICK failed. Dispatching motion events to simulate click."); + + mDispatcher.clickWithTouchEvents(event, rawEvent, policyFlags); + return true; } return true; } @@ -819,6 +819,7 @@ public class TouchExplorer extends BaseEventStreamTransformation // Announce the end of a the touch interaction. mAms.onTouchInteractionEnd(); + mDispatcher.clear(); mDispatcher.sendAccessibilityEvent(TYPE_TOUCH_INTERACTION_END); } break; @@ -851,7 +852,7 @@ public class TouchExplorer extends BaseEventStreamTransformation * @param policyFlags The policy flags associated with the event. */ private void sendHoverExitAndTouchExplorationGestureEndIfNeeded(int policyFlags) { - MotionEvent event = mDispatcher.getLastInjectedHoverEvent(); + MotionEvent event = mState.getLastInjectedHoverEvent(); if (event != null && event.getActionMasked() != ACTION_HOVER_EXIT) { final int pointerIdBits = event.getPointerIdBits(); if (!mSendTouchExplorationEndDelayed.isPending()) { @@ -873,7 +874,7 @@ public class TouchExplorer extends BaseEventStreamTransformation * @param policyFlags The policy flags associated with the event. */ private void sendTouchExplorationGestureStartAndHoverEnterIfNeeded(int policyFlags) { - MotionEvent event = mDispatcher.getLastInjectedHoverEvent(); + MotionEvent event = mState.getLastInjectedHoverEvent(); if (event != null && event.getActionMasked() == ACTION_HOVER_EXIT) { final int pointerIdBits = event.getPointerIdBits(); mDispatcher.sendMotionEvent( @@ -1198,7 +1199,6 @@ public class TouchExplorer extends BaseEventStreamTransformation + ", mDetermineUserIntentTimeout: " + mDetermineUserIntentTimeout + ", mDoubleTapSlop: " + mDoubleTapSlop + ", mDraggingPointerId: " + mDraggingPointerId - + ", mTempPoint: " + mTempPoint + " }"; } } diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java index d23dbbefd325..7a39bc29e8e5 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java @@ -75,6 +75,16 @@ public class TouchState { private MotionEvent mLastReceivedEvent; // The accompanying raw event without any transformations. private MotionEvent mLastReceivedRawEvent; + // The id of the last touch explored window. + private int mLastTouchedWindowId; + // The last injected hover event. + private MotionEvent mLastInjectedHoverEvent; + // The last injected hover event used for performing clicks. + private MotionEvent mLastInjectedHoverEventForClick; + // The time of the last injected down. + private long mLastInjectedDownEventTime; + // Keep track of which pointers sent to the system are down. + private int mInjectedPointersDown; public TouchState() { mReceivedPointerTracker = new ReceivedPointerTracker(); @@ -88,7 +98,9 @@ public class TouchState { mLastReceivedEvent.recycle(); mLastReceivedEvent = null; } + mLastTouchedWindowId = -1; mReceivedPointerTracker.clear(); + mInjectedPointersDown = 0; } /** @@ -107,6 +119,71 @@ public class TouchState { mReceivedPointerTracker.onMotionEvent(rawEvent); } + /** + * Processes an injected {@link MotionEvent} event. + * + * @param event The event to process. + */ + void onInjectedMotionEvent(MotionEvent event) { + final int action = event.getActionMasked(); + final int pointerId = event.getPointerId(event.getActionIndex()); + final int pointerFlag = (1 << pointerId); + switch (action) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: + mInjectedPointersDown |= pointerFlag; + mLastInjectedDownEventTime = event.getDownTime(); + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: + mInjectedPointersDown &= ~pointerFlag; + if (mInjectedPointersDown == 0) { + mLastInjectedDownEventTime = 0; + } + break; + case MotionEvent.ACTION_HOVER_ENTER: + case MotionEvent.ACTION_HOVER_MOVE: + if (mLastInjectedHoverEvent != null) { + mLastInjectedHoverEvent.recycle(); + } + mLastInjectedHoverEvent = MotionEvent.obtain(event); + break; + case MotionEvent.ACTION_HOVER_EXIT: + if (mLastInjectedHoverEvent != null) { + mLastInjectedHoverEvent.recycle(); + } + mLastInjectedHoverEvent = MotionEvent.obtain(event); + if (mLastInjectedHoverEventForClick != null) { + mLastInjectedHoverEventForClick.recycle(); + } + mLastInjectedHoverEventForClick = MotionEvent.obtain(event); + break; + } + if (DEBUG) { + Slog.i(LOG_TAG, "Injected pointer:\n" + toString()); + } + } + + /** Updates state in response to an accessibility event received from the outside. */ + public void onReceivedAccessibilityEvent(AccessibilityEvent event) { + // If a new window opens or the accessibility focus moves we no longer + // want to click/long press on the last touch explored location. + switch (event.getEventType()) { + case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: + case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: + if (mLastInjectedHoverEventForClick != null) { + mLastInjectedHoverEventForClick.recycle(); + mLastInjectedHoverEventForClick = null; + } + mLastTouchedWindowId = -1; + break; + case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER: + case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: + mLastTouchedWindowId = event.getWindowId(); + break; + } + } + public void onInjectedAccessibilityEvent(int type) { // The below state transitions go here because the related events are often sent on a // delay. @@ -236,6 +313,46 @@ public class TouchState { return mLastReceivedEvent; } + /** @return The the last injected hover event. */ + public MotionEvent getLastInjectedHoverEvent() { + return mLastInjectedHoverEvent; + } + + /** @return The time of the last injected down event. */ + public long getLastInjectedDownEventTime() { + return mLastInjectedDownEventTime; + } + + public int getLastTouchedWindowId() { + return mLastTouchedWindowId; + } + + /** @return The number of down pointers injected to the view hierarchy. */ + public int getInjectedPointerDownCount() { + return Integer.bitCount(mInjectedPointersDown); + } + + /** @return The bits of the injected pointers that are down. */ + public int getInjectedPointersDown() { + return mInjectedPointersDown; + } + + /** + * Whether an injected pointer is down. + * + * @param pointerId The unique pointer id. + * @return True if the pointer is down. + */ + public boolean isInjectedPointerDown(int pointerId) { + final int pointerFlag = (1 << pointerId); + return (mInjectedPointersDown & pointerFlag) != 0; + } + + /** @return The the last injected hover event used for a click. */ + public MotionEvent getLastInjectedHoverEventForClick() { + return mLastInjectedHoverEventForClick; + } + /** This class tracks where and when a pointer went down. It does not track its movement. */ class ReceivedPointerTracker { private static final String LOG_TAG_RECEIVED_POINTER_TRACKER = "ReceivedPointerTracker"; diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java index 7f6dc14f3793..c87dcd7874f8 100644 --- a/services/core/java/com/android/server/GestureLauncherService.java +++ b/services/core/java/com/android/server/GestureLauncherService.java @@ -75,6 +75,16 @@ public class GestureLauncherService extends SystemService { */ @VisibleForTesting static final long POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS = 500; + /** + * Number of taps required to launch panic ui. + */ + private static final int PANIC_POWER_TAP_COUNT_THRESHOLD = 5; + + /** + * Number of taps required to launch camera shortcut. + */ + private static final int CAMERA_POWER_TAP_COUNT_THRESHOLD = 2; + /** The listener that receives the gesture event. */ private final GestureEventListener mGestureListener = new GestureEventListener(); private final CameraLiftTriggerEventListener mCameraLiftTriggerListener = @@ -135,6 +145,7 @@ public class GestureLauncherService extends SystemService { private long mLastPowerDown; private int mPowerButtonConsecutiveTaps; + private int mPowerButtonSlowConsecutiveTaps; public GestureLauncherService(Context context) { this(context, new MetricsLogger()); @@ -350,9 +361,8 @@ public class GestureLauncherService extends SystemService { * Whether to enable panic button gesture. */ public static boolean isPanicButtonGestureEnabled(Context context, int userId) { - return isCameraLaunchEnabled(context.getResources()) - && (Settings.Secure.getIntForUser(context.getContentResolver(), - Settings.Secure.PANIC_GESTURE_ENABLED, 0, userId) != 0); + return Settings.Secure.getIntForUser(context.getContentResolver(), + Settings.Secure.PANIC_GESTURE_ENABLED, 0, userId) != 0; } /** @@ -384,6 +394,13 @@ public class GestureLauncherService extends SystemService { isCameraLiftTriggerEnabled(resources); } + /** + * Attempts to intercept power key down event by detecting certain gesture patterns + * + * @param interactive true if the event's policy contains {@code FLAG_INTERACTIVE} + * @param outLaunched true if some action is taken as part of the key intercept (eg, app launch) + * @return true if the key down event is intercepted + */ public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive, MutableBoolean outLaunched) { if (event.isLongPress()) { @@ -392,41 +409,60 @@ public class GestureLauncherService extends SystemService { // taps or consecutive taps, so we want to ignore the long press event. return false; } - boolean launched = false; + boolean launchCamera = false; + boolean launchPanic = false; boolean intercept = false; long powerTapInterval; synchronized (this) { powerTapInterval = event.getEventTime() - mLastPowerDown; - if (mCameraDoubleTapPowerEnabled - && powerTapInterval < CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS) { - launched = true; - intercept = interactive; - mPowerButtonConsecutiveTaps++; - } else if (powerTapInterval < POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS) { - mPowerButtonConsecutiveTaps++; - } else { + mLastPowerDown = event.getEventTime(); + if (powerTapInterval >= POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS) { + // Tap too slow, reset consecutive tap counts. + mPowerButtonConsecutiveTaps = 1; + mPowerButtonSlowConsecutiveTaps = 1; + } else if (powerTapInterval >= CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS) { + // Tap too slow for shortcuts mPowerButtonConsecutiveTaps = 1; + mPowerButtonSlowConsecutiveTaps++; + } else { + // Fast consecutive tap + mPowerButtonConsecutiveTaps++; + mPowerButtonSlowConsecutiveTaps++; + } + if (mPanicButtonGestureEnabled + && mPowerButtonConsecutiveTaps == PANIC_POWER_TAP_COUNT_THRESHOLD) { + launchPanic = true; + intercept = interactive; + } else if (mCameraDoubleTapPowerEnabled + && powerTapInterval < CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS + && mPowerButtonConsecutiveTaps == CAMERA_POWER_TAP_COUNT_THRESHOLD) { + launchCamera = true; + intercept = interactive; } - mLastPowerDown = event.getEventTime(); } - if (DBG && mPowerButtonConsecutiveTaps > 1) { - Slog.i(TAG, Long.valueOf(mPowerButtonConsecutiveTaps) + - " consecutive power button taps detected"); + if (mPowerButtonConsecutiveTaps > 1 || mPowerButtonSlowConsecutiveTaps > 1) { + Slog.i(TAG, Long.valueOf(mPowerButtonConsecutiveTaps) + + " consecutive power button taps detected, " + + Long.valueOf(mPowerButtonSlowConsecutiveTaps) + + " consecutive slow power button taps detected"); } - if (launched) { + if (launchCamera) { Slog.i(TAG, "Power button double tap gesture detected, launching camera. Interval=" + powerTapInterval + "ms"); - launched = handleCameraGesture(false /* useWakelock */, + launchCamera = handleCameraGesture(false /* useWakelock */, StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP); - if (launched) { + if (launchCamera) { mMetricsLogger.action(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE, (int) powerTapInterval); } + } else if (launchPanic) { + Slog.i(TAG, "Panic gesture detected, launching panic."); } - mMetricsLogger.histogram("power_consecutive_short_tap_count", mPowerButtonConsecutiveTaps); + mMetricsLogger.histogram("power_consecutive_short_tap_count", + mPowerButtonSlowConsecutiveTaps); mMetricsLogger.histogram("power_double_tap_interval", (int) powerTapInterval); - outLaunched.value = launched; - return intercept && launched; + outLaunched.value = launchCamera || launchPanic; + return intercept && (launchCamera || launchPanic); } /** diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 816d663e09de..1520dd351c97 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -3238,6 +3238,12 @@ class StorageManagerService extends IStorageManager.Stub @Override public void lockUserKey(int userId) { + // Do not lock user 0 data for headless system user + if (userId == UserHandle.USER_SYSTEM + && UserManager.isHeadlessSystemUserMode()) { + throw new IllegalArgumentException("Headless system user data cannot be locked.."); + } + enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); try { diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING index dd485fe3342f..1cb7c4d18326 100644 --- a/services/core/java/com/android/server/TEST_MAPPING +++ b/services/core/java/com/android/server/TEST_MAPPING @@ -25,21 +25,6 @@ { "name": "CtsScopedStorageHostTest", "file_patterns": ["StorageManagerService\\.java"] - }, - { - "name": "FrameworksMockingServicesTests", - "file_patterns": ["AppStateTracker\\.java"], - "options": [ - { - "include-filter": "com.android.server.AppStateTrackerTest" - }, - { - "include-annotation": "android.platform.test.annotations.Presubmit" - }, - { - "exclude-annotation": "androidx.test.filters.FlakyTest" - } - ] } ] } diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index 49676ded1d4e..1815dac4c3a8 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -23,7 +23,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.hidl.manager.V1_0.IServiceManager; import android.os.Binder; -import android.os.Build; import android.os.Debug; import android.os.Handler; import android.os.IPowerManager; @@ -32,10 +31,6 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; -import android.system.ErrnoException; -import android.system.Os; -import android.system.OsConstants; -import android.system.StructRlimit; import android.util.EventLog; import android.util.Log; import android.util.Slog; @@ -51,13 +46,8 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.StringWriter; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -143,7 +133,6 @@ public class Watchdog { private IActivityController mController; private boolean mAllowRestart = true; - private final OpenFdMonitor mOpenFdMonitor; private final List<Integer> mInterestingJavaPids = new ArrayList<>(); /** @@ -349,8 +338,6 @@ public class Watchdog { // Initialize monitor for Binder threads. addMonitor(new BinderThreadMonitor()); - mOpenFdMonitor = OpenFdMonitor.create(); - mInterestingJavaPids.add(Process.myPid()); // See the notes on DEFAULT_TIMEOUT. @@ -602,40 +589,30 @@ public class Watchdog { timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start); } - boolean fdLimitTriggered = false; - if (mOpenFdMonitor != null) { - fdLimitTriggered = mOpenFdMonitor.monitor(); - } - - if (!fdLimitTriggered) { - final int waitState = evaluateCheckerCompletionLocked(); - if (waitState == COMPLETED) { - // The monitors have returned; reset - waitedHalf = false; - continue; - } else if (waitState == WAITING) { - // still waiting but within their configured intervals; back off and recheck - continue; - } else if (waitState == WAITED_HALF) { - if (!waitedHalf) { - Slog.i(TAG, "WAITED_HALF"); - // We've waited half the deadlock-detection interval. Pull a stack - // trace and wait another half. - ArrayList<Integer> pids = new ArrayList<>(mInterestingJavaPids); - ActivityManagerService.dumpStackTraces(pids, null, null, - getInterestingNativePids(), null); - waitedHalf = true; - } - continue; + final int waitState = evaluateCheckerCompletionLocked(); + if (waitState == COMPLETED) { + // The monitors have returned; reset + waitedHalf = false; + continue; + } else if (waitState == WAITING) { + // still waiting but within their configured intervals; back off and recheck + continue; + } else if (waitState == WAITED_HALF) { + if (!waitedHalf) { + Slog.i(TAG, "WAITED_HALF"); + // We've waited half the deadlock-detection interval. Pull a stack + // trace and wait another half. + ArrayList<Integer> pids = new ArrayList<>(mInterestingJavaPids); + ActivityManagerService.dumpStackTraces(pids, null, null, + getInterestingNativePids(), null); + waitedHalf = true; } - - // something is overdue! - blockedCheckers = getBlockedCheckersLocked(); - subject = describeCheckersLocked(blockedCheckers); - } else { - blockedCheckers = Collections.emptyList(); - subject = "Open FD high water mark reached"; + continue; } + + // something is overdue! + blockedCheckers = getBlockedCheckersLocked(); + subject = describeCheckersLocked(blockedCheckers); allowRestart = mAllowRestart; } @@ -738,94 +715,4 @@ public class Watchdog { Slog.w(TAG, "Failed to write to /proc/sysrq-trigger", e); } } - - public static final class OpenFdMonitor { - /** - * Number of FDs below the soft limit that we trigger a runtime restart at. This was - * chosen arbitrarily, but will need to be at least 6 in order to have a sufficient number - * of FDs in reserve to complete a dump. - */ - private static final int FD_HIGH_WATER_MARK = 12; - - private final File mDumpDir; - private final File mFdHighWaterMark; - - public static OpenFdMonitor create() { - // Only run the FD monitor on debuggable builds (such as userdebug and eng builds). - if (!Build.IS_DEBUGGABLE) { - return null; - } - - final StructRlimit rlimit; - try { - rlimit = android.system.Os.getrlimit(OsConstants.RLIMIT_NOFILE); - } catch (ErrnoException errno) { - Slog.w(TAG, "Error thrown from getrlimit(RLIMIT_NOFILE)", errno); - return null; - } - - // The assumption we're making here is that FD numbers are allocated (more or less) - // sequentially, which is currently (and historically) true since open is currently - // specified to always return the lowest-numbered non-open file descriptor for the - // current process. - // - // We do this to avoid having to enumerate the contents of /proc/self/fd in order to - // count the number of descriptors open in the process. - final File fdThreshold = new File("/proc/self/fd/" + (rlimit.rlim_cur - FD_HIGH_WATER_MARK)); - return new OpenFdMonitor(new File("/data/anr"), fdThreshold); - } - - OpenFdMonitor(File dumpDir, File fdThreshold) { - mDumpDir = dumpDir; - mFdHighWaterMark = fdThreshold; - } - - /** - * Dumps open file descriptors and their full paths to a temporary file in {@code mDumpDir}. - */ - private void dumpOpenDescriptors() { - // We cannot exec lsof to get more info about open file descriptors because a newly - // forked process will not have the permissions to readlink. Instead list all open - // descriptors from /proc/pid/fd and resolve them. - List<String> dumpInfo = new ArrayList<>(); - String fdDirPath = String.format("/proc/%d/fd/", Process.myPid()); - File[] fds = new File(fdDirPath).listFiles(); - if (fds == null) { - dumpInfo.add("Unable to list " + fdDirPath); - } else { - for (File f : fds) { - String fdSymLink = f.getAbsolutePath(); - String resolvedPath = ""; - try { - resolvedPath = Os.readlink(fdSymLink); - } catch (ErrnoException ex) { - resolvedPath = ex.getMessage(); - } - dumpInfo.add(fdSymLink + "\t" + resolvedPath); - } - } - - // Dump the fds & paths to a temp file. - try { - File dumpFile = File.createTempFile("anr_fd_", "", mDumpDir); - Path out = Paths.get(dumpFile.getAbsolutePath()); - Files.write(out, dumpInfo, StandardCharsets.UTF_8); - } catch (IOException ex) { - Slog.w(TAG, "Unable to write open descriptors to file: " + ex); - } - } - - /** - * @return {@code true} if the high water mark was breached and a dump was written, - * {@code false} otherwise. - */ - public boolean monitor() { - if (mFdHighWaterMark.exists()) { - dumpOpenDescriptors(); - return true; - } - - return false; - } - } } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 3f867f656c24..bd51c7a1773d 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -215,7 +215,7 @@ public final class ActiveServices { * Watch for apps being put into forced app standby, so we can step their fg * services down. */ - class ForcedStandbyListener extends AppStateTracker.Listener { + class ForcedStandbyListener implements AppStateTracker.ServiceStateListener { @Override public void stopForegroundServicesForUidPackage(final int uid, final String packageName) { synchronized (mAm) { @@ -403,7 +403,7 @@ public final class ActiveServices { void systemServicesReady() { AppStateTracker ast = LocalServices.getService(AppStateTracker.class); - ast.addListener(new ForcedStandbyListener()); + ast.addServiceStateListener(new ForcedStandbyListener()); mAppWidgetManagerInternal = LocalServices.getService(AppWidgetManagerInternal.class); setWhiteListAllowWhileInUsePermissionInFgs(); } @@ -690,7 +690,7 @@ public final class ActiveServices { } if (allowBackgroundActivityStarts) { - r.whitelistBgActivityStartsOnServiceStart(); + r.allowBgActivityStartsOnServiceStart(); } ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting); @@ -2045,7 +2045,7 @@ public final class ActiveServices { s.whitelistManager = true; } if ((flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) { - s.setHasBindingWhitelistingBgActivityStarts(true); + s.setAllowedBgActivityStartsByBinding(true); } if (s.app != null) { updateServiceClientActivitiesLocked(s.app, c, true); @@ -3457,9 +3457,9 @@ public final class ActiveServices { updateWhitelistManagerLocked(s.app); } } - // And do the same for bg activity starts whitelisting. + // And do the same for bg activity starts ability. if ((c.flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) { - s.updateHasBindingWhitelistingBgActivityStarts(); + s.updateIsAllowedBgActivityStartsByBinding(); } if (s.app != null) { updateServiceClientActivitiesLocked(s.app, c, true); diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index 09ed16ef793b..775119c18037 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -253,7 +253,8 @@ final class ActivityManagerConstants extends ContentObserver { // allowing the next pending start to run. public long BG_START_TIMEOUT = DEFAULT_BG_START_TIMEOUT; - // For how long after a whitelisted service's start its process can start a background activity + // For a service that has been allowed to start background activities, how long after it started + // its process can start a background activity. public long SERVICE_BG_ACTIVITY_START_TIMEOUT = DEFAULT_SERVICE_BG_ACTIVITY_START_TIMEOUT; // Initial backoff delay for retrying bound foreground services diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index fa18ccb53408..2b6da4cfc62c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -4900,7 +4900,13 @@ public class ActivityManagerService extends IActivityManager.Stub mAppErrors.resetProcessCrashTimeLocked(packageName == null, appId, userId); } - boolean didSomething = mProcessList.killPackageProcessesLocked(packageName, appId, userId, + // Notify first that the package is stopped, so its process won't be restarted unexpectedly + // if there is an activity of the package without attached process becomes visible when + // killing its other processes with visible activities. + boolean didSomething = + mAtmInternal.onForceStopPackage(packageName, doit, evenPersistent, userId); + + didSomething |= mProcessList.killPackageProcessesLocked(packageName, appId, userId, ProcessList.INVALID_ADJ, callerWillRestart, false /* allowRestart */, doit, evenPersistent, true /* setRemoved */, packageName == null ? ApplicationExitInfo.REASON_USER_STOPPED @@ -4909,9 +4915,6 @@ public class ActivityManagerService extends IActivityManager.Stub (packageName == null ? ("stop user " + userId) : ("stop " + packageName)) + " due to " + reason); - didSomething |= - mAtmInternal.onForceStopPackage(packageName, doit, evenPersistent, userId); - if (mServices.bringDownDisabledPackageServicesLocked( packageName, null /* filterByClasses */, userId, evenPersistent, doit)) { if (!doit) { @@ -20515,4 +20518,17 @@ public class ActivityManagerService extends IActivityManager.Stub Binder.restoreCallingIdentity(token); } } + + /** + * Resets the state of the {@link com.android.server.am.AppErrors} instance. + * This is intended for testing within the CTS only and is protected by + * android.permission.RESET_APP_ERRORS. + */ + @Override + public void resetAppErrors() { + enforceCallingPermission(Manifest.permission.RESET_APP_ERRORS, "resetAppErrors"); + synchronized (this) { + mAppErrors.resetStateLocked(); + } + } } diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index a36a18b4cf5c..2e92ac0fb3d6 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -107,6 +107,16 @@ class AppErrors { mPackageWatchdog = watchdog; } + /** Resets the current state but leaves the constructor-provided fields unchanged. */ + public void resetStateLocked() { + Slog.i(TAG, "Resetting AppErrors"); + mAppsNotReportingCrashes.clear(); + mProcessCrashTimes.clear(); + mProcessCrashTimesPersistent.clear(); + mProcessCrashShowDialogTimes.clear(); + mBadProcesses.clear(); + } + void dumpDebug(ProtoOutputStream proto, long fieldId, String dumpPackage) { if (mProcessCrashTimes.getMap().isEmpty() && mBadProcesses.getMap().isEmpty()) { return; diff --git a/services/core/java/com/android/server/am/BroadcastConstants.java b/services/core/java/com/android/server/am/BroadcastConstants.java index be17b1bc600c..494f06ebc324 100644 --- a/services/core/java/com/android/server/am/BroadcastConstants.java +++ b/services/core/java/com/android/server/am/BroadcastConstants.java @@ -62,7 +62,8 @@ public class BroadcastConstants { public float DEFERRAL_DECAY_FACTOR = DEFAULT_DEFERRAL_DECAY_FACTOR; // Minimum that the deferral time can decay to until the backlog fully clears public long DEFERRAL_FLOOR = DEFAULT_DEFERRAL_FLOOR; - // For how long after a whitelisted receiver's start its process can start a background activity + // For a receiver that has been allowed to start background activities, how long after it + // started its process can start a background activity. public long ALLOW_BG_ACTIVITY_START_TIMEOUT = DEFAULT_ALLOW_BG_ACTIVITY_START_TIMEOUT; // Settings override tracking for this instance diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java index 8ef67f97e8d4..40743b8be1ea 100644 --- a/services/core/java/com/android/server/am/BroadcastRecord.java +++ b/services/core/java/com/android/server/am/BroadcastRecord.java @@ -89,8 +89,8 @@ final class BroadcastRecord extends Binder { int manifestSkipCount; // number of manifest receivers skipped. BroadcastQueue queue; // the outbound queue handling this broadcast - // if set to true, app's process will be temporarily whitelisted to start activities - // from background for the duration of the broadcast dispatch + // if set to true, app's process will be temporarily allowed to start activities from background + // for the duration of the broadcast dispatch final boolean allowBackgroundActivityStarts; static final int IDLE = 0; diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index c5152c081e70..42e3061a840e 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -274,7 +274,7 @@ class ProcessRecord implements WindowProcessListener { final ArrayMap<String, ContentProviderRecord> pubProviders = new ArrayMap<>(); // All ContentProviderRecord process is using final ArrayList<ContentProviderConnection> conProviders = new ArrayList<>(); - // A set of tokens that currently contribute to this process being temporarily whitelisted + // A set of tokens that currently contribute to this process being temporarily allowed // to start activities even if it's not in the foreground final ArraySet<Binder> mAllowBackgroundActivityStartsTokens = new ArraySet<>(); // a set of UIDs of all bound clients @@ -626,7 +626,7 @@ class ProcessRecord implements WindowProcessListener { } } if (mAllowBackgroundActivityStartsTokens.size() > 0) { - pw.print(prefix); pw.println("Background activity start whitelist tokens:"); + pw.print(prefix); pw.println("Background activity start tokens:"); for (int i = 0; i < mAllowBackgroundActivityStartsTokens.size(); i++) { pw.print(prefix); pw.print(" - "); pw.println(mAllowBackgroundActivityStartsTokens.valueAt(i)); diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index 828ac71eccfe..db05d65b92fe 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -131,13 +131,13 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN int pendingConnectionImportance; // To be filled in to ProcessRecord once it connects // any current binding to this service has BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS flag? - private boolean mHasBindingWhitelistingBgActivityStarts; - // is this service currently whitelisted to start activities from background by providing + private boolean mIsAllowedBgActivityStartsByBinding; + // is this service currently allowed to start activities from background by providing // allowBackgroundActivityStarts=true to startServiceLocked()? - private boolean mHasStartedWhitelistingBgActivityStarts; - // used to clean up the state of hasStartedWhitelistingBgActivityStarts after a timeout - private Runnable mStartedWhitelistingBgActivityStartsCleanUp; - private ProcessRecord mAppForStartedWhitelistingBgActivityStarts; + private boolean mIsAllowedBgActivityStartsByStart; + // used to clean up the state of mIsAllowedBgActivityStartsByStart after a timeout + private Runnable mCleanUpAllowBgActivityStartsByStartCallback; + private ProcessRecord mAppForAllowingBgActivityStartsByStart; // allow while-in-use permissions in foreground service or not. // while-in-use permissions in FGS started from background might be restricted. @@ -396,13 +396,13 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN if (whitelistManager) { pw.print(prefix); pw.print("whitelistManager="); pw.println(whitelistManager); } - if (mHasBindingWhitelistingBgActivityStarts) { - pw.print(prefix); pw.print("hasBindingWhitelistingBgActivityStarts="); - pw.println(mHasBindingWhitelistingBgActivityStarts); + if (mIsAllowedBgActivityStartsByBinding) { + pw.print(prefix); pw.print("mIsAllowedBgActivityStartsByBinding="); + pw.println(mIsAllowedBgActivityStartsByBinding); } - if (mHasStartedWhitelistingBgActivityStarts) { - pw.print(prefix); pw.print("hasStartedWhitelistingBgActivityStarts="); - pw.println(mHasStartedWhitelistingBgActivityStarts); + if (mIsAllowedBgActivityStartsByStart) { + pw.print(prefix); pw.print("mIsAllowedBgActivityStartsByStart="); + pw.println(mIsAllowedBgActivityStartsByStart); } pw.print(prefix); pw.print("allowWhileInUsePermissionInFgs="); pw.println(mAllowWhileInUsePermissionInFgs); @@ -560,31 +560,31 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN public void setProcess(ProcessRecord _proc) { if (_proc != null) { - // We're starting a new process for this service, but a previous one is whitelisted. - // Remove that whitelisting now (unless the new process is the same as the previous one, - // which is a common case). - if (mAppForStartedWhitelistingBgActivityStarts != null) { - if (mAppForStartedWhitelistingBgActivityStarts != _proc) { - mAppForStartedWhitelistingBgActivityStarts + // We're starting a new process for this service, but a previous one is allowed to start + // background activities. Remove that ability now (unless the new process is the same as + // the previous one, which is a common case). + if (mAppForAllowingBgActivityStartsByStart != null) { + if (mAppForAllowingBgActivityStartsByStart != _proc) { + mAppForAllowingBgActivityStartsByStart .removeAllowBackgroundActivityStartsToken(this); - ams.mHandler.removeCallbacks(mStartedWhitelistingBgActivityStartsCleanUp); + ams.mHandler.removeCallbacks(mCleanUpAllowBgActivityStartsByStartCallback); } } // Make sure the cleanup callback knows about the new process. - mAppForStartedWhitelistingBgActivityStarts = mHasStartedWhitelistingBgActivityStarts + mAppForAllowingBgActivityStartsByStart = mIsAllowedBgActivityStartsByStart ? _proc : null; - if (mHasStartedWhitelistingBgActivityStarts - || mHasBindingWhitelistingBgActivityStarts) { + if (mIsAllowedBgActivityStartsByStart + || mIsAllowedBgActivityStartsByBinding) { _proc.addAllowBackgroundActivityStartsToken(this); } else { _proc.removeAllowBackgroundActivityStartsToken(this); } } if (app != null && app != _proc) { - // If the old app is whitelisted because of a service start, leave it whitelisted until - // the cleanup callback runs. Otherwise we can remove it from the whitelist immediately - // (it can't be bound now). - if (!mHasStartedWhitelistingBgActivityStarts) { + // If the old app is allowed to start bg activities because of a service start, leave it + // that way until the cleanup callback runs. Otherwise we can remove its bg activity + // start ability immediately (it can't be bound now). + if (!mIsAllowedBgActivityStartsByStart) { app.removeAllowBackgroundActivityStartsToken(this); } app.updateBoundClientUids(); @@ -648,89 +648,88 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN return startRequested && (stopIfKilled || isStartCanceled) && pendingStarts.isEmpty(); } - void updateHasBindingWhitelistingBgActivityStarts() { - boolean hasWhitelistingBinding = false; + void updateIsAllowedBgActivityStartsByBinding() { + boolean isAllowedByBinding = false; for (int conni = connections.size() - 1; conni >= 0; conni--) { ArrayList<ConnectionRecord> cr = connections.valueAt(conni); for (int i = 0; i < cr.size(); i++) { if ((cr.get(i).flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) { - hasWhitelistingBinding = true; + isAllowedByBinding = true; break; } } - if (hasWhitelistingBinding) { + if (isAllowedByBinding) { break; } } - setHasBindingWhitelistingBgActivityStarts(hasWhitelistingBinding); + setAllowedBgActivityStartsByBinding(isAllowedByBinding); } - void setHasBindingWhitelistingBgActivityStarts(boolean newValue) { - if (mHasBindingWhitelistingBgActivityStarts != newValue) { - mHasBindingWhitelistingBgActivityStarts = newValue; - updateParentProcessBgActivityStartsWhitelistingToken(); + void setAllowedBgActivityStartsByBinding(boolean newValue) { + if (mIsAllowedBgActivityStartsByBinding != newValue) { + mIsAllowedBgActivityStartsByBinding = newValue; + updateParentProcessBgActivityStartsToken(); } } /** - * Called when the service is started with allowBackgroundActivityStarts set. We whitelist - * it for background activity starts, setting up a callback to remove the whitelisting after a - * timeout. Note that the whitelisting persists for the process even if the service is - * subsequently stopped. + * Called when the service is started with allowBackgroundActivityStarts set. We allow + * it for background activity starts, setting up a callback to remove this ability after a + * timeout. Note that the ability for starting background activities persists for the process + * even if the service is subsequently stopped. */ - void whitelistBgActivityStartsOnServiceStart() { - setHasStartedWhitelistingBgActivityStarts(true); + void allowBgActivityStartsOnServiceStart() { + setAllowedBgActivityStartsByStart(true); if (app != null) { - mAppForStartedWhitelistingBgActivityStarts = app; + mAppForAllowingBgActivityStartsByStart = app; } // This callback is stateless, so we create it once when we first need it. - if (mStartedWhitelistingBgActivityStartsCleanUp == null) { - mStartedWhitelistingBgActivityStartsCleanUp = () -> { + if (mCleanUpAllowBgActivityStartsByStartCallback == null) { + mCleanUpAllowBgActivityStartsByStartCallback = () -> { synchronized (ams) { - if (app == mAppForStartedWhitelistingBgActivityStarts) { - // The process we whitelisted is still running the service. We remove - // the started whitelisting, but it may still be whitelisted via bound - // connections. - setHasStartedWhitelistingBgActivityStarts(false); - } else if (mAppForStartedWhitelistingBgActivityStarts != null) { - // The process we whitelisted is not running the service. It therefore - // can't be bound so we can unconditionally remove the whitelist. - mAppForStartedWhitelistingBgActivityStarts + if (app == mAppForAllowingBgActivityStartsByStart) { + // The process we allowed is still running the service. We remove + // the ability by start, but it may still be allowed via bound connections. + setAllowedBgActivityStartsByStart(false); + } else if (mAppForAllowingBgActivityStartsByStart != null) { + // The process we allowed is not running the service. It therefore can't be + // bound so we can unconditionally remove the ability. + mAppForAllowingBgActivityStartsByStart .removeAllowBackgroundActivityStartsToken(ServiceRecord.this); } - mAppForStartedWhitelistingBgActivityStarts = null; + mAppForAllowingBgActivityStartsByStart = null; } }; } // if there's a request pending from the past, drop it before scheduling a new one - ams.mHandler.removeCallbacks(mStartedWhitelistingBgActivityStartsCleanUp); - ams.mHandler.postDelayed(mStartedWhitelistingBgActivityStartsCleanUp, + ams.mHandler.removeCallbacks(mCleanUpAllowBgActivityStartsByStartCallback); + ams.mHandler.postDelayed(mCleanUpAllowBgActivityStartsByStartCallback, ams.mConstants.SERVICE_BG_ACTIVITY_START_TIMEOUT); } - private void setHasStartedWhitelistingBgActivityStarts(boolean newValue) { - if (mHasStartedWhitelistingBgActivityStarts != newValue) { - mHasStartedWhitelistingBgActivityStarts = newValue; - updateParentProcessBgActivityStartsWhitelistingToken(); + private void setAllowedBgActivityStartsByStart(boolean newValue) { + if (mIsAllowedBgActivityStartsByStart != newValue) { + mIsAllowedBgActivityStartsByStart = newValue; + updateParentProcessBgActivityStartsToken(); } } /** - * Whether the process this service runs in should be temporarily whitelisted to start + * Whether the process this service runs in should be temporarily allowed to start * activities from background depends on the current state of both - * {@code hasStartedWhitelistingBgActivityStarts} and - * {@code hasBindingWhitelistingBgActivityStarts}. If either is true, this ServiceRecord + * {@code mIsAllowedBgActivityStartsByStart} and + * {@code mIsAllowedBgActivityStartsByBinding}. If either is true, this ServiceRecord * should be contributing as a token in parent ProcessRecord. * * @see com.android.server.am.ProcessRecord#mAllowBackgroundActivityStartsTokens */ - private void updateParentProcessBgActivityStartsWhitelistingToken() { + private void updateParentProcessBgActivityStartsToken() { if (app == null) { return; } - if (mHasStartedWhitelistingBgActivityStarts || mHasBindingWhitelistingBgActivityStarts) { + if (mIsAllowedBgActivityStartsByStart || mIsAllowedBgActivityStartsByBinding) { // if the token is already there it's safe to "re-add it" - we're dealing with // a set of Binder objects app.addAllowBackgroundActivityStartsToken(this); diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index b3231909e4b7..e6480fc6cde8 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -2059,6 +2059,8 @@ public class AppOpsService extends IAppOpsService.Stub { public void getHistoricalOps(int uid, String packageName, String attributionTag, List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis, int flags, RemoteCallback callback) { + PackageManager pm = mContext.getPackageManager(); + ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter, beginTimeMillis, endTimeMillis, flags); Objects.requireNonNull(callback, "callback cannot be null"); @@ -2066,8 +2068,16 @@ public class AppOpsService extends IAppOpsService.Stub { ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class); boolean isCallerInstrumented = ami.isUidCurrentlyInstrumented(Binder.getCallingUid()); boolean isCallerSystem = Binder.getCallingPid() == Process.myPid(); + boolean isCallerPermissionController; + try { + isCallerPermissionController = pm.getPackageUid( + mContext.getPackageManager().getPermissionControllerPackageName(), 0) + == Binder.getCallingUid(); + } catch (PackageManager.NameNotFoundException doesNotHappen) { + return; + } - if (!isCallerSystem && !isCallerInstrumented) { + if (!isCallerSystem && !isCallerInstrumented && !isCallerPermissionController) { mHandler.post(() -> callback.sendResult(new Bundle())); return; } @@ -6020,7 +6030,7 @@ public class AppOpsService extends IAppOpsService.Stub { private void resampleAppOpForPackageLocked(@NonNull String packageName, boolean pickOp) { mMessagesCollectedCount = 0.0f; mSampledAppOpCode = pickOp ? ThreadLocalRandom.current().nextInt(_NUM_OP) : OP_NONE; - mAcceptableLeftDistance = _NUM_OP; + mAcceptableLeftDistance = _NUM_OP - 1; mSampledPackage = packageName; } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java index 6afe61e07465..e4387c9e2b81 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java @@ -135,19 +135,27 @@ public class FingerprintService extends SystemService { return; } - if (Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId) - && Utils.isKeyguard(getContext(), opPackageName)) { - // If this happens, something in KeyguardUpdateMonitor is wrong. - // SafetyNet for b/79776455 - EventLog.writeEvent(0x534e4554, "79776455"); - Slog.e(TAG, "Authenticate invoked when user is encrypted or lockdown"); - return; + // Keyguard check must be done on the caller's binder identity, since it also checks + // permission. + final boolean isKeyguard = Utils.isKeyguard(getContext(), opPackageName); + + // Clear calling identity when checking LockPatternUtils for StrongAuth flags. + final long identity = Binder.clearCallingIdentity(); + try { + if (isKeyguard && Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) { + // If this happens, something in KeyguardUpdateMonitor is wrong. + // SafetyNet for b/79776455 + EventLog.writeEvent(0x534e4554, "79776455"); + Slog.e(TAG, "Authenticate invoked when user is encrypted or lockdown"); + return; + } + } finally { + Binder.restoreCallingIdentity(identity); } final boolean restricted = getContext().checkCallingPermission(MANAGE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED; - final int statsClient = Utils.isKeyguard(getContext(), opPackageName) - ? BiometricsProtoEnums.CLIENT_KEYGUARD + final int statsClient = isKeyguard ? BiometricsProtoEnums.CLIENT_KEYGUARD : BiometricsProtoEnums.CLIENT_FINGERPRINT_MANAGER; mFingerprint21.scheduleAuthenticate(token, operationId, userId, 0 /* cookie */, new ClientMonitorCallbackConverter(receiver), opPackageName, surface, diff --git a/services/core/java/com/android/server/content/SyncAdapterStateFetcher.java b/services/core/java/com/android/server/content/SyncAdapterStateFetcher.java index 62fb75107755..ffaf364934f6 100644 --- a/services/core/java/com/android/server/content/SyncAdapterStateFetcher.java +++ b/services/core/java/com/android/server/content/SyncAdapterStateFetcher.java @@ -15,11 +15,11 @@ */ package com.android.server.content; +import android.app.ActivityManagerInternal; import android.app.usage.UsageStatsManagerInternal; import android.os.SystemClock; import android.util.Pair; -import com.android.server.AppStateTracker; import com.android.server.LocalServices; import java.util.HashMap; @@ -57,12 +57,7 @@ class SyncAdapterStateFetcher { * Return UID active state. */ public boolean isAppActive(int uid) { - final AppStateTracker ast = - LocalServices.getService(AppStateTracker.class); - if (ast == null) { - return false; - } - - return ast.isUidActive(uid); + final ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class); + return (ami != null) ? ami.isUidActive(uid) : false; } } diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index 5ff40d0e14ee..48fa1bf9f246 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -134,7 +134,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { hdrCapabilities, isDefaultDisplay); mDevices.put(physicalDisplayId, device); sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED); - } else if (device.updateDisplayPropertiesLocked(configs, activeConfig, + } else if (device.updateDisplayPropertiesLocked(info, configs, activeConfig, configSpecs, colorModes, activeColorMode, hdrCapabilities)) { sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED); } @@ -212,8 +212,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + physicalDisplayId); mPhysicalDisplayId = physicalDisplayId; mIsDefaultDisplay = isDefaultDisplay; - mDisplayInfo = info; - updateDisplayPropertiesLocked(configs, activeConfigId, configSpecs, colorModes, + updateDisplayPropertiesLocked(info, configs, activeConfigId, configSpecs, colorModes, activeColorMode, hdrCapabilities); mSidekickInternal = LocalServices.getService(SidekickInternal.class); if (mIsDefaultDisplay) { @@ -238,12 +237,15 @@ final class LocalDisplayAdapter extends DisplayAdapter { /** * Returns true if there is a change. **/ - public boolean updateDisplayPropertiesLocked(SurfaceControl.DisplayConfig[] configs, + public boolean updateDisplayPropertiesLocked(SurfaceControl.DisplayInfo info, + SurfaceControl.DisplayConfig[] configs, int activeConfigId, SurfaceControl.DesiredDisplayConfigSpecs configSpecs, int[] colorModes, int activeColorMode, Display.HdrCapabilities hdrCapabilities) { boolean changed = updateDisplayConfigsLocked(configs, activeConfigId, configSpecs); + changed |= updateDisplayInfo(info); changed |= updateColorModesLocked(colorModes, activeColorMode); changed |= updateHdrCapabilitiesLocked(hdrCapabilities); + if (changed) { mHavePendingChanges = true; } @@ -420,6 +422,14 @@ final class LocalDisplayAdapter extends DisplayAdapter { mSystemBrightnessToNits = sysToNits; } + private boolean updateDisplayInfo(SurfaceControl.DisplayInfo info) { + if (Objects.equals(mDisplayInfo, info)) { + return false; + } + mDisplayInfo = info; + return true; + } + private boolean updateColorModesLocked(int[] colorModes, int activeColorMode) { if (colorModes == null) { return false; diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 2c0ddaf35182..804cc92cca08 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -1667,6 +1667,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { if (avr == null) { return; } + setArcStatus(false); // Seq #44. removeAction(RequestArcInitiationAction.class); diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index d9b25baf2482..74ed815f080a 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -236,7 +236,7 @@ public class InputManagerService extends IInputManager.Stub private static native void nativeSetInteractive(long ptr, boolean interactive); private static native void nativeReloadCalibration(long ptr); private static native void nativeVibrate(long ptr, int deviceId, long[] pattern, - int repeat, int token); + int[] amplitudes, int repeat, int token); private static native void nativeCancelVibrate(long ptr, int deviceId, int token); private static native void nativeReloadKeyboardLayouts(long ptr); private static native void nativeReloadDeviceAliases(long ptr); @@ -1716,7 +1716,7 @@ public class InputManagerService extends IInputManager.Stub // Binder call @Override - public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) { + public void vibrate(int deviceId, long[] pattern, int[] amplitudes, int repeat, IBinder token) { if (repeat >= pattern.length) { throw new ArrayIndexOutOfBoundsException(); } @@ -1738,7 +1738,7 @@ public class InputManagerService extends IInputManager.Stub synchronized (v) { v.mVibrating = true; - nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue); + nativeVibrate(mPtr, deviceId, pattern, amplitudes, repeat, v.mTokenValue); } } diff --git a/services/core/java/com/android/server/location/ConcurrentLinkedEvictingDeque.java b/services/core/java/com/android/server/location/ConcurrentLinkedEvictingDeque.java new file mode 100644 index 000000000000..6910c353e546 --- /dev/null +++ b/services/core/java/com/android/server/location/ConcurrentLinkedEvictingDeque.java @@ -0,0 +1,43 @@ +/* + * 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.location; + +import java.util.concurrent.ConcurrentLinkedDeque; + +/** + * Helper class to make a ConcurrentLinkedDeque fixed-size, evicting old entries when full. + * + * @param <E> The type of elements held in this queue. + */ +public class ConcurrentLinkedEvictingDeque<E> extends ConcurrentLinkedDeque<E> { + private int mSize; + + ConcurrentLinkedEvictingDeque(int size) { + mSize = size; + } + + @Override + public boolean add(E elem) { + synchronized (this) { + if (size() == mSize) { + poll(); + } + + return super.add(elem); + } + } +} diff --git a/services/core/java/com/android/server/location/ContextHubClientManager.java b/services/core/java/com/android/server/location/ContextHubClientManager.java index 0f70bb8bc840..33ceeeff331f 100644 --- a/services/core/java/com/android/server/location/ContextHubClientManager.java +++ b/services/core/java/com/android/server/location/ContextHubClientManager.java @@ -36,7 +36,6 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedDeque; import java.util.function.Consumer; /** @@ -104,28 +103,6 @@ import java.util.function.Consumer; public static final int ACTION_CANCELLED = 2; /** - * Helper class to make a ConcurrentLinkedDeque fixed-size, evicting old entries when full. - */ - private class ConcurrentLinkedEvictingDeque<E> extends ConcurrentLinkedDeque<E> { - private int mSize; - - ConcurrentLinkedEvictingDeque(int size) { - mSize = size; - } - - @Override - public boolean add(E elem) { - synchronized (this) { - if (size() == mSize) { - poll(); - } - - return super.add(elem); - } - } - } - - /** * A container class to store a record of ContextHubClient registration. */ private class RegistrationRecord { diff --git a/services/core/java/com/android/server/location/ContextHubService.java b/services/core/java/com/android/server/location/ContextHubService.java index 48b22704fd07..264c611d45fe 100644 --- a/services/core/java/com/android/server/location/ContextHubService.java +++ b/services/core/java/com/android/server/location/ContextHubService.java @@ -43,6 +43,7 @@ import android.hardware.location.NanoAppInstanceInfo; import android.hardware.location.NanoAppMessage; import android.hardware.location.NanoAppState; import android.location.LocationManager; +import android.os.Binder; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.UserHandle; @@ -386,7 +387,7 @@ public class ContextHubService extends IContextHubService.Stub { createLoadTransactionCallback(contextHubHandle, nanoAppBinary); ContextHubServiceTransaction transaction = mTransactionManager.createLoadTransaction( - contextHubHandle, nanoAppBinary, onCompleteCallback); + contextHubHandle, nanoAppBinary, onCompleteCallback, getCallingPackageName()); mTransactionManager.addTransaction(transaction); return 0; @@ -411,7 +412,7 @@ public class ContextHubService extends IContextHubService.Stub { IContextHubTransactionCallback onCompleteCallback = createUnloadTransactionCallback(contextHubId); ContextHubServiceTransaction transaction = mTransactionManager.createUnloadTransaction( - contextHubId, nanoAppId, onCompleteCallback); + contextHubId, nanoAppId, onCompleteCallback, getCallingPackageName()); mTransactionManager.addTransaction(transaction); return 0; @@ -464,7 +465,7 @@ public class ContextHubService extends IContextHubService.Stub { IContextHubTransactionCallback onCompleteCallback = createQueryTransactionCallback(contextHubId); ContextHubServiceTransaction transaction = mTransactionManager.createQueryTransaction( - contextHubId, onCompleteCallback); + contextHubId, onCompleteCallback, getCallingPackageName()); mTransactionManager.addTransaction(transaction); return Result.OK; @@ -696,7 +697,7 @@ public class ContextHubService extends IContextHubService.Stub { } ContextHubServiceTransaction transaction = mTransactionManager.createLoadTransaction( - contextHubId, nanoAppBinary, transactionCallback); + contextHubId, nanoAppBinary, transactionCallback, getCallingPackageName()); mTransactionManager.addTransaction(transaction); } @@ -720,7 +721,7 @@ public class ContextHubService extends IContextHubService.Stub { } ContextHubServiceTransaction transaction = mTransactionManager.createUnloadTransaction( - contextHubId, nanoAppId, transactionCallback); + contextHubId, nanoAppId, transactionCallback, getCallingPackageName()); mTransactionManager.addTransaction(transaction); } @@ -744,7 +745,7 @@ public class ContextHubService extends IContextHubService.Stub { } ContextHubServiceTransaction transaction = mTransactionManager.createEnableTransaction( - contextHubId, nanoAppId, transactionCallback); + contextHubId, nanoAppId, transactionCallback, getCallingPackageName()); mTransactionManager.addTransaction(transaction); } @@ -768,7 +769,7 @@ public class ContextHubService extends IContextHubService.Stub { } ContextHubServiceTransaction transaction = mTransactionManager.createDisableTransaction( - contextHubId, nanoAppId, transactionCallback); + contextHubId, nanoAppId, transactionCallback, getCallingPackageName()); mTransactionManager.addTransaction(transaction); } @@ -790,7 +791,7 @@ public class ContextHubService extends IContextHubService.Stub { } ContextHubServiceTransaction transaction = mTransactionManager.createQueryTransaction( - contextHubId, transactionCallback); + contextHubId, transactionCallback, getCallingPackageName()); mTransactionManager.addTransaction(transaction); } @@ -822,6 +823,10 @@ public class ContextHubService extends IContextHubService.Stub { pw.println("=================== CLIENTS ===================="); pw.println(mClientManager); + pw.println(""); + pw.println("=================== TRANSACTIONS ===================="); + pw.println(mTransactionManager); + // dump eventLog } @@ -924,4 +929,8 @@ public class ContextHubService extends IContextHubService.Stub { mContextHubWrapper.onSettingChanged(Setting.LOCATION, enabled ? SettingValue.ENABLED : SettingValue.DISABLED); } + + private String getCallingPackageName() { + return mContext.getPackageManager().getNameForUid(Binder.getCallingUid()); + } } diff --git a/services/core/java/com/android/server/location/ContextHubServiceTransaction.java b/services/core/java/com/android/server/location/ContextHubServiceTransaction.java index c1fc98248e08..62bd91bda1b8 100644 --- a/services/core/java/com/android/server/location/ContextHubServiceTransaction.java +++ b/services/core/java/com/android/server/location/ContextHubServiceTransaction.java @@ -32,14 +32,32 @@ import java.util.concurrent.TimeUnit; @ContextHubTransaction.Type private final int mTransactionType; + /* The ID of the nanoapp this transaction is targeted for, null if not applicable. */ + private final Long mNanoAppId; + + /* + * The host package associated with this transaction. + */ + private final String mPackage; + /* * true if the transaction has already completed, false otherwise */ private boolean mIsComplete = false; - /* package */ ContextHubServiceTransaction(int id, int type) { + /* package */ ContextHubServiceTransaction(int id, int type, String packageName) { + mTransactionId = id; + mTransactionType = type; + mNanoAppId = null; + mPackage = packageName; + } + + /* package */ ContextHubServiceTransaction(int id, int type, long nanoAppId, + String packageName) { mTransactionId = id; mTransactionType = type; + mNanoAppId = nanoAppId; + mPackage = packageName; } /** @@ -129,7 +147,13 @@ import java.util.concurrent.TimeUnit; @Override public String toString() { - return ContextHubTransaction.typeToString(mTransactionType, true /* upperCase */) - + " transaction (ID = " + mTransactionId + ")"; + String out = ContextHubTransaction.typeToString(mTransactionType, true /* upperCase */) + + " ("; + if (mNanoAppId != null) { + out += "appId = 0x" + Long.toHexString(mNanoAppId) + ", "; + } + out += "package = " + mPackage + ")"; + + return out; } } diff --git a/services/core/java/com/android/server/location/ContextHubTransactionManager.java b/services/core/java/com/android/server/location/ContextHubTransactionManager.java index cced781f8e1b..d3fc7058bcf2 100644 --- a/services/core/java/com/android/server/location/ContextHubTransactionManager.java +++ b/services/core/java/com/android/server/location/ContextHubTransactionManager.java @@ -26,11 +26,15 @@ import android.hardware.location.NanoAppState; import android.os.RemoteException; import android.util.Log; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.ArrayDeque; import java.util.Collections; +import java.util.Date; +import java.util.Iterator; import java.util.List; -import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -53,6 +57,11 @@ import java.util.concurrent.atomic.AtomicInteger; private static final int MAX_PENDING_REQUESTS = 10000; /* + * The DateFormat for printing TransactionRecord. + */ + private static final DateFormat DATE_FORMAT = new SimpleDateFormat("MM/dd HH:mm:ss.SSS"); + + /* * The proxy to talk to the Context Hub */ private final IContexthub mContextHubProxy; @@ -83,6 +92,33 @@ import java.util.concurrent.atomic.AtomicInteger; private final ScheduledThreadPoolExecutor mTimeoutExecutor = new ScheduledThreadPoolExecutor(1); private ScheduledFuture<?> mTimeoutFuture = null; + /* + * The list of previous transaction records. + */ + private static final int NUM_TRANSACTION_RECORDS = 20; + private final ConcurrentLinkedEvictingDeque<TransactionRecord> mTransactionRecordDeque = + new ConcurrentLinkedEvictingDeque<>(NUM_TRANSACTION_RECORDS); + + /** + * A container class to store a record of transactions. + */ + private class TransactionRecord { + private final String mTransaction; + private final long mTimestamp; + + TransactionRecord(String transaction) { + mTransaction = transaction; + mTimestamp = System.currentTimeMillis(); + } + + // TODO: Add dump to proto here + + @Override + public String toString() { + return DATE_FORMAT.format(new Date(mTimestamp)) + " " + mTransaction; + } + } + /* package */ ContextHubTransactionManager( IContexthub contextHubProxy, ContextHubClientManager clientManager, NanoAppStateManager nanoAppStateManager) { @@ -101,11 +137,12 @@ import java.util.concurrent.atomic.AtomicInteger; */ /* package */ ContextHubServiceTransaction createLoadTransaction( int contextHubId, NanoAppBinary nanoAppBinary, - IContextHubTransactionCallback onCompleteCallback) { + IContextHubTransactionCallback onCompleteCallback, String packageName) { return new ContextHubServiceTransaction( - mNextAvailableId.getAndIncrement(), ContextHubTransaction.TYPE_LOAD_NANOAPP) { + mNextAvailableId.getAndIncrement(), ContextHubTransaction.TYPE_LOAD_NANOAPP, + nanoAppBinary.getNanoAppId(), packageName) { @Override - /* package */ int onTransact() { + /* package */ int onTransact() { android.hardware.contexthub.V1_0.NanoAppBinary hidlNanoAppBinary = ContextHubServiceUtil.createHidlNanoAppBinary(nanoAppBinary); try { @@ -119,7 +156,7 @@ import java.util.concurrent.atomic.AtomicInteger; } @Override - /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) { + /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) { if (result == ContextHubTransaction.RESULT_SUCCESS) { // NOTE: The legacy JNI code used to do a query right after a load success // to synchronize the service cache. Instead store the binary that was @@ -149,11 +186,13 @@ import java.util.concurrent.atomic.AtomicInteger; * @return the generated transaction */ /* package */ ContextHubServiceTransaction createUnloadTransaction( - int contextHubId, long nanoAppId, IContextHubTransactionCallback onCompleteCallback) { + int contextHubId, long nanoAppId, IContextHubTransactionCallback onCompleteCallback, + String packageName) { return new ContextHubServiceTransaction( - mNextAvailableId.getAndIncrement(), ContextHubTransaction.TYPE_UNLOAD_NANOAPP) { + mNextAvailableId.getAndIncrement(), ContextHubTransaction.TYPE_UNLOAD_NANOAPP, + nanoAppId, packageName) { @Override - /* package */ int onTransact() { + /* package */ int onTransact() { try { return mContextHubProxy.unloadNanoApp( contextHubId, nanoAppId, this.getTransactionId()); @@ -165,7 +204,7 @@ import java.util.concurrent.atomic.AtomicInteger; } @Override - /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) { + /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) { if (result == ContextHubTransaction.RESULT_SUCCESS) { mNanoAppStateManager.removeNanoAppInstance(contextHubId, nanoAppId); } @@ -190,11 +229,13 @@ import java.util.concurrent.atomic.AtomicInteger; * @return the generated transaction */ /* package */ ContextHubServiceTransaction createEnableTransaction( - int contextHubId, long nanoAppId, IContextHubTransactionCallback onCompleteCallback) { + int contextHubId, long nanoAppId, IContextHubTransactionCallback onCompleteCallback, + String packageName) { return new ContextHubServiceTransaction( - mNextAvailableId.getAndIncrement(), ContextHubTransaction.TYPE_ENABLE_NANOAPP) { + mNextAvailableId.getAndIncrement(), ContextHubTransaction.TYPE_ENABLE_NANOAPP, + packageName) { @Override - /* package */ int onTransact() { + /* package */ int onTransact() { try { return mContextHubProxy.enableNanoApp( contextHubId, nanoAppId, this.getTransactionId()); @@ -206,7 +247,7 @@ import java.util.concurrent.atomic.AtomicInteger; } @Override - /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) { + /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) { try { onCompleteCallback.onTransactionComplete(result); } catch (RemoteException e) { @@ -225,11 +266,13 @@ import java.util.concurrent.atomic.AtomicInteger; * @return the generated transaction */ /* package */ ContextHubServiceTransaction createDisableTransaction( - int contextHubId, long nanoAppId, IContextHubTransactionCallback onCompleteCallback) { + int contextHubId, long nanoAppId, IContextHubTransactionCallback onCompleteCallback, + String packageName) { return new ContextHubServiceTransaction( - mNextAvailableId.getAndIncrement(), ContextHubTransaction.TYPE_DISABLE_NANOAPP) { + mNextAvailableId.getAndIncrement(), ContextHubTransaction.TYPE_DISABLE_NANOAPP, + packageName) { @Override - /* package */ int onTransact() { + /* package */ int onTransact() { try { return mContextHubProxy.disableNanoApp( contextHubId, nanoAppId, this.getTransactionId()); @@ -241,7 +284,7 @@ import java.util.concurrent.atomic.AtomicInteger; } @Override - /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) { + /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) { try { onCompleteCallback.onTransactionComplete(result); } catch (RemoteException e) { @@ -259,11 +302,13 @@ import java.util.concurrent.atomic.AtomicInteger; * @return the generated transaction */ /* package */ ContextHubServiceTransaction createQueryTransaction( - int contextHubId, IContextHubTransactionCallback onCompleteCallback) { + int contextHubId, IContextHubTransactionCallback onCompleteCallback, + String packageName) { return new ContextHubServiceTransaction( - mNextAvailableId.getAndIncrement(), ContextHubTransaction.TYPE_QUERY_NANOAPPS) { + mNextAvailableId.getAndIncrement(), ContextHubTransaction.TYPE_QUERY_NANOAPPS, + packageName) { @Override - /* package */ int onTransact() { + /* package */ int onTransact() { try { return mContextHubProxy.queryApps(contextHubId); } catch (RemoteException e) { @@ -273,12 +318,12 @@ import java.util.concurrent.atomic.AtomicInteger; } @Override - /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) { + /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) { onQueryResponse(result, Collections.emptyList()); } @Override - /* package */ void onQueryResponse( + /* package */ void onQueryResponse( @ContextHubTransaction.Result int result, List<NanoAppState> nanoAppStateList) { try { onCompleteCallback.onQueryResponse(result, nanoAppStateList); @@ -307,6 +352,7 @@ import java.util.concurrent.atomic.AtomicInteger; + MAX_PENDING_REQUESTS + ")"); } mTransactionQueue.add(transaction); + mTransactionRecordDeque.add(new TransactionRecord(transaction.toString())); if (mTransactionQueue.size() == 1) { startNextTransaction(); @@ -433,4 +479,23 @@ import java.util.concurrent.atomic.AtomicInteger; } } } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(100); + TransactionRecord[] arr; + synchronized (this) { + arr = mTransactionQueue.toArray(new TransactionRecord[0]); + } + for (int i = 0; i < arr.length; i++) { + sb.append(i + ": " + arr[i] + "\n"); + } + + sb.append("Transaction History:\n"); + Iterator<TransactionRecord> iterator = mTransactionRecordDeque.descendingIterator(); + while (iterator.hasNext()) { + sb.append(iterator.next() + "\n"); + } + return sb.toString(); + } } diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 00cb22e9d4b5..391a08db6716 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -459,12 +459,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final int returnCode = args.argi1; args.recycle(); - final boolean showNotification; - synchronized (mLock) { - showNotification = isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(); - } sendOnPackageInstalled(mContext, statusReceiver, sessionId, - showNotification, userId, + isInstallerDeviceOwnerOrAffiliatedProfileOwner(), userId, packageName, returnCode, message, extras); break; @@ -494,8 +490,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { /** * @return {@code true} iff the installing is app an device owner or affiliated profile owner. */ - @GuardedBy("mLock") - private boolean isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked() { + private boolean isInstallerDeviceOwnerOrAffiliatedProfileOwner() { + assertNotLocked("isInstallerDeviceOwnerOrAffiliatedProfileOwner"); + // It is safe to access mInstallerUid and mInstallSource without lock + // because they are immutable after sealing. + assertSealed("isInstallerDeviceOwnerOrAffiliatedProfileOwner"); if (userId != UserHandle.getUserId(mInstallerUid)) { return false; } @@ -513,12 +512,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { * * @return {@code true} iff we need to ask to confirm the permissions? */ - @GuardedBy("mLock") - private boolean needToAskForPermissionsLocked() { - if (mPermissionsManuallyAccepted) { - return false; + private boolean needToAskForPermissions() { + final String packageName; + synchronized (mLock) { + if (mPermissionsManuallyAccepted) { + return false; + } + packageName = mPackageName; } + // It is safe to access mInstallerUid and mInstallSource without lock + // because they are immutable after sealing. final boolean isInstallPermissionGranted = (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, mInstallerUid) == PackageManager.PERMISSION_GRANTED); @@ -528,7 +532,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final boolean isUpdatePermissionGranted = (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGE_UPDATES, mInstallerUid) == PackageManager.PERMISSION_GRANTED); - final int targetPackageUid = mPm.getPackageUid(mPackageName, 0, userId); + final int targetPackageUid = mPm.getPackageUid(packageName, 0, userId); final boolean isPermissionGranted = isInstallPermissionGranted || (isUpdatePermissionGranted && targetPackageUid != -1) || (isSelfUpdatePermissionGranted && targetPackageUid == mInstallerUid); @@ -540,7 +544,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // Device owners and affiliated profile owners are allowed to silently install packages, so // the permission check is waived if the installer is the device owner. return forcePermissionPrompt || !(isPermissionGranted || isInstallerRoot - || isInstallerSystem || isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked()); + || isInstallerSystem || isInstallerDeviceOwnerOrAffiliatedProfileOwner()); } public PackageInstallerSession(PackageInstallerService.InternalCallback callback, @@ -740,6 +744,18 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + private void assertNotLocked(String cookie) { + if (Thread.holdsLock(mLock)) { + throw new IllegalStateException(cookie + " is holding mLock"); + } + } + + private void assertSealed(String cookie) { + if (!isSealed()) { + throw new IllegalStateException(cookie + " before sealing"); + } + } + @GuardedBy("mLock") private void assertPreparedAndNotSealedLocked(String cookie) { assertPreparedAndNotCommittedOrDestroyedLocked(cookie); @@ -1693,11 +1709,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } private void handleInstall() { - final boolean needsLogging; - synchronized (mLock) { - needsLogging = isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(); - } - if (needsLogging) { + if (isInstallerDeviceOwnerOrAffiliatedProfileOwner()) { DevicePolicyEventLogger .createEvent(DevicePolicyEnums.INSTALL_PACKAGE) .setAdmin(mInstallSource.installerPackageName) @@ -1724,9 +1736,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { List<PackageInstallerSession> childSessions = getChildSessionsNotLocked(); try { - synchronized (mLock) { - installNonStagedLocked(childSessions); - } + installNonStaged(childSessions); } catch (PackageManagerException e) { final String completeMsg = ExceptionUtils.getCompleteMessage(e); Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg); @@ -1735,11 +1745,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } - @GuardedBy("mLock") - private void installNonStagedLocked(List<PackageInstallerSession> childSessions) + private void installNonStaged(List<PackageInstallerSession> childSessions) throws PackageManagerException { final PackageManagerService.ActiveInstallSession installingSession = - makeSessionActiveLocked(); + makeSessionActive(); if (installingSession == null) { return; } @@ -1752,7 +1761,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final PackageInstallerSession session = childSessions.get(i); try { final PackageManagerService.ActiveInstallSession installingChildSession = - session.makeSessionActiveLocked(); + session.makeSessionActive(); if (installingChildSession != null) { installingChildSessions.add(installingChildSession); } @@ -1762,8 +1771,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } if (!success) { - sendOnPackageInstalled(mContext, mRemoteStatusReceiver, sessionId, - isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId, null, + final IntentSender statusReceiver; + synchronized (mLock) { + statusReceiver = mRemoteStatusReceiver; + } + sendOnPackageInstalled(mContext, statusReceiver, sessionId, + isInstallerDeviceOwnerOrAffiliatedProfileOwner(), userId, null, failure.error, failure.getLocalizedMessage(), null); return; } @@ -1778,41 +1791,58 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { * {@link PackageManagerService.ActiveInstallSession} representing this new staged state or null * in case permissions need to be requested before install can proceed. */ - @GuardedBy("mLock") - private PackageManagerService.ActiveInstallSession makeSessionActiveLocked() + private PackageManagerService.ActiveInstallSession makeSessionActive() throws PackageManagerException { - if (mRelinquished) { - throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, - "Session relinquished"); + assertNotLocked("makeSessionActive"); + + synchronized (mLock) { + if (mRelinquished) { + throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, + "Session relinquished"); + } + if (mDestroyed) { + throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, + "Session destroyed"); + } + if (!mSealed) { + throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, + "Session not sealed"); + } } - if (mDestroyed) { - throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed"); + + if (!params.isMultiPackage && needToAskForPermissions()) { + // User needs to confirm installation; + // give installer an intent they can use to involve + // user. + final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_INSTALL); + intent.setPackage(mPm.getPackageInstallerPackageName()); + intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); + + final IntentSender statusReceiver; + synchronized (mLock) { + statusReceiver = mRemoteStatusReceiver; + } + sendOnUserActionRequired(mContext, statusReceiver, sessionId, intent); + + // Commit was keeping session marked as active until now; release + // that extra refcount so session appears idle. + closeInternal(false); + return null; } - if (!mSealed) { - throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed"); + + synchronized (mLock) { + return makeSessionActiveLocked(); } + } + @GuardedBy("mLock") + private PackageManagerService.ActiveInstallSession makeSessionActiveLocked() + throws PackageManagerException { if (!params.isMultiPackage) { Objects.requireNonNull(mPackageName); Objects.requireNonNull(mSigningDetails); Objects.requireNonNull(mResolvedBaseFile); - if (needToAskForPermissionsLocked()) { - // User needs to confirm installation; - // give installer an intent they can use to involve - // user. - final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_INSTALL); - intent.setPackage(mPm.getPackageInstallerPackageName()); - intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); - - sendOnUserActionRequired(mContext, mRemoteStatusReceiver, sessionId, intent); - - // Commit was keeping session marked as active until now; release - // that extra refcount so session appears idle. - closeInternal(false); - return null; - } - // Inherit any packages and native libraries from existing install that // haven't been overridden. if (params.mode == SessionParams.MODE_INHERIT_EXISTING) { @@ -2438,7 +2468,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { * Determine if creating hard links between source and destination is * possible. That is, do they all live on the same underlying device. */ - private boolean isLinkPossible(List<File> fromFiles, File toDir) { + private static boolean isLinkPossible(List<File> fromFiles, File toDir) { try { final StructStat toStat = Os.stat(toDir.getAbsolutePath()); for (File fromFile : fromFiles) { @@ -2915,7 +2945,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } case IDataLoaderStatusListener.DATA_LOADER_UNAVAILABLE: { // Don't fail or commit the session. Allow caller to commit again. - sendPendingStreaming("DataLoader unavailable"); + final IntentSender statusReceiver; + synchronized (mLock) { + statusReceiver = mRemoteStatusReceiver; + } + sendPendingStreaming(mContext, statusReceiver, sessionId, + "DataLoader unavailable"); break; } case IDataLoaderStatusListener.DATA_LOADER_UNRECOVERABLE: @@ -2929,7 +2964,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } catch (RemoteException e) { // In case of streaming failure we don't want to fail or commit the session. // Just return from this method and allow caller to commit again. - sendPendingStreaming(e.getMessage()); + final IntentSender statusReceiver; + synchronized (mLock) { + statusReceiver = mRemoteStatusReceiver; + } + sendPendingStreaming(mContext, statusReceiver, sessionId, e.getMessage()); } } }; @@ -3004,16 +3043,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { detailMessage).sendToTarget(); } + @GuardedBy("mLock") + private int[] getChildSessionIdsLocked() { + final int[] childSessionIds = mChildSessionIds.copyKeys(); + return childSessionIds != null ? childSessionIds : EMPTY_CHILD_SESSION_ARRAY; + } + @Override public int[] getChildSessionIds() { - final int[] childSessionIds; synchronized (mLock) { - childSessionIds = mChildSessionIds.copyKeys(); + return getChildSessionIdsLocked(); } - if (childSessionIds != null) { - return childSessionIds; - } - return EMPTY_CHILD_SESSION_ARRAY; } private boolean canBeAddedAsChild(int parentCandidate) { @@ -3323,6 +3363,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { pw.decreaseIndent(); } + /** + * This method doesn't change internal states and is safe to call outside the lock. + */ private static void sendOnUserActionRequired(Context context, IntentSender target, int sessionId, Intent intent) { final Intent fillIn = new Intent(); @@ -3335,6 +3378,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + /** + * This method doesn't change internal states and is safe to call outside the lock. + */ private static void sendOnPackageInstalled(Context context, IntentSender target, int sessionId, boolean showNotification, int userId, String basePackageName, int returnCode, String msg, Bundle extras) { @@ -3375,13 +3421,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } - private void sendPendingStreaming(@Nullable String cause) { - final IntentSender statusReceiver; - synchronized (mLock) { - statusReceiver = mRemoteStatusReceiver; - } - - if (statusReceiver == null) { + /** + * This method doesn't change internal states and is safe to call outside the lock. + */ + private static void sendPendingStreaming(Context context, IntentSender target, int sessionId, + @Nullable String cause) { + if (target == null) { Slog.e(TAG, "Missing receiver for pending streaming status."); return; } @@ -3396,7 +3441,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { intent.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, "Staging Image Not Ready"); } try { - statusReceiver.sendIntent(mContext, 0, intent, null, null); + target.sendIntent(context, 0, intent, null, null); } catch (IntentSender.SendIntentException ignored) { } } @@ -3470,10 +3515,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (stageCid != null) { writeStringAttribute(out, ATTR_SESSION_STAGE_CID, stageCid); } - writeBooleanAttribute(out, ATTR_PREPARED, isPrepared()); - writeBooleanAttribute(out, ATTR_COMMITTED, isCommitted()); - writeBooleanAttribute(out, ATTR_DESTROYED, isDestroyed()); - writeBooleanAttribute(out, ATTR_SEALED, isSealed()); + writeBooleanAttribute(out, ATTR_PREPARED, mPrepared); + writeBooleanAttribute(out, ATTR_COMMITTED, mCommitted); + writeBooleanAttribute(out, ATTR_DESTROYED, mDestroyed); + writeBooleanAttribute(out, ATTR_SEALED, mSealed); writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage); writeBooleanAttribute(out, ATTR_STAGED_SESSION, params.isStaged); @@ -3535,7 +3580,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { params.appIconLastModified = appIconFile.lastModified(); } - final int[] childSessionIds = getChildSessionIds(); + final int[] childSessionIds = getChildSessionIdsLocked(); for (int childSessionId : childSessionIds) { out.startTag(null, TAG_CHILD_SESSION); writeIntAttribute(out, ATTR_SESSION_ID, childSessionId); @@ -3543,7 +3588,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } final InstallationFile[] files = getInstallationFilesLocked(); - for (InstallationFile file : getInstallationFilesLocked()) { + for (InstallationFile file : files) { out.startTag(null, TAG_SESSION_FILE); writeIntAttribute(out, ATTR_LOCATION, file.getLocation()); writeStringAttribute(out, ATTR_NAME, file.getName()); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index bd12fd5f5d9a..2854b337fd29 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -651,6 +651,23 @@ public class PackageManagerService extends IPackageManager.Stub private static final long THROW_EXCEPTION_ON_REQUIRE_INSTALL_PACKAGES_TO_ADD_INSTALLER_PACKAGE = 150857253; + /** + * Apps targeting Android S and above need to declare dependencies to the public native + * shared libraries that are defined by the device maker using {@code uses-native-library} tag + * in its {@code AndroidManifest.xml}. + * + * If any of the dependencies cannot be satisfied, i.e. one of the dependency doesn't exist, + * the package manager rejects to install the app. The dependency can be specified as optional + * using {@code android:required} attribute in the tag, in which case failing to satisfy the + * dependency doesn't stop the installation. + * <p>Once installed, an app is provided with only the native shared libraries that are + * specified in the app manifest. {@code dlopen}ing a native shared library that doesn't appear + * in the app manifest will fail even if it actually exists on the device. + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R) + private static final long ENFORCE_NATIVE_SHARED_LIBRARY_DEPENDENCIES = 142191088; + public static final String PLATFORM_PACKAGE_NAME = "android"; private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive"; @@ -2952,9 +2969,8 @@ public class PackageManagerService extends IPackageManager.Stub = systemConfig.getSharedLibraries(); final int builtInLibCount = libConfig.size(); for (int i = 0; i < builtInLibCount; i++) { - String name = libConfig.keyAt(i); SystemConfig.SharedLibraryEntry entry = libConfig.valueAt(i); - addBuiltInSharedLibraryLocked(entry.filename, name); + addBuiltInSharedLibraryLocked(libConfig.valueAt(i)); } // Now that we have added all the libraries, iterate again to add dependency @@ -10486,6 +10502,19 @@ public class PackageManagerService extends IPackageManager.Stub null, null, pkg.getPackageName(), false, pkg.getTargetSdkVersion(), usesLibraryInfos, availablePackages, existingLibraries, newLibraries); } + // TODO(b/160928779) gate this behavior using ENFORCE_NATIVE_SHARED_LIBRARY_DEPENDENCIES + if (pkg.getTargetSdkVersion() > 30) { + if (!pkg.getUsesNativeLibraries().isEmpty() && pkg.getTargetSdkVersion() > 30) { + usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesNativeLibraries(), null, + null, pkg.getPackageName(), true, pkg.getTargetSdkVersion(), + usesLibraryInfos, availablePackages, existingLibraries, newLibraries); + } + if (!pkg.getUsesOptionalNativeLibraries().isEmpty()) { + usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesOptionalNativeLibraries(), + null, null, pkg.getPackageName(), false, pkg.getTargetSdkVersion(), + usesLibraryInfos, availablePackages, existingLibraries, newLibraries); + } + } return usesLibraryInfos; } @@ -12177,15 +12206,16 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy("mLock") - private boolean addBuiltInSharedLibraryLocked(String path, String name) { - if (nonStaticSharedLibExistsLocked(name)) { + private boolean addBuiltInSharedLibraryLocked(SystemConfig.SharedLibraryEntry entry) { + if (nonStaticSharedLibExistsLocked(entry.name)) { return false; } - SharedLibraryInfo libraryInfo = new SharedLibraryInfo(path, null, null, name, - (long) SharedLibraryInfo.VERSION_UNDEFINED, SharedLibraryInfo.TYPE_BUILTIN, - new VersionedPackage(PLATFORM_PACKAGE_NAME, (long) 0), - null, null); + SharedLibraryInfo libraryInfo = new SharedLibraryInfo(entry.filename, null, null, + entry.name, (long) SharedLibraryInfo.VERSION_UNDEFINED, + SharedLibraryInfo.TYPE_BUILTIN, + new VersionedPackage(PLATFORM_PACKAGE_NAME, (long)0), null, null, + entry.isNative); commitSharedLibraryInfoLocked(libraryInfo); return true; @@ -21900,7 +21930,11 @@ public class PackageManagerService extends IPackageManager.Stub pw.print(" -> "); } if (libraryInfo.getPath() != null) { - pw.print(" (jar) "); + if (libraryInfo.isNative()) { + pw.print(" (so) "); + } else { + pw.print(" (jar) "); + } pw.print(libraryInfo.getPath()); } else { pw.print(" (apk) "); diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 13b927e7d9f4..7106499f9b56 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -4784,6 +4784,23 @@ public final class Settings { } } + List<String> usesNativeLibraries = pkg.getUsesNativeLibraries(); + if (usesNativeLibraries.size() > 0) { + pw.print(prefix); pw.println(" usesNativeLibraries:"); + for (int i=0; i< usesNativeLibraries.size(); i++) { + pw.print(prefix); pw.print(" "); pw.println(usesNativeLibraries.get(i)); + } + } + + List<String> usesOptionalNativeLibraries = pkg.getUsesOptionalNativeLibraries(); + if (usesOptionalNativeLibraries.size() > 0) { + pw.print(prefix); pw.println(" usesOptionalNativeLibraries:"); + for (int i=0; i< usesOptionalNativeLibraries.size(); i++) { + pw.print(prefix); pw.print(" "); + pw.println(usesOptionalNativeLibraries.get(i)); + } + } + List<String> usesLibraryFiles = ps.getPkgState().getUsesLibraryFiles(); if (usesLibraryFiles.size() > 0) { pw.print(prefix); pw.println(" usesLibraryFiles:"); diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index c37f09a96f95..a44d1797b82b 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -3306,27 +3306,6 @@ public class UserManagerService extends IUserManager.Stub { } } - private long logUserCreateJourneyBegin(@UserIdInt int userId, String userType, - @UserInfoFlag int flags) { - final long sessionId = ThreadLocalRandom.current().nextLong(1, Long.MAX_VALUE); - // log the journey atom with the user metadata - FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED, sessionId, - FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_CREATE, - /* origin_user= */ -1, userId, UserManager.getUserTypeForStatsd(userType), flags); - // log the event atom to indicate the event start - FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED, sessionId, userId, - FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__CREATE_USER, - FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__BEGIN); - return sessionId; - } - - private void logUserCreateJourneyFinish(long sessionId, @UserIdInt int userId, boolean finish) { - FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED, sessionId, userId, - FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__CREATE_USER, - finish ? FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__FINISH - : FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__NONE); - } - private UserInfo createUserInternalUncheckedNoTracing(@Nullable String name, @NonNull String userType, @UserInfoFlag int flags, @UserIdInt int parentId, boolean preCreate, @Nullable String[] disallowedPackages, @@ -3433,6 +3412,7 @@ public class UserManagerService extends IUserManager.Stub { } userId = getNextAvailableId(); + Slog.i(LOG_TAG, "Creating user " + userId + " of type " + userType); Environment.getUserSystemDirectory(userId).mkdirs(); synchronized (mUsersLock) { @@ -3684,6 +3664,27 @@ public class UserManagerService extends IUserManager.Stub { && !userTypeDetails.getName().equals(UserManager.USER_TYPE_FULL_RESTRICTED); } + private long logUserCreateJourneyBegin(@UserIdInt int userId, String userType, + @UserInfoFlag int flags) { + final long sessionId = ThreadLocalRandom.current().nextLong(1, Long.MAX_VALUE); + // log the journey atom with the user metadata + FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED, sessionId, + FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_CREATE, + /* origin_user= */ -1, userId, UserManager.getUserTypeForStatsd(userType), flags); + // log the event atom to indicate the event start + FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED, sessionId, userId, + FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__CREATE_USER, + FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__BEGIN); + return sessionId; + } + + private void logUserCreateJourneyFinish(long sessionId, @UserIdInt int userId, boolean finish) { + FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED, sessionId, userId, + FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__EVENT__CREATE_USER, + finish ? FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__FINISH + : FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED__STATE__NONE); + } + @VisibleForTesting UserData putUserInfo(UserInfo userInfo) { final UserData userData = new UserData(); diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java index c9e0bb467ce4..39784cf32cea 100644 --- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java +++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java @@ -252,6 +252,19 @@ public interface AndroidPackage extends PkgAppInfo, PkgPackageInfo, ParsingPacka @NonNull List<String> getUsesOptionalLibraries(); + /** @see R.styleabele#AndroidManifestUsesNativeLibrary */ + @NonNull + List<String> getUsesNativeLibraries(); + + /** + * Like {@link #getUsesNativeLibraries()}, but marked optional by setting + * {@link R.styleable#AndroidManifestUsesNativeLibrary_required} to false . Application is + * expected to handle absence manually. + * @see R.styleable#AndroidManifestUsesNativeLibrary + */ + @NonNull + List<String> getUsesOptionalNativeLibraries(); + /** * TODO(b/135203078): Move static library stuff to an inner data class * @see R.styleable#AndroidManifestUsesStaticLibrary diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index e75dab73478e..03868e922bdd 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -209,7 +209,6 @@ import com.android.server.policy.keyguard.KeyguardStateMonitor.StateCallback; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.vr.VrManagerInternal; import com.android.server.wm.ActivityTaskManagerInternal; -import com.android.server.wm.ActivityTaskManagerInternal.SleepToken; import com.android.server.wm.AppTransition; import com.android.server.wm.DisplayPolicy; import com.android.server.wm.DisplayRotation; @@ -491,7 +490,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private boolean mPendingKeyguardOccluded; private boolean mKeyguardOccludedChanged; - SleepToken mScreenOffSleepToken; + private ActivityTaskManagerInternal.SleepTokenAcquirer mScreenOffSleepTokenAcquirer; volatile boolean mKeyguardOccluded; Intent mHomeIntent; Intent mCarDockIntent; @@ -1741,6 +1740,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { new AccessibilityShortcutController(mContext, new Handler(), mCurrentUserId); mLogger = new MetricsLogger(); + mScreenOffSleepTokenAcquirer = mActivityTaskManagerInternal + .createSleepTokenAcquirer("ScreenOff"); + Resources res = mContext.getResources(); mWakeOnDpadKeyPress = res.getBoolean(com.android.internal.R.bool.config_wakeOnDpadKeyPress); @@ -4984,15 +4986,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // TODO (multidisplay): Support multiple displays in WindowManagerPolicy. private void updateScreenOffSleepToken(boolean acquire) { if (acquire) { - if (mScreenOffSleepToken == null) { - mScreenOffSleepToken = mActivityTaskManagerInternal.acquireSleepToken( - "ScreenOff", DEFAULT_DISPLAY); - } + mScreenOffSleepTokenAcquirer.acquire(DEFAULT_DISPLAY); } else { - if (mScreenOffSleepToken != null) { - mScreenOffSleepToken.release(); - mScreenOffSleepToken = null; - } + mScreenOffSleepTokenAcquirer.release(DEFAULT_DISPLAY); } } diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 7b0675939a33..4c4680b17372 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -44,8 +44,8 @@ import android.hardware.SystemSensorManager; import android.hardware.display.AmbientDisplayConfiguration; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; +import android.hardware.power.Boost; import android.hardware.power.Mode; -import android.hardware.power.V1_0.PowerHint; import android.net.Uri; import android.os.BatteryManager; import android.os.BatteryManagerInternal; @@ -203,9 +203,6 @@ public final class PowerManagerService extends SystemService // How long a partial wake lock must be held until we consider it a long wake lock. static final long MIN_LONG_WAKE_CHECK_INTERVAL = 60*1000; - // Power features defined in hardware/libhardware/include/hardware/power.h. - private static final int POWER_FEATURE_DOUBLE_TAP_TO_WAKE = 1; - // Default setting for double tap to wake. private static final int DEFAULT_DOUBLE_TAP_TO_WAKE = 0; @@ -325,7 +322,7 @@ public final class PowerManagerService extends SystemService private long mLastUserActivityTime; private long mLastUserActivityTimeNoChangeLights; - // Timestamp of last interactive power hint. + // Timestamp of last time power boost interaction was sent. private long mLastInteractivePowerHintTime; // Timestamp of the last screen brightness boost. @@ -719,21 +716,11 @@ public final class PowerManagerService extends SystemService PowerManagerService.nativeReleaseSuspendBlocker(name); } - /** Wrapper for PowerManager.nativeSetInteractive */ - public void nativeSetInteractive(boolean enable) { - PowerManagerService.nativeSetInteractive(enable); - } - /** Wrapper for PowerManager.nativeSetAutoSuspend */ public void nativeSetAutoSuspend(boolean enable) { PowerManagerService.nativeSetAutoSuspend(enable); } - /** Wrapper for PowerManager.nativeSendPowerHint */ - public void nativeSendPowerHint(int hintId, int data) { - PowerManagerService.nativeSendPowerHint(hintId, data); - } - /** Wrapper for PowerManager.nativeSetPowerBoost */ public void nativeSetPowerBoost(int boost, int durationMs) { PowerManagerService.nativeSetPowerBoost(boost, durationMs); @@ -744,11 +731,6 @@ public final class PowerManagerService extends SystemService return PowerManagerService.nativeSetPowerMode(mode, enabled); } - /** Wrapper for PowerManager.nativeSetFeature */ - public void nativeSetFeature(int featureId, int data) { - PowerManagerService.nativeSetFeature(featureId, data); - } - /** Wrapper for PowerManager.nativeForceSuspend */ public boolean nativeForceSuspend() { return PowerManagerService.nativeForceSuspend(); @@ -851,12 +833,9 @@ public final class PowerManagerService extends SystemService private native void nativeInit(); private static native void nativeAcquireSuspendBlocker(String name); private static native void nativeReleaseSuspendBlocker(String name); - private static native void nativeSetInteractive(boolean enable); private static native void nativeSetAutoSuspend(boolean enable); - private static native void nativeSendPowerHint(int hintId, int data); private static native void nativeSetPowerBoost(int boost, int durationMs); private static native boolean nativeSetPowerMode(int mode, boolean enabled); - private static native void nativeSetFeature(int featureId, int data); private static native boolean nativeForceSuspend(); public PowerManagerService(Context context) { @@ -1000,8 +979,8 @@ public final class PowerManagerService extends SystemService mNativeWrapper.nativeInit(this); mNativeWrapper.nativeSetAutoSuspend(false); - mNativeWrapper.nativeSetInteractive(true); - mNativeWrapper.nativeSetFeature(POWER_FEATURE_DOUBLE_TAP_TO_WAKE, 0); + mNativeWrapper.nativeSetPowerMode(Mode.INTERACTIVE, true); + mNativeWrapper.nativeSetPowerMode(Mode.DOUBLE_TAP_TO_WAKE, false); mInjector.invalidateIsInteractiveCaches(); } } @@ -1252,8 +1231,7 @@ public final class PowerManagerService extends SystemService UserHandle.USER_CURRENT) != 0; if (doubleTapWakeEnabled != mDoubleTapWakeEnabled) { mDoubleTapWakeEnabled = doubleTapWakeEnabled; - mNativeWrapper.nativeSetFeature( - POWER_FEATURE_DOUBLE_TAP_TO_WAKE, mDoubleTapWakeEnabled ? 1 : 0); + mNativeWrapper.nativeSetPowerMode(Mode.DOUBLE_TAP_TO_WAKE, mDoubleTapWakeEnabled); } } @@ -1612,7 +1590,7 @@ public final class PowerManagerService extends SystemService Trace.traceBegin(Trace.TRACE_TAG_POWER, "userActivity"); try { if (eventTime > mLastInteractivePowerHintTime) { - powerHintInternal(PowerHint.INTERACTION, 0); + setPowerBoostInternal(Boost.INTERACTION, 0); mLastInteractivePowerHintTime = eventTime; } @@ -3171,7 +3149,7 @@ public final class PowerManagerService extends SystemService mHalInteractiveModeEnabled = enable; Trace.traceBegin(Trace.TRACE_TAG_POWER, "setHalInteractive(" + enable + ")"); try { - mNativeWrapper.nativeSetInteractive(enable); + mNativeWrapper.nativeSetPowerMode(Mode.INTERACTIVE, enable); } finally { Trace.traceEnd(Trace.TRACE_TAG_POWER); } @@ -3645,19 +3623,6 @@ public final class PowerManagerService extends SystemService mIsVrModeEnabled = enabled; } - private void powerHintInternal(int hintId, int data) { - // Maybe filter the event. - switch (hintId) { - case PowerHint.LAUNCH: // 1: activate launch boost 0: deactivate. - if (data == 1 && mBatterySaverController.isLaunchBoostDisabled()) { - return; - } - break; - } - - mNativeWrapper.nativeSendPowerHint(hintId, data); - } - private void setPowerBoostInternal(int boost, int durationMs) { // Maybe filter the event. mNativeWrapper.nativeSetPowerBoost(boost, durationMs); @@ -4404,7 +4369,7 @@ public final class PowerManagerService extends SystemService private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() { @Override public void onVrStateChanged(boolean enabled) { - powerHintInternal(PowerHint.VR_MODE, enabled ? 1 : 0); + setPowerModeInternal(Mode.VR, enabled); synchronized (mLock) { if (mIsVrModeEnabled != enabled) { @@ -4715,16 +4680,6 @@ public final class PowerManagerService extends SystemService } @Override // Binder call - public void powerHint(int hintId, int data) { - if (!mSystemReady) { - // Service not ready yet, so who the heck cares about power hints, bah. - return; - } - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); - powerHintInternal(hintId, data); - } - - @Override // Binder call public void setPowerBoost(int boost, int durationMs) { if (!mSystemReady) { // Service not ready yet, so who the heck cares about power hints, bah. @@ -5559,11 +5514,6 @@ public final class PowerManagerService extends SystemService } @Override - public void powerHint(int hintId, int data) { - powerHintInternal(hintId, data); - } - - @Override public void setPowerBoost(int boost, int durationMs) { setPowerBoostInternal(boost, durationMs); } diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java index 2a4a69ddde4f..dd287ca6ed00 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java @@ -23,7 +23,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManagerInternal; -import android.hardware.power.V1_0.PowerHint; +import android.hardware.power.Mode; import android.os.BatteryManager; import android.os.BatterySaverPolicyConfig; import android.os.Handler; @@ -49,6 +49,7 @@ import com.android.server.power.batterysaver.BatterySaverPolicy.Policy; import com.android.server.power.batterysaver.BatterySavingStats.BatterySaverState; import com.android.server.power.batterysaver.BatterySavingStats.DozeState; import com.android.server.power.batterysaver.BatterySavingStats.InteractiveState; +import com.android.server.power.batterysaver.BatterySavingStats.PlugState; import java.util.ArrayList; import java.util.Objects; @@ -474,7 +475,7 @@ public class BatterySaverController implements BatterySaverPolicyListener { final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class); if (pmi != null) { - pmi.powerHint(PowerHint.LOW_POWER, isEnabled() ? 1 : 0); + pmi.setPowerMode(Mode.LOW_POWER, isEnabled()); } updateBatterySavingStats(); @@ -551,17 +552,14 @@ public class BatterySaverController implements BatterySaverPolicyListener { : DozeState.NOT_DOZING; synchronized (mLock) { - if (mIsPluggedIn) { - mBatterySavingStats.startCharging(); - return; - } mBatterySavingStats.transitionState( getFullEnabledLocked() ? BatterySaverState.ON : (getAdaptiveEnabledLocked() ? BatterySaverState.ADAPTIVE : BatterySaverState.OFF), isInteractive ? InteractiveState.INTERACTIVE : InteractiveState.NON_INTERACTIVE, - dozeMode); + dozeMode, + mIsPluggedIn ? PlugState.PLUGGED : PlugState.UNPLUGGED); } } diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java index 3dbc0072f8b4..05695d919910 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java @@ -17,8 +17,8 @@ package com.android.server.power.batterysaver; import android.os.BatteryManagerInternal; import android.os.SystemClock; -import android.util.ArrayMap; import android.util.Slog; +import android.util.SparseArray; import android.util.TimeUtils; import com.android.internal.annotations.GuardedBy; @@ -93,6 +93,20 @@ public class BatterySavingStats { } } + /** Whether the device is plugged in or not. */ + interface PlugState { + int UNPLUGGED = 0; + int PLUGGED = 1; + + int SHIFT = DozeState.SHIFT + DozeState.BITS; + int BITS = 1; + int MASK = (1 << BITS) - 1; + + static int fromIndex(int index) { + return (index >> SHIFT) & MASK; + } + } + /** * Various stats in each state. */ @@ -140,7 +154,6 @@ public class BatterySavingStats { private BatteryManagerInternal mBatteryManagerInternal; private static final int STATE_NOT_INITIALIZED = -1; - private static final int STATE_CHARGING = -2; /** * Current state, one of STATE_* or values returned by {@link #statesToIndex}. @@ -153,20 +166,26 @@ public class BatterySavingStats { */ @VisibleForTesting @GuardedBy("mLock") - final ArrayMap<Integer, Stat> mStats = new ArrayMap<>(); + final SparseArray<Stat> mStats = new SparseArray<>(); @GuardedBy("mLock") private int mBatterySaverEnabledCount = 0; @GuardedBy("mLock") - private boolean mIsBatterySaverEnabled; - - @GuardedBy("mLock") private long mLastBatterySaverEnabledTime = 0; @GuardedBy("mLock") private long mLastBatterySaverDisabledTime = 0; + @GuardedBy("mLock") + private int mAdaptiveBatterySaverEnabledCount = 0; + + @GuardedBy("mLock") + private long mLastAdaptiveBatterySaverEnabledTime = 0; + + @GuardedBy("mLock") + private long mLastAdaptiveBatterySaverDisabledTime = 0; + /** Visible for unit tests */ @VisibleForTesting public BatterySavingStats(Object lock) { @@ -189,10 +208,11 @@ public class BatterySavingStats { */ @VisibleForTesting static int statesToIndex( - int batterySaverState, int interactiveState, int dozeState) { + int batterySaverState, int interactiveState, int dozeState, int plugState) { int ret = batterySaverState & BatterySaverState.MASK; ret |= (interactiveState & InteractiveState.MASK) << InteractiveState.SHIFT; ret |= (dozeState & DozeState.MASK) << DozeState.SHIFT; + ret |= (plugState & PlugState.MASK) << PlugState.SHIFT; return ret; } @@ -204,12 +224,11 @@ public class BatterySavingStats { switch (state) { case STATE_NOT_INITIALIZED: return "NotInitialized"; - case STATE_CHARGING: - return "Charging"; } return "BS=" + BatterySaverState.fromIndex(state) + ",I=" + InteractiveState.fromIndex(state) - + ",D=" + DozeState.fromIndex(state); + + ",D=" + DozeState.fromIndex(state) + + ",P=" + PlugState.fromIndex(state); } /** @@ -230,8 +249,9 @@ public class BatterySavingStats { /** * @return {@link Stat} fo a given state triplet. */ - private Stat getStat(int batterySaverState, int interactiveState, int dozeState) { - return getStat(statesToIndex(batterySaverState, interactiveState, dozeState)); + private Stat getStat(int batterySaverState, int interactiveState, int dozeState, + int plugState) { + return getStat(statesToIndex(batterySaverState, interactiveState, dozeState, plugState)); } @VisibleForTesting @@ -258,26 +278,17 @@ public class BatterySavingStats { } /** - * Called from the outside whenever any of the states changes, when the device is not plugged - * in. + * Called from the outside whenever any of the states change. */ - public void transitionState(int batterySaverState, int interactiveState, int dozeState) { + void transitionState(int batterySaverState, int interactiveState, int dozeState, + int plugState) { synchronized (mLock) { final int newState = statesToIndex( - batterySaverState, interactiveState, dozeState); + batterySaverState, interactiveState, dozeState, plugState); transitionStateLocked(newState); } } - /** - * Called from the outside when the device is plugged in. - */ - public void startCharging() { - synchronized (mLock) { - transitionStateLocked(STATE_CHARGING); - } - } - @GuardedBy("mLock") private void transitionStateLocked(int newState) { if (mCurrentState == newState) { @@ -287,17 +298,33 @@ public class BatterySavingStats { final int batteryLevel = injectBatteryLevel(); final int batteryPercent = injectBatteryPercent(); - final boolean oldBatterySaverEnabled = - BatterySaverState.fromIndex(mCurrentState) != BatterySaverState.OFF; - final boolean newBatterySaverEnabled = - BatterySaverState.fromIndex(newState) != BatterySaverState.OFF; - if (oldBatterySaverEnabled != newBatterySaverEnabled) { - mIsBatterySaverEnabled = newBatterySaverEnabled; - if (newBatterySaverEnabled) { - mBatterySaverEnabledCount++; - mLastBatterySaverEnabledTime = injectCurrentTime(); - } else { - mLastBatterySaverDisabledTime = injectCurrentTime(); + final int oldBatterySaverState = mCurrentState < 0 + ? BatterySaverState.OFF : BatterySaverState.fromIndex(mCurrentState); + final int newBatterySaverState = newState < 0 + ? BatterySaverState.OFF : BatterySaverState.fromIndex(newState); + if (oldBatterySaverState != newBatterySaverState) { + switch (newBatterySaverState) { + case BatterySaverState.ON: + mBatterySaverEnabledCount++; + mLastBatterySaverEnabledTime = now; + if (oldBatterySaverState == BatterySaverState.ADAPTIVE) { + mLastAdaptiveBatterySaverDisabledTime = now; + } + break; + case BatterySaverState.OFF: + if (oldBatterySaverState == BatterySaverState.ON) { + mLastBatterySaverDisabledTime = now; + } else { + mLastAdaptiveBatterySaverDisabledTime = now; + } + break; + case BatterySaverState.ADAPTIVE: + mAdaptiveBatterySaverEnabledCount++; + mLastAdaptiveBatterySaverEnabledTime = now; + if (oldBatterySaverState == BatterySaverState.ON) { + mLastBatterySaverDisabledTime = now; + } + break; } } @@ -377,7 +404,18 @@ public class BatterySavingStats { pw.print(indent); pw.print("Battery Saver is currently: "); - pw.println(mIsBatterySaverEnabled ? "ON" : "OFF"); + switch (BatterySaverState.fromIndex(mCurrentState)) { + case BatterySaverState.OFF: + pw.println("OFF"); + break; + case BatterySaverState.ON: + pw.println("ON"); + break; + case BatterySaverState.ADAPTIVE: + pw.println("ADAPTIVE"); + break; + } + if (mLastBatterySaverEnabledTime > 0) { pw.print(indent); pw.print(" "); @@ -400,9 +438,34 @@ public class BatterySavingStats { pw.print(indent); pw.print(" "); - pw.print("Times enabled: "); + pw.print("Times full enabled: "); pw.println(mBatterySaverEnabledCount); + if (mLastAdaptiveBatterySaverEnabledTime > 0) { + pw.print(indent); + pw.print(" "); + pw.print("Last ADAPTIVE ON time: "); + pw.print(sdf.format( + new Date(now - nowElapsed + mLastAdaptiveBatterySaverEnabledTime))); + pw.print(" "); + TimeUtils.formatDuration(mLastAdaptiveBatterySaverEnabledTime, nowElapsed, pw); + pw.println(); + } + if (mLastAdaptiveBatterySaverDisabledTime > 0) { + pw.print(indent); + pw.print(" "); + pw.print("Last ADAPTIVE OFF time: "); + pw.print(sdf.format( + new Date(now - nowElapsed + mLastAdaptiveBatterySaverDisabledTime))); + pw.print(" "); + TimeUtils.formatDuration(mLastAdaptiveBatterySaverDisabledTime, nowElapsed, pw); + pw.println(); + } + pw.print(indent); + pw.print(" "); + pw.print("Times adaptive enabled: "); + pw.println(mAdaptiveBatterySaverEnabledCount); + pw.println(); pw.print(indent); @@ -436,8 +499,10 @@ public class BatterySavingStats { pw.print(interactiveLabel); pw.print(": "); - final Stat offStat = getStat(BatterySaverState.OFF, interactiveState, dozeState); - final Stat onStat = getStat(BatterySaverState.ON, interactiveState, dozeState); + final Stat offStat = getStat(BatterySaverState.OFF, interactiveState, dozeState, + PlugState.UNPLUGGED); + final Stat onStat = getStat(BatterySaverState.ON, interactiveState, dozeState, + PlugState.UNPLUGGED); pw.println(String.format("%6dm %6dmAh(%3d%%) %8.1fmAh/h %6dm %6dmAh(%3d%%) %8.1fmAh/h", offStat.totalMinutes(), diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index 4f18d07a843f..6ba675db0aed 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -640,7 +640,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba } for (String apexPackageName : apexPackageNames) { - // We will not recieve notifications when an apex is updated, + // We will not receive notifications when an apex is updated, // so check now in case any rollbacks ought to be expired. The // onPackagedReplace function is safe to call if the package // hasn't actually been updated. @@ -827,7 +827,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba } /** - * Do code and userdata backups to enable rollback of the given session. + * Do code and user-data backups to enable rollback of the given session. * In case of multiPackage sessions, <code>session</code> should be one of * the child sessions, not the parent session. * @@ -915,7 +915,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba } } - /** + /* * The order is important here! Always enable the embedded apk-in-apex (if any) before * enabling the embedding apex. Otherwise the rollback object might be in an inconsistent * state where an embedding apex is successfully enabled while one of its embedded @@ -1323,7 +1323,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba assertInWorkerThread(); int rollbackId = allocateRollbackId(); final int userId; - if (parentSession.getUser() == UserHandle.ALL) { + if (parentSession.getUser().equals(UserHandle.ALL)) { userId = UserHandle.SYSTEM.getIdentifier(); } else { userId = parentSession.getUser().getIdentifier(); diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java index d9415ce81636..3ec61fdda917 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java @@ -49,6 +49,7 @@ import com.android.server.timezonedetector.TimeZoneDetectorStrategy.StrategyList import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Iterator; import java.util.Objects; /** @@ -188,20 +189,14 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub int userId = UserHandle.getCallingUserId(); ConfigListenerInfo listenerInfo = new ConfigListenerInfo(userId, listener); - final IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() { - @Override - public void binderDied() { - synchronized (mConfigurationListeners) { - Slog.i(TAG, "Configuration listener died: " + listenerInfo); - mConfigurationListeners.remove(listenerInfo); - } - } - }; synchronized (mConfigurationListeners) { + if (mConfigurationListeners.contains(listenerInfo)) { + return; + } try { - // Remove the record of the listener if the client process dies. - listener.asBinder().linkToDeath(deathRecipient, 0 /* flags */); + // Ensure the reference to the listener is removed if the client process dies. + listenerInfo.linkToDeath(); // Only add the listener if we can linkToDeath(). mConfigurationListeners.add(listenerInfo); @@ -211,6 +206,31 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub } } + @Override + public void removeConfigurationListener(@NonNull ITimeZoneConfigurationListener listener) { + enforceManageTimeZoneDetectorConfigurationPermission(); + Objects.requireNonNull(listener); + int userId = UserHandle.getCallingUserId(); + + synchronized (mConfigurationListeners) { + ConfigListenerInfo toRemove = new ConfigListenerInfo(userId, listener); + Iterator<ConfigListenerInfo> listenerIterator = mConfigurationListeners.iterator(); + while (listenerIterator.hasNext()) { + ConfigListenerInfo currentListenerInfo = listenerIterator.next(); + if (currentListenerInfo.equals(toRemove)) { + listenerIterator.remove(); + + // Stop listening for the client process to die. + try { + currentListenerInfo.unlinkToDeath(); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to unlinkToDeath() for listener=" + listener, e); + } + } + } + } + } + void handleConfigurationChanged() { // Note: we could trigger an async time zone detection operation here via a call to // handleAutoTimeZoneDetectionChanged(), but that is triggered in response to the underlying @@ -319,7 +339,7 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub this, in, out, err, args, callback, resultReceiver); } - private static class ConfigListenerInfo { + private class ConfigListenerInfo implements IBinder.DeathRecipient { private final @UserIdInt int mUserId; private final ITimeZoneConfigurationListener mListener; @@ -337,6 +357,40 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub return mListener; } + void linkToDeath() throws RemoteException { + mListener.asBinder().linkToDeath(this, 0 /* flags */); + } + + void unlinkToDeath() throws RemoteException { + mListener.asBinder().unlinkToDeath(this, 0 /* flags */); + } + + @Override + public void binderDied() { + synchronized (mConfigurationListeners) { + Slog.i(TAG, "Configuration listener client died: " + this); + mConfigurationListeners.remove(this); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ConfigListenerInfo that = (ConfigListenerInfo) o; + return mUserId == that.mUserId + && mListener.equals(that.mListener); + } + + @Override + public int hashCode() { + return Objects.hash(mUserId, mListener); + } + @Override public String toString() { return "ConfigListenerInfo{" diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java index f5eed30a19bf..f5e1602ee6be 100644 --- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java +++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java @@ -51,6 +51,7 @@ import android.app.AppGlobals; import android.app.GrantedUriPermission; import android.app.IUriGrantsManager; import android.content.ClipData; +import android.content.ComponentName; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; @@ -698,6 +699,11 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub { final UriPermission perm = findOrCreateUriPermissionLocked( sourcePkg, targetPkg, targetUid, grantUri); perm.initPersistedModes(modeFlags, createdTime); + mPmInternal.grantImplicitAccess( + targetUserId, null, + UserHandle.getAppId(targetUid), + pi.applicationInfo.uid, + false /* direct */); } } else { Slog.w(TAG, "Persisted grant for " + uri + " had source " + sourcePkg @@ -1171,6 +1177,9 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub { // grant, we can skip generating any bookkeeping; when any advanced // features have been requested, we proceed below to make sure the // provider supports granting permissions + mPmInternal.grantImplicitAccess( + UserHandle.getUserId(targetUid), null, + UserHandle.getAppId(targetUid), pi.applicationInfo.uid, false); return -1; } diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index 189b21fb81a6..7565d8f9647c 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -396,8 +396,7 @@ class ActivityMetricsLogger { mLastLogTimeSecs = now; mWindowState = WINDOW_STATE_INVALID; - ActivityStack stack = - mSupervisor.mRootWindowContainer.getTopDisplayFocusedStack(); + Task stack = mSupervisor.mRootWindowContainer.getTopDisplayFocusedStack(); if (stack == null) { return; } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index a3acc1d90862..63ece0465993 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -136,18 +136,6 @@ import static com.android.server.wm.ActivityRecordProto.VISIBLE; import static com.android.server.wm.ActivityRecordProto.VISIBLE_REQUESTED; import static com.android.server.wm.ActivityRecordProto.VISIBLE_SET_FROM_TRANSFERRED_STARTING_WINDOW; import static com.android.server.wm.ActivityRecordProto.WINDOW_TOKEN; -import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED; -import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING; -import static com.android.server.wm.ActivityStack.ActivityState.FINISHING; -import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING; -import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; -import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; -import static com.android.server.wm.ActivityStack.ActivityState.RESTARTING_PROCESS; -import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; -import static com.android.server.wm.ActivityStack.ActivityState.STARTED; -import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; -import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; -import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_APP; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP; @@ -192,6 +180,18 @@ import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION; +import static com.android.server.wm.Task.ActivityState.DESTROYED; +import static com.android.server.wm.Task.ActivityState.DESTROYING; +import static com.android.server.wm.Task.ActivityState.FINISHING; +import static com.android.server.wm.Task.ActivityState.INITIALIZING; +import static com.android.server.wm.Task.ActivityState.PAUSED; +import static com.android.server.wm.Task.ActivityState.PAUSING; +import static com.android.server.wm.Task.ActivityState.RESTARTING_PROCESS; +import static com.android.server.wm.Task.ActivityState.RESUMED; +import static com.android.server.wm.Task.ActivityState.STARTED; +import static com.android.server.wm.Task.ActivityState.STOPPED; +import static com.android.server.wm.Task.ActivityState.STOPPING; +import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE; import static com.android.server.wm.TaskPersister.DEBUG; import static com.android.server.wm.TaskPersister.IMAGE_EXTENSION; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; @@ -309,8 +309,8 @@ import com.android.server.protolog.common.ProtoLog; import com.android.server.uri.NeededUriGrants; import com.android.server.uri.UriPermissionOwner; import com.android.server.wm.ActivityMetricsLogger.TransitionInfoSnapshot; -import com.android.server.wm.ActivityStack.ActivityState; import com.android.server.wm.SurfaceAnimator.AnimationType; +import com.android.server.wm.Task.ActivityState; import com.android.server.wm.WindowManagerService.H; import com.android.server.wm.utils.InsetUtils; @@ -1155,7 +1155,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } void updateMultiWindowMode() { - if (task == null || task.getStack() == null || !attachedToProcess()) { + if (task == null || task.getRootTask() == null || !attachedToProcess()) { return; } @@ -1180,7 +1180,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } void updatePictureInPictureMode(Rect targetStackBounds, boolean forceUpdate) { - if (task == null || task.getStack() == null || !attachedToProcess()) { + if (task == null || task.getRootTask() == null || !attachedToProcess()) { return; } @@ -1221,8 +1221,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A this.task = task; } - ActivityStack getStack() { - return task != null ? task.getStack() : null; + Task getStack() { + return task != null ? task.getRootTask() : null; } @Override @@ -1269,10 +1269,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (getDisplayContent() != null) { getDisplayContent().mClosingApps.remove(this); } - } else if (mLastParent != null && mLastParent.getStack() != null) { - task.getStack().mExitingActivities.remove(this); + } else if (mLastParent != null && mLastParent.getRootTask() != null) { + task.getRootTask().mExitingActivities.remove(this); } - final ActivityStack stack = getStack(); + final Task stack = getStack(); // If we reparent, make sure to remove ourselves from the old animation registry. if (mAnimatingActivityRegistry != null) { @@ -2125,8 +2125,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } /** @return Root task of this activity, null if there is no task. */ - ActivityStack getRootTask() { - return task != null ? (ActivityStack) task.getRootTask() : null; + Task getRootTask() { + return task != null ? task.getRootTask() : null; } int getRootTaskId() { @@ -2134,7 +2134,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } DisplayContent getDisplay() { - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); return stack != null ? stack.getDisplay() : null; } @@ -2204,7 +2204,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } boolean isInStackLocked() { - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); return stack != null && stack.isInTask(this) != null; } @@ -2414,7 +2414,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return false; } - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); if (stack == null) { Slog.w(TAG, "moveActivityStackToFront: invalid task or stack: activity=" + this + " task=" + task); @@ -2546,7 +2546,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return FINISH_RESULT_CANCELLED; } - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); final boolean mayAdjustTop = (isState(RESUMED) || stack.mResumedActivity == null) && stack.isFocusedStackOnDisplay(); final boolean shouldAdjustGlobalFocus = mayAdjustTop @@ -2576,7 +2576,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // We are finishing the top focused activity and its task has nothing to be focused so // the next focusable task should be focused. - if (mayAdjustTop && ((ActivityStack) task).topRunningActivity(true /* focusableOnly */) + if (mayAdjustTop && task.topRunningActivity(true /* focusableOnly */) == null) { task.adjustFocusToNextFocusableTask("finish-top", false /* allowFocusSelf */, shouldAdjustGlobalFocus); @@ -2705,7 +2705,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final boolean isCurrentVisible = mVisibleRequested || isState(PAUSED); if (isCurrentVisible) { - final ActivityStack stack = getStack(); + final Task stack = getStack(); final ActivityRecord activity = stack.mResumedActivity; boolean ensureVisibility = false; if (activity != null && !activity.occludesParent()) { @@ -2775,7 +2775,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Make sure the record is cleaned out of other places. mStackSupervisor.mStoppingActivities.remove(this); - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); final TaskDisplayArea taskDisplayArea = getDisplayArea(); // TODO(b/137329632): Exclude current activity when looking for the next one with // DisplayContent#topRunningActivity(). @@ -2935,7 +2935,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A boolean safelyDestroy(String reason) { if (isDestroyable()) { if (DEBUG_SWITCH) { - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); Slog.v(TAG_SWITCH, "Safely destroying " + this + " in state " + getState() + " resumed=" + stack.mResumedActivity + " pausing=" + stack.mPausingActivity @@ -2952,8 +2952,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A null /* resultData */, null /* resultGrants */); makeFinishingLocked(); if (ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE) { - Slog.i(TAG_ADD_REMOVE, "Removing activity " + this + " from stack callers=" - + Debug.getCallers(5)); + Slog.i(TAG_ADD_REMOVE, "Removing activity " + this + " from stack, reason=" + + reason + ", callers=" + Debug.getCallers(5)); } takeFromHistory(); @@ -3229,7 +3229,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A getDisplayContent().mNoAnimationNotifyOnTransitionFinished.add(token); } - final ActivityStack stack = getStack(); + final Task stack = getStack(); if (delayed && !isEmpty()) { // set the token aside because it has an active animation to be finished ProtoLog.v(WM_DEBUG_ADD_REMOVE, @@ -3743,7 +3743,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } final boolean isSleeping() { - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); return stack != null ? stack.shouldSleepActivities() : mAtmService.isSleepingLocked(); } @@ -4578,7 +4578,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return visibleIgnoringKeyguard; } - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); if (stack == null) { return false; } @@ -4615,7 +4615,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } boolean shouldBeVisible() { - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); if (stack == null) { return false; } @@ -4636,7 +4636,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // If this activity is paused, tell it to now show its window. if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making visible and scheduling visibility: " + this); - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); try { if (stack.mTranslucentActivityWaiting != null) { updateOptionsLocked(returningOptions); @@ -4913,7 +4913,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mStackSupervisor.reportResumedActivityLocked(this); resumeKeyDispatchingLocked(); - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); mStackSupervisor.mNoAnimActivities.clear(); // Mark the point when the activity is resuming @@ -4941,7 +4941,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Activity paused: token=" + appToken + ", timeout=" + timeout); - final ActivityStack stack = getStack(); + final Task stack = getStack(); if (stack != null) { removePauseTimeout(); @@ -5006,7 +5006,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A void stopIfPossible() { if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Stopping: " + this); - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); if (isNoHistory()) { if (!finishing) { if (!stack.shouldSleepActivities()) { @@ -5063,7 +5063,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A void activityStopped(Bundle newIcicle, PersistableBundle newPersistentState, CharSequence description) { - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); final boolean isStopping = mState == STOPPING; if (!isStopping && mState != RESTARTING_PROCESS) { Slog.i(TAG, "Activity reported stop, but no longer stopping: " + this); @@ -5113,7 +5113,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mStackSupervisor.mStoppingActivities.add(this); } - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); // If we already have a few activities waiting to stop, then give up on things going idle // and start clearing them out. Or if r is the last of activity of the last task the stack // will be empty and must be cleared immediately. @@ -5149,7 +5149,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return false; } - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); if (stack == null) { return false; } @@ -5165,7 +5165,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A void finishLaunchTickingLocked() { launchTickTime = 0; - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); if (stack == null) { return; } @@ -5596,7 +5596,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // First find the real culprit... if this activity has stopped, then the key dispatching // timeout should not be caused by this. if (stopped) { - final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack(); + final Task stack = mRootWindowContainer.getTopDisplayFocusedStack(); if (stack == null) { return this; } @@ -5660,7 +5660,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return (r != null) ? r.getRootTask().isInTask(r) : null; } - static ActivityStack getStackLocked(IBinder token) { + static Task getStackLocked(IBinder token) { final ActivityRecord r = ActivityRecord.isInStackLocked(token); if (r != null) { return r.getRootTask(); @@ -5673,7 +5673,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * {@link android.view.Display#INVALID_DISPLAY} if not attached. */ int getDisplayId() { - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); if (stack == null) { return INVALID_DISPLAY; } @@ -5685,7 +5685,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // This would be redundant. return false; } - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); if (isState(RESUMED) || stack == null || this == stack.mPausingActivity || !mHaveState || !stopped) { // We're not ready for this kind of thing. @@ -6007,7 +6007,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A getTransit(), task)) { task.getBounds(mTmpRect); } else { - final ActivityStack stack = getStack(); + final Task stack = getStack(); if (stack == null) { return; } @@ -6830,7 +6830,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A private void applyAspectRatio(Rect outBounds, Rect containingAppBounds, Rect containingBounds) { final float maxAspectRatio = info.maxAspectRatio; - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); final float minAspectRatio = info.minAspectRatio; if (task == null || stack == null || (inMultiWindowMode() && !shouldUseSizeCompatMode()) @@ -6936,7 +6936,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A */ boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow, boolean ignoreVisibility) { - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); if (stack.mConfigWillChange) { if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Skipping config check (will change): " + this); @@ -7487,7 +7487,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (!getTurnScreenOnFlag()) { return false; } - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); return stack != null && !stack.inMultiWindowMode() && stack.checkKeyguardVisibility(this, true /* shouldBeVisible */, diff --git a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java index 5dfc261480f2..8540fa7cf347 100644 --- a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java +++ b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java @@ -16,10 +16,10 @@ package com.android.server.wm; -import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; -import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.Task.ActivityState.PAUSING; +import static com.android.server.wm.Task.ActivityState.RESUMED; import android.util.ArraySet; import android.util.Slog; diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java deleted file mode 100644 index 9f0bf052ecad..000000000000 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ /dev/null @@ -1,3264 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.wm; - -import static android.app.ActivityTaskManager.INVALID_TASK_ID; -import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; -import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; -import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; -import static android.app.WindowConfiguration.activityTypeToString; -import static android.app.WindowConfiguration.windowingModeToString; -import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT; -import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING; -import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; -import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; -import static android.view.Display.DEFAULT_DISPLAY; -import static android.view.Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; -import static android.view.Display.INVALID_DISPLAY; -import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE; -import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN; -import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE; -import static android.view.WindowManager.TRANSIT_NONE; -import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY; -import static android.view.WindowManager.TRANSIT_TASK_CLOSE; -import static android.view.WindowManager.TRANSIT_TASK_OPEN; -import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND; -import static android.view.WindowManager.TRANSIT_TASK_TO_BACK; -import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT; - -import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; -import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; -import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; -import static com.android.server.wm.ActivityStack.ActivityState.STARTED; -import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; -import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; -import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME; -import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; -import static com.android.server.wm.ActivityStackSupervisor.dumpHistoryList; -import static com.android.server.wm.ActivityStackSupervisor.printThisActivity; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_APP; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_APP; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CLEANUP; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATES; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TRANSITION; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_USER_LEAVING; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_STACK_MSG; -import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; -import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; -import static com.android.server.wm.TaskProto.ACTIVITY_TYPE; -import static com.android.server.wm.TaskProto.ANIMATING_BOUNDS; -import static com.android.server.wm.TaskProto.BOUNDS; -import static com.android.server.wm.TaskProto.CREATED_BY_ORGANIZER; -import static com.android.server.wm.TaskProto.DISPLAY_ID; -import static com.android.server.wm.TaskProto.FILLS_PARENT; -import static com.android.server.wm.TaskProto.LAST_NON_FULLSCREEN_BOUNDS; -import static com.android.server.wm.TaskProto.MIN_HEIGHT; -import static com.android.server.wm.TaskProto.MIN_WIDTH; -import static com.android.server.wm.TaskProto.ORIG_ACTIVITY; -import static com.android.server.wm.TaskProto.REAL_ACTIVITY; -import static com.android.server.wm.TaskProto.RESIZE_MODE; -import static com.android.server.wm.TaskProto.RESUMED_ACTIVITY; -import static com.android.server.wm.TaskProto.ROOT_TASK_ID; -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.TAG_WM; - -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; -import android.app.ActivityOptions; -import android.app.AppGlobals; -import android.app.IActivityController; -import android.app.RemoteAction; -import android.app.ResultInfo; -import android.app.servertransaction.ActivityResultItem; -import android.app.servertransaction.ClientTransaction; -import android.app.servertransaction.NewIntentItem; -import android.app.servertransaction.PauseActivityItem; -import android.app.servertransaction.ResumeActivityItem; -import android.content.ComponentName; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.content.res.Configuration; -import android.graphics.Point; -import android.graphics.Rect; -import android.os.Binder; -import android.os.Debug; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.RemoteException; -import android.os.SystemClock; -import android.os.Trace; -import android.os.UserHandle; -import android.service.voice.IVoiceInteractionSession; -import android.util.Log; -import android.util.Slog; -import android.util.proto.ProtoOutputStream; -import android.view.Display; -import android.view.DisplayInfo; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.app.IVoiceInteractor; -import com.android.internal.os.logging.MetricsLoggerWrapper; -import com.android.internal.util.function.pooled.PooledConsumer; -import com.android.internal.util.function.pooled.PooledFunction; -import com.android.internal.util.function.pooled.PooledLambda; -import com.android.server.Watchdog; -import com.android.server.am.ActivityManagerService; -import com.android.server.am.ActivityManagerService.ItemMatcher; -import com.android.server.am.AppTimeTracker; -import com.android.server.uri.NeededUriGrants; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Consumer; - -/** - * State and management of a single stack of activities. - */ -class ActivityStack extends Task { - private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_ATM; - static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE; - private static final String TAG_APP = TAG + POSTFIX_APP; - static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP; - private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE; - private static final String TAG_RELEASE = TAG + POSTFIX_RELEASE; - private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS; - private static final String TAG_STACK = TAG + POSTFIX_STACK; - private static final String TAG_STATES = TAG + POSTFIX_STATES; - private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH; - static final String TAG_TASKS = TAG + POSTFIX_TASKS; - private static final String TAG_TRANSITION = TAG + POSTFIX_TRANSITION; - private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING; - static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY; - - // Set to false to disable the preview that is shown while a new activity - // is being started. - private static final boolean SHOW_APP_STARTING_PREVIEW = true; - - // How long to wait for all background Activities to redraw following a call to - // convertToTranslucent(). - private static final long TRANSLUCENT_CONVERSION_TIMEOUT = 2000; - - @IntDef(prefix = {"STACK_VISIBILITY"}, value = { - STACK_VISIBILITY_VISIBLE, - STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, - STACK_VISIBILITY_INVISIBLE, - }) - @interface StackVisibility {} - - /** Stack is visible. No other stacks on top that fully or partially occlude it. */ - static final int STACK_VISIBILITY_VISIBLE = 0; - - /** Stack is partially occluded by other translucent stack(s) on top of it. */ - static final int STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT = 1; - - /** Stack is completely invisible. */ - static final int STACK_VISIBILITY_INVISIBLE = 2; - - enum ActivityState { - INITIALIZING, - STARTED, - RESUMED, - PAUSING, - PAUSED, - STOPPING, - STOPPED, - FINISHING, - DESTROYING, - DESTROYED, - RESTARTING_PROCESS - } - - // The topmost Activity passed to convertToTranslucent(). When non-null it means we are - // waiting for all Activities in mUndrawnActivitiesBelowTopTranslucent to be removed as they - // are drawn. When the last member of mUndrawnActivitiesBelowTopTranslucent is removed the - // Activity in mTranslucentActivityWaiting is notified via - // Activity.onTranslucentConversionComplete(false). If a timeout occurs prior to the last - // background activity being drawn then the same call will be made with a true value. - ActivityRecord mTranslucentActivityWaiting = null; - ArrayList<ActivityRecord> mUndrawnActivitiesBelowTopTranslucent = new ArrayList<>(); - - /** - * Set when we know we are going to be calling updateConfiguration() - * soon, so want to skip intermediate config checks. - */ - boolean mConfigWillChange; - - /** - * Used to keep resumeTopActivityUncheckedLocked() from being entered recursively - */ - boolean mInResumeTopActivity = false; - - int mCurrentUser; - - /** For comparison with DisplayContent bounds. */ - private Rect mTmpRect = new Rect(); - private Rect mTmpRect2 = new Rect(); - - // If this is true, we are in the bounds animating mode. The task will be down or upscaled to - // perfectly fit the region it would have been cropped to. We may also avoid certain logic we - // would otherwise apply while resizing, while resizing in the bounds animating mode. - private boolean mBoundsAnimating = false; - // Set when an animation has been requested but has not yet started from the UI thread. This is - // cleared when the animation actually starts. - private boolean mBoundsAnimatingRequested = false; - private Rect mBoundsAnimationTarget = new Rect(); - private Rect mBoundsAnimationSourceHintBounds = new Rect(); - - Rect mPreAnimationBounds = new Rect(); - - private final AnimatingActivityRegistry mAnimatingActivityRegistry = - new AnimatingActivityRegistry(); - - private boolean mTopActivityOccludesKeyguard; - private ActivityRecord mTopDismissingKeyguardActivity; - - private static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 1; - - private final Handler mHandler; - - private class ActivityStackHandler extends Handler { - - ActivityStackHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case TRANSLUCENT_TIMEOUT_MSG: { - synchronized (mAtmService.mGlobalLock) { - notifyActivityDrawnLocked(null); - } - } break; - } - } - } - - private static final ResetTargetTaskHelper sResetTargetTaskHelper = new ResetTargetTaskHelper(); - private final EnsureActivitiesVisibleHelper mEnsureActivitiesVisibleHelper = - new EnsureActivitiesVisibleHelper(this); - private final EnsureVisibleActivitiesConfigHelper mEnsureVisibleActivitiesConfigHelper = - new EnsureVisibleActivitiesConfigHelper(); - private class EnsureVisibleActivitiesConfigHelper { - private boolean mUpdateConfig; - private boolean mPreserveWindow; - private boolean mBehindFullscreen; - - void reset(boolean preserveWindow) { - mPreserveWindow = preserveWindow; - mUpdateConfig = false; - mBehindFullscreen = false; - } - - void process(ActivityRecord start, boolean preserveWindow) { - if (start == null || !start.mVisibleRequested) { - return; - } - reset(preserveWindow); - - final PooledFunction f = PooledLambda.obtainFunction( - EnsureVisibleActivitiesConfigHelper::processActivity, this, - PooledLambda.__(ActivityRecord.class)); - forAllActivities(f, start, true /*includeBoundary*/, true /*traverseTopToBottom*/); - f.recycle(); - - if (mUpdateConfig) { - // Ensure the resumed state of the focus activity if we updated the configuration of - // any activity. - mRootWindowContainer.resumeFocusedStacksTopActivities(); - } - } - - boolean processActivity(ActivityRecord r) { - mUpdateConfig |= r.ensureActivityConfiguration(0 /*globalChanges*/, mPreserveWindow); - mBehindFullscreen |= r.occludesParent(); - return mBehindFullscreen; - } - } - - // TODO: Can we just loop through WindowProcessController#mActivities instead of doing this? - private final RemoveHistoryRecordsForApp mRemoveHistoryRecordsForApp = - new RemoveHistoryRecordsForApp(); - private class RemoveHistoryRecordsForApp { - private boolean mHasVisibleActivities; - private boolean mIsProcessRemoved; - private WindowProcessController mApp; - private ArrayList<ActivityRecord> mToRemove = new ArrayList<>(); - - boolean process(WindowProcessController app) { - mToRemove.clear(); - mHasVisibleActivities = false; - mApp = app; - mIsProcessRemoved = app.isRemoved(); - if (mIsProcessRemoved) { - // The package of the died process should be force-stopped, so make its activities - // as finishing to prevent the process from being started again if the next top - // (or being visible) activity also resides in the same process. - app.makeFinishingForProcessRemoved(); - } - - final PooledConsumer c = PooledLambda.obtainConsumer( - RemoveHistoryRecordsForApp::addActivityToRemove, this, - PooledLambda.__(ActivityRecord.class)); - forAllActivities(c); - c.recycle(); - - while (!mToRemove.isEmpty()) { - processActivity(mToRemove.remove(0)); - } - - mApp = null; - return mHasVisibleActivities; - } - - private void addActivityToRemove(ActivityRecord r) { - if (r.app == mApp) { - mToRemove.add(r); - } - } - - private void processActivity(ActivityRecord r) { - if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP, "Record " + r + ": app=" + r.app); - - if (r.app != mApp) { - return; - } - if (r.isVisible() || r.mVisibleRequested) { - // While an activity launches a new activity, it's possible that the old - // activity is already requested to be hidden (mVisibleRequested=false), but - // this visibility is not yet committed, so isVisible()=true. - mHasVisibleActivities = true; - } - final boolean remove; - if ((r.mRelaunchReason == RELAUNCH_REASON_WINDOWING_MODE_RESIZE - || r.mRelaunchReason == RELAUNCH_REASON_FREE_RESIZE) - && r.launchCount < 3 && !r.finishing) { - // If the process crashed during a resize, always try to relaunch it, unless - // it has failed more than twice. Skip activities that's already finishing - // cleanly by itself. - remove = false; - } else if ((!r.hasSavedState() && !r.stateNotNeeded - && !r.isState(ActivityState.RESTARTING_PROCESS)) || r.finishing) { - // Don't currently have state for the activity, or - // it is finishing -- always remove it. - remove = true; - } else if (!r.mVisibleRequested && r.launchCount > 2 - && r.lastLaunchTime > (SystemClock.uptimeMillis() - 60000)) { - // We have launched this activity too many times since it was - // able to run, so give up and remove it. - // (Note if the activity is visible, we don't remove the record. - // We leave the dead window on the screen but the process will - // not be restarted unless user explicitly tap on it.) - remove = true; - } else { - // The process may be gone, but the activity lives on! - remove = false; - } - if (remove) { - if (DEBUG_ADD_REMOVE || DEBUG_CLEANUP) Slog.i(TAG_ADD_REMOVE, - "Removing activity " + r + " from stack " - + ": hasSavedState=" + r.hasSavedState() - + " stateNotNeeded=" + r.stateNotNeeded - + " finishing=" + r.finishing - + " state=" + r.getState() + " callers=" + Debug.getCallers(5)); - if (!r.finishing || mIsProcessRemoved) { - Slog.w(TAG, "Force removing " + r + ": app died, no saved state"); - EventLogTags.writeWmFinishActivity(r.mUserId, - System.identityHashCode(r), r.getTask().mTaskId, - r.shortComponentName, "proc died without state saved"); - } - } else { - // We have the current state for this activity, so - // it can be restarted later when needed. - if (DEBUG_ALL) Slog.v(TAG, "Keeping entry, setting app to null"); - if (DEBUG_APP) Slog.v(TAG_APP, - "Clearing app during removeHistory for activity " + r); - r.app = null; - // Set nowVisible to previous visible state. If the app was visible while - // it died, we leave the dead window on screen so it's basically visible. - // This is needed when user later tap on the dead window, we need to stop - // other apps when user transfers focus to the restarted activity. - r.nowVisible = r.mVisibleRequested; - } - r.cleanUp(true /* cleanServices */, true /* setState */); - if (remove) { - r.removeFromHistory("appDied"); - } - } - } - - ActivityStack(ActivityTaskManagerService atmService, int id, int activityType, - ActivityInfo info, Intent intent, boolean createdByOrganizer) { - this(atmService, id, info, intent, null /*voiceSession*/, null /*voiceInteractor*/, - null /*taskDescription*/, null /*stack*/); - mCreatedByOrganizer = createdByOrganizer; - setActivityType(activityType); - } - - ActivityStack(ActivityTaskManagerService atmService, int id, ActivityInfo info, Intent _intent, - IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, - ActivityManager.TaskDescription _taskDescription, ActivityStack stack) { - this(atmService, id, _intent, null /*_affinityIntent*/, null /*_affinity*/, - null /*_rootAffinity*/, null /*_realActivity*/, null /*_origActivity*/, - false /*_rootWasReset*/, false /*_autoRemoveRecents*/, false /*_askedCompatMode*/, - UserHandle.getUserId(info.applicationInfo.uid), 0 /*_effectiveUid*/, - null /*_lastDescription*/, System.currentTimeMillis(), - true /*neverRelinquishIdentity*/, - _taskDescription != null ? _taskDescription : new ActivityManager.TaskDescription(), - id, INVALID_TASK_ID, INVALID_TASK_ID, - info.applicationInfo.uid, info.packageName, null, info.resizeMode, - info.supportsPictureInPicture(), false /*_realActivitySuspended*/, - false /*userSetupComplete*/, INVALID_MIN_SIZE, INVALID_MIN_SIZE, info, - _voiceSession, _voiceInteractor, stack); - } - - ActivityStack(ActivityTaskManagerService atmService, int id, 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, - ActivityManager.TaskDescription _lastTaskDescription, int taskAffiliation, - int prevTaskId, int nextTaskId, int callingUid, - 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, - callingUid, callingPackage, callingFeatureId, resizeMode, supportsPictureInPicture, - _realActivitySuspended, userSetupComplete, minWidth, minHeight, info, _voiceSession, - _voiceInteractor, stack); - - EventLogTags.writeWmStackCreated(id); - mHandler = new ActivityStackHandler(mStackSupervisor.mLooper); - mCurrentUser = mAtmService.mAmInternal.getCurrentUserId(); - } - - @Override - public void onConfigurationChanged(Configuration newParentConfig) { - // Calling Task#onConfigurationChanged() for leaf task since the ops in this method are - // particularly for ActivityStack, like preventing bounds changes when inheriting certain - // windowing mode. - if (!isRootTask()) { - super.onConfigurationChanged(newParentConfig); - return; - } - - final int prevWindowingMode = getWindowingMode(); - final boolean prevIsAlwaysOnTop = isAlwaysOnTop(); - final int prevRotation = getWindowConfiguration().getRotation(); - final Rect newBounds = mTmpRect; - // Initialize the new bounds by previous bounds as the input and output for calculating - // override bounds in pinned (pip) or split-screen mode. - getBounds(newBounds); - - super.onConfigurationChanged(newParentConfig); - - final TaskDisplayArea taskDisplayArea = getDisplayArea(); - if (taskDisplayArea == null) { - return; - } - - if (prevWindowingMode != getWindowingMode()) { - taskDisplayArea.onStackWindowingModeChanged(this); - } - - final DisplayContent display = getDisplay(); - if (display == null ) { - return; - } - - final boolean windowingModeChanged = prevWindowingMode != getWindowingMode(); - final int overrideWindowingMode = getRequestedOverrideWindowingMode(); - // Update bounds if applicable - boolean hasNewOverrideBounds = false; - // Use override windowing mode to prevent extra bounds changes if inheriting the mode. - if ((overrideWindowingMode != WINDOWING_MODE_PINNED) - && !getRequestedOverrideBounds().isEmpty()) { - // If the parent (display) has rotated, rotate our bounds to best-fit where their - // bounds were on the pre-rotated display. - final int newRotation = getWindowConfiguration().getRotation(); - final boolean rotationChanged = prevRotation != newRotation; - if (rotationChanged) { - display.mDisplayContent.rotateBounds( - newParentConfig.windowConfiguration.getBounds(), prevRotation, newRotation, - newBounds); - hasNewOverrideBounds = true; - } - } - - if (windowingModeChanged) { - taskDisplayArea.onStackWindowingModeChanged(this); - } - if (hasNewOverrideBounds) { - if (inSplitScreenWindowingMode()) { - setBounds(newBounds); - } else if (overrideWindowingMode != WINDOWING_MODE_PINNED) { - // For pinned stack, resize is now part of the {@link WindowContainerTransaction} - resize(new Rect(newBounds), PRESERVE_WINDOWS, true /* deferResume */); - } - } - if (prevIsAlwaysOnTop != isAlwaysOnTop()) { - // Since always on top is only on when the stack is freeform or pinned, the state - // can be toggled when the windowing mode changes. We must make sure the stack is - // placed properly when always on top state changes. - taskDisplayArea.positionStackAtTop(this, false /* includingParents */); - } - } - - @Override - public void setWindowingMode(int windowingMode) { - // Reset the cached result of toString() - stringName = null; - - // Calling Task#setWindowingMode() for leaf task since this is the a specialization of - // {@link #setWindowingMode(int)} for ActivityStack. - if (!isRootTask()) { - super.setWindowingMode(windowingMode); - return; - } - - setWindowingMode(windowingMode, false /* creating */); - } - - /** - * Specialization of {@link #setWindowingMode(int)} for this subclass. - * - * @param preferredWindowingMode the preferred windowing mode. This may not be honored depending - * on the state of things. For example, WINDOWING_MODE_UNDEFINED will resolve to the - * previous non-transient mode if this stack is currently in a transient mode. - * @param creating {@code true} if this is being run during ActivityStack construction. - */ - void setWindowingMode(int preferredWindowingMode, boolean creating) { - mWmService.inSurfaceTransaction(() -> setWindowingModeInSurfaceTransaction( - preferredWindowingMode, creating)); - } - - private void setWindowingModeInSurfaceTransaction(int preferredWindowingMode, - boolean creating) { - final TaskDisplayArea taskDisplayArea = getDisplayArea(); - if (taskDisplayArea == null) { - Slog.d(TAG, "taskDisplayArea is null, bail early"); - return; - } - final int currentMode = getWindowingMode(); - final int currentOverrideMode = getRequestedOverrideWindowingMode(); - final Task topTask = getTopMostTask(); - int windowingMode = preferredWindowingMode; - - // Need to make sure windowing mode is supported. If we in the process of creating the stack - // no need to resolve the windowing mode again as it is already resolved to the right mode. - if (!creating) { - if (!taskDisplayArea.isValidWindowingMode(windowingMode, null /* ActivityRecord */, - topTask, getActivityType())) { - windowingMode = WINDOWING_MODE_UNDEFINED; - } - } - - final boolean alreadyInSplitScreenMode = taskDisplayArea.isSplitScreenModeActivated(); - - if (creating && alreadyInSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN - && isActivityTypeStandardOrUndefined()) { - // If the stack is being created explicitly in fullscreen mode, dismiss split-screen - // and display a warning toast about it. - mAtmService.getTaskChangeNotificationController() - .notifyActivityDismissingDockedStack(); - taskDisplayArea.onSplitScreenModeDismissed(this); - } - - if (currentMode == windowingMode) { - // You are already in the window mode, so we can skip most of the work below. However, - // it's possible that we have inherited the current windowing mode from a parent. So, - // fulfill this method's contract by setting the override mode directly. - getRequestedOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode); - return; - } - - final ActivityRecord topActivity = getTopNonFinishingActivity(); - - // For now, assume that the Stack's windowing mode is what will actually be used - // by it's activities. In the future, there may be situations where this doesn't - // happen; so at that point, this message will need to handle that. - int likelyResolvedMode = windowingMode; - if (windowingMode == WINDOWING_MODE_UNDEFINED) { - final ConfigurationContainer parent = getParent(); - likelyResolvedMode = parent != null ? parent.getWindowingMode() - : WINDOWING_MODE_FULLSCREEN; - } - if (currentMode == WINDOWING_MODE_PINNED) { - mAtmService.getTaskChangeNotificationController().notifyActivityUnpinned(); - } - if (likelyResolvedMode == WINDOWING_MODE_PINNED - && taskDisplayArea.getRootPinnedTask() != null) { - // Can only have 1 pip at a time, so replace an existing pip - taskDisplayArea.getRootPinnedTask().dismissPip(); - } - if (likelyResolvedMode != WINDOWING_MODE_FULLSCREEN - && topActivity != null && !topActivity.noDisplay - && topActivity.isNonResizableOrForcedResizable(likelyResolvedMode)) { - // Inform the user that they are starting an app that may not work correctly in - // multi-window mode. - final String packageName = topActivity.info.applicationInfo.packageName; - mAtmService.getTaskChangeNotificationController().notifyActivityForcedResizable( - topTask.mTaskId, FORCED_RESIZEABLE_REASON_SPLIT_SCREEN, packageName); - } - - mAtmService.deferWindowLayout(); - try { - if (topActivity != null) { - mStackSupervisor.mNoAnimActivities.add(topActivity); - } - super.setWindowingMode(windowingMode); - // setWindowingMode triggers an onConfigurationChanged cascade which can result in a - // different resolved windowing mode (usually when preferredWindowingMode is UNDEFINED). - windowingMode = getWindowingMode(); - - if (creating) { - // Nothing else to do if we don't have a window container yet. E.g. call from ctor. - return; - } - - if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && alreadyInSplitScreenMode) { - // We already have a split-screen stack in this display, so just move the tasks over. - // TODO: Figure-out how to do all the stuff in - // AMS.setTaskWindowingModeSplitScreenPrimary - throw new IllegalArgumentException("Setting primary split-screen windowing mode" - + " while there is already one isn't currently supported"); - //return; - } - } finally { - mAtmService.continueWindowLayout(); - } - - mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); - mRootWindowContainer.resumeFocusedStacksTopActivities(); - } - - @Override - public boolean isCompatible(int windowingMode, int activityType) { - // TODO: Should we just move this to ConfigurationContainer? - if (activityType == ACTIVITY_TYPE_UNDEFINED) { - // Undefined activity types end up in a standard stack once the stack is created on a - // display, so they should be considered compatible. - activityType = ACTIVITY_TYPE_STANDARD; - } - return super.isCompatible(windowingMode, activityType); - } - - /** Resume next focusable stack after reparenting to another display. */ - void postReparent() { - adjustFocusToNextFocusableTask("reparent", true /* allowFocusSelf */, - true /* moveDisplayToTop */); - mRootWindowContainer.resumeFocusedStacksTopActivities(); - // Update visibility of activities before notifying WM. This way it won't try to resize - // windows that are no longer visible. - mRootWindowContainer.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, - !PRESERVE_WINDOWS); - } - - DisplayContent getDisplay() { - return getDisplayContent(); - } - - /** @return true if the stack can only contain one task */ - boolean isSingleTaskInstance() { - final DisplayContent display = getDisplay(); - return display != null && display.isSingleTaskInstance(); - } - - final boolean isHomeOrRecentsStack() { - return isActivityTypeHome() || isActivityTypeRecents(); - } - - final boolean isOnHomeDisplay() { - return getDisplayId() == DEFAULT_DISPLAY; - } - - void moveToFront(String reason) { - moveToFront(reason, null); - } - - /** - * @param reason The reason for moving the stack to the front. - * @param task If non-null, the task will be moved to the top of the stack. - * */ - void moveToFront(String reason, Task task) { - if (!isAttached()) { - return; - } - - final TaskDisplayArea taskDisplayArea = getDisplayArea(); - - if (inSplitScreenSecondaryWindowingMode()) { - // If the stack is in split-screen secondary mode, we need to make sure we move the - // primary split-screen stack forward in the case it is currently behind a fullscreen - // stack so both halves of the split-screen appear on-top and the fullscreen stack isn't - // cutting between them. - // TODO(b/70677280): This is a workaround until we can fix as part of b/70677280. - final ActivityStack topFullScreenStack = - taskDisplayArea.getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN); - if (topFullScreenStack != null) { - final ActivityStack primarySplitScreenStack = - taskDisplayArea.getRootSplitScreenPrimaryTask(); - if (primarySplitScreenStack != null - && taskDisplayArea.getIndexOf(topFullScreenStack) - > taskDisplayArea.getIndexOf(primarySplitScreenStack)) { - primarySplitScreenStack.moveToFront(reason + " splitScreenToTop"); - } - } - } - - if (!isActivityTypeHome() && returnsToHomeStack()) { - // Make sure the home stack is behind this stack since that is where we should return to - // when this stack is no longer visible. - taskDisplayArea.moveHomeStackToFront(reason + " returnToHome"); - } - - if (isRootTask()) { - taskDisplayArea.positionStackAtTop(this, false /* includingParents */, reason); - } - if (task == null) { - task = this; - } - task.getParent().positionChildAt(POSITION_TOP, task, true /* includingParents */); - } - - /** - * This moves 'task' to the back of this task and also recursively moves this task to the back - * of its parents (if applicable). - * - * @param reason The reason for moving the stack to the back. - * @param task If non-null, the task will be moved to the bottom of the stack. - **/ - void moveToBack(String reason, Task task) { - if (!isAttached()) { - return; - } - final TaskDisplayArea displayArea = getDisplayArea(); - if (!mCreatedByOrganizer) { - // If this is just a normal task, so move to back of parent and then move 'task' to - // back of this. - final WindowContainer parent = getParent(); - final Task parentTask = parent != null ? parent.asTask() : null; - if (parentTask != null) { - ((ActivityStack) parentTask).moveToBack(reason, this); - } else { - displayArea.positionStackAtBottom(this, reason); - } - if (task != null && task != this) { - positionChildAtBottom(task); - } - return; - } - if (task == null || task == this) { - return; - } - // This is a created-by-organizer task. In this case, let the organizer deal with this - // task's ordering. However, we still need to move 'task' to back. The intention is that - // this ends up behind the home-task so that it is made invisible; so, if the home task - // is not a child of this, reparent 'task' to the back of the home task's actual parent. - displayArea.positionTaskBehindHome((ActivityStack) task); - } - - // TODO: Should each user have there own stacks? - @Override - void switchUser(int userId) { - if (mCurrentUser == userId) { - return; - } - mCurrentUser = userId; - - super.switchUser(userId); - forAllLeafTasks((t) -> { - if (t.showToCurrentUser() && t != this) { - mChildren.remove(t); - mChildren.add(t); - } - }, true /* traverseTopToBottom */); - } - - void minimalResumeActivityLocked(ActivityRecord r) { - if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + r + " (starting new instance)" - + " callers=" + Debug.getCallers(5)); - r.setState(RESUMED, "minimalResumeActivityLocked"); - r.completeResumeLocked(); - } - - private void clearLaunchTime(ActivityRecord r) { - // Make sure that there is no activity waiting for this to launch. - if (!mStackSupervisor.mWaitingActivityLaunched.isEmpty()) { - mStackSupervisor.removeIdleTimeoutForActivity(r); - mStackSupervisor.scheduleIdleTimeout(r); - } - } - - void awakeFromSleepingLocked() { - // Ensure activities are no longer sleeping. - forAllActivities((Consumer<ActivityRecord>) (r) -> r.setSleeping(false)); - if (mPausingActivity != null) { - Slog.d(TAG, "awakeFromSleepingLocked: previously pausing activity didn't pause"); - mPausingActivity.activityPaused(true); - } - } - - void checkReadyForSleep() { - if (shouldSleepActivities() && goToSleepIfPossible(false /* shuttingDown */)) { - mStackSupervisor.checkReadyForSleepLocked(true /* allowDelay */); - } - } - - /** - * Tries to put the activities in the stack to sleep. - * - * If the stack is not in a state where its activities can be put to sleep, this function will - * start any necessary actions to move the stack into such a state. It is expected that this - * function get called again when those actions complete. - * - * @param shuttingDown true when the called because the device is shutting down. - * @return true if the stack finished going to sleep, false if the stack only started the - * process of going to sleep (checkReadyForSleep will be called when that process finishes). - */ - boolean goToSleepIfPossible(boolean shuttingDown) { - boolean shouldSleep = true; - - if (mResumedActivity != null) { - // Still have something resumed; can't sleep until it is paused. - if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep needs to pause " + mResumedActivity); - if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING, - "Sleep => pause with userLeaving=false"); - - startPausingLocked(false /* userLeaving */, true /* uiSleeping */, null /* resuming */); - shouldSleep = false ; - } else if (mPausingActivity != null) { - // Still waiting for something to pause; can't sleep yet. - if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still waiting to pause " + mPausingActivity); - shouldSleep = false; - } - - if (!shuttingDown) { - if (containsActivityFromStack(mStackSupervisor.mStoppingActivities)) { - // Still need to tell some activities to stop; can't sleep yet. - if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to stop " - + mStackSupervisor.mStoppingActivities.size() + " activities"); - - mStackSupervisor.scheduleIdle(); - shouldSleep = false; - } - } - - if (shouldSleep) { - goToSleep(); - } - - return shouldSleep; - } - - void goToSleep() { - // Make sure all visible activities are now sleeping. This will update the activity's - // visibility and onStop() will be called. - forAllActivities((r) -> { - if (r.isState(STARTED, RESUMED, PAUSING, PAUSED, STOPPING, STOPPED)) { - r.setSleeping(true); - } - }); - - // Ensure visibility after updating sleep states without updating configuration, - // as activities are about to be sent to sleep. - ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, - !PRESERVE_WINDOWS); - } - - private boolean containsActivityFromStack(List<ActivityRecord> rs) { - for (ActivityRecord r : rs) { - if (r.getRootTask() == this) { - return true; - } - } - return false; - } - - /** - * Start pausing the currently resumed activity. It is an error to call this if there - * is already an activity being paused or there is no resumed activity. - * - * @param userLeaving True if this should result in an onUserLeaving to the current activity. - * @param uiSleeping True if this is happening with the user interface going to sleep (the - * screen turning off). - * @param resuming The activity we are currently trying to resume or null if this is not being - * called as part of resuming the top activity, so we shouldn't try to instigate - * a resume here if not null. - * @return Returns true if an activity now is in the PAUSING state, and we are waiting for - * it to tell us when it is done. - */ - final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, - ActivityRecord resuming) { - if (mPausingActivity != null) { - Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity - + " state=" + mPausingActivity.getState()); - if (!shouldSleepActivities()) { - // Avoid recursion among check for sleep and complete pause during sleeping. - // Because activity will be paused immediately after resume, just let pause - // be completed by the order of activity paused from clients. - completePauseLocked(false, resuming); - } - } - ActivityRecord prev = mResumedActivity; - - if (prev == null) { - if (resuming == null) { - Slog.wtf(TAG, "Trying to pause when nothing is resumed"); - mRootWindowContainer.resumeFocusedStacksTopActivities(); - } - return false; - } - - if (prev == resuming) { - Slog.wtf(TAG, "Trying to pause activity that is in process of being resumed"); - return false; - } - - if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSING: " + prev); - else if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Start pausing: " + prev); - mPausingActivity = prev; - mLastPausedActivity = prev; - mLastNoHistoryActivity = prev.isNoHistory() ? prev : null; - prev.setState(PAUSING, "startPausingLocked"); - prev.getTask().touchActiveTime(); - clearLaunchTime(prev); - - mAtmService.updateCpuStats(); - - boolean pauseImmediately = false; - if (resuming != null && (resuming.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0) { - // If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous - // activity to be paused, while at the same time resuming the new resume activity - // only if the previous activity can't go into Pip since we want to give Pip - // activities a chance to enter Pip before resuming the next activity. - final boolean lastResumedCanPip = prev != null && prev.checkEnterPictureInPictureState( - "shouldResumeWhilePausing", userLeaving); - if (!lastResumedCanPip) { - pauseImmediately = true; - } - } - - if (prev.attachedToProcess()) { - if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev); - try { - EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev), - prev.shortComponentName, "userLeaving=" + userLeaving); - - mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(), - prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving, - prev.configChangeFlags, pauseImmediately)); - } catch (Exception e) { - // Ignore exception, if process died other code will cleanup. - Slog.w(TAG, "Exception thrown during pause", e); - mPausingActivity = null; - mLastPausedActivity = null; - mLastNoHistoryActivity = null; - } - } else { - mPausingActivity = null; - mLastPausedActivity = null; - mLastNoHistoryActivity = null; - } - - // If we are not going to sleep, we want to ensure the device is - // awake until the next activity is started. - if (!uiSleeping && !mAtmService.isSleepingOrShuttingDownLocked()) { - mStackSupervisor.acquireLaunchWakelock(); - } - - if (mPausingActivity != null) { - // Have the window manager pause its key dispatching until the new - // activity has started. If we're pausing the activity just because - // the screen is being turned off and the UI is sleeping, don't interrupt - // key dispatch; the same activity will pick it up again on wakeup. - if (!uiSleeping) { - prev.pauseKeyDispatchingLocked(); - } else if (DEBUG_PAUSE) { - Slog.v(TAG_PAUSE, "Key dispatch not paused for screen off"); - } - - if (pauseImmediately) { - // If the caller said they don't want to wait for the pause, then complete - // the pause now. - completePauseLocked(false, resuming); - return false; - - } else { - prev.schedulePauseTimeout(); - return true; - } - - } else { - // This activity failed to schedule the - // pause, so just treat it as being paused now. - if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Activity not running, resuming next."); - if (resuming == null) { - mRootWindowContainer.resumeFocusedStacksTopActivities(); - } - return false; - } - } - - @VisibleForTesting - void completePauseLocked(boolean resumeNext, ActivityRecord resuming) { - ActivityRecord prev = mPausingActivity; - if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Complete pause: " + prev); - - if (prev != null) { - prev.setWillCloseOrEnterPip(false); - final boolean wasStopping = prev.isState(STOPPING); - prev.setState(PAUSED, "completePausedLocked"); - if (prev.finishing) { - if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev); - prev = prev.completeFinishing("completePausedLocked"); - } else if (prev.hasProcess()) { - if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev - + " wasStopping=" + wasStopping - + " visibleRequested=" + prev.mVisibleRequested); - if (prev.deferRelaunchUntilPaused) { - // Complete the deferred relaunch that was waiting for pause to complete. - if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Re-launching after pause: " + prev); - prev.relaunchActivityLocked(prev.preserveWindowOnDeferredRelaunch); - } else if (wasStopping) { - // We are also stopping, the stop request must have gone soon after the pause. - // We can't clobber it, because the stop confirmation will not be handled. - // We don't need to schedule another stop, we only need to let it happen. - prev.setState(STOPPING, "completePausedLocked"); - } else if (!prev.mVisibleRequested || shouldSleepOrShutDownActivities()) { - // Clear out any deferred client hide we might currently have. - prev.setDeferHidingClient(false); - // If we were visible then resumeTopActivities will release resources before - // stopping. - prev.addToStopping(true /* scheduleIdle */, false /* idleDelayed */, - "completePauseLocked"); - } - } else { - if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "App died during pause, not stopping: " + prev); - prev = null; - } - // It is possible the activity was freezing the screen before it was paused. - // In that case go ahead and remove the freeze this activity has on the screen - // since it is no longer visible. - if (prev != null) { - prev.stopFreezingScreenLocked(true /*force*/); - } - mPausingActivity = null; - } - - if (resumeNext) { - final ActivityStack topStack = mRootWindowContainer.getTopDisplayFocusedStack(); - if (topStack != null && !topStack.shouldSleepOrShutDownActivities()) { - mRootWindowContainer.resumeFocusedStacksTopActivities(topStack, prev, null); - } else { - checkReadyForSleep(); - final ActivityRecord top = topStack != null ? topStack.topRunningActivity() : null; - if (top == null || (prev != null && top != prev)) { - // If there are no more activities available to run, do resume anyway to start - // something. Also if the top activity on the stack is not the just paused - // activity, we need to go ahead and resume it to ensure we complete an - // in-flight app switch. - mRootWindowContainer.resumeFocusedStacksTopActivities(); - } - } - } - - if (prev != null) { - prev.resumeKeyDispatchingLocked(); - - if (prev.hasProcess() && prev.cpuTimeAtResume > 0) { - final long diff = prev.app.getCpuTime() - prev.cpuTimeAtResume; - if (diff > 0) { - final Runnable r = PooledLambda.obtainRunnable( - ActivityManagerInternal::updateForegroundTimeIfOnBattery, - mAtmService.mAmInternal, prev.info.packageName, - prev.info.applicationInfo.uid, - diff); - mAtmService.mH.post(r); - } - } - prev.cpuTimeAtResume = 0; // reset it - } - - mRootWindowContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS); - - // Notify when the task stack has changed, but only if visibilities changed (not just - // focus). Also if there is an active pinned stack - we always want to notify it about - // task stack changes, because its positioning may depend on it. - if (mStackSupervisor.mAppVisibilitiesChangedSinceLastPause - || (getDisplayArea() != null && getDisplayArea().hasPinnedTask())) { - mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged(); - mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = false; - } - } - - boolean isTopStackInDisplayArea() { - final TaskDisplayArea taskDisplayArea = getDisplayArea(); - return taskDisplayArea != null && taskDisplayArea.isTopStack(this); - } - - /** - * @return {@code true} if this is the focused stack on its current display, {@code false} - * otherwise. - */ - boolean isFocusedStackOnDisplay() { - final DisplayContent display = getDisplay(); - return display != null && this == display.getFocusedStack(); - } - - /** - * Make sure that all activities that need to be visible in the stack (that is, they - * currently can be seen by the user) actually are and update their configuration. - * @param starting The top most activity in the task. - * The activity is either starting or resuming. - * Caller should ensure starting activity is visible. - * @param preserveWindows Flag indicating whether windows should be preserved when updating - * configuration in {@link mEnsureActivitiesVisibleHelper}. - * @param configChanges Parts of the configuration that changed for this activity for evaluating - * if the screen should be frozen as part of - * {@link mEnsureActivitiesVisibleHelper}. - * - */ - void ensureActivitiesVisible(@Nullable ActivityRecord starting, int configChanges, - boolean preserveWindows) { - ensureActivitiesVisible(starting, configChanges, preserveWindows, true /* notifyClients */); - } - - /** - * Ensure visibility with an option to also update the configuration of visible activities. - * @see #ensureActivitiesVisible(ActivityRecord, int, boolean) - * @see RootWindowContainer#ensureActivitiesVisible(ActivityRecord, int, boolean) - * @param starting The top most activity in the task. - * The activity is either starting or resuming. - * Caller should ensure starting activity is visible. - * @param notifyClients Flag indicating whether the visibility updates should be sent to the - * clients in {@link mEnsureActivitiesVisibleHelper}. - * @param preserveWindows Flag indicating whether windows should be preserved when updating - * configuration in {@link mEnsureActivitiesVisibleHelper}. - * @param configChanges Parts of the configuration that changed for this activity for evaluating - * if the screen should be frozen as part of - * {@link mEnsureActivitiesVisibleHelper}. - */ - // TODO: Should be re-worked based on the fact that each task as a stack in most cases. - void ensureActivitiesVisible(@Nullable ActivityRecord starting, int configChanges, - boolean preserveWindows, boolean notifyClients) { - mTopActivityOccludesKeyguard = false; - mTopDismissingKeyguardActivity = null; - mStackSupervisor.beginActivityVisibilityUpdate(); - try { - mEnsureActivitiesVisibleHelper.process( - starting, configChanges, preserveWindows, notifyClients); - - if (mTranslucentActivityWaiting != null && - mUndrawnActivitiesBelowTopTranslucent.isEmpty()) { - // Nothing is getting drawn or everything was already visible, don't wait for timeout. - notifyActivityDrawnLocked(null); - } - } finally { - mStackSupervisor.endActivityVisibilityUpdate(); - } - } - - /** - * @return true if the top visible activity wants to occlude the Keyguard, false otherwise - */ - boolean topActivityOccludesKeyguard() { - return mTopActivityOccludesKeyguard; - } - - /** - * Returns true if this stack should be resized to match the bounds specified by - * {@link ActivityOptions#setLaunchBounds} when launching an activity into the stack. - */ - boolean shouldResizeStackWithLaunchBounds() { - return inPinnedWindowingMode(); - } - - // TODO(NOW!) - /** - * Returns {@code true} if this is the top-most split-screen-primary or - * split-screen-secondary stack, {@code false} otherwise. - */ - boolean isTopSplitScreenStack() { - return inSplitScreenWindowingMode() - && this == getDisplayArea().getTopStackInWindowingMode(getWindowingMode()); - } - - /** - * @return the top most visible activity that wants to dismiss Keyguard - */ - ActivityRecord getTopDismissingKeyguardActivity() { - return mTopDismissingKeyguardActivity; - } - - /** - * Checks whether {@param r} should be visible depending on Keyguard state and updates - * {@link #mTopActivityOccludesKeyguard} and {@link #mTopDismissingKeyguardActivity} if - * necessary. - * - * @return true if {@param r} is visible taken Keyguard state into account, false otherwise - */ - boolean checkKeyguardVisibility(ActivityRecord r, boolean shouldBeVisible, boolean isTop) { - int displayId = getDisplayId(); - if (displayId == INVALID_DISPLAY) displayId = DEFAULT_DISPLAY; - - final boolean keyguardOrAodShowing = mStackSupervisor.getKeyguardController() - .isKeyguardOrAodShowing(displayId); - final boolean keyguardLocked = mStackSupervisor.getKeyguardController().isKeyguardLocked(); - final boolean showWhenLocked = r.canShowWhenLocked(); - final boolean dismissKeyguard = r.containsDismissKeyguardWindow(); - if (shouldBeVisible) { - if (dismissKeyguard && mTopDismissingKeyguardActivity == null) { - mTopDismissingKeyguardActivity = r; - } - - // Only the top activity may control occluded, as we can't occlude the Keyguard if the - // top app doesn't want to occlude it. - if (isTop) { - mTopActivityOccludesKeyguard |= showWhenLocked; - } - - final boolean canShowWithKeyguard = canShowWithInsecureKeyguard() - && mStackSupervisor.getKeyguardController().canDismissKeyguard(); - if (canShowWithKeyguard) { - return true; - } - } - if (keyguardOrAodShowing) { - // If keyguard is showing, nothing is visible, except if we are able to dismiss Keyguard - // right away and AOD isn't visible. - return shouldBeVisible && mStackSupervisor.getKeyguardController() - .canShowActivityWhileKeyguardShowing(r, dismissKeyguard); - } else if (keyguardLocked) { - return shouldBeVisible && mStackSupervisor.getKeyguardController().canShowWhileOccluded( - dismissKeyguard, showWhenLocked); - } else { - return shouldBeVisible; - } - } - - /** - * Check if the display to which this stack is attached has - * {@link Display#FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD} applied. - */ - boolean canShowWithInsecureKeyguard() { - final DisplayContent displayContent = getDisplay(); - if (displayContent == null) { - throw new IllegalStateException("Stack is not attached to any display, stackId=" - + getRootTaskId()); - } - - final int flags = displayContent.mDisplay.getFlags(); - return (flags & FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0; - } - - void checkTranslucentActivityWaiting(ActivityRecord top) { - if (mTranslucentActivityWaiting != top) { - mUndrawnActivitiesBelowTopTranslucent.clear(); - if (mTranslucentActivityWaiting != null) { - // Call the callback with a timeout indication. - notifyActivityDrawnLocked(null); - mTranslucentActivityWaiting = null; - } - mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG); - } - } - - void convertActivityToTranslucent(ActivityRecord r) { - mTranslucentActivityWaiting = r; - mUndrawnActivitiesBelowTopTranslucent.clear(); - mHandler.sendEmptyMessageDelayed(TRANSLUCENT_TIMEOUT_MSG, TRANSLUCENT_CONVERSION_TIMEOUT); - } - - /** - * Called as activities below the top translucent activity are redrawn. When the last one is - * redrawn notify the top activity by calling - * {@link Activity#onTranslucentConversionComplete}. - * - * @param r The most recent background activity to be drawn. Or, if r is null then a timeout - * occurred and the activity will be notified immediately. - */ - void notifyActivityDrawnLocked(ActivityRecord r) { - if ((r == null) - || (mUndrawnActivitiesBelowTopTranslucent.remove(r) && - mUndrawnActivitiesBelowTopTranslucent.isEmpty())) { - // The last undrawn activity below the top has just been drawn. If there is an - // opaque activity at the top, notify it that it can become translucent safely now. - final ActivityRecord waitingActivity = mTranslucentActivityWaiting; - mTranslucentActivityWaiting = null; - mUndrawnActivitiesBelowTopTranslucent.clear(); - mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG); - - if (waitingActivity != null) { - mWmService.setWindowOpaqueLocked(waitingActivity.appToken, false); - if (waitingActivity.attachedToProcess()) { - try { - waitingActivity.app.getThread().scheduleTranslucentConversionComplete( - waitingActivity.appToken, r != null); - } catch (RemoteException e) { - } - } - } - } - } - - /** - * Ensure that the top activity in the stack is resumed. - * - * @param prev The previously resumed activity, for when in the process - * of pausing; can be null to call from elsewhere. - * @param options Activity options. - * - * @return Returns true if something is being resumed, or false if - * nothing happened. - * - * NOTE: It is not safe to call this method directly as it can cause an activity in a - * non-focused stack to be resumed. - * Use {@link RootWindowContainer#resumeFocusedStacksTopActivities} to resume the - * right activity for the current system state. - */ - @GuardedBy("mService") - boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) { - if (mInResumeTopActivity) { - // Don't even start recursing. - return false; - } - - boolean result = false; - try { - // Protect against recursion. - mInResumeTopActivity = true; - result = resumeTopActivityInnerLocked(prev, options); - - // When resuming the top activity, it may be necessary to pause the top activity (for - // example, returning to the lock screen. We suppress the normal pause logic in - // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the - // end. We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here - // to ensure any necessary pause logic occurs. In the case where the Activity will be - // shown regardless of the lock screen, the call to - // {@link ActivityStackSupervisor#checkReadyForSleepLocked} is skipped. - final ActivityRecord next = topRunningActivity(true /* focusableOnly */); - if (next == null || !next.canTurnScreenOn()) { - checkReadyForSleep(); - } - } finally { - mInResumeTopActivity = false; - } - - return result; - } - - @GuardedBy("mService") - private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) { - if (!mAtmService.isBooting() && !mAtmService.isBooted()) { - // Not ready yet! - return false; - } - - // Find the next top-most activity to resume in this stack that is not finishing and is - // focusable. If it is not focusable, we will fall into the case below to resume the - // top activity in the next focusable task. - ActivityRecord next = topRunningActivity(true /* focusableOnly */); - - final boolean hasRunningActivity = next != null; - - // TODO: Maybe this entire condition can get removed? - if (hasRunningActivity && !isAttached()) { - return false; - } - - mRootWindowContainer.cancelInitializingActivities(); - - // Remember how we'll process this pause/resume situation, and ensure - // that the state is reset however we wind up proceeding. - boolean userLeaving = mStackSupervisor.mUserLeaving; - mStackSupervisor.mUserLeaving = false; - - if (!hasRunningActivity) { - // There are no activities left in the stack, let's look somewhere else. - return resumeNextFocusableActivityWhenStackIsEmpty(prev, options); - } - - next.delayedResume = false; - final TaskDisplayArea taskDisplayArea = getDisplayArea(); - - // If the top activity is the resumed one, nothing to do. - if (mResumedActivity == next && next.isState(RESUMED) - && taskDisplayArea.allResumedActivitiesComplete()) { - // Make sure we have executed any pending transitions, since there - // should be nothing left to do at this point. - executeAppTransition(options); - if (DEBUG_STATES) Slog.d(TAG_STATES, - "resumeTopActivityLocked: Top activity resumed " + next); - return false; - } - - if (!next.canResumeByCompat()) { - return false; - } - - // If we are currently pausing an activity, then don't do anything until that is done. - final boolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete(); - if (!allPausedComplete) { - if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) { - Slog.v(TAG_PAUSE, "resumeTopActivityLocked: Skip resume: some activity pausing."); - } - return false; - } - - // If we are sleeping, and there is no resumed activity, and the top activity is paused, - // well that is the state we want. - if (shouldSleepOrShutDownActivities() - && mLastPausedActivity == next - && mRootWindowContainer.allPausedActivitiesComplete()) { - // If the current top activity may be able to occlude keyguard but the occluded state - // has not been set, update visibility and check again if we should continue to resume. - boolean nothingToResume = true; - if (!mAtmService.mShuttingDown) { - final boolean canShowWhenLocked = !mTopActivityOccludesKeyguard - && next.canShowWhenLocked(); - final boolean mayDismissKeyguard = mTopDismissingKeyguardActivity != next - && next.containsDismissKeyguardWindow(); - - if (canShowWhenLocked || mayDismissKeyguard) { - ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, - !PRESERVE_WINDOWS); - nothingToResume = shouldSleepActivities(); - } else if (next.currentLaunchCanTurnScreenOn() && next.canTurnScreenOn()) { - nothingToResume = false; - } - } - if (nothingToResume) { - // Make sure we have executed any pending transitions, since there - // should be nothing left to do at this point. - executeAppTransition(options); - if (DEBUG_STATES) Slog.d(TAG_STATES, - "resumeTopActivityLocked: Going to sleep and all paused"); - return false; - } - } - - // Make sure that the user who owns this activity is started. If not, - // we will just leave it as is because someone should be bringing - // another user's activities to the top of the stack. - if (!mAtmService.mAmInternal.hasStartedUserState(next.mUserId)) { - Slog.w(TAG, "Skipping resume of top activity " + next - + ": user " + next.mUserId + " is stopped"); - return false; - } - - // The activity may be waiting for stop, but that is no longer - // appropriate for it. - mStackSupervisor.mStoppingActivities.remove(next); - next.setSleeping(false); - - if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next); - - // If we are currently pausing an activity, then don't do anything until that is done. - if (!mRootWindowContainer.allPausedActivitiesComplete()) { - if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE, - "resumeTopActivityLocked: Skip resume: some activity pausing."); - - return false; - } - - mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid); - - ActivityRecord lastResumed = null; - final ActivityStack lastFocusedStack = taskDisplayArea.getLastFocusedStack(); - if (lastFocusedStack != null && lastFocusedStack != this) { - // So, why aren't we using prev here??? See the param comment on the method. prev doesn't - // represent the last resumed activity. However, the last focus stack does if it isn't null. - lastResumed = lastFocusedStack.mResumedActivity; - if (userLeaving && inMultiWindowMode() && lastFocusedStack.shouldBeVisible(next)) { - // The user isn't leaving if this stack is the multi-window mode and the last - // focused stack should still be visible. - if(DEBUG_USER_LEAVING) Slog.i(TAG_USER_LEAVING, "Overriding userLeaving to false" - + " next=" + next + " lastResumed=" + lastResumed); - userLeaving = false; - } - } - - boolean pausing = taskDisplayArea.pauseBackStacks(userLeaving, next); - if (mResumedActivity != null) { - if (DEBUG_STATES) Slog.d(TAG_STATES, - "resumeTopActivityLocked: Pausing " + mResumedActivity); - pausing |= startPausingLocked(userLeaving, false /* uiSleeping */, next); - } - if (pausing) { - if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG_STATES, - "resumeTopActivityLocked: Skip resume: need to start pausing"); - // At this point we want to put the upcoming activity's process - // at the top of the LRU list, since we know we will be needing it - // very soon and it would be a waste to let it get killed if it - // happens to be sitting towards the end. - if (next.attachedToProcess()) { - next.app.updateProcessInfo(false /* updateServiceConnectionActivities */, - true /* activityChange */, false /* updateOomAdj */, - false /* addPendingTopUid */); - } else if (!next.isProcessRunning()) { - // Since the start-process is asynchronous, if we already know the process of next - // activity isn't running, we can start the process earlier to save the time to wait - // for the current activity to be paused. - final boolean isTop = this == taskDisplayArea.getFocusedStack(); - mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop, - isTop ? "pre-top-activity" : "pre-activity"); - } - if (lastResumed != null) { - lastResumed.setWillCloseOrEnterPip(true); - } - return true; - } else if (mResumedActivity == next && next.isState(RESUMED) - && taskDisplayArea.allResumedActivitiesComplete()) { - // It is possible for the activity to be resumed when we paused back stacks above if the - // next activity doesn't have to wait for pause to complete. - // So, nothing else to-do except: - // Make sure we have executed any pending transitions, since there - // should be nothing left to do at this point. - executeAppTransition(options); - if (DEBUG_STATES) Slog.d(TAG_STATES, - "resumeTopActivityLocked: Top activity resumed (dontWaitForPause) " + next); - return true; - } - - // If the most recent activity was noHistory but was only stopped rather - // than stopped+finished because the device went to sleep, we need to make - // sure to finish it as we're making a new activity topmost. - if (shouldSleepActivities() && mLastNoHistoryActivity != null && - !mLastNoHistoryActivity.finishing) { - if (DEBUG_STATES) Slog.d(TAG_STATES, - "no-history finish of " + mLastNoHistoryActivity + " on new resume"); - mLastNoHistoryActivity.finishIfPossible("resume-no-history", false /* oomAdj */); - mLastNoHistoryActivity = null; - } - - if (prev != null && prev != next && next.nowVisible) { - - // The next activity is already visible, so hide the previous - // activity's windows right now so we can show the new one ASAP. - // We only do this if the previous is finishing, which should mean - // it is on top of the one being resumed so hiding it quickly - // is good. Otherwise, we want to do the normal route of allowing - // the resumed activity to be shown so we can decide if the - // previous should actually be hidden depending on whether the - // new one is found to be full-screen or not. - if (prev.finishing) { - prev.setVisibility(false); - if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, - "Not waiting for visible to hide: " + prev - + ", nowVisible=" + next.nowVisible); - } else { - if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, - "Previous already visible but still waiting to hide: " + prev - + ", nowVisible=" + next.nowVisible); - } - - } - - // Launching this app's activity, make sure the app is no longer - // considered stopped. - try { - mAtmService.getPackageManager().setPackageStoppedState( - next.packageName, false, next.mUserId); /* TODO: Verify if correct userid */ - } catch (RemoteException e1) { - } catch (IllegalArgumentException e) { - Slog.w(TAG, "Failed trying to unstop package " - + next.packageName + ": " + e); - } - - // We are starting up the next activity, so tell the window manager - // that the previous one will be hidden soon. This way it can know - // to ignore it when computing the desired screen orientation. - boolean anim = true; - final DisplayContent dc = taskDisplayArea.mDisplayContent; - if (prev != null) { - if (prev.finishing) { - if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, - "Prepare close transition: prev=" + prev); - if (mStackSupervisor.mNoAnimActivities.contains(prev)) { - anim = false; - dc.prepareAppTransition(TRANSIT_NONE, false); - } else { - dc.prepareAppTransition( - prev.getTask() == next.getTask() ? TRANSIT_ACTIVITY_CLOSE - : TRANSIT_TASK_CLOSE, false); - } - prev.setVisibility(false); - } else { - if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, - "Prepare open transition: prev=" + prev); - if (mStackSupervisor.mNoAnimActivities.contains(next)) { - anim = false; - dc.prepareAppTransition(TRANSIT_NONE, false); - } else { - dc.prepareAppTransition( - prev.getTask() == next.getTask() ? TRANSIT_ACTIVITY_OPEN - : next.mLaunchTaskBehind ? TRANSIT_TASK_OPEN_BEHIND - : TRANSIT_TASK_OPEN, false); - } - } - } else { - if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous"); - if (mStackSupervisor.mNoAnimActivities.contains(next)) { - anim = false; - dc.prepareAppTransition(TRANSIT_NONE, false); - } else { - dc.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false); - } - } - - if (anim) { - next.applyOptionsLocked(); - } else { - next.clearOptionsLocked(); - } - - mStackSupervisor.mNoAnimActivities.clear(); - - if (next.attachedToProcess()) { - if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next - + " stopped=" + next.stopped - + " visibleRequested=" + next.mVisibleRequested); - - // If the previous activity is translucent, force a visibility update of - // the next activity, so that it's added to WM's opening app list, and - // transition animation can be set up properly. - // For example, pressing Home button with a translucent activity in focus. - // Launcher is already visible in this case. If we don't add it to opening - // apps, maybeUpdateTransitToWallpaper() will fail to identify this as a - // TRANSIT_WALLPAPER_OPEN animation, and run some funny animation. - final boolean lastActivityTranslucent = lastFocusedStack != null - && (lastFocusedStack.inMultiWindowMode() - || (lastFocusedStack.mLastPausedActivity != null - && !lastFocusedStack.mLastPausedActivity.occludesParent())); - - // This activity is now becoming visible. - if (!next.mVisibleRequested || next.stopped || lastActivityTranslucent) { - next.setVisibility(true); - } - - // schedule launch ticks to collect information about slow apps. - next.startLaunchTickingLocked(); - - ActivityRecord lastResumedActivity = - lastFocusedStack == null ? null : lastFocusedStack.mResumedActivity; - final ActivityState lastState = next.getState(); - - mAtmService.updateCpuStats(); - - if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + next - + " (in existing)"); - - next.setState(RESUMED, "resumeTopActivityInnerLocked"); - - next.app.updateProcessInfo(false /* updateServiceConnectionActivities */, - true /* activityChange */, true /* updateOomAdj */, - true /* addPendingTopUid */); - - // Have the window manager re-evaluate the orientation of - // the screen based on the new activity order. - boolean notUpdated = true; - - // Activity should also be visible if set mLaunchTaskBehind to true (see - // ActivityRecord#shouldBeVisibleIgnoringKeyguard()). - if (shouldBeVisible(next)) { - // We have special rotation behavior when here is some active activity that - // requests specific orientation or Keyguard is locked. Make sure all activity - // visibilities are set correctly as well as the transition is updated if needed - // to get the correct rotation behavior. Otherwise the following call to update - // the orientation may cause incorrect configurations delivered to client as a - // result of invisible window resize. - // TODO: Remove this once visibilities are set correctly immediately when - // starting an activity. - notUpdated = !mRootWindowContainer.ensureVisibilityAndConfig(next, getDisplayId(), - true /* markFrozenIfConfigChanged */, false /* deferResume */); - } - - if (notUpdated) { - // The configuration update wasn't able to keep the existing - // instance of the activity, and instead started a new one. - // We should be all done, but let's just make sure our activity - // is still at the top and schedule another run if something - // weird happened. - ActivityRecord nextNext = topRunningActivity(); - if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_STATES, - "Activity config changed during resume: " + next - + ", new next: " + nextNext); - if (nextNext != next) { - // Do over! - mStackSupervisor.scheduleResumeTopActivities(); - } - if (!next.mVisibleRequested || next.stopped) { - next.setVisibility(true); - } - next.completeResumeLocked(); - return true; - } - - try { - final ClientTransaction transaction = - ClientTransaction.obtain(next.app.getThread(), next.appToken); - // Deliver all pending results. - ArrayList<ResultInfo> a = next.results; - if (a != null) { - final int N = a.size(); - if (!next.finishing && N > 0) { - if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, - "Delivering results to " + next + ": " + a); - transaction.addCallback(ActivityResultItem.obtain(a)); - } - } - - if (next.newIntents != null) { - transaction.addCallback( - NewIntentItem.obtain(next.newIntents, true /* resume */)); - } - - // Well the app will no longer be stopped. - // Clear app token stopped state in window manager if needed. - next.notifyAppResumed(next.stopped); - - EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next), - next.getTask().mTaskId, next.shortComponentName); - - next.setSleeping(false); - mAtmService.getAppWarningsLocked().onResumeActivity(next); - next.app.setPendingUiCleanAndForceProcessStateUpTo(mAtmService.mTopProcessState); - next.clearOptionsLocked(); - transaction.setLifecycleStateRequest( - ResumeActivityItem.obtain(next.app.getReportedProcState(), - dc.isNextTransitionForward())); - mAtmService.getLifecycleManager().scheduleTransaction(transaction); - - if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed " - + next); - } catch (Exception e) { - // Whoops, need to restart this activity! - if (DEBUG_STATES) Slog.v(TAG_STATES, "Resume failed; resetting state to " - + lastState + ": " + next); - next.setState(lastState, "resumeTopActivityInnerLocked"); - - // lastResumedActivity being non-null implies there is a lastStack present. - if (lastResumedActivity != null) { - lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked"); - } - - Slog.i(TAG, "Restarting because process died: " + next); - if (!next.hasBeenLaunched) { - next.hasBeenLaunched = true; - } else if (SHOW_APP_STARTING_PREVIEW && lastFocusedStack != null - && lastFocusedStack.isTopStackInDisplayArea()) { - next.showStartingWindow(null /* prev */, false /* newTask */, - false /* taskSwitch */); - } - mStackSupervisor.startSpecificActivity(next, true, false); - return true; - } - - // From this point on, if something goes wrong there is no way - // to recover the activity. - try { - next.completeResumeLocked(); - } catch (Exception e) { - // If any exception gets thrown, toss away this - // activity and try the next one. - Slog.w(TAG, "Exception thrown during resume of " + next, e); - next.finishIfPossible("resume-exception", true /* oomAdj */); - return true; - } - } else { - // Whoops, need to restart this activity! - if (!next.hasBeenLaunched) { - next.hasBeenLaunched = true; - } else { - if (SHOW_APP_STARTING_PREVIEW) { - next.showStartingWindow(null /* prev */, false /* newTask */, - false /* taskSwich */); - } - if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next); - } - if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Restarting " + next); - mStackSupervisor.startSpecificActivity(next, true, true); - } - - return true; - } - - /** - * Resume the next eligible activity in a focusable stack when this one does not have any - * running activities left. The focus will be adjusted to the next focusable stack and - * top running activities will be resumed in all focusable stacks. However, if the current stack - * is a home stack - we have to keep it focused, start and resume a home activity on the current - * display instead to make sure that the display is not empty. - */ - private boolean resumeNextFocusableActivityWhenStackIsEmpty(ActivityRecord prev, - ActivityOptions options) { - final String reason = "noMoreActivities"; - - if (!isActivityTypeHome()) { - final ActivityStack nextFocusedStack = adjustFocusToNextFocusableTask(reason); - if (nextFocusedStack != null) { - // Try to move focus to the next visible stack with a running activity if this - // stack is not covering the entire screen or is on a secondary display with no home - // stack. - return mRootWindowContainer.resumeFocusedStacksTopActivities(nextFocusedStack, - prev, null /* targetOptions */); - } - } - - // If the current stack is a home stack, or if focus didn't switch to a different stack - - // just start up the Launcher... - ActivityOptions.abort(options); - if (DEBUG_STATES) Slog.d(TAG_STATES, - "resumeNextFocusableActivityWhenStackIsEmpty: " + reason + ", go home"); - return mRootWindowContainer.resumeHomeActivity(prev, reason, getDisplayArea()); - } - - void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity, - boolean newTask, boolean keepCurTransition, ActivityOptions options) { - Task rTask = r.getTask(); - final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront(); - final boolean isOrhasTask = rTask == this || hasChild(rTask); - // mLaunchTaskBehind tasks get placed at the back of the task stack. - if (!r.mLaunchTaskBehind && allowMoveToFront && (!isOrhasTask || newTask)) { - // Last activity in task had been removed or ActivityManagerService is reusing task. - // Insert or replace. - // Might not even be in. - positionChildAtTop(rTask); - } - Task task = null; - if (!newTask && isOrhasTask) { - // Starting activity cannot be occluding activity, otherwise starting window could be - // remove immediately without transferring to starting activity. - final ActivityRecord occludingActivity = getOccludingActivityAbove(r); - if (occludingActivity != null) { - // Here it is! Now, if this is not yet visible (occluded by another task) to the - // user, then just add it without starting; it will get started when the user - // navigates back to it. - if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task " + task, - new RuntimeException("here").fillInStackTrace()); - rTask.positionChildAtTop(r); - ActivityOptions.abort(options); - return; - } - } - - // Place a new activity at top of stack, so it is next to interact with the user. - - // If we are not placing the new activity frontmost, we do not want to deliver the - // onUserLeaving callback to the actual frontmost activity - final Task activityTask = r.getTask(); - if (task == activityTask && mChildren.indexOf(task) != (getChildCount() - 1)) { - mStackSupervisor.mUserLeaving = false; - if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING, - "startActivity() behind front, mUserLeaving=false"); - } - - task = activityTask; - - // Slot the activity into the history stack and proceed - if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task, - new RuntimeException("here").fillInStackTrace()); - task.positionChildAtTop(r); - - // The transition animation and starting window are not needed if {@code allowMoveToFront} - // is false, because the activity won't be visible. - if ((!isHomeOrRecentsStack() || hasActivity()) && allowMoveToFront) { - final DisplayContent dc = getDisplay().mDisplayContent; - if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, - "Prepare open transition: starting " + r); - if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) { - dc.prepareAppTransition(TRANSIT_NONE, keepCurTransition); - mStackSupervisor.mNoAnimActivities.add(r); - } else { - int transit = TRANSIT_ACTIVITY_OPEN; - if (newTask) { - if (r.mLaunchTaskBehind) { - transit = TRANSIT_TASK_OPEN_BEHIND; - } else if (getDisplay().isSingleTaskInstance()) { - // If a new task is being launched in a single task display, we don't need - // to play normal animation, but need to trigger a callback when an app - // transition is actually handled. So ignore already prepared activity, and - // override it. - transit = TRANSIT_SHOW_SINGLE_TASK_DISPLAY; - keepCurTransition = false; - } else { - // If a new task is being launched, then mark the existing top activity as - // supporting picture-in-picture while pausing only if the starting activity - // would not be considered an overlay on top of the current activity - // (eg. not fullscreen, or the assistant) - if (canEnterPipOnTaskSwitch(focusedTopActivity, - null /* toFrontTask */, r, options)) { - focusedTopActivity.supportsEnterPipOnTaskSwitch = true; - } - transit = TRANSIT_TASK_OPEN; - } - } - dc.prepareAppTransition(transit, keepCurTransition); - mStackSupervisor.mNoAnimActivities.remove(r); - } - boolean doShow = true; - if (newTask) { - // Even though this activity is starting fresh, we still need - // to reset it to make sure we apply affinities to move any - // existing activities from other tasks in to it. - // If the caller has requested that the target task be - // reset, then do so. - if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { - resetTaskIfNeeded(r, r); - doShow = topRunningNonDelayedActivityLocked(null) == r; - } - } else if (options != null && options.getAnimationType() - == ActivityOptions.ANIM_SCENE_TRANSITION) { - doShow = false; - } - if (r.mLaunchTaskBehind) { - // Don't do a starting window for mLaunchTaskBehind. More importantly make sure we - // tell WindowManager that r is visible even though it is at the back of the stack. - r.setVisibility(true); - ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); - // Go ahead to execute app transition for this activity since the app transition - // will not be triggered through the resume channel. - getDisplay().mDisplayContent.executeAppTransition(); - } else if (SHOW_APP_STARTING_PREVIEW && doShow) { - // Figure out if we are transitioning from another activity that is - // "has the same starting icon" as the next one. This allows the - // window manager to keep the previous window it had previously - // created, if it still had one. - Task prevTask = r.getTask(); - ActivityRecord prev = prevTask.topActivityWithStartingWindow(); - if (prev != null) { - // We don't want to reuse the previous starting preview if: - // (1) The current activity is in a different task. - if (prev.getTask() != prevTask) { - prev = null; - } - // (2) The current activity is already displayed. - else if (prev.nowVisible) { - prev = null; - } - } - r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity)); - } - } else { - // If this is the first activity, don't do any fancy animations, - // because there is nothing for it to animate on top of. - ActivityOptions.abort(options); - } - } - - /** - * @return Whether the switch to another task can trigger the currently running activity to - * enter PiP while it is pausing (if supported). Only one of {@param toFrontTask} or - * {@param toFrontActivity} should be set. - */ - private boolean canEnterPipOnTaskSwitch(ActivityRecord pipCandidate, - Task toFrontTask, ActivityRecord toFrontActivity, ActivityOptions opts) { - if (opts != null && opts.disallowEnterPictureInPictureWhileLaunching()) { - // Ensure the caller has requested not to trigger auto-enter PiP - return false; - } - if (pipCandidate == null || pipCandidate.inPinnedWindowingMode()) { - // Ensure that we do not trigger entering PiP an activity on the pinned stack - return false; - } - final ActivityStack targetStack = toFrontTask != null - ? toFrontTask.getStack() : toFrontActivity.getRootTask(); - if (targetStack != null && targetStack.isActivityTypeAssistant()) { - // Ensure the task/activity being brought forward is not the assistant - return false; - } - return true; - } - - private boolean isTaskSwitch(ActivityRecord r, ActivityRecord topFocusedActivity) { - return topFocusedActivity != null && r.getTask() != topFocusedActivity.getTask(); - } - - /** - * Reset the task by reparenting the activities that have same affinity to the task or - * reparenting the activities that have different affinityies out of the task, while these - * activities allow task reparenting. - * - * @param taskTop Top activity of the task might be reset. - * @param newActivity The activity that going to be started. - * @return The non-finishing top activity of the task after reset or the original task top - * activity if all activities within the task are finishing. - */ - ActivityRecord resetTaskIfNeeded(ActivityRecord taskTop, ActivityRecord newActivity) { - final boolean forceReset = - (newActivity.info.flags & ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0; - final Task task = taskTop.getTask(); - - // If ActivityOptions are moved out and need to be aborted or moved to taskTop. - final ActivityOptions topOptions = sResetTargetTaskHelper.process(task, forceReset); - - if (mChildren.contains(task)) { - final ActivityRecord newTop = task.getTopNonFinishingActivity(); - if (newTop != null) { - taskTop = newTop; - } - } - - if (topOptions != null) { - // If we got some ActivityOptions from an activity on top that - // was removed from the task, propagate them to the new real top. - taskTop.updateOptionsLocked(topOptions); - } - - return taskTop; - } - - /** - * Finish the topmost activity that belongs to the crashed app. We may also finish the activity - * that requested launch of the crashed one to prevent launch-crash loop. - * @param app The app that crashed. - * @param reason Reason to perform this action. - * @return The task that was finished in this stack, {@code null} if top running activity does - * not belong to the crashed app. - */ - final Task finishTopCrashedActivityLocked(WindowProcessController app, String reason) { - final ActivityRecord r = topRunningActivity(); - if (r == null || r.app != app) { - return null; - } - if (r.isActivityTypeHome() && mAtmService.mHomeProcess == app) { - // Home activities should not be force-finished as we have nothing else to go - // back to. AppErrors will get to it after two crashes in MIN_CRASH_INTERVAL. - Slog.w(TAG, " Not force finishing home activity " - + r.intent.getComponent().flattenToShortString()); - return null; - } - Slog.w(TAG, " Force finishing activity " - + r.intent.getComponent().flattenToShortString()); - Task finishedTask = r.getTask(); - getDisplay().mDisplayContent.prepareAppTransition( - TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */); - r.finishIfPossible(reason, false /* oomAdj */); - - // Also terminate any activities below it that aren't yet stopped, to avoid a situation - // where one will get re-start our crashing activity once it gets resumed again. - final ActivityRecord activityBelow = getActivityBelow(r); - if (activityBelow != null) { - if (activityBelow.isState(STARTED, RESUMED, PAUSING, PAUSED)) { - if (!activityBelow.isActivityTypeHome() - || mAtmService.mHomeProcess != activityBelow.app) { - Slog.w(TAG, " Force finishing activity " - + activityBelow.intent.getComponent().flattenToShortString()); - activityBelow.finishIfPossible(reason, false /* oomAdj */); - } - } - } - - return finishedTask; - } - - void finishVoiceTask(IVoiceInteractionSession session) { - final PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::finishIfVoiceTask, - PooledLambda.__(Task.class), session.asBinder()); - forAllLeafTasks(c, true /* traverseTopToBottom */); - c.recycle(); - } - - private static void finishIfVoiceTask(Task tr, IBinder binder) { - if (tr.voiceSession != null && tr.voiceSession.asBinder() == binder) { - tr.forAllActivities((r) -> { - if (r.finishing) return; - r.finishIfPossible("finish-voice", false /* oomAdj */); - tr.mAtmService.updateOomAdj(); - }); - } else { - // Check if any of the activities are using voice - final PooledFunction f = PooledLambda.obtainFunction( - ActivityStack::finishIfVoiceActivity, PooledLambda.__(ActivityRecord.class), - binder); - tr.forAllActivities(f); - f.recycle(); - } - } - - private static boolean finishIfVoiceActivity(ActivityRecord r, IBinder binder) { - if (r.voiceSession == null || r.voiceSession.asBinder() != binder) return false; - // Inform of cancellation - r.clearVoiceSessionLocked(); - try { - r.app.getThread().scheduleLocalVoiceInteractionStarted(r.appToken, null); - } catch (RemoteException re) { - // Ok Boomer... - } - r.mAtmService.finishRunningVoiceLocked(); - return true; - } - - /** Finish all activities in the stack without waiting. */ - void finishAllActivitiesImmediately() { - if (!hasChild()) { - removeIfPossible(); - return; - } - forAllActivities((r) -> { - Slog.d(TAG, "finishAllActivitiesImmediatelyLocked: finishing " + r); - r.destroyIfPossible("finishAllActivitiesImmediately"); - }); - } - - /** @return true if the stack behind this one is a standard activity type. */ - private boolean inFrontOfStandardStack() { - final TaskDisplayArea taskDisplayArea = getDisplayArea(); - if (taskDisplayArea == null) { - return false; - } - final int index = taskDisplayArea.getIndexOf(this); - if (index == 0) { - return false; - } - final ActivityStack stackBehind = taskDisplayArea.getChildAt(index - 1); - return stackBehind.isActivityTypeStandard(); - } - - boolean shouldUpRecreateTaskLocked(ActivityRecord srec, String destAffinity) { - // Basic case: for simple app-centric recents, we need to recreate - // the task if the affinity has changed. - - final String affinity = ActivityRecord.getTaskAffinityWithUid(destAffinity, srec.getUid()); - if (srec == null || srec.getTask().affinity == null - || !srec.getTask().affinity.equals(affinity)) { - return true; - } - // Document-centric case: an app may be split in to multiple documents; - // they need to re-create their task if this current activity is the root - // of a document, unless simply finishing it will return them to the the - // correct app behind. - final Task task = srec.getTask(); - if (srec.isRootOfTask() && task.getBaseIntent() != null - && task.getBaseIntent().isDocument()) { - // Okay, this activity is at the root of its task. What to do, what to do... - if (!inFrontOfStandardStack()) { - // Finishing won't return to an application, so we need to recreate. - return true; - } - // We now need to get the task below it to determine what to do. - final Task prevTask = getTaskBelow(task); - if (prevTask == null) { - Slog.w(TAG, "shouldUpRecreateTask: task not in history for " + srec); - return false; - } - if (!task.affinity.equals(prevTask.affinity)) { - // These are different apps, so need to recreate. - return true; - } - } - return false; - } - - boolean navigateUpTo(ActivityRecord srec, Intent destIntent, NeededUriGrants destGrants, - int resultCode, Intent resultData, NeededUriGrants resultGrants) { - if (!srec.attachedToProcess()) { - // Nothing to do if the caller is not attached, because this method should be called - // from an alive activity. - return false; - } - final Task task = srec.getTask(); - if (!srec.isDescendantOf(this)) { - return false; - } - - ActivityRecord parent = task.getActivityBelow(srec); - boolean foundParentInTask = false; - final ComponentName dest = destIntent.getComponent(); - if (task.getBottomMostActivity() != srec && dest != null) { - final ActivityRecord candidate = task.getActivity((ar) -> - ar.info.packageName.equals(dest.getPackageName()) && - ar.info.name.equals(dest.getClassName()), srec, false /*includeBoundary*/, - true /*traverseTopToBottom*/); - if (candidate != null) { - parent = candidate; - foundParentInTask = true; - } - } - - // TODO: There is a dup. of this block of code in ActivityTaskManagerService.finishActivity - // We should consolidate. - IActivityController controller = mAtmService.mController; - if (controller != null) { - ActivityRecord next = topRunningActivity(srec.appToken, INVALID_TASK_ID); - if (next != null) { - // ask watcher if this is allowed - boolean resumeOK = true; - try { - resumeOK = controller.activityResuming(next.packageName); - } catch (RemoteException e) { - mAtmService.mController = null; - Watchdog.getInstance().setActivityController(null); - } - - if (!resumeOK) { - return false; - } - } - } - final long origId = Binder.clearCallingIdentity(); - - final int[] resultCodeHolder = new int[1]; - resultCodeHolder[0] = resultCode; - final Intent[] resultDataHolder = new Intent[1]; - resultDataHolder[0] = resultData; - final NeededUriGrants[] resultGrantsHolder = new NeededUriGrants[1]; - resultGrantsHolder[0] = resultGrants; - final ActivityRecord finalParent = parent; - task.forAllActivities((ar) -> { - if (ar == finalParent) return true; - - ar.finishIfPossible(resultCodeHolder[0], resultDataHolder[0], resultGrantsHolder[0], - "navigate-up", true /* oomAdj */); - // Only return the supplied result for the first activity finished - resultCodeHolder[0] = Activity.RESULT_CANCELED; - resultDataHolder[0] = null; - return false; - }, srec, true, true); - resultCode = resultCodeHolder[0]; - resultData = resultDataHolder[0]; - - if (parent != null && foundParentInTask) { - final int callingUid = srec.info.applicationInfo.uid; - final int parentLaunchMode = parent.info.launchMode; - final int destIntentFlags = destIntent.getFlags(); - if (parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE || - parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK || - parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP || - (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) { - parent.deliverNewIntentLocked(callingUid, destIntent, destGrants, srec.packageName); - } else { - try { - ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo( - destIntent.getComponent(), ActivityManagerService.STOCK_PM_FLAGS, - srec.mUserId); - // TODO(b/64750076): Check if calling pid should really be -1. - final int res = mAtmService.getActivityStartController() - .obtainStarter(destIntent, "navigateUpTo") - .setCaller(srec.app.getThread()) - .setActivityInfo(aInfo) - .setResultTo(parent.appToken) - .setCallingPid(-1) - .setCallingUid(callingUid) - .setCallingPackage(srec.packageName) - .setCallingFeatureId(parent.launchedFromFeatureId) - .setRealCallingPid(-1) - .setRealCallingUid(callingUid) - .setComponentSpecified(true) - .execute(); - foundParentInTask = res == ActivityManager.START_SUCCESS; - } catch (RemoteException e) { - foundParentInTask = false; - } - parent.finishIfPossible(resultCode, resultData, resultGrants, - "navigate-top", true /* oomAdj */); - } - } - Binder.restoreCallingIdentity(origId); - return foundParentInTask; - } - - void removeLaunchTickMessages() { - forAllActivities(ActivityRecord::removeLaunchTickRunnable); - } - - private void updateTransitLocked(int transit, ActivityOptions options, boolean forceOverride) { - if (options != null) { - ActivityRecord r = topRunningActivity(); - if (r != null && !r.isState(RESUMED)) { - r.updateOptionsLocked(options); - } else { - ActivityOptions.abort(options); - } - } - getDisplay().mDisplayContent.prepareAppTransition(transit, false, - 0 /* flags */, forceOverride); - } - - final void moveTaskToFront(Task tr, boolean noAnimation, ActivityOptions options, - AppTimeTracker timeTracker, String reason) { - moveTaskToFront(tr, noAnimation, options, timeTracker, !DEFER_RESUME, reason); - } - - final void moveTaskToFront(Task tr, boolean noAnimation, ActivityOptions options, - AppTimeTracker timeTracker, boolean deferResume, String reason) { - if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr); - - final ActivityStack topStack = getDisplayArea().getTopStack(); - final ActivityRecord topActivity = topStack != null - ? topStack.getTopNonFinishingActivity() : null; - - if (tr != this && !tr.isDescendantOf(this)) { - // nothing to do! - if (noAnimation) { - ActivityOptions.abort(options); - } else if (isSingleTaskInstance()) { - // When a task is moved front on the display which can only contain one task, start - // a special transition. - // {@link AppTransitionController#handleAppTransitionReady} later picks up the - // transition, and schedules - // {@link ITaskStackListener#onSingleTaskDisplayDrawn} callback which is triggered - // after contents are drawn on the display. - updateTransitLocked(TRANSIT_SHOW_SINGLE_TASK_DISPLAY, options, - true /* forceOverride */); - } else { - updateTransitLocked(TRANSIT_TASK_TO_FRONT, options, false /* forceOverride */); - } - return; - } - - if (timeTracker != null) { - // The caller wants a time tracker associated with this task. - final PooledConsumer c = PooledLambda.obtainConsumer(ActivityRecord::setAppTimeTracker, - PooledLambda.__(ActivityRecord.class), timeTracker); - tr.forAllActivities(c); - c.recycle(); - } - - try { - // Defer updating the IME target since the new IME target will try to get computed - // before updating all closing and opening apps, which can cause the ime target to - // get calculated incorrectly. - getDisplay().deferUpdateImeTarget(); - - // Shift all activities with this task up to the top - // of the stack, keeping them in the same internal order. - positionChildAtTop(tr); - - // Don't refocus if invisible to current user - final ActivityRecord top = tr.getTopNonFinishingActivity(); - if (top == null || !top.okToShowLocked()) { - if (top != null) { - mStackSupervisor.mRecentTasks.add(top.getTask()); - } - ActivityOptions.abort(options); - return; - } - - // Set focus to the top running activity of this stack. - final ActivityRecord r = topRunningActivity(); - if (r != null) { - r.moveFocusableActivityToTop(reason); - } - - if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr); - if (noAnimation) { - getDisplay().mDisplayContent.prepareAppTransition(TRANSIT_NONE, false); - if (r != null) { - mStackSupervisor.mNoAnimActivities.add(r); - } - ActivityOptions.abort(options); - } else if (isSingleTaskInstance()) { - updateTransitLocked(TRANSIT_SHOW_SINGLE_TASK_DISPLAY, options, - true /* forceOverride */); - } else { - updateTransitLocked(TRANSIT_TASK_TO_FRONT, options, false /* forceOverride */); - } - - // If a new task is moved to the front, then mark the existing top activity as - // supporting - - // picture-in-picture while paused only if the task would not be considered an oerlay - // on top - // of the current activity (eg. not fullscreen, or the assistant) - if (canEnterPipOnTaskSwitch(topActivity, tr, null /* toFrontActivity */, - options)) { - topActivity.supportsEnterPipOnTaskSwitch = true; - } - - if (!deferResume) { - mRootWindowContainer.resumeFocusedStacksTopActivities(); - } - EventLogTags.writeWmTaskToFront(tr.mUserId, tr.mTaskId); - mAtmService.getTaskChangeNotificationController() - .notifyTaskMovedToFront(tr.getTaskInfo()); - } finally { - getDisplay().continueUpdateImeTarget(); - } - } - - /** - * Worker method for rearranging history stack. Implements the function of moving all - * activities for a specific task (gathering them if disjoint) into a single group at the - * bottom of the stack. - * - * If a watcher is installed, the action is preflighted and the watcher has an opportunity - * to premeptively cancel the move. - * - * @param tr The task to collect and move to the bottom. - * @return Returns true if the move completed, false if not. - */ - boolean moveTaskToBack(Task tr) { - Slog.i(TAG, "moveTaskToBack: " + tr); - - // In LockTask mode, moving a locked task to the back of the stack may expose unlocked - // ones. Therefore we need to check if this operation is allowed. - if (!mAtmService.getLockTaskController().canMoveTaskToBack(tr)) { - return false; - } - - // If we have a watcher, preflight the move before committing to it. First check - // for *other* available tasks, but if none are available, then try again allowing the - // current task to be selected. - if (isTopStackInDisplayArea() && mAtmService.mController != null) { - ActivityRecord next = topRunningActivity(null, tr.mTaskId); - if (next == null) { - next = topRunningActivity(null, INVALID_TASK_ID); - } - if (next != null) { - // ask watcher if this is allowed - boolean moveOK = true; - try { - moveOK = mAtmService.mController.activityResuming(next.packageName); - } catch (RemoteException e) { - mAtmService.mController = null; - Watchdog.getInstance().setActivityController(null); - } - if (!moveOK) { - return false; - } - } - } - - if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to back transition: task=" - + tr.mTaskId); - - getDisplay().mDisplayContent.prepareAppTransition(TRANSIT_TASK_TO_BACK, false); - moveToBack("moveTaskToBackLocked", tr); - - if (inPinnedWindowingMode()) { - mStackSupervisor.removeStack(this); - return true; - } - - mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */, - getDisplay().mDisplayId, false /* markFrozenIfConfigChanged */, - false /* deferResume */); - - ActivityRecord topActivity = getDisplayArea().topRunningActivity(); - ActivityStack topStack = topActivity.getRootTask(); - if (topStack != null && topStack != this && topActivity.isState(RESUMED)) { - // Usually resuming a top activity triggers the next app transition, but nothing's got - // resumed in this case, so we need to execute it explicitly. - getDisplay().mDisplayContent.executeAppTransition(); - } else { - mRootWindowContainer.resumeFocusedStacksTopActivities(); - } - return true; - } - - /** - * Ensures all visible activities at or below the input activity have the right configuration. - */ - void ensureVisibleActivitiesConfiguration(ActivityRecord start, boolean preserveWindow) { - mEnsureVisibleActivitiesConfigHelper.process(start, preserveWindow); - } - - // TODO: Can only be called from special methods in ActivityStackSupervisor. - // Need to consolidate those calls points into this resize method so anyone can call directly. - void resize(Rect displayedBounds, boolean preserveWindows, boolean deferResume) { - Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "stack.resize_" + getRootTaskId()); - mAtmService.deferWindowLayout(); - try { - // TODO: Why not just set this on the stack directly vs. on each tasks? - // Update override configurations of all tasks in the stack. - final PooledConsumer c = PooledLambda.obtainConsumer( - ActivityStack::processTaskResizeBounds, PooledLambda.__(Task.class), - displayedBounds); - forAllTasks(c, true /* traverseTopToBottom */); - c.recycle(); - - if (mBoundsAnimating) { - // Force to update task surface bounds and relayout windows, since configBounds - // remains unchanged during bounds animation. - updateSurfaceBounds(); - getDisplay().setLayoutNeeded(); - mWmService.requestTraversal(); - } - - if (!deferResume) { - ensureVisibleActivitiesConfiguration(topRunningActivity(), preserveWindows); - } - } finally { - mAtmService.continueWindowLayout(); - Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); - } - } - - private static void processTaskResizeBounds(Task task, Rect displayedBounds) { - if (!task.isResizeable()) return; - - task.setBounds(displayedBounds); - } - - /** - * Until we can break this "set task bounds to same as stack bounds" behavior, this - * basically resizes both stack and task bounds to the same bounds. - */ - private void setTaskBounds(Rect bounds) { - final PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::setTaskBounds, - PooledLambda.__(Task.class), bounds); - forAllLeafTasks(c, true /* traverseTopToBottom */); - c.recycle(); - } - - private static void setTaskBounds(Task task, Rect bounds) { - task.setBounds(task.isResizeable() ? bounds : null); - } - - boolean willActivityBeVisible(IBinder token) { - final ActivityRecord r = ActivityRecord.forTokenLocked(token); - if (r == null) { - return false; - } - - // See if there is an occluding activity on-top of this one. - final ActivityRecord occludingActivity = getOccludingActivityAbove(r); - if (occludingActivity != null) return false; - - if (r.finishing) Slog.e(TAG, "willActivityBeVisible: Returning false," - + " would have returned true for r=" + r); - return !r.finishing; - } - - void unhandledBackLocked() { - final ActivityRecord topActivity = getTopMostActivity(); - if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, - "Performing unhandledBack(): top activity: " + topActivity); - if (topActivity != null) { - topActivity.finishIfPossible("unhandled-back", true /* oomAdj */); - } - } - - /** - * Reset local parameters because an app's activity died. - * @param app The app of the activity that died. - * @return result from removeHistoryRecordsForAppLocked. - */ - boolean handleAppDied(WindowProcessController app) { - if (mPausingActivity != null && mPausingActivity.app == app) { - if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG_PAUSE, - "App died while pausing: " + mPausingActivity); - mPausingActivity = null; - } - if (mLastPausedActivity != null && mLastPausedActivity.app == app) { - mLastPausedActivity = null; - mLastNoHistoryActivity = null; - } - - mStackSupervisor.removeHistoryRecords(app); - return mRemoveHistoryRecordsForApp.process(app); - } - - boolean dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient, - String dumpPackage, final boolean needSep) { - Runnable headerPrinter = () -> { - if (needSep) { - pw.println(); - } - pw.println(" Stack #" + getRootTaskId() - + ": type=" + activityTypeToString(getActivityType()) - + " mode=" + windowingModeToString(getWindowingMode())); - pw.println(" isSleeping=" + shouldSleepActivities()); - pw.println(" mBounds=" + getRequestedOverrideBounds()); - }; - - boolean printed = false; - - if (dumpPackage == null) { - // If we are not filtering by package, we want to print absolutely everything, - // so always print the header even if there are no tasks/activities inside. - headerPrinter.run(); - headerPrinter = null; - printed = true; - } - - printed |= printThisActivity(pw, mPausingActivity, dumpPackage, false, - " mPausingActivity: ", null); - printed |= printThisActivity(pw, getResumedActivity(), dumpPackage, false, - " mResumedActivity: ", null); - if (dumpAll) { - printed |= printThisActivity(pw, mLastPausedActivity, dumpPackage, false, - " mLastPausedActivity: ", null); - printed |= printThisActivity(pw, mLastNoHistoryActivity, dumpPackage, - false, " mLastNoHistoryActivity: ", null); - } - - printed |= dumpActivities(fd, pw, dumpAll, dumpClient, dumpPackage, false, headerPrinter); - - return printed; - } - - private boolean dumpActivities(FileDescriptor fd, PrintWriter pw, boolean dumpAll, - boolean dumpClient, String dumpPackage, boolean needSep, Runnable header) { - if (!hasChild()) { - return false; - } - final AtomicBoolean printedHeader = new AtomicBoolean(false); - final AtomicBoolean printed = new AtomicBoolean(false); - forAllLeafTasks((task) -> { - final String prefix = " "; - Runnable headerPrinter = () -> { - printed.set(true); - if (!printedHeader.get()) { - if (needSep) { - pw.println(""); - } - if (header != null) { - header.run(); - } - printedHeader.set(true); - } - pw.print(prefix); pw.print("* "); pw.println(task); - pw.print(prefix); pw.print(" mBounds="); - pw.println(task.getRequestedOverrideBounds()); - pw.print(prefix); pw.print(" mMinWidth="); pw.print(task.mMinWidth); - pw.print(" mMinHeight="); pw.println(task.mMinHeight); - if (mLastNonFullscreenBounds != null) { - pw.print(prefix); - pw.print(" mLastNonFullscreenBounds="); - pw.println(task.mLastNonFullscreenBounds); - } - task.dump(pw, prefix + " "); - }; - if (dumpPackage == null) { - // If we are not filtering by package, we want to print absolutely everything, - // so always print the header even if there are no activities inside. - headerPrinter.run(); - headerPrinter = null; - } - final ArrayList<ActivityRecord> activities = new ArrayList<>(); - // Add activities by traversing the hierarchy from bottom to top, since activities - // are dumped in reverse order in {@link ActivityStackSupervisor#dumpHistoryList()}. - task.forAllActivities((Consumer<ActivityRecord>) activities::add, - false /* traverseTopToBottom */); - dumpHistoryList(fd, pw, activities, prefix, "Hist", true, !dumpAll, dumpClient, - dumpPackage, false, headerPrinter, task); - }, true /* traverseTopToBottom */); - return printed.get(); - } - - ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) { - ArrayList<ActivityRecord> activities = new ArrayList<>(); - - if ("all".equals(name)) { - forAllActivities((Consumer<ActivityRecord>) activities::add); - } else if ("top".equals(name)) { - final ActivityRecord topActivity = getTopMostActivity(); - if (topActivity != null) { - activities.add(topActivity); - } - } else { - ItemMatcher matcher = new ItemMatcher(); - matcher.build(name); - - forAllActivities((r) -> { - if (matcher.match(r, r.intent.getComponent())) { - activities.add(r); - } - }); - } - - return activities; - } - - ActivityRecord restartPackage(String packageName) { - ActivityRecord starting = topRunningActivity(); - - // All activities that came from the package must be - // restarted as if there was a config change. - PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::restartPackage, - PooledLambda.__(ActivityRecord.class), starting, packageName); - forAllActivities(c); - c.recycle(); - - return starting; - } - - private static void restartPackage( - ActivityRecord r, ActivityRecord starting, String packageName) { - if (r.info.packageName.equals(packageName)) { - r.forceNewConfig = true; - if (starting != null && r == starting && r.mVisibleRequested) { - r.startFreezingScreenLocked(CONFIG_SCREEN_LAYOUT); - } - } - } - - Task reuseOrCreateTask(ActivityInfo info, Intent intent, boolean toTop) { - return reuseOrCreateTask(info, intent, null /*voiceSession*/, null /*voiceInteractor*/, - toTop, null /*activity*/, null /*source*/, null /*options*/); - } - // TODO: Can be removed once we change callpoints creating stacks to be creating tasks. - /** Either returns this current task to be re-used or creates a new child task. */ - Task reuseOrCreateTask(ActivityInfo info, Intent intent, IVoiceInteractionSession voiceSession, - IVoiceInteractor voiceInteractor, boolean toTop, ActivityRecord activity, - ActivityRecord source, ActivityOptions options) { - - Task task; - if (DisplayContent.alwaysCreateStack(getWindowingMode(), getActivityType())) { - // This stack will only contain one task, so just return itself since all stacks ara now - // tasks and all tasks are now stacks. - task = reuseAsLeafTask(voiceSession, voiceInteractor, intent, info, activity); - } else { - // Create child task since this stack can contain multiple tasks. - final int taskId = activity != null - ? mStackSupervisor.getNextTaskIdForUser(activity.mUserId) - : mStackSupervisor.getNextTaskIdForUser(); - task = new ActivityStack(mAtmService, taskId, info, intent, voiceSession, - voiceInteractor, null /* taskDescription */, this); - - // add the task to stack first, mTaskPositioner might need the stack association - addChild(task, toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0); - } - - int displayId = getDisplayId(); - if (displayId == INVALID_DISPLAY) displayId = DEFAULT_DISPLAY; - final boolean isLockscreenShown = mAtmService.mStackSupervisor.getKeyguardController() - .isKeyguardOrAodShowing(displayId); - if (!mStackSupervisor.getLaunchParamsController() - .layoutTask(task, info.windowLayout, activity, source, options) - && !getRequestedOverrideBounds().isEmpty() - && task.isResizeable() && !isLockscreenShown) { - task.setBounds(getRequestedOverrideBounds()); - } - - return task; - } - - void addChild(WindowContainer child, final boolean toTop, boolean showForAllUsers) { - if (isSingleTaskInstance() && hasChild()) { - throw new IllegalStateException("Can only have one child on stack=" + this); - } - - Task task = child.asTask(); - try { - if (task != null) { - task.setForceShowForAllUsers(showForAllUsers); - } - // We only want to move the parents to the parents if we are creating this task at the - // top of its stack. - addChild(child, toTop ? MAX_VALUE : 0, toTop /*moveParents*/); - } finally { - if (task != null) { - task.setForceShowForAllUsers(false); - } - } - } - - void positionChildAt(Task task, int position) { - if (task.getStack() != this) { - throw new IllegalArgumentException("AS.positionChildAt: task=" + task - + " is not a child of stack=" + this + " current parent=" + task.getStack()); - } - - task.updateOverrideConfigurationForStack(this); - - final ActivityRecord topRunningActivity = task.topRunningActivityLocked(); - final boolean wasResumed = topRunningActivity == task.getStack().mResumedActivity; - - boolean toTop = position >= getChildCount(); - boolean includingParents = toTop || getDisplayArea().getNextFocusableStack(this, - true /* ignoreCurrent */) == null; - if (WindowManagerDebugConfig.DEBUG_STACK) { - Slog.i(TAG_WM, "positionChildAt: positioning task=" + task + " at " + position); - } - positionChildAt(position, task, includingParents); - task.updateTaskMovement(toTop); - getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); - - - // TODO: Investigate if this random code is really needed. - if (task.voiceSession != null) { - try { - task.voiceSession.taskStarted(task.intent, task.mTaskId); - } catch (RemoteException e) { - } - } - - if (wasResumed) { - if (mResumedActivity != null) { - Log.wtf(TAG, "mResumedActivity was already set when moving mResumedActivity from" - + " other stack to this stack mResumedActivity=" + mResumedActivity - + " other mResumedActivity=" + topRunningActivity); - } - topRunningActivity.setState(RESUMED, "positionChildAt"); - } - - // The task might have already been running and its visibility needs to be synchronized with - // the visibility of the stack / windows. - ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); - mRootWindowContainer.resumeFocusedStacksTopActivities(); - } - - public void setAlwaysOnTop(boolean alwaysOnTop) { - if (isAlwaysOnTop() == alwaysOnTop) { - return; - } - super.setAlwaysOnTop(alwaysOnTop); - final TaskDisplayArea taskDisplayArea = getDisplayArea(); - // positionChildAtTop() must be called even when always on top gets turned off because we - // need to make sure that the stack is moved from among always on top windows to below other - // always on top windows. Since the position the stack should be inserted into is calculated - // properly in {@link DisplayContent#getTopInsertPosition()} in both cases, we can just - // request that the stack is put at top here. - taskDisplayArea.positionStackAtTop(this, false /* includingParents */); - } - - /** NOTE: Should only be called from {@link Task#reparent}. */ - void moveToFrontAndResumeStateIfNeeded(ActivityRecord r, boolean moveToFront, boolean setResume, - boolean setPause, String reason) { - if (!moveToFront) { - return; - } - - final ActivityState origState = r.getState(); - // If the activity owns the last resumed activity, transfer that together, - // so that we don't resume the same activity again in the new stack. - // Apps may depend on onResume()/onPause() being called in pairs. - if (setResume) { - r.setState(RESUMED, "moveToFrontAndResumeStateIfNeeded"); - } - // If the activity was previously pausing, then ensure we transfer that as well - if (setPause) { - mPausingActivity = r; - r.schedulePauseTimeout(); - } - // Move the stack in which we are placing the activity to the front. - moveToFront(reason); - // If the original state is resumed, there is no state change to update focused app. - // So here makes sure the activity focus is set if it is the top. - if (origState == RESUMED && r == mRootWindowContainer.getTopResumedActivity()) { - mAtmService.setResumedActivityUncheckLocked(r, reason); - } - } - - void dismissPip() { - if (!isActivityTypeStandardOrUndefined()) { - throw new IllegalArgumentException( - "You can't move tasks from non-standard stacks."); - } - if (getWindowingMode() != WINDOWING_MODE_PINNED) { - throw new IllegalArgumentException( - "Can't exit pinned mode if it's not pinned already."); - } - - mWmService.inSurfaceTransaction(() -> { - final Task task = getBottomMostTask(); - setWindowingMode(WINDOWING_MODE_UNDEFINED); - - getDisplayArea().positionStackAtTop(this, false /* includingParents */); - - mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, this); - MetricsLoggerWrapper.logPictureInPictureFullScreen(mAtmService.mContext, - task.effectiveUid, task.realActivity.flattenToString()); - }); - } - - void prepareFreezingTaskBounds() { - forAllLeafTasks(Task::prepareFreezingBounds, true /* traverseTopToBottom */); - } - - @Override - public int setBounds(Rect bounds) { - // Calling Task#setBounds() for leaf task since this is the a specialization of - // {@link #setBounds(int)} for ActivityStack. - if (!isRootTask()) { - return super.setBounds(bounds); - } else { - return setBounds(getRequestedOverrideBounds(), bounds); - } - } - - private int setBounds(Rect existing, Rect bounds) { - if (equivalentBounds(existing, bounds)) { - return BOUNDS_CHANGE_NONE; - } - - final int result = super.setBounds(!inMultiWindowMode() ? null : bounds); - - updateSurfaceBounds(); - return result; - } - - /** Bounds of the stack without adjusting for other factors in the system like visibility - * of docked stack. - * Most callers should be using {@link ConfigurationContainer#getRequestedOverrideBounds} a - * it takes into consideration other system factors. */ - void getRawBounds(Rect out) { - out.set(getRawBounds()); - } - - private Rect getRawBounds() { - return super.getBounds(); - } - - @Override - public void getBounds(Rect bounds) { - bounds.set(getBounds()); - } - - /** - * @return the final bounds for the bounds animation. - */ - void getFinalAnimationBounds(Rect outBounds) { - outBounds.set(mBoundsAnimationTarget); - } - - /** - * @return the final source bounds for the bounds animation. - */ - void getFinalAnimationSourceHintBounds(Rect outBounds) { - outBounds.set(mBoundsAnimationSourceHintBounds); - } - - /** Bounds of the stack with other system factors taken into consideration. */ - void getDimBounds(Rect out) { - getBounds(out); - } - - /** - * Put a Task in this stack. Used for adding only. - * When task is added to top of the stack, the entire branch of the hierarchy (including stack - * and display) will be brought to top. - * @param child The child to add. - * @param position Target position to add the task to. - */ - private void addChild(WindowContainer child, int position, boolean moveParents) { - // Add child task. - addChild(child, null); - - // Move child to a proper position, as some restriction for position might apply. - positionChildAt(position, child, moveParents /* includingParents */); - } - - void positionChildAtTop(Task child) { - if (child == null) { - // TODO: Fix the call-points that cause this to happen. - return; - } - - if (child == this) { - // TODO: Fix call-points - moveToFront("positionChildAtTop"); - return; - } - - positionChildAt(POSITION_TOP, child, true /* includingParents */); - child.updateTaskMovement(true); - - final DisplayContent displayContent = getDisplayContent(); - displayContent.layoutAndAssignWindowLayersIfNeeded(); - } - - void positionChildAtBottom(Task child) { - // If there are other focusable stacks on the display, the z-order of the display should not - // be changed just because a task was placed at the bottom. E.g. if it is moving the topmost - // task to bottom, the next focusable stack on the same display should be focused. - final ActivityStack nextFocusableStack = getDisplayArea().getNextFocusableStack( - child.getStack(), true /* ignoreCurrent */); - positionChildAtBottom(child, nextFocusableStack == null /* includingParents */); - child.updateTaskMovement(true); - } - - @VisibleForTesting - void positionChildAtBottom(Task child, boolean includingParents) { - if (child == null) { - // TODO: Fix the call-points that cause this to happen. - return; - } - - positionChildAt(POSITION_BOTTOM, child, includingParents); - getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); - } - - @Override - void onChildPositionChanged(WindowContainer child) { - if (isOrganized()) { - mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, false /* force */); - } - - if (!mChildren.contains(child)) { - return; - } - - final boolean isTop = getTopChild() == child; - - final Task task = child.asTask(); - if (task != null) { - task.updateTaskMovement(isTop); - } - - if (isTop) { - final DisplayContent displayContent = getDisplayContent(); - displayContent.layoutAndAssignWindowLayersIfNeeded(); - } - } - - @Override - void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { - final DisplayContent display = newParent != null - ? ((WindowContainer) newParent).getDisplayContent() : null; - final DisplayContent oldDisplay = oldParent != null - ? ((WindowContainer) oldParent).getDisplayContent() : null; - super.onParentChanged(newParent, oldParent); - - // Resume next focusable stack after reparenting to another display if we aren't removing - // the prevous display. - if (oldDisplay != null && oldDisplay.isRemoving()) { - postReparent(); - } - } - - void reparent(TaskDisplayArea newParent, boolean onTop) { - reparent(newParent, onTop ? POSITION_TOP : POSITION_BOTTOM); - } - - private void updateSurfaceBounds() { - updateSurfaceSize(getSyncTransaction()); - updateSurfacePosition(); - scheduleAnimation(); - } - - @Override - void getRelativePosition(Point outPos) { - super.getRelativePosition(outPos); - final int outset = getTaskOutset(); - outPos.x -= outset; - outPos.y -= outset; - } - - @Override - void onDisplayChanged(DisplayContent dc) { - super.onDisplayChanged(dc); - if (isRootTask()) { - updateSurfaceBounds(); - } - } - - boolean shouldIgnoreInput() { - if (inSplitScreenPrimaryWindowingMode() && !isFocusable()) { - return true; - } - if (mAtmService.mHasLeanbackFeature && inPinnedWindowingMode() - && !isFocusedStackOnDisplay()) { - // Preventing Picture-in-Picture stack from receiving input on TVs. - return true; - } - return false; - } - - @Override - void dump(PrintWriter pw, String prefix, boolean dumpAll) { - super.dump(pw, prefix, dumpAll); - if (!mExitingActivities.isEmpty()) { - pw.println(); - pw.println(prefix + "Exiting application tokens:"); - final String doublePrefix = prefix + " "; - for (int i = mExitingActivities.size() - 1; i >= 0; i--) { - WindowToken token = mExitingActivities.get(i); - pw.print(doublePrefix + "Exiting App #" + i); - pw.print(' '); pw.print(token); - pw.println(':'); - token.dump(pw, doublePrefix, dumpAll); - } - pw.println(); - } - mAnimatingActivityRegistry.dump(pw, "AnimatingApps:", prefix); - } - - /** - * Sets the current picture-in-picture aspect ratio. - */ - void setPictureInPictureAspectRatio(float aspectRatio) { - if (!mWmService.mAtmService.mSupportsPictureInPicture) { - return; - } - - final DisplayContent displayContent = getDisplayContent(); - if (displayContent == null) { - return; - } - - if (!inPinnedWindowingMode()) { - return; - } - - final PinnedStackController pinnedStackController = - getDisplayContent().getPinnedStackController(); - - if (Float.compare(aspectRatio, pinnedStackController.getAspectRatio()) == 0) { - return; - } - - // Notify the pinned stack controller about aspect ratio change. - // This would result a callback delivered from SystemUI to WM to start animation, - // if the bounds are ought to be altered due to aspect ratio change. - pinnedStackController.setAspectRatio( - pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio) - ? aspectRatio : -1f); - } - - /** - * Sets the current picture-in-picture actions. - */ - void setPictureInPictureActions(List<RemoteAction> actions) { - if (!mWmService.mAtmService.mSupportsPictureInPicture) { - return; - } - - if (!inPinnedWindowingMode()) { - return; - } - - getDisplayContent().getPinnedStackController().setActions(actions); - } - - public boolean isForceScaled() { - return mBoundsAnimating; - } - - /** Returns true if a removal action is still being deferred. */ - boolean handleCompleteDeferredRemoval() { - if (isAnimating(TRANSITION | CHILDREN)) { - return true; - } - - return super.handleCompleteDeferredRemoval(); - } - - public DisplayInfo getDisplayInfo() { - return mDisplayContent.getDisplayInfo(); - } - - AnimatingActivityRegistry getAnimatingActivityRegistry() { - return mAnimatingActivityRegistry; - } - - void executeAppTransition(ActivityOptions options) { - getDisplay().mDisplayContent.executeAppTransition(); - ActivityOptions.abort(options); - } - - boolean shouldSleepActivities() { - final DisplayContent display = getDisplay(); - - // Do not sleep activities in this stack if we're marked as focused and the keyguard - // is in the process of going away. - if (isFocusedStackOnDisplay() - && mStackSupervisor.getKeyguardController().isKeyguardGoingAway()) { - return false; - } - - return display != null ? display.isSleeping() : mAtmService.isSleepingLocked(); - } - - boolean shouldSleepOrShutDownActivities() { - return shouldSleepActivities() || mAtmService.mShuttingDown; - } - - @Override - public void dumpDebug(ProtoOutputStream proto, long fieldId, - @WindowTraceLogLevel int logLevel) { - if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) { - return; - } - - final long token = proto.start(fieldId); - super.dumpDebug(proto, WINDOW_CONTAINER, logLevel); - - proto.write(TaskProto.ID, mTaskId); - proto.write(DISPLAY_ID, getDisplayId()); - proto.write(ROOT_TASK_ID, getRootTaskId()); - - if (mResumedActivity != null) { - mResumedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY); - } - if (realActivity != null) { - proto.write(REAL_ACTIVITY, realActivity.flattenToShortString()); - } - if (origActivity != null) { - proto.write(ORIG_ACTIVITY, origActivity.flattenToShortString()); - } - proto.write(ACTIVITY_TYPE, getActivityType()); - proto.write(RESIZE_MODE, mResizeMode); - proto.write(MIN_WIDTH, mMinWidth); - proto.write(MIN_HEIGHT, mMinHeight); - - proto.write(FILLS_PARENT, matchParentBounds()); - getRawBounds().dumpDebug(proto, BOUNDS); - - if (mLastNonFullscreenBounds != null) { - mLastNonFullscreenBounds.dumpDebug(proto, LAST_NON_FULLSCREEN_BOUNDS); - } - - proto.write(ANIMATING_BOUNDS, mBoundsAnimating); - - if (mSurfaceControl != null) { - proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth()); - proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight()); - } - - proto.write(CREATED_BY_ORGANIZER, mCreatedByOrganizer); - - proto.end(token); - } -} diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index 8666a9efaeeb..0cd7ffce2ed4 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -46,9 +46,6 @@ import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.TYPE_VIRTUAL; -import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; -import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; -import static com.android.server.wm.ActivityStack.TAG_CLEANUP; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IDLE; @@ -74,11 +71,14 @@ import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_ import static com.android.server.wm.RootWindowContainer.TAG_STATES; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; +import static com.android.server.wm.Task.ActivityState.PAUSED; +import static com.android.server.wm.Task.ActivityState.PAUSING; import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK; import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE; import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; import static com.android.server.wm.Task.LOCK_TASK_AUTH_WHITELISTED; import static com.android.server.wm.Task.REPARENT_KEEP_STACK_AT_FRONT; +import static com.android.server.wm.Task.TAG_CLEANUP; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import static com.android.server.wm.WindowContainer.POSITION_TOP; @@ -380,12 +380,12 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { final ActivityRecord r; final ActivityRecord sourceRecord; final int startFlags; - final ActivityStack stack; + final Task stack; final WindowProcessController callerApp; final NeededUriGrants intentGrants; PendingActivityLaunch(ActivityRecord r, ActivityRecord sourceRecord, - int startFlags, ActivityStack stack, WindowProcessController callerApp, + int startFlags, Task stack, WindowProcessController callerApp, NeededUriGrants intentGrants) { this.r = r; this.sourceRecord = sourceRecord; @@ -493,7 +493,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { } void moveRecentsStackToFront(String reason) { - final ActivityStack recentsStack = mRootWindowContainer.getDefaultTaskDisplayArea() + final Task recentsStack = mRootWindowContainer.getDefaultTaskDisplayArea() .getStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS); if (recentsStack != null) { recentsStack.moveToFront(reason); @@ -729,7 +729,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { } final Task task = r.getTask(); - final ActivityStack stack = task.getStack(); + final Task rootTask = task.getRootTask(); beginDeferResume(); @@ -905,7 +905,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { if (andResume && readyToResume()) { // As part of the process of launching, ActivityThread also performs // a resume. - stack.minimalResumeActivityLocked(r); + rootTask.minimalResumeActivityLocked(r); } else { // This activity is not starting in the resumed state... which should look like we asked // it to pause+stop (but remain visible), and it has done so and reported back the @@ -923,7 +923,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { // launching the initial activity (that is, home), so that it can have // a chance to initialize itself while in the background, making the // switch back to it faster and look better. - if (mRootWindowContainer.isTopDisplayFocusedStack(stack)) { + if (mRootWindowContainer.isTopDisplayFocusedStack(rootTask)) { mService.getActivityStartController().startSetupActivity(); } @@ -990,7 +990,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { int requestCode, int callingPid, int callingUid, String callingPackage, @Nullable String callingFeatureId, boolean ignoreTargetSecurity, boolean launchingInTask, WindowProcessController callerApp, ActivityRecord resultRecord, - ActivityStack resultStack) { + Task resultStack) { final boolean isCallerRecents = mService.getRecentTasks() != null && mService.getRecentTasks().isCallerRecents(callingUid); final int startAnyPerm = mService.checkPermission(START_ANY_ACTIVITY, callingPid, @@ -1332,7 +1332,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { /** This doesn't just find a task, it also moves the task to front. */ void findTaskToMoveToFront(Task task, int flags, ActivityOptions options, String reason, boolean forceNonResizeable) { - ActivityStack currentStack = task.getStack(); + Task currentStack = task.getRootTask(); if (currentStack == null) { Slog.e(TAG, "findTaskToMoveToFront: can't move task=" + task + " to front. Stack is null"); @@ -1349,7 +1349,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { final Rect bounds = options.getLaunchBounds(); task.setBounds(bounds); - ActivityStack stack = + Task stack = mRootWindowContainer.getLaunchStack(null, options, task, ON_TOP); if (stack != currentStack) { @@ -1388,7 +1388,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { private void moveHomeStackToFrontIfNeeded(int flags, TaskDisplayArea taskDisplayArea, String reason) { - final ActivityStack focusedStack = taskDisplayArea.getFocusedStack(); + final Task focusedStack = taskDisplayArea.getFocusedStack(); if ((taskDisplayArea.getWindowingMode() == WINDOWING_MODE_FULLSCREEN && (flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0) @@ -1423,7 +1423,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { mWindowManager.setDockedStackResizing(resizing); } - private void removePinnedStackInSurfaceTransaction(ActivityStack stack) { + private void removePinnedStackInSurfaceTransaction(Task stack) { /** * Workaround: Force-stop all the activities in the pinned stack before we reparent them * to the fullscreen stack. This is to guarantee that when we are removing a stack, @@ -1459,7 +1459,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { } } - private void removeStackInSurfaceTransaction(ActivityStack stack) { + private void removeStackInSurfaceTransaction(Task stack) { if (stack.getWindowingMode() == WINDOWING_MODE_PINNED) { removePinnedStackInSurfaceTransaction(stack); } else { @@ -1479,7 +1479,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { * pinned stack, then its tasks are not explicitly removed when the stack is destroyed, but * instead moved back onto the fullscreen stack. */ - void removeStack(ActivityStack stack) { + void removeStack(Task stack) { mWindowManager.inSurfaceTransaction(() -> removeStackInSurfaceTransaction(stack)); } @@ -1597,7 +1597,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { * @return true if the task has been restored successfully. */ boolean restoreRecentTaskLocked(Task task, ActivityOptions aOptions, boolean onTop) { - final ActivityStack stack = + final Task stack = mRootWindowContainer.getLaunchStack(null, aOptions, task, onTop); final WindowContainer parent = task.getParent(); @@ -1639,8 +1639,8 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { * the various checks on tasks that are going to be reparented from one stack to another. */ // TODO: Look into changing users to this method to DisplayContent.resolveWindowingMode() - ActivityStack getReparentTargetStack(Task task, ActivityStack stack, boolean toTop) { - final ActivityStack prevStack = task.getStack(); + Task getReparentTargetStack(Task task, Task stack, boolean toTop) { + final Task prevStack = task.getRootTask(); final int rootTaskId = stack.mTaskId; final boolean inMultiWindowMode = stack.inMultiWindowMode(); @@ -1769,7 +1769,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { // A resumed activity cannot be stopping. remove from list mStoppingActivities.remove(r); - final ActivityStack stack = r.getRootTask(); + final Task stack = r.getRootTask(); if (stack.getDisplayArea().allResumedActivitiesComplete()) { mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); // Make sure activity & window visibility should be identical @@ -1783,15 +1783,15 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { // Called when WindowManager has finished animating the launchingBehind activity to the back. private void handleLaunchTaskBehindCompleteLocked(ActivityRecord r) { final Task task = r.getTask(); - final ActivityStack stack = task.getStack(); + final Task rootTask = task.getRootTask(); mRecentTasks.add(task); mService.getTaskChangeNotificationController().notifyTaskStackChanged(); - stack.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); + rootTask.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); // When launching tasks behind, update the last active time of the top task after the new // task has been shown briefly - final ActivityRecord top = stack.getTopNonFinishingActivity(); + final ActivityRecord top = rootTask.getTopNonFinishingActivity(); if (top != null) { top.getTask().touchActiveTime(); } @@ -2028,7 +2028,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { */ void updateTopResumedActivityIfNeeded() { final ActivityRecord prevTopActivity = mTopResumedActivity; - final ActivityStack topStack = mRootWindowContainer.getTopDisplayFocusedStack(); + final Task topStack = mRootWindowContainer.getTopDisplayFocusedStack(); if (topStack == null || topStack.mResumedActivity == prevTopActivity) { return; } @@ -2124,13 +2124,13 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { } void handleNonResizableTaskIfNeeded(Task task, int preferredWindowingMode, - TaskDisplayArea preferredTaskDisplayArea, ActivityStack actualStack) { + TaskDisplayArea preferredTaskDisplayArea, Task actualStack) { handleNonResizableTaskIfNeeded(task, preferredWindowingMode, preferredTaskDisplayArea, actualStack, false /* forceNonResizable */); } void handleNonResizableTaskIfNeeded(Task task, int preferredWindowingMode, - TaskDisplayArea preferredTaskDisplayArea, ActivityStack actualStack, + TaskDisplayArea preferredTaskDisplayArea, Task actualStack, boolean forceNonResizable) { final boolean isSecondaryDisplayPreferred = preferredTaskDisplayArea != null && preferredTaskDisplayArea.getDisplayId() != DEFAULT_DISPLAY; @@ -2186,7 +2186,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { // split-screen in split-screen. mService.getTaskChangeNotificationController() .notifyActivityDismissingDockedStack(); - taskDisplayArea.onSplitScreenModeDismissed((ActivityStack) task); + taskDisplayArea.onSplitScreenModeDismissed(task); taskDisplayArea.mDisplayContent.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS, true /* notifyClients */); } @@ -2242,14 +2242,14 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { } } - void scheduleUpdatePictureInPictureModeIfNeeded(Task task, ActivityStack prevStack) { - final ActivityStack stack = task.getStack(); - if ((prevStack == null || (prevStack != stack - && !prevStack.inPinnedWindowingMode() && !stack.inPinnedWindowingMode()))) { + void scheduleUpdatePictureInPictureModeIfNeeded(Task task, Task prevStack) { + final Task rootTask = task.getRootTask(); + if ((prevStack == null || (prevStack != rootTask + && !prevStack.inPinnedWindowingMode() && !rootTask.inPinnedWindowingMode()))) { return; } - scheduleUpdatePictureInPictureModeIfNeeded(task, stack.getRequestedOverrideBounds()); + scheduleUpdatePictureInPictureModeIfNeeded(task, rootTask.getRequestedOverrideBounds()); } private void scheduleUpdatePictureInPictureModeIfNeeded(Task task, Rect targetStackBounds) { @@ -2281,7 +2281,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { final PooledConsumer c = PooledLambda.obtainConsumer( ActivityRecord::updatePictureInPictureMode, PooledLambda.__(ActivityRecord.class), targetStackBounds, forceUpdate); - task.getStack().setBounds(targetStackBounds); + task.getRootTask().setBounds(targetStackBounds); task.forAllActivities(c); c.recycle(); } @@ -2349,7 +2349,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { int uid = 0; synchronized (mService.mGlobalLock) { if (r.attachedToProcess() - && r.isState(ActivityStack.ActivityState.RESTARTING_PROCESS)) { + && r.isState(Task.ActivityState.RESTARTING_PROCESS)) { processName = r.app.mName; uid = r.app.mUid; } @@ -2516,7 +2516,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { mService.getActivityStartController().postStartActivityProcessingForLastStarter( task.getTopNonFinishingActivity(), ActivityManager.START_TASK_TO_FRONT, - task.getStack()); + task.getRootTask()); return ActivityManager.START_TASK_TO_FRONT; } callingPackage = task.mCallingPackage; diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index 16ca60d1519b..e944faed6494 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -164,7 +164,7 @@ public class ActivityStartController { * last starter for an arbitrary task record. Re-evaluate whether we can remove. */ void postStartActivityProcessingForLastStarter(ActivityRecord r, int result, - ActivityStack targetStack) { + Task targetStack) { if (mLastStarter == null) { return; } @@ -190,7 +190,7 @@ public class ActivityStartController { // The home activity will be started later, defer resuming to avoid unneccerary operations // (e.g. start home recursively) when creating home stack. mSupervisor.beginDeferResume(); - final ActivityStack homeStack; + final Task homeStack; try { // Make sure home stack exists on display area. homeStack = taskDisplayArea.getOrCreateRootHomeTask(ON_TOP); diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index a8818b2775e2..e84f040931bb 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -56,7 +56,6 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Process.INVALID_UID; import static android.view.Display.DEFAULT_DISPLAY; -import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; @@ -76,6 +75,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS import static com.android.server.wm.ActivityTaskManagerService.ANIMATE; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY; +import static com.android.server.wm.Task.ActivityState.RESUMED; import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT; import static com.android.server.wm.WindowContainer.POSITION_TOP; @@ -180,8 +180,8 @@ class ActivityStarter { private ActivityInfo mNewTaskInfo; private Intent mNewTaskIntent; - private ActivityStack mSourceStack; - private ActivityStack mTargetStack; + private Task mSourceStack; + private Task mTargetStack; // The task that the last activity was started into. We currently reset the actual start // activity's task and as a result may not have a reference to the task in all cases private Task mTargetTask; @@ -651,7 +651,7 @@ class ActivityStarter { synchronized (mService.mGlobalLock) { final boolean globalConfigWillChange = mRequest.globalConfig != null && mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0; - final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack(); + final Task stack = mRootWindowContainer.getTopDisplayFocusedStack(); if (stack != null) { stack.mConfigWillChange = globalConfigWillChange; } @@ -984,7 +984,7 @@ class ActivityStarter { } } - final ActivityStack resultStack = resultRecord == null + final Task resultStack = resultRecord == null ? null : resultRecord.getRootTask(); if (err != START_SUCCESS) { @@ -1122,7 +1122,7 @@ class ActivityStarter { null /*profilerInfo*/); if (DEBUG_PERMISSIONS_REVIEW) { - final ActivityStack focusedStack = + final Task focusedStack = mRootWindowContainer.getTopDisplayFocusedStack(); Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false) + "} from uid " + callingUid + " on display " @@ -1163,7 +1163,7 @@ class ActivityStarter { r.appTimeTracker = sourceRecord.appTimeTracker; } - final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack(); + final Task stack = mRootWindowContainer.getTopDisplayFocusedStack(); // If we are starting an activity that is not from the same uid as the currently resumed // one, check whether app switches are allowed. @@ -1288,11 +1288,11 @@ class ActivityStarter { return false; } // if the realCallingUid is a persistent system process, abort if the IntentSender - // wasn't whitelisted to start an activity + // wasn't allowed to start an activity if (isRealCallingUidPersistentSystemProcess && allowBackgroundActivityStart) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid - + ") is persistent system process AND intent sender whitelisted " + + ") is persistent system process AND intent sender allowed " + "(allowBackgroundActivityStart = true)"); } return false; @@ -1346,23 +1346,23 @@ class ActivityStarter { // If we don't have callerApp at this point, no caller was provided to startActivity(). // That's the case for PendingIntent-based starts, since the creator's process might not be // up and alive. If that's the case, we retrieve the WindowProcessController for the send() - // caller, so that we can make the decision based on its foreground/whitelisted state. + // caller, so that we can make the decision based on its state. int callerAppUid = callingUid; if (callerApp == null) { callerApp = mService.getProcessController(realCallingPid, realCallingUid); callerAppUid = realCallingUid; } - // don't abort if the callerApp or other processes of that uid are whitelisted in any way + // don't abort if the callerApp or other processes of that uid are allowed in any way if (callerApp != null) { // first check the original calling process if (callerApp.areBackgroundActivityStartsAllowed()) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "Background activity start allowed: callerApp process (pid = " - + callerApp.getPid() + ", uid = " + callerAppUid + ") is whitelisted"); + + callerApp.getPid() + ", uid = " + callerAppUid + ") is allowed"); } return false; } - // only if that one wasn't whitelisted, check the other ones + // only if that one wasn't allowed, check the other ones final ArraySet<WindowProcessController> uidProcesses = mService.mProcessMap.getProcesses(callerAppUid); if (uidProcesses != null) { @@ -1372,7 +1372,7 @@ class ActivityStarter { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "Background activity start allowed: process " + proc.getPid() - + " from uid " + callerAppUid + " is whitelisted"); + + " from uid " + callerAppUid + " is allowed"); } return false; } @@ -1401,7 +1401,7 @@ class ActivityStarter { + "; isRealCallingUidPersistentSystemProcess: " + isRealCallingUidPersistentSystemProcess + "; originatingPendingIntent: " + originatingPendingIntent - + "; isBgStartWhitelisted: " + allowBackgroundActivityStart + + "; allowBackgroundActivityStart: " + allowBackgroundActivityStart + "; intent: " + intent + "; callerApp: " + callerApp + "]"); @@ -1445,7 +1445,7 @@ class ActivityStarter { } void postStartActivityProcessing(ActivityRecord r, int result, - ActivityStack startedActivityStack) { + Task startedActivityStack) { if (!ActivityManager.isStartResultSuccessful(result)) { if (mFrozeTaskList) { // If we specifically froze the task list as part of starting an activity, then @@ -1479,7 +1479,7 @@ class ActivityStarter { // The activity was already running so it wasn't started, but either brought to the // front or the new intent was delivered to it since it was already in front. Notify // anyone interested in this piece of information. - final ActivityStack homeStack = targetTask.getDisplayArea().getRootHomeTask(); + final Task homeStack = targetTask.getDisplayArea().getRootHomeTask(); final boolean homeTaskVisible = homeStack != null && homeStack.shouldBeVisible(null); mService.getTaskChangeNotificationController().notifyActivityRestartAttempt( targetTask.getTaskInfo(), homeTaskVisible, clearedTask, @@ -1514,7 +1514,7 @@ class ActivityStarter { int startFlags, boolean doResume, ActivityOptions options, Task inTask, boolean restrictedBgActivity, NeededUriGrants intentGrants) { int result = START_CANCELED; - final ActivityStack startedActivityStack; + final Task startedActivityStack; try { mService.deferWindowLayout(); Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner"); @@ -1537,9 +1537,9 @@ class ActivityStarter { * * @return the stack where the successful started activity resides. */ - private @Nullable ActivityStack handleStartResult(@NonNull ActivityRecord started, int result) { - final ActivityStack currentStack = started.getRootTask(); - ActivityStack startedActivityStack = currentStack != null ? currentStack : mTargetStack; + private @Nullable Task handleStartResult(@NonNull ActivityRecord started, int result) { + final Task currentStack = started.getRootTask(); + Task startedActivityStack = currentStack != null ? currentStack : mTargetStack; if (ActivityManager.isStartResultSuccessful(result)) { if (startedActivityStack != null) { @@ -1559,7 +1559,7 @@ class ActivityStarter { // If we are not able to proceed, disassociate the activity from the task. Leaving an // activity in an incomplete state can lead to issues, such as performing operations // without a window container. - final ActivityStack stack = mStartActivity.getRootTask(); + final Task stack = mStartActivity.getRootTask(); if (stack != null) { mStartActivity.finishIfPossible("startActivity", true /* oomAdj */); } @@ -1634,7 +1634,7 @@ class ActivityStarter { // If the activity being launched is the same as the one currently at the top, then // we need to check if it should only be launched once. - final ActivityStack topStack = mRootWindowContainer.getTopDisplayFocusedStack(); + final Task topStack = mRootWindowContainer.getTopDisplayFocusedStack(); if (topStack != null) { startResult = deliverToCurrentTopIfNeeded(topStack, intentGrants); if (startResult != START_SUCCESS) { @@ -1659,7 +1659,7 @@ class ActivityStarter { } if (!mAvoidMoveToFront && mDoResume) { - mTargetStack.getStack().moveToFront("reuseOrNewTask", targetTask); + mTargetStack.getRootTask().moveToFront("reuseOrNewTask", targetTask); if (mOptions != null) { if (mOptions.getTaskAlwaysOnTop()) { mTargetStack.setAlwaysOnTop(true); @@ -1752,7 +1752,7 @@ class ActivityStarter { } else if (mInTask != null) { return mInTask; } else { - final ActivityStack stack = getLaunchStack(mStartActivity, mLaunchFlags, + final Task stack = getLaunchStack(mStartActivity, mLaunchFlags, null /* task */, mOptions); final ActivityRecord top = stack.getTopNonFinishingActivity(); if (top != null) { @@ -1767,7 +1767,7 @@ class ActivityStarter { private void computeLaunchParams(ActivityRecord r, ActivityRecord sourceRecord, Task targetTask) { - final ActivityStack sourceStack = mSourceStack != null ? mSourceStack + final Task sourceStack = mSourceStack != null ? mSourceStack : mRootWindowContainer.getTopDisplayFocusedStack(); if (sourceStack != null && sourceStack.inSplitScreenWindowingMode() && (mOptions == null @@ -1851,7 +1851,7 @@ class ActivityStarter { // Should not recycle task which is from a different user, just adding the starting // activity to the task. if (targetTask.mUserId != mStartActivity.mUserId) { - mTargetStack = targetTask.getStack(); + mTargetStack = targetTask.getRootTask(); mAddingToTask = true; return START_SUCCESS; } @@ -1949,7 +1949,7 @@ class ActivityStarter { * Check if the activity being launched is the same as the one currently at the top and it * should only be launched once. */ - private int deliverToCurrentTopIfNeeded(ActivityStack topStack, NeededUriGrants intentGrants) { + private int deliverToCurrentTopIfNeeded(Task topStack, NeededUriGrants intentGrants) { final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop); final boolean dontStart = top != null && mStartActivity.resultTo == null && top.mActivityComponent.equals(mStartActivity.mActivityComponent) @@ -2042,7 +2042,7 @@ class ActivityStarter { // running, and the caller has asked to clear the current task to have this // activity at the top. mAddingToTask = true; - if (targetTask.getStack() == null) { + if (targetTask.getRootTask() == null) { // Target stack got cleared when we all activities were removed above. // Go ahead and reset it. mTargetStack = @@ -2262,7 +2262,7 @@ class ActivityStarter { if ((startFlags & START_FLAG_ONLY_IF_NEEDED) != 0) { ActivityRecord checkedCaller = sourceRecord; if (checkedCaller == null) { - ActivityStack topFocusedStack = mRootWindowContainer.getTopDisplayFocusedStack(); + Task topFocusedStack = mRootWindowContainer.getTopDisplayFocusedStack(); if (topFocusedStack != null) { checkedCaller = topFocusedStack.topRunningNonDelayedActivityLocked(mNotTop); } @@ -2299,7 +2299,7 @@ class ActivityStarter { private void computeLaunchingTaskFlags() { // If the caller is not coming from another activity, but has given us an explicit task into // which they would like us to launch the new activity, then let's see about doing that. - if (mSourceRecord == null && mInTask != null && mInTask.getStack() != null) { + if (mSourceRecord == null && mInTask != null && mInTask.getRootTask() != null) { final Intent baseIntent = mInTask.getBaseIntent(); final ActivityRecord root = mInTask.getRootActivity(); if (baseIntent == null) { @@ -2482,7 +2482,7 @@ class ActivityStarter { // to the front if the caller is not itself in the front. final boolean differentTopTask; if (mTargetStack.getDisplayArea() == mPreferredTaskDisplayArea) { - final ActivityStack focusStack = mTargetStack.getDisplay().getFocusedStack(); + final Task focusStack = mTargetStack.getDisplay().getFocusedStack(); final ActivityRecord curTop = (focusStack == null) ? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop); final Task topTask = curTop != null ? curTop.getTask() : null; @@ -2503,7 +2503,7 @@ class ActivityStarter { intentActivity.setTaskToAffiliateWith(mSourceRecord.getTask()); } - final ActivityStack launchStack = + final Task launchStack = getLaunchStack(mStartActivity, mLaunchFlags, intentTask, mOptions); if (launchStack == null || launchStack == mTargetStack) { // Do not set mMovedToFront to true below for split-screen-top stack, or @@ -2616,11 +2616,11 @@ class ActivityStarter { return launchFlags; } - private ActivityStack getLaunchStack(ActivityRecord r, int launchFlags, Task task, + private Task getLaunchStack(ActivityRecord r, int launchFlags, Task task, ActivityOptions aOptions) { // We are reusing a task, keep the stack! if (mReuseTask != null) { - return mReuseTask.getStack(); + return mReuseTask.getRootTask(); } final boolean onTop = diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index d5df9068e81d..a903bcd3d728 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -125,20 +125,30 @@ public abstract class ActivityTaskManagerInternal { * Sleep tokens cause the activity manager to put the top activity to sleep. * They are used by components such as dreams that may hide and block interaction * with underlying activities. + * The Acquirer provides an interface that encapsulates the underlying work, so the user does + * not need to handle the token by him/herself. */ - public static abstract class SleepToken { + public interface SleepTokenAcquirer { - /** Releases the sleep token. */ - public abstract void release(); + /** + * Acquires a sleep token. + * @param displayId The display to apply to. + */ + void acquire(int displayId); + + /** + * Releases the sleep token. + * @param displayId The display to apply to. + */ + void release(int displayId); } /** - * Acquires a sleep token for the specified display with the specified tag. + * Creates a sleep token acquirer for the specified display with the specified tag. * - * @param tag A string identifying the purpose of the token (eg. "Dream"). - * @param displayId The display to apply the sleep token to. + * @param tag A string identifying the purpose (eg. "Dream"). */ - public abstract SleepToken acquireSleepToken(@NonNull String tag, int displayId); + public abstract SleepTokenAcquirer createSleepTokenAcquirer(@NonNull String tag); /** * Returns home activity for the specified user. diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 4e1d789bebd8..029b5547ae29 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -86,8 +86,6 @@ import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.Scr import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE; import static com.android.server.am.EventLogTags.writeBootProgressEnableScreen; import static com.android.server.am.EventLogTags.writeConfigurationChanged; -import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED; -import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING; import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; @@ -120,6 +118,8 @@ import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_P import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION; import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_ONLY; import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS; +import static com.android.server.wm.Task.ActivityState.DESTROYED; +import static com.android.server.wm.Task.ActivityState.DESTROYING; import static com.android.server.wm.Task.LOCK_TASK_AUTH_DONT_LOCK; import static com.android.server.wm.Task.REPARENT_KEEP_STACK_AT_FRONT; import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE; @@ -1119,7 +1119,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { synchronized (mGlobalLock) { // If this is coming from the currently resumed activity, it is // effectively saying that app switches are allowed at this point. - final ActivityStack stack = getTopDisplayFocusedStack(); + final Task stack = getTopDisplayFocusedStack(); if (stack != null && stack.mResumedActivity != null && stack.mResumedActivity.info.applicationInfo.uid == Binder.getCallingUid()) { mAppSwitchesAllowedTime = 0; @@ -1868,7 +1868,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { r = ActivityRecord.isInStackLocked(token); if (r != null) { if (r.attachedToProcess() - && r.isState(ActivityStack.ActivityState.RESTARTING_PROCESS)) { + && r.isState(Task.ActivityState.RESTARTING_PROCESS)) { // The activity was requested to restart from // {@link #restartActivityProcessIfVisible}. restartingName = r.app.mName; @@ -1996,7 +1996,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public boolean isTopActivityImmersive() { enforceNotIsolatedCaller("isTopActivityImmersive"); synchronized (mGlobalLock) { - final ActivityStack topFocusedStack = getTopDisplayFocusedStack(); + final Task topFocusedStack = getTopDisplayFocusedStack(); if (topFocusedStack == null) { return false; } @@ -2018,7 +2018,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final long origId = Binder.clearCallingIdentity(); if (self.isState( - ActivityStack.ActivityState.RESUMED, ActivityStack.ActivityState.PAUSING)) { + Task.ActivityState.RESUMED, Task.ActivityState.PAUSING)) { self.getDisplay().mDisplayContent.mAppTransition.overridePendingAppTransition( packageName, enterAnim, exitAnim, null, null); } @@ -2031,7 +2031,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public int getFrontActivityScreenCompatMode() { enforceNotIsolatedCaller("getFrontActivityScreenCompatMode"); synchronized (mGlobalLock) { - final ActivityStack stack = getTopDisplayFocusedStack(); + final Task stack = getTopDisplayFocusedStack(); final ActivityRecord r = stack != null ? stack.topRunningActivity() : null; if (r == null) { return ActivityManager.COMPAT_MODE_UNKNOWN; @@ -2046,7 +2046,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { "setFrontActivityScreenCompatMode"); ApplicationInfo ai; synchronized (mGlobalLock) { - final ActivityStack stack = getTopDisplayFocusedStack(); + final Task stack = getTopDisplayFocusedStack(); final ActivityRecord r = stack != null ? stack.topRunningActivity() : null; if (r == null) { Slog.w(TAG, "setFrontActivityScreenCompatMode failed: no top activity"); @@ -2143,7 +2143,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public int getDisplayId(IBinder activityToken) throws RemoteException { synchronized (mGlobalLock) { - final ActivityStack stack = ActivityRecord.getStackLocked(activityToken); + final Task stack = ActivityRecord.getStackLocked(activityToken); if (stack != null) { final int displayId = stack.getDisplayId(); return displayId != INVALID_DISPLAY ? displayId : DEFAULT_DISPLAY; @@ -2158,7 +2158,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { - ActivityStack focusedStack = getTopDisplayFocusedStack(); + Task focusedStack = getTopDisplayFocusedStack(); if (focusedStack != null) { return mRootWindowContainer.getStackInfo(focusedStack.mTaskId); } @@ -2176,7 +2176,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final long callingId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { - final ActivityStack stack = mRootWindowContainer.getStack(stackId); + final Task stack = mRootWindowContainer.getStack(stackId); if (stack == null) { Slog.w(TAG, "setFocusedStack: No stack with id=" + stackId); return; @@ -2393,7 +2393,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { + windowingMode); } - final ActivityStack stack = task.getStack(); + final Task stack = task.getRootTask(); if (toTop) { stack.moveToFront("setTaskWindowingMode", task); } @@ -2453,7 +2453,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { synchronized (mGlobalLock) { final long origId = Binder.clearCallingIdentity(); try { - final ActivityStack topFocusedStack = getTopDisplayFocusedStack(); + final Task topFocusedStack = getTopDisplayFocusedStack(); if (topFocusedStack != null) { topFocusedStack.unhandledBackLocked(); } @@ -2470,7 +2470,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (r == null) { return; } - ActivityStack stack = r.getRootTask(); + Task stack = r.getRootTask(); final TaskOrganizerController taskOrgController = mWindowOrganizerController.mTaskOrganizerController; if (taskOrgController.handleInterceptBackPressedOnTaskRoot(stack)) { @@ -2727,7 +2727,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public boolean willActivityBeVisible(IBinder token) { synchronized (mGlobalLock) { - ActivityStack stack = ActivityRecord.getStackLocked(token); + Task stack = ActivityRecord.getStackLocked(token); if (stack != null) { return stack.willActivityBeVisible(token); } @@ -2750,7 +2750,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId + " to stackId=" + stackId + " toTop=" + toTop); - final ActivityStack stack = mRootWindowContainer.getStack(stackId); + final Task stack = mRootWindowContainer.getStack(stackId); if (stack == null) { throw new IllegalStateException( "moveTaskToStack: No stack for stackId=" + stackId); @@ -2829,7 +2829,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { void moveTaskToSplitScreenPrimaryTask(Task task, boolean toTop) { final TaskDisplayArea taskDisplayArea = task.getDisplayArea(); - final ActivityStack primarySplitTask = taskDisplayArea.getRootSplitScreenPrimaryTask(); + final Task primarySplitTask = taskDisplayArea.getRootSplitScreenPrimaryTask(); if (primarySplitTask == null) { throw new IllegalStateException("Can't enter split without associated organized task"); } @@ -2841,8 +2841,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { WindowContainerTransaction wct = new WindowContainerTransaction(); // Clear out current windowing mode before reparenting to split taks. wct.setWindowingMode( - task.getStack().mRemoteToken.toWindowContainerToken(), WINDOWING_MODE_UNDEFINED); - wct.reparent(task.getStack().mRemoteToken.toWindowContainerToken(), + task.getRootTask().mRemoteToken.toWindowContainerToken(), WINDOWING_MODE_UNDEFINED); + wct.reparent(task.getRootTask().mRemoteToken.toWindowContainerToken(), primarySplitTask.mRemoteToken.toWindowContainerToken(), toTop); mWindowOrganizerController.applyTransaction(wct); } @@ -2990,7 +2990,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } // When starting lock task mode the stack must be in front and focused - task.getStack().moveToFront("startSystemLockTaskMode"); + task.getRootTask().moveToFront("startSystemLockTaskMode"); startLockTaskModeLocked(task, true /* isSystemCaller */); } } finally { @@ -3025,7 +3025,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return; } - final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack(); + final Task stack = mRootWindowContainer.getTopDisplayFocusedStack(); if (stack == null || task != stack.getTopMostTask()) { throw new IllegalArgumentException("Invalid task, not in foreground"); } @@ -3299,7 +3299,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { + ainfo.applicationInfo.uid + ", calling uid=" + callingUid); } - final ActivityStack stack = r.getRootTask(); + final Task stack = r.getRootTask(); final Task task = stack.getDisplayArea().createStack(stack.getWindowingMode(), stack.getActivityType(), !ON_TOP, ainfo, intent, false /* createdByOrganizer */); @@ -3460,7 +3460,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { synchronized (mGlobalLock) { final long ident = Binder.clearCallingIdentity(); try { - final ActivityStack stack = mRootWindowContainer.getStack(stackId); + final Task stack = mRootWindowContainer.getStack(stackId); if (stack == null) { Slog.w(TAG, "removeStack: No stack with id=" + stackId); return; @@ -3504,7 +3504,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { + token); } - final ActivityStack stack = r.getRootTask(); + final Task stack = r.getRootTask(); if (stack == null) { throw new IllegalStateException("toggleFreeformWindowingMode: the activity " + "doesn't have a stack"); @@ -3668,7 +3668,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { "enqueueAssistContext()"); synchronized (mGlobalLock) { - final ActivityStack stack = getTopDisplayFocusedStack(); + final Task stack = getTopDisplayFocusedStack(); ActivityRecord activity = stack != null ? stack.getTopNonFinishingActivity() : null; if (activity == null) { Slog.w(TAG, "getAssistContextExtras failed: no top activity"); @@ -3797,7 +3797,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public boolean isAssistDataAllowedOnCurrentActivity() { int userId; synchronized (mGlobalLock) { - final ActivityStack focusedStack = getTopDisplayFocusedStack(); + final Task focusedStack = getTopDisplayFocusedStack(); if (focusedStack == null || focusedStack.isActivityTypeAssistant()) { return false; } @@ -3970,7 +3970,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { + taskId); } - final ActivityStack stack = mRootWindowContainer.getStack(stackId); + final Task stack = mRootWindowContainer.getStack(stackId); if (stack == null) { throw new IllegalArgumentException("positionTaskInStack: no stack for id=" @@ -3983,7 +3983,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // TODO: Have the callers of this API call a separate reparent method if that is // what they intended to do vs. having this method also do reparenting. - if (task.getStack() == stack) { + if (task.getRootTask() == stack) { // Change position in current stack. stack.positionChildAt(task, position); } else { @@ -4089,7 +4089,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final List<RemoteAction> actions = r.pictureInPictureArgs.getActions(); mRootWindowContainer.moveActivityToPinnedStack( r, "enterPictureInPictureMode"); - final ActivityStack stack = r.getRootTask(); + final Task stack = r.getRootTask(); stack.setPictureInPictureAspectRatio(aspectRatio); stack.setPictureInPictureActions(actions); MetricsLoggerWrapper.logPictureInPictureEnter(mContext, @@ -4134,7 +4134,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // If the activity is already in picture-in-picture, update the pinned stack now // if it is not already expanding to fullscreen. Otherwise, the arguments will // be used the next time the activity enters PiP - final ActivityStack stack = r.getRootTask(); + final Task stack = r.getRootTask(); stack.setPictureInPictureAspectRatio( r.pictureInPictureArgs.getAspectRatio()); stack.setPictureInPictureActions(r.pictureInPictureArgs.getActions()); @@ -4798,7 +4798,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } - ActivityStack getTopDisplayFocusedStack() { + Task getTopDisplayFocusedStack() { return mRootWindowContainer.getTopDisplayFocusedStack(); } @@ -5070,7 +5070,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final long sleepToken = proto.start(ActivityManagerServiceDumpProcessesProto.SLEEP_STATUS); proto.write(ActivityManagerServiceDumpProcessesProto.SleepStatus.WAKEFULNESS, PowerManagerInternal.wakefulnessToProtoEnum(wakeFullness)); - for (ActivityTaskManagerInternal.SleepToken st : mRootWindowContainer.mSleepTokens) { + final int tokenSize = mRootWindowContainer.mSleepTokens.size(); + for (int i = 0; i < tokenSize; i++) { + final RootWindowContainer.SleepToken st = + mRootWindowContainer.mSleepTokens.valueAt(i); proto.write(ActivityManagerServiceDumpProcessesProto.SleepStatus.SLEEP_TOKENS, st.toString()); } @@ -5504,12 +5507,35 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { reason); } - ActivityTaskManagerInternal.SleepToken acquireSleepToken(String tag, int displayId) { - synchronized (mGlobalLock) { - final ActivityTaskManagerInternal.SleepToken token = - mRootWindowContainer.createSleepToken(tag, displayId); - updateSleepIfNeededLocked(); - return token; + final class SleepTokenAcquirerImpl implements ActivityTaskManagerInternal.SleepTokenAcquirer { + private final String mTag; + private final SparseArray<RootWindowContainer.SleepToken> mSleepTokens = + new SparseArray<>(); + + SleepTokenAcquirerImpl(@NonNull String tag) { + mTag = tag; + } + + @Override + public void acquire(int displayId) { + synchronized (mGlobalLock) { + if (!mSleepTokens.contains(displayId)) { + mSleepTokens.append(displayId, + mRootWindowContainer.createSleepToken(mTag, displayId)); + updateSleepIfNeededLocked(); + } + } + } + + @Override + public void release(int displayId) { + synchronized (mGlobalLock) { + final RootWindowContainer.SleepToken token = mSleepTokens.get(displayId); + if (token != null) { + mRootWindowContainer.removeSleepToken(token); + mSleepTokens.remove(displayId); + } + } } } @@ -5769,7 +5795,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { /** Applies latest configuration and/or visibility updates if needed. */ boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) { boolean kept = true; - final ActivityStack mainStack = mRootWindowContainer.getTopDisplayFocusedStack(); + final Task mainStack = mRootWindowContainer.getTopDisplayFocusedStack(); // mainStack is null during startup. if (mainStack != null) { if (changes != 0 && starting == null) { @@ -6068,9 +6094,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final class LocalService extends ActivityTaskManagerInternal { @Override - public SleepToken acquireSleepToken(String tag, int displayId) { + public SleepTokenAcquirer createSleepTokenAcquirer(@NonNull String tag) { Objects.requireNonNull(tag); - return ActivityTaskManagerService.this.acquireSleepToken(tag, displayId); + return new SleepTokenAcquirerImpl(tag); } @Override @@ -6820,7 +6846,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { synchronized (mGlobalLock) { // Clean-up disabled activities. if (mRootWindowContainer.finishDisabledPackageActivities( - packageName, disabledClasses, true, false, userId) && booted) { + packageName, disabledClasses, true /* doit */, false /* evenPersistent */, + userId, false /* onlyRemoveNoProcess */) && booted) { mRootWindowContainer.resumeFocusedStacksTopActivities(); mStackSupervisor.scheduleIdle(); } @@ -6839,7 +6866,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { boolean didSomething = getActivityStartController().clearPendingActivityLaunches(packageName); didSomething |= mRootWindowContainer.finishDisabledPackageActivities(packageName, - null, doit, evenPersistent, userId); + null /* filterByClasses */, doit, evenPersistent, userId, + // Only remove the activities without process because the activities with + // attached process will be removed when handling process died with + // WindowProcessController#isRemoved == true. + true /* onlyRemoveNoProcess */); return didSomething; } } @@ -7024,7 +7055,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mRootWindowContainer.dumpDisplayConfigs(pw, " "); } if (dumpAll) { - final ActivityStack topFocusedStack = getTopDisplayFocusedStack(); + final Task topFocusedStack = getTopDisplayFocusedStack(); if (dumpPackage == null && topFocusedStack != null) { pw.println(" mConfigWillChange: " + topFocusedStack.mConfigWillChange); } @@ -7107,7 +7138,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { synchronized (mGlobalLock) { if (dumpPackage == null) { getGlobalConfiguration().dumpDebug(proto, GLOBAL_CONFIGURATION); - final ActivityStack topFocusedStack = getTopDisplayFocusedStack(); + final Task topFocusedStack = getTopDisplayFocusedStack(); if (topFocusedStack != null) { proto.write(CONFIG_WILL_CHANGE, topFocusedStack.mConfigWillChange); } diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java index 320ca65d215b..167afab9db0e 100644 --- a/services/core/java/com/android/server/wm/CompatModePackages.java +++ b/services/core/java/com/android/server/wm/CompatModePackages.java @@ -22,20 +22,6 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFI import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; - -import com.android.internal.util.FastXmlSerializer; - import android.app.ActivityManager; import android.app.AppGlobals; import android.content.pm.ApplicationInfo; @@ -51,6 +37,20 @@ import android.util.Slog; import android.util.SparseArray; import android.util.Xml; +import com.android.internal.util.FastXmlSerializer; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + public final class CompatModePackages { private static final String TAG = TAG_WITH_CLASS_NAME ? "CompatModePackages" : TAG_ATM; private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION; @@ -321,7 +321,7 @@ public final class CompatModePackages { scheduleWrite(); - final ActivityStack stack = mService.getTopDisplayFocusedStack(); + final Task stack = mService.getTopDisplayFocusedStack(); ActivityRecord starting = stack.restartPackage(packageName); // Tell all processes that loaded this package about the change. diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java index fbb2fcb15aee..546c5d4c29de 100644 --- a/services/core/java/com/android/server/wm/DisplayArea.java +++ b/services/core/java/com/android/server/wm/DisplayArea.java @@ -93,7 +93,7 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> { // Verify that we have proper ordering Type.checkChild(mType, Type.typeOf(child)); - if (child instanceof ActivityStack) { + if (child instanceof Task) { // TODO(display-area): ActivityStacks are type ANY, but are allowed to have siblings. // They might need a separate type. return; @@ -487,7 +487,7 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> { return ((DisplayArea) c).mType; } else if (c instanceof WindowToken && !(c instanceof ActivityRecord)) { return typeOf((WindowToken) c); - } else if (c instanceof ActivityStack) { + } else if (c instanceof Task) { return ANY; } else { throw new IllegalArgumentException("Unknown container: " + c); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 8fff81a1e8c4..0b1f4d9e1613 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -78,7 +78,6 @@ import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_A import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; -import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK; import static com.android.server.wm.DisplayContentProto.APP_TRANSITION; import static com.android.server.wm.DisplayContentProto.CLOSING_APPS; @@ -103,6 +102,7 @@ import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON; import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; +import static com.android.server.wm.Task.ActivityState.RESUMED; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import static com.android.server.wm.WindowContainerChildProto.DISPLAY_CONTENT; @@ -490,6 +490,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp */ private ActivityRecord mFixedRotationLaunchingApp; + /** The delay to avoid toggling the animation quickly. */ + private static final long FIXED_ROTATION_HIDE_ANIMATION_DEBOUNCE_DELAY_MS = 250; private FixedRotationAnimationController mFixedRotationAnimationController; final FixedRotationTransitionListener mFixedRotationTransitionListener = @@ -585,9 +587,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp private IntArray mDisplayAccessUIDs = new IntArray(); /** All tokens used to put activities on this stack to sleep (including mOffToken) */ - final ArrayList<ActivityTaskManagerInternal.SleepToken> mAllSleepTokens = new ArrayList<>(); - /** The token acquired by ActivityStackSupervisor to put stacks on the display to sleep */ - ActivityTaskManagerInternal.SleepToken mOffToken; + final ArrayList<RootWindowContainer.SleepToken> mAllSleepTokens = new ArrayList<>(); + /** The token acquirer to put stacks on the display to sleep */ + private final ActivityTaskManagerInternal.SleepTokenAcquirer mOffTokenAcquirer; private boolean mSleeping; @@ -923,6 +925,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mAtmService = mWmService.mAtmService; mDisplay = display; mDisplayId = display.getDisplayId(); + mOffTokenAcquirer = mRootWindowContainer.mDisplayOffTokenAcquirer; mWallpaperController = new WallpaperController(mWmService, this); display.getDisplayInfo(mDisplayInfo); display.getMetrics(mDisplayMetrics); @@ -1523,10 +1526,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp void setFixedRotationLaunchingAppUnchecked(@Nullable ActivityRecord r, int rotation) { if (mFixedRotationLaunchingApp == null && r != null) { mWmService.mDisplayNotificationController.dispatchFixedRotationStarted(this, rotation); - if (mFixedRotationAnimationController == null) { - mFixedRotationAnimationController = new FixedRotationAnimationController(this); - mFixedRotationAnimationController.hide(); - } + startFixedRotationAnimation( + // Delay the hide animation to avoid blinking by clicking navigation bar that + // may toggle fixed rotation in a short time. + r == mFixedRotationTransitionListener.mAnimatingRecents /* shouldDebounce */); } else if (mFixedRotationLaunchingApp != null && r == null) { mWmService.mDisplayNotificationController.dispatchFixedRotationFinished(this); finishFixedRotationAnimationIfPossible(); @@ -1624,6 +1627,32 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } } + /** + * Starts the hide animation for the windows which will be rotated seamlessly. + * + * @return {@code true} if the animation is executed right now. + */ + private boolean startFixedRotationAnimation(boolean shouldDebounce) { + if (shouldDebounce) { + mWmService.mH.postDelayed(() -> { + synchronized (mWmService.mGlobalLock) { + if (mFixedRotationLaunchingApp != null + && startFixedRotationAnimation(false /* shouldDebounce */)) { + // Apply the transaction so the animation leash can take effect immediately. + getPendingTransaction().apply(); + } + } + }, FIXED_ROTATION_HIDE_ANIMATION_DEBOUNCE_DELAY_MS); + return false; + } + if (mFixedRotationAnimationController == null) { + mFixedRotationAnimationController = new FixedRotationAnimationController(this); + mFixedRotationAnimationController.hide(); + return true; + } + return false; + } + /** Re-show the previously hidden windows if all seamless rotated windows are done. */ void finishFixedRotationAnimationIfPossible() { final FixedRotationAnimationController controller = mFixedRotationAnimationController; @@ -2193,13 +2222,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * activity type. Null is no compatible stack on the display. */ @Nullable - ActivityStack getStack(int windowingMode, int activityType) { + Task getStack(int windowingMode, int activityType) { return getItemFromTaskDisplayAreas(taskDisplayArea -> taskDisplayArea.getStack(windowingMode, activityType)); } @Nullable - ActivityStack getStack(int rootTaskId) { + Task getStack(int rootTaskId) { return getItemFromTaskDisplayAreas(taskDisplayArea -> taskDisplayArea.getStack(rootTaskId)); } @@ -2211,7 +2240,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp @VisibleForTesting @Nullable - ActivityStack getTopStack() { + Task getTopStack() { return getItemFromTaskDisplayAreas(TaskDisplayArea::getTopStack); } @@ -2831,7 +2860,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } proto.write(SINGLE_TASK_INSTANCE, mSingleTaskInstance); - final ActivityStack focusedStack = getFocusedStack(); + final Task focusedStack = getFocusedStack(); if (focusedStack != null) { proto.write(FOCUSED_ROOT_TASK_ID, focusedStack.getRootTaskId()); final ActivityRecord focusedActivity = focusedStack.getDisplayArea() @@ -2956,26 +2985,26 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp pw.println(); // Dump stack references - final ActivityStack homeStack = getDefaultTaskDisplayArea().getRootHomeTask(); + final Task homeStack = getDefaultTaskDisplayArea().getRootHomeTask(); if (homeStack != null) { pw.println(prefix + "homeStack=" + homeStack.getName()); } - final ActivityStack pinnedStack = getDefaultTaskDisplayArea().getRootPinnedTask(); + final Task pinnedStack = getDefaultTaskDisplayArea().getRootPinnedTask(); if (pinnedStack != null) { pw.println(prefix + "pinnedStack=" + pinnedStack.getName()); } - final ActivityStack splitScreenPrimaryStack = getDefaultTaskDisplayArea() + final Task splitScreenPrimaryStack = getDefaultTaskDisplayArea() .getRootSplitScreenPrimaryTask(); if (splitScreenPrimaryStack != null) { pw.println(prefix + "splitScreenPrimaryStack=" + splitScreenPrimaryStack.getName()); } // TODO: Support recents on non-default task containers - final ActivityStack recentsStack = getDefaultTaskDisplayArea().getStack( + final Task recentsStack = getDefaultTaskDisplayArea().getStack( WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS); if (recentsStack != null) { pw.println(prefix + "recentsStack=" + recentsStack.getName()); } - final ActivityStack dreamStack = + final Task dreamStack = getStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_DREAM); if (dreamStack != null) { pw.println(prefix + "dreamStack=" + dreamStack.getName()); @@ -3527,18 +3556,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp == mRemoteInsetsControlTarget)) { return mRemoteInsetsControlTarget; } else { - // Now, a special case -- if the last target's window is in the process of exiting, but - // not removed, keep on the last target to avoid IME flicker. - final WindowState cur = InsetsControlTarget.asWindowOrNull(mInputMethodControlTarget); - if (cur != null && !cur.mRemoved && cur.isDisplayedLw() && cur.isClosing() - && !cur.isActivityTypeHome()) { - if (DEBUG_INPUT_METHOD) { - Slog.v(TAG_WM, "Not changing control while current window" - + " is closing and not removed"); - } - return cur; - } - // Otherwise, we just use the ime target as received from IME. return mInputMethodInputTarget; } } @@ -4139,7 +4156,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } private boolean processTask(Task task) { - if (!task.getStack().getWindowConfiguration().canResizeTask()) { + if (!task.getRootTask().getWindowConfiguration().canResizeTask()) { return true; } @@ -4931,11 +4948,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp final int displayId = mDisplay.getDisplayId(); if (displayId != DEFAULT_DISPLAY) { final int displayState = mDisplay.getState(); - if (displayState == Display.STATE_OFF && mOffToken == null) { - mOffToken = mAtmService.acquireSleepToken("Display-off", displayId); - } else if (displayState == Display.STATE_ON && mOffToken != null) { - mOffToken.release(); - mOffToken = null; + if (displayState == Display.STATE_OFF) { + mOffTokenAcquirer.acquire(mDisplayId); + } else if (displayState == Display.STATE_ON) { + mOffTokenAcquirer.release(mDisplayId); } } mWmService.requestTraversal(); @@ -4953,7 +4969,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } @Nullable - ActivityStack getFocusedStack() { + Task getFocusedStack() { return getItemFromTaskDisplayAreas(TaskDisplayArea::getFocusedStack); } @@ -5150,12 +5166,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp void remove() { mRemoving = true; - ActivityStack lastReparentedStack; + Task lastReparentedStack; mRootWindowContainer.mStackSupervisor.beginDeferResume(); try { lastReparentedStack = reduceOnAllTaskDisplayAreas((taskDisplayArea, stack) -> { - final ActivityStack lastReparentedStackFromArea = taskDisplayArea.remove(); + final Task lastReparentedStackFromArea = taskDisplayArea.remove(); if (lastReparentedStackFromArea != null) { return lastReparentedStackFromArea; } @@ -5175,7 +5191,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mDisplayPolicy.release(); if (!mAllSleepTokens.isEmpty()) { - mRootWindowContainer.mSleepTokens.removeAll(mAllSleepTokens); + mAllSleepTokens.forEach(token -> + mRootWindowContainer.mSleepTokens.remove(token.mHashKey)); mAllSleepTokens.clear(); mAtmService.updateSleepIfNeededLocked(); } @@ -5191,7 +5208,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp if (taskDisplayArea.getStackCount() != 1) { return true; } - final ActivityStack stack = taskDisplayArea.getStackAt(0); + final Task stack = taskDisplayArea.getStackAt(0); return !stack.isActivityTypeHome() || stack.hasChild(); }); if (!hasNonEmptyHomeStack) { @@ -5294,7 +5311,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp + this); } if (stackCount > 0) { - final ActivityStack stack = getDefaultTaskDisplayArea().getStackAt(0); + final Task stack = getDefaultTaskDisplayArea().getStackAt(0); if (stack.getChildCount() > 1) { throw new IllegalArgumentException("Display stack already has multiple tasks." + " display=" + this + " stack=" + stack); @@ -5311,7 +5328,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp @VisibleForTesting void removeAllTasks() { - forAllTasks((t) -> { t.getStack().removeChild(t, "removeAllTasks"); }); + forAllTasks((t) -> { t.getRootTask().removeChild(t, "removeAllTasks"); }); } /** diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 53f16a7241fc..0e24fc8bd307 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -144,7 +144,7 @@ import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Region; import android.hardware.input.InputManager; -import android.hardware.power.V1_0.PowerHint; +import android.hardware.power.Boost; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -567,8 +567,8 @@ public class DisplayPolicy { @Override public void onFling(int duration) { if (mService.mPowerManagerInternal != null) { - mService.mPowerManagerInternal.powerHint( - PowerHint.INTERACTION, duration); + mService.mPowerManagerInternal.setPowerBoost( + Boost.INTERACTION, duration); } } diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index 0747e243e276..c63128c15e8d 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -42,7 +42,7 @@ import android.content.pm.ActivityInfo.ScreenOrientation; import android.content.pm.PackageManager; import android.content.res.Resources; import android.database.ContentObserver; -import android.hardware.power.V1_0.PowerHint; +import android.hardware.power.Boost; import android.net.Uri; import android.os.Handler; import android.os.RemoteException; @@ -1473,7 +1473,7 @@ public class DisplayRotation { @Override public void run() { // Send interaction power boost to improve redraw performance. - mService.mPowerManagerInternal.powerHint(PowerHint.INTERACTION, 0); + mService.mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, 0); if (isRotationChoicePossible(mCurrentAppOrientation)) { final boolean isValid = isValidRotationChoice(mRotation); sendProposedRotationChangeToStatusBarInternal(mRotation, isValid); diff --git a/services/core/java/com/android/server/wm/DragResizeMode.java b/services/core/java/com/android/server/wm/DragResizeMode.java index 71beb5032914..eb27b046b9ab 100644 --- a/services/core/java/com/android/server/wm/DragResizeMode.java +++ b/services/core/java/com/android/server/wm/DragResizeMode.java @@ -35,7 +35,7 @@ class DragResizeMode { */ static final int DRAG_RESIZE_MODE_DOCKED_DIVIDER = 1; - static boolean isModeAllowedForStack(ActivityStack stack, int mode) { + static boolean isModeAllowedForStack(Task stack, int mode) { switch (mode) { case DRAG_RESIZE_MODE_FREEFORM: return stack.getWindowingMode() == WINDOWING_MODE_FREEFORM; diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java index c4e03f5c65f5..c7cba77f6797 100644 --- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java +++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java @@ -18,8 +18,8 @@ package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; -import static com.android.server.wm.ActivityStack.TAG_VISIBILITY; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY; +import static com.android.server.wm.Task.TAG_VISIBILITY; import android.annotation.Nullable; import android.util.Slog; @@ -29,7 +29,7 @@ import com.android.internal.util.function.pooled.PooledLambda; /** Helper class to ensure activities are in the right visible state for a container. */ class EnsureActivitiesVisibleHelper { - private final ActivityStack mContiner; + private final Task mContiner; private ActivityRecord mTop; private ActivityRecord mStarting; private boolean mAboveTop; @@ -39,7 +39,7 @@ class EnsureActivitiesVisibleHelper { private boolean mPreserveWindows; private boolean mNotifyClients; - EnsureActivitiesVisibleHelper(ActivityStack container) { + EnsureActivitiesVisibleHelper(Task container) { mContiner = container; } @@ -69,7 +69,7 @@ class EnsureActivitiesVisibleHelper { /** * Ensure visibility with an option to also update the configuration of visible activities. - * @see ActivityStack#ensureActivitiesVisible(ActivityRecord, int, boolean) + * @see Task#ensureActivitiesVisible(ActivityRecord, int, boolean) * @see RootWindowContainer#ensureActivitiesVisible(ActivityRecord, int, boolean) * @param starting The top most activity in the task. * The activity is either starting or resuming. diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index 76f236534b69..c36a75b01293 100644 --- a/services/core/java/com/android/server/wm/KeyguardController.java +++ b/services/core/java/com/android/server/wm/KeyguardController.java @@ -50,7 +50,6 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.server.policy.WindowManagerPolicy; -import com.android.server.wm.ActivityTaskManagerInternal.SleepToken; import java.io.PrintWriter; @@ -74,11 +73,14 @@ class KeyguardController { private final SparseArray<KeyguardDisplayState> mDisplayStates = new SparseArray<>(); private final ActivityTaskManagerService mService; private RootWindowContainer mRootWindowContainer; + private final ActivityTaskManagerInternal.SleepTokenAcquirer mSleepTokenAcquirer; + KeyguardController(ActivityTaskManagerService service, ActivityStackSupervisor stackSupervisor) { mService = service; mStackSupervisor = stackSupervisor; + mSleepTokenAcquirer = mService.new SleepTokenAcquirerImpl("keyguard"); } void setWindowManager(WindowManagerService windowManager) { @@ -412,17 +414,17 @@ class KeyguardController { private void updateKeyguardSleepToken(int displayId) { final KeyguardDisplayState state = getDisplay(displayId); - if (isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken == null) { - state.acquiredSleepToken(); - } else if (!isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken != null) { - state.releaseSleepToken(); + if (isKeyguardUnoccludedOrAodShowing(displayId)) { + state.mSleepTokenAcquirer.acquire(displayId); + } else if (!isKeyguardUnoccludedOrAodShowing(displayId)) { + state.mSleepTokenAcquirer.release(displayId); } } private KeyguardDisplayState getDisplay(int displayId) { KeyguardDisplayState state = mDisplayStates.get(displayId); if (state == null) { - state = new KeyguardDisplayState(mService, displayId); + state = new KeyguardDisplayState(mService, displayId, mSleepTokenAcquirer); mDisplayStates.append(displayId, state); } return state; @@ -443,29 +445,18 @@ class KeyguardController { private ActivityRecord mDismissingKeyguardActivity; private boolean mRequestDismissKeyguard; private final ActivityTaskManagerService mService; - private SleepToken mSleepToken; + private final ActivityTaskManagerInternal.SleepTokenAcquirer mSleepTokenAcquirer; - KeyguardDisplayState(ActivityTaskManagerService service, int displayId) { + KeyguardDisplayState(ActivityTaskManagerService service, int displayId, + ActivityTaskManagerInternal.SleepTokenAcquirer acquirer) { mService = service; mDisplayId = displayId; + mSleepTokenAcquirer = acquirer; } void onRemoved() { mDismissingKeyguardActivity = null; - releaseSleepToken(); - } - - void acquiredSleepToken() { - if (mSleepToken == null) { - mSleepToken = mService.acquireSleepToken("keyguard", mDisplayId); - } - } - - void releaseSleepToken() { - if (mSleepToken != null) { - mSleepToken.release(); - mSleepToken = null; - } + mSleepTokenAcquirer.release(mDisplayId); } void visibilitiesUpdated(KeyguardController controller, DisplayContent display) { @@ -475,7 +466,7 @@ class KeyguardController { mOccluded = false; mDismissingKeyguardActivity = null; - final ActivityStack stack = getStackForControllingOccluding(display); + final Task stack = getStackForControllingOccluding(display); if (stack != null) { final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity(); mOccluded = stack.topActivityOccludesKeyguard() || (topDismissing != null @@ -516,10 +507,10 @@ class KeyguardController { * occlusion state. */ @Nullable - private ActivityStack getStackForControllingOccluding(DisplayContent display) { + private Task getStackForControllingOccluding(DisplayContent display) { return display.getItemFromTaskDisplayAreas(taskDisplayArea -> { for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + final Task stack = taskDisplayArea.getStackAt(sNdx); if (stack != null && stack.isFocusableAndVisible() && !stack.inPinnedWindowingMode()) { return stack; diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java index 513be7a6becc..56e1187d51da 100644 --- a/services/core/java/com/android/server/wm/LaunchParamsController.java +++ b/services/core/java/com/android/server/wm/LaunchParamsController.java @@ -145,10 +145,10 @@ class LaunchParamsController { } if (mTmpParams.hasWindowingMode() - && mTmpParams.mWindowingMode != task.getStack().getWindowingMode()) { + && mTmpParams.mWindowingMode != task.getRootTask().getWindowingMode()) { final int activityType = activity != null ? activity.getActivityType() : task.getActivityType(); - task.getStack().setWindowingMode(task.getDisplayArea().validateWindowingMode( + task.getRootTask().setWindowingMode(task.getDisplayArea().validateWindowingMode( mTmpParams.mWindowingMode, activity, task, activityType)); } @@ -156,7 +156,7 @@ class LaunchParamsController { return false; } - if (task.getStack().inFreeformWindowingMode()) { + if (task.getRootTask().inFreeformWindowingMode()) { // Only set bounds if it's in freeform mode. task.setBounds(mTmpParams.mBounds); return true; diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java index 892ee717e21f..c7a438d527ad 100644 --- a/services/core/java/com/android/server/wm/LockTaskController.java +++ b/services/core/java/com/android/server/wm/LockTaskController.java @@ -151,7 +151,7 @@ public class LockTaskController { * The first task in the list, which started the current LockTask session, is called the root * task. It coincides with the Home task in a typical multi-app kiosk deployment. When there are * more than one locked tasks, the root task can't be finished. Nor can it be moved to the back - * of the stack by {@link ActivityStack#moveTaskToBack(Task)}; + * of the stack by {@link Task#moveTaskToBack(Task)}; * * Calling {@link Activity#stopLockTask()} on the root task will finish all tasks but itself in * this list, and the device will exit LockTask mode. @@ -252,7 +252,7 @@ public class LockTaskController { /** * @return whether the given task can be moved to the back of the stack with - * {@link ActivityStack#moveTaskToBack(Task)} + * {@link Task#moveTaskToBack(Task)} * @see #mLockTaskModeTasks */ boolean canMoveTaskToBack(Task task) { @@ -617,14 +617,14 @@ public class LockTaskController { mSupervisor.findTaskToMoveToFront(task, 0, null, reason, lockTaskModeState != LOCK_TASK_MODE_NONE); mSupervisor.mRootWindowContainer.resumeFocusedStacksTopActivities(); - final ActivityStack stack = task.getStack(); - if (stack != null) { - stack.getDisplay().mDisplayContent.executeAppTransition(); + final Task rootTask = task.getRootTask(); + if (rootTask != null) { + rootTask.getDisplay().mDisplayContent.executeAppTransition(); } } else if (lockTaskModeState != LOCK_TASK_MODE_NONE) { mSupervisor.handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED, mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea(), - task.getStack(), true /* forceNonResizable */); + task.getRootTask(), true /* forceNonResizable */); } } diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java index 851b533a550d..ba2c0b6dc0ac 100644 --- a/services/core/java/com/android/server/wm/RecentTasks.java +++ b/services/core/java/com/android/server/wm/RecentTasks.java @@ -215,7 +215,7 @@ class RecentTasks { final RootWindowContainer rac = mService.mRootWindowContainer; final DisplayContent dc = rac.getDisplayContent(displayId).mDisplayContent; if (dc.pointWithinAppWindow(x, y)) { - final ActivityStack stack = mService.getTopDisplayFocusedStack(); + final Task stack = mService.getTopDisplayFocusedStack(); final Task topTask = stack != null ? stack.getTopMostTask() : null; resetFreezeTaskListReordering(topTask); } @@ -323,7 +323,7 @@ class RecentTasks { @VisibleForTesting void resetFreezeTaskListReorderingOnTimeout() { synchronized (mService.mGlobalLock) { - final ActivityStack focusedStack = mService.getTopDisplayFocusedStack(); + final Task focusedStack = mService.getTopDisplayFocusedStack(); final Task topTask = focusedStack != null ? focusedStack.getTopMostTask() : null; resetFreezeTaskListReordering(topTask); } @@ -520,9 +520,9 @@ class RecentTasks { * Kicks off the task persister to write any pending tasks to disk. */ void notifyTaskPersisterLocked(Task task, boolean flush) { - final ActivityStack stack = task != null ? task.getStack() : null; - if (stack != null && stack.isHomeOrRecentsStack()) { - // Never persist the home or recents stack. + final Task rootTask = task != null ? task.getRootTask() : null; + if (rootTask != null && rootTask.isHomeOrRecentsStack()) { + // Never persist the home or recents task. return; } syncPersistentTaskIdsLocked(); @@ -554,8 +554,8 @@ class RecentTasks { } private static boolean shouldPersistTaskLocked(Task task) { - final ActivityStack stack = task.getStack(); - return task.isPersistable && (stack == null || !stack.isHomeOrRecentsStack()); + final Task rootTask = task.getRootTask(); + return task.isPersistable && (rootTask == null || !rootTask.isHomeOrRecentsStack()); } void onSystemReadyLocked() { @@ -975,9 +975,9 @@ class RecentTasks { final Task task = mTasks.get(i); if (TaskPersister.DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task + " persistable=" + task.isPersistable); - final ActivityStack stack = task.getStack(); + final Task rootTask = task.getRootTask(); if ((task.isPersistable || task.inRecents) - && (stack == null || !stack.isHomeOrRecentsStack())) { + && (rootTask == null || !rootTask.isHomeOrRecentsStack())) { if (TaskPersister.DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task); persistentTaskIds.add(task.mTaskId); } else { @@ -1325,10 +1325,10 @@ class RecentTasks { return false; case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: if (DEBUG_RECENTS_TRIM_TASKS) { - Slog.d(TAG, "\ttop=" + task.getStack().getTopMostTask()); + Slog.d(TAG, "\ttop=" + task.getRootTask().getTopMostTask()); } - final ActivityStack stack = task.getStack(); - if (stack != null && stack.getTopMostTask() == task) { + final Task rootTask = task.getRootTask(); + if (rootTask != null && rootTask.getTopMostTask() == task) { // Only the non-top task of the primary split screen mode is visible return false; } @@ -1344,9 +1344,9 @@ class RecentTasks { // Tasks managed by/associated with an ActivityView should be excluded from recents. // singleTaskInstance is set on the VirtualDisplay managed by ActivityView // TODO(b/126185105): Find a different signal to use besides isSingleTaskInstance - final ActivityStack stack = task.getStack(); - if (stack != null) { - DisplayContent display = stack.getDisplay(); + final Task rootTask = task.getRootTask(); + if (rootTask != null) { + DisplayContent display = rootTask.getDisplay(); if (display != null && display.isSingleTaskInstance()) { return false; } @@ -1400,21 +1400,21 @@ class RecentTasks { /** @return whether the given task can be trimmed even if it is outside the visible range. */ protected boolean isTrimmable(Task task) { - final ActivityStack stack = task.getStack(); + final Task rootTask = task.getRootTask(); // No stack for task, just trim it - if (stack == null) { + if (rootTask == null) { return true; } // Ignore tasks from different displays // TODO (b/115289124): No Recents on non-default displays. - if (!stack.isOnHomeDisplay()) { + if (!rootTask.isOnHomeDisplay()) { return false; } - final ActivityStack rootHomeTask = stack.getDisplayArea().getRootHomeTask(); - // Home stack does not exist. Don't trim the task. + final Task rootHomeTask = rootTask.getDisplayArea().getRootHomeTask(); + // Home task does not exist. Don't trim the task. if (rootHomeTask == null) { return false; } diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index 00272ad57be4..d7b43bc5537d 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -76,7 +76,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, private ActivityRecord mLaunchedTargetActivity; // The stack to restore the target stack behind when the animation is finished - private ActivityStack mRestoreTargetBehindStack; + private Task mRestoreTargetBehindStack; RecentsAnimation(ActivityTaskManagerService atm, ActivityStackSupervisor stackSupervisor, ActivityStartController activityStartController, WindowManagerService wm, @@ -107,7 +107,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, void preloadRecentsActivity() { ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Preload recents with %s", mTargetIntent); - ActivityStack targetStack = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED, + Task targetStack = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED, mTargetActivityType); ActivityRecord targetActivity = getTargetActivity(targetStack); if (targetActivity != null) { @@ -150,8 +150,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks, // Invisible activity should be stopped. If the recents activity is alive and its doesn't // need to relaunch by current configuration, then it may be already in stopped state. - if (!targetActivity.isState(ActivityStack.ActivityState.STOPPING, - ActivityStack.ActivityState.STOPPED)) { + if (!targetActivity.isState(Task.ActivityState.STOPPING, + Task.ActivityState.STOPPED)) { // Add to stopping instead of stop immediately. So the client has the chance to perform // traversal in non-stopped state (ViewRootImpl.mStopped) that would initialize more // things (e.g. the measure can be done earlier). The actual stop will be performed when @@ -166,7 +166,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "RecentsAnimation#startRecentsActivity"); // If the activity is associated with the recents stack, then try and get that first - ActivityStack targetStack = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED, + Task targetStack = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED, mTargetActivityType); ActivityRecord targetActivity = getTargetActivity(targetStack); final boolean hasExistingActivity = targetActivity != null; @@ -299,7 +299,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, try { mWindowManager.cleanupRecentsAnimation(reorderMode); - final ActivityStack targetStack = mDefaultTaskDisplayArea.getStack( + final Task targetStack = mDefaultTaskDisplayArea.getStack( WINDOWING_MODE_UNDEFINED, mTargetActivityType); // Prefer to use the original target activity instead of top activity because // we may have moved another task to top (starting 3p launcher). @@ -333,7 +333,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, } if (WM_DEBUG_RECENTS_ANIMATIONS.isLogToAny()) { - final ActivityStack topStack = getTopNonAlwaysOnTopStack(); + final Task topStack = getTopNonAlwaysOnTopStack(); if (topStack != targetStack) { ProtoLog.w(WM_DEBUG_RECENTS_ANIMATIONS, "Expected target stack=%s" @@ -347,7 +347,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, taskDisplayArea.moveStackBehindStack(targetStack, mRestoreTargetBehindStack); if (WM_DEBUG_RECENTS_ANIMATIONS.isLogToAny()) { - final ActivityStack aboveTargetStack = getStackAbove(targetStack); + final Task aboveTargetStack = getStackAbove(targetStack); if (mRestoreTargetBehindStack != null && aboveTargetStack != mRestoreTargetBehindStack) { ProtoLog.w(WM_DEBUG_RECENTS_ANIMATIONS, @@ -411,7 +411,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, } @Override - public void onStackOrderChanged(ActivityStack stack) { + public void onStackOrderChanged(Task stack) { ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "onStackOrderChanged(): stack=%s", stack); if (mDefaultTaskDisplayArea.getIndexOf(stack) == -1 || !stack.shouldBeVisible(null)) { // The stack is not visible, so ignore this change @@ -466,9 +466,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks, /** * @return The top stack that is not always-on-top. */ - private ActivityStack getTopNonAlwaysOnTopStack() { + private Task getTopNonAlwaysOnTopStack() { for (int i = mDefaultTaskDisplayArea.getStackCount() - 1; i >= 0; i--) { - final ActivityStack s = mDefaultTaskDisplayArea.getStackAt(i); + final Task s = mDefaultTaskDisplayArea.getStackAt(i); if (s.getWindowConfiguration().isAlwaysOnTop()) { continue; } @@ -481,7 +481,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, * @return the top activity in the {@param targetStack} matching the {@param component}, or just * the top activity of the top task if no task matches the component. */ - private ActivityRecord getTargetActivity(ActivityStack targetStack) { + private ActivityRecord getTargetActivity(Task targetStack) { if (targetStack == null) { return null; } diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 55bca2ee2791..f5bd4cd866a6 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -362,7 +362,7 @@ public class RecentsAnimationController implements DeathRecipient { // TODO(b/153090560): Support Recents on multiple task display areas final ArrayList<Task> visibleTasks = mDisplayContent.getDefaultTaskDisplayArea() .getVisibleTasks(); - final ActivityStack targetStack = mDisplayContent.getDefaultTaskDisplayArea() + final Task targetStack = mDisplayContent.getDefaultTaskDisplayArea() .getStack(WINDOWING_MODE_UNDEFINED, targetActivityType); if (targetStack != null) { final PooledConsumer c = PooledLambda.obtainConsumer((t, outList) -> @@ -406,7 +406,7 @@ public class RecentsAnimationController implements DeathRecipient { } // Save the minimized home height - final ActivityStack rootHomeTask = + final Task rootHomeTask = mDisplayContent.getDefaultTaskDisplayArea().getRootHomeTask(); mMinimizedHomeBounds = rootHomeTask != null ? rootHomeTask.getBounds() : null; diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java index 32de699eaae9..cc5ed36e0f47 100644 --- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java +++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java @@ -16,10 +16,10 @@ package com.android.server.wm; -import static com.android.server.wm.ActivityStack.TAG_ADD_REMOVE; -import static com.android.server.wm.ActivityStack.TAG_TASKS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; +import static com.android.server.wm.Task.TAG_ADD_REMOVE; +import static com.android.server.wm.Task.TAG_TASKS; import android.app.ActivityOptions; import android.content.Intent; @@ -37,7 +37,7 @@ import java.util.ArrayList; class ResetTargetTaskHelper { private Task mTask; private Task mTargetTask; - private ActivityStack mTargetStack; + private Task mTargetStack; private ActivityRecord mRoot; private boolean mForceReset; private boolean mCanMoveOptions; @@ -61,7 +61,7 @@ class ResetTargetTaskHelper { mForceReset = forceReset; mTargetTask = targetTask; mTargetTaskFound = false; - mTargetStack = targetTask.getStack(); + mTargetStack = targetTask.getRootTask(); mActivityReparentPosition = -1; final PooledConsumer c = PooledLambda.obtainConsumer( diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 50ae4ea2f627..06dec7c8023d 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -44,11 +44,6 @@ import static android.view.WindowManager.TRANSIT_TASK_TO_BACK; import static com.android.server.policy.PhoneWindowManager.SYSTEM_DIALOG_REASON_ASSIST; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; -import static com.android.server.wm.ActivityStack.ActivityState.FINISHING; -import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; -import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; -import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; -import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; import static com.android.server.wm.ActivityStackSupervisor.dumpHistoryList; @@ -74,6 +69,11 @@ import static com.android.server.wm.RootWindowContainerProto.IS_HOME_RECENTS_COM import static com.android.server.wm.RootWindowContainerProto.KEYGUARD_CONTROLLER; import static com.android.server.wm.RootWindowContainerProto.PENDING_ACTIVITIES; import static com.android.server.wm.RootWindowContainerProto.WINDOW_CONTAINER; +import static com.android.server.wm.Task.ActivityState.FINISHING; +import static com.android.server.wm.Task.ActivityState.PAUSED; +import static com.android.server.wm.Task.ActivityState.RESUMED; +import static com.android.server.wm.Task.ActivityState.STOPPED; +import static com.android.server.wm.Task.ActivityState.STOPPING; import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE; import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS; @@ -112,7 +112,7 @@ import android.content.res.Resources; import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerInternal; -import android.hardware.power.V1_0.PowerHint; +import android.hardware.power.Mode; import android.net.Uri; import android.os.Binder; import android.os.Debug; @@ -220,6 +220,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // transaction from the global transaction. private final SurfaceControl.Transaction mDisplayTransaction; + /** The token acquirer to put stacks on the displays to sleep */ + final ActivityTaskManagerInternal.SleepTokenAcquirer mDisplayOffTokenAcquirer; + /** * The modes which affect which tasks are returned when calling * {@link RootWindowContainer#anyTaskForId(int)}. @@ -259,7 +262,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> * They are used by components that may hide and block interaction with underlying * activities. */ - final ArrayList<ActivityTaskManagerInternal.SleepToken> mSleepTokens = new ArrayList<>(); + final SparseArray<SleepToken> mSleepTokens = new SparseArray<>(); /** Set when a power mode launch has started, but not ended. */ private boolean mPowerModeLaunchStarted; @@ -314,7 +317,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> * Returns the top activity in any existing task matching the given Intent in the input * result. Returns null if no such task is found. */ - void process(ActivityRecord target, ActivityStack parent) { + void process(ActivityRecord target, Task parent) { mTarget = target; intent = target.intent; @@ -444,6 +447,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> mService = service.mAtmService; mStackSupervisor = mService.mStackSupervisor; mStackSupervisor.mRootWindowContainer = this; + mDisplayOffTokenAcquirer = mService.new SleepTokenAcquirerImpl("Display-off"); } boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) { @@ -951,9 +955,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> if (mSustainedPerformanceModeCurrent != mSustainedPerformanceModeEnabled) { mSustainedPerformanceModeEnabled = mSustainedPerformanceModeCurrent; - mWmService.mPowerManagerInternal.powerHint( - PowerHint.SUSTAINED_PERFORMANCE, - mSustainedPerformanceModeEnabled ? 1 : 0); + mWmService.mPowerManagerInternal.setPowerMode( + Mode.SUSTAINED_PERFORMANCE, + mSustainedPerformanceModeEnabled); } if (mUpdateRotation) { @@ -1475,7 +1479,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> boolean fromHomeKey) { // Fallback to top focused display or default display if the displayId is invalid. if (displayId == INVALID_DISPLAY) { - final ActivityStack stack = getTopDisplayFocusedStack(); + final Task stack = getTopDisplayFocusedStack(); displayId = stack != null ? stack.getDisplayId() : DEFAULT_DISPLAY; } @@ -1501,7 +1505,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> boolean allowInstrumenting, boolean fromHomeKey) { // Fallback to top focused display area if the provided one is invalid. if (taskDisplayArea == null) { - final ActivityStack stack = getTopDisplayFocusedStack(); + final Task stack = getTopDisplayFocusedStack(); taskDisplayArea = stack != null ? stack.getDisplayArea() : getDefaultTaskDisplayArea(); } @@ -1818,12 +1822,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent> */ List<IBinder> getTopVisibleActivities() { final ArrayList<IBinder> topActivityTokens = new ArrayList<>(); - final ActivityStack topFocusedStack = getTopDisplayFocusedStack(); + final Task topFocusedStack = getTopDisplayFocusedStack(); // Traverse all displays. forAllTaskDisplayAreas(taskDisplayArea -> { // Traverse all stacks on a display area. for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + final Task stack = taskDisplayArea.getStackAt(sNdx); // Get top activity from a visible stack and add it to the list. if (stack.shouldBeVisible(null /* starting */)) { final ActivityRecord top = stack.getTopNonFinishingActivity(); @@ -1841,9 +1845,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } @Nullable - ActivityStack getTopDisplayFocusedStack() { + Task getTopDisplayFocusedStack() { for (int i = getChildCount() - 1; i >= 0; --i) { - final ActivityStack focusedStack = getChildAt(i).getFocusedStack(); + final Task focusedStack = getChildAt(i).getFocusedStack(); if (focusedStack != null) { return focusedStack; } @@ -1853,7 +1857,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> @Nullable ActivityRecord getTopResumedActivity() { - final ActivityStack focusedStack = getTopDisplayFocusedStack(); + final Task focusedStack = getTopDisplayFocusedStack(); if (focusedStack == null) { return null; } @@ -1866,7 +1870,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return getItemFromTaskDisplayAreas(TaskDisplayArea::getFocusedActivity); } - boolean isTopDisplayFocusedStack(ActivityStack stack) { + boolean isTopDisplayFocusedStack(Task stack) { return stack != null && stack == getTopDisplayFocusedStack(); } @@ -1879,7 +1883,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // foreground. WindowProcessController fgApp = reduceOnAllTaskDisplayAreas((taskDisplayArea, app) -> { for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + final Task stack = taskDisplayArea.getStackAt(sNdx); if (isTopDisplayFocusedStack(stack)) { final ActivityRecord resumedActivity = stack.getResumedActivity(); if (resumedActivity != null) { @@ -1907,7 +1911,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> boolean didSomething = false; for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) { final DisplayContent display = getChildAt(displayNdx); - final ActivityStack stack = display.getFocusedStack(); + final Task stack = display.getFocusedStack(); if (stack == null) { continue; } @@ -1984,7 +1988,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } boolean switchUser(int userId, UserState uss) { - final ActivityStack topFocusedStack = getTopDisplayFocusedStack(); + final Task topFocusedStack = getTopDisplayFocusedStack(); final int focusStackId = topFocusedStack != null ? topFocusedStack.getRootTaskId() : INVALID_TASK_ID; // We dismiss the docked stack whenever we switch users. @@ -2002,13 +2006,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent> mStackSupervisor.mStartingUsers.add(uss); forAllTaskDisplayAreas(taskDisplayArea -> { for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + final Task stack = taskDisplayArea.getStackAt(sNdx); stack.switchUser(userId); } }); final int restoreStackId = mUserStackInFront.get(userId); - ActivityStack stack = getStack(restoreStackId); + Task stack = getStack(restoreStackId); if (stack == null) { stack = getDefaultTaskDisplayArea().getOrCreateRootHomeTask(); } @@ -2030,7 +2034,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> * Update the last used stack id for non-current user (current user's last * used stack is the focused stack) */ - void updateUserStack(int userId, ActivityStack stack) { + void updateUserStack(int userId, Task stack) { if (userId != mCurrentUser) { if (stack == null) { stack = getDefaultTaskDisplayArea().getOrCreateRootHomeTask(); @@ -2047,7 +2051,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> * @param onTop Indicates whether container should be place on top or on bottom. */ void moveStackToTaskDisplayArea(int stackId, TaskDisplayArea taskDisplayArea, boolean onTop) { - final ActivityStack stack = getStack(stackId); + final Task stack = getStack(stackId); if (stack == null) { throw new IllegalArgumentException("moveStackToTaskDisplayArea: Unknown stackId=" + stackId); @@ -2096,7 +2100,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } boolean moveTopStackActivityToPinnedStack(int stackId) { - final ActivityStack stack = getStack(stackId); + final Task stack = getStack(stackId); if (stack == null) { throw new IllegalArgumentException( "moveTopStackActivityToPinnedStack: Unknown stackId=" + stackId); @@ -2126,7 +2130,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> try { final Task task = r.getTask(); - final ActivityStack pinnedStack = taskDisplayArea.getRootPinnedTask(); + final Task pinnedStack = taskDisplayArea.getRootPinnedTask(); // This will change the pinned stack's windowing mode to its original mode, ensuring // we only have one stack that is in pinned mode. @@ -2139,9 +2143,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> r.getDisplayContent().prepareAppTransition(TRANSIT_NONE, false); final boolean singleActivity = task.getChildCount() == 1; - final ActivityStack stack; + final Task stack; if (singleActivity) { - stack = (ActivityStack) task; + stack = task; } else { // In the case of multiple activities, we will create a new task for it and then // move the PIP activity into the task. @@ -2248,13 +2252,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent> * @return The task id that was finished in this stack, or INVALID_TASK_ID if none was finished. */ int finishTopCrashedActivities(WindowProcessController app, String reason) { - ActivityStack focusedStack = getTopDisplayFocusedStack(); + Task focusedStack = getTopDisplayFocusedStack(); Task finishedTask = reduceOnAllTaskDisplayAreas((taskDisplayArea, task) -> { // It is possible that request to finish activity might also remove its task and // stack, so we need to be careful with indexes in the loop and check child count // every time. for (int stackNdx = 0; stackNdx < taskDisplayArea.getStackCount(); ++stackNdx) { - final ActivityStack stack = taskDisplayArea.getStackAt(stackNdx); + final Task stack = taskDisplayArea.getStackAt(stackNdx); final Task t = stack.finishTopCrashedActivityLocked(app, reason); if (stack == focusedStack || task == null) { task = t; @@ -2270,7 +2274,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } boolean resumeFocusedStacksTopActivities( - ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) { + Task targetStack, ActivityRecord target, ActivityOptions targetOptions) { if (!mStackSupervisor.readyToResume()) { return false; @@ -2292,7 +2296,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> boolean resumedOnDisplay = display.reduceOnAllTaskDisplayAreas( (taskDisplayArea, resumed) -> { for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + final Task stack = taskDisplayArea.getStackAt(sNdx); final ActivityRecord topRunningActivity = stack.topRunningActivity(); if (!stack.isFocusableAndVisible() || topRunningActivity == null) { continue; @@ -2322,7 +2326,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // crashed) it's possible that nothing was resumed on a display. Requesting resume // of top activity in focused stack explicitly will make sure that at least home // activity is started and resumed, and no recursion occurs. - final ActivityStack focusedStack = display.getFocusedStack(); + final Task focusedStack = display.getFocusedStack(); if (focusedStack != null) { result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions); } else if (targetStack == null) { @@ -2352,7 +2356,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // Set the sleeping state of the stacks on the display. display.forAllTaskDisplayAreas(taskDisplayArea -> { for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + final Task stack = taskDisplayArea.getStackAt(sNdx); if (displayShouldSleep) { stack.goToSleepIfPossible(false /* shuttingDown */); } else { @@ -2393,9 +2397,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } } - protected ActivityStack getStack(int stackId) { + protected Task getStack(int stackId) { for (int i = getChildCount() - 1; i >= 0; --i) { - final ActivityStack stack = getChildAt(i).getStack(stackId); + final Task stack = getChildAt(i).getStack(stackId); if (stack != null) { return stack; } @@ -2404,9 +2408,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } /** @see DisplayContent#getStack(int, int) */ - ActivityStack getStack(int windowingMode, int activityType) { + Task getStack(int windowingMode, int activityType) { for (int i = getChildCount() - 1; i >= 0; --i) { - final ActivityStack stack = getChildAt(i).getStack(windowingMode, activityType); + final Task stack = getChildAt(i).getStack(windowingMode, activityType); if (stack != null) { return stack; } @@ -2414,7 +2418,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return null; } - private ActivityStack getStack(int windowingMode, int activityType, + private Task getStack(int windowingMode, int activityType, int displayId) { DisplayContent display = getDisplayContent(displayId); if (display == null) { @@ -2423,7 +2427,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return display.getStack(windowingMode, activityType); } - private ActivityManager.StackInfo getStackInfo(ActivityStack stack) { + private ActivityManager.StackInfo getStackInfo(Task stack) { final TaskDisplayArea taskDisplayArea = stack.getDisplayArea(); ActivityManager.StackInfo info = new ActivityManager.StackInfo(); stack.getBounds(info.bounds); @@ -2469,7 +2473,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } ActivityManager.StackInfo getStackInfo(int stackId) { - ActivityStack stack = getStack(stackId); + Task stack = getStack(stackId); if (stack != null) { return getStackInfo(stack); } @@ -2477,12 +2481,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } ActivityManager.StackInfo getStackInfo(int windowingMode, int activityType) { - final ActivityStack stack = getStack(windowingMode, activityType); + final Task stack = getStack(windowingMode, activityType); return (stack != null) ? getStackInfo(stack) : null; } ActivityManager.StackInfo getStackInfo(int windowingMode, int activityType, int displayId) { - final ActivityStack stack = getStack(windowingMode, activityType, displayId); + final Task stack = getStack(windowingMode, activityType, displayId); return (stack != null) ? getStackInfo(stack) : null; } @@ -2492,7 +2496,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> if (displayId == INVALID_DISPLAY) { forAllTaskDisplayAreas(taskDisplayArea -> { for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + final Task stack = taskDisplayArea.getStackAt(sNdx); list.add(getStackInfo(stack)); } }); @@ -2504,7 +2508,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } display.forAllTaskDisplayAreas(taskDisplayArea -> { for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + final Task stack = taskDisplayArea.getStackAt(sNdx); list.add(getStackInfo(stack)); } }); @@ -2576,7 +2580,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> mDisplayManagerInternal.setDisplayAccessUIDs(mDisplayAccessUIDs); } - ActivityStack findStackBehind(ActivityStack stack) { + Task findStackBehind(Task stack) { final TaskDisplayArea taskDisplayArea = stack.getDisplayArea(); if (taskDisplayArea != null) { for (int i = taskDisplayArea.getStackCount() - 1; i >= 0; i--) { @@ -2619,20 +2623,29 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } } - ActivityTaskManagerInternal.SleepToken createSleepToken(String tag, int displayId) { + SleepToken createSleepToken(String tag, int displayId) { final DisplayContent display = getDisplayContent(displayId); if (display == null) { throw new IllegalArgumentException("Invalid display: " + displayId); } - final SleepTokenImpl token = new SleepTokenImpl(tag, displayId); - mSleepTokens.add(token); - display.mAllSleepTokens.add(token); + final int tokenKey = makeSleepTokenKey(tag, displayId); + SleepToken token = mSleepTokens.get(tokenKey); + if (token == null) { + token = new SleepToken(tag, displayId); + mSleepTokens.put(tokenKey, token); + display.mAllSleepTokens.add(token); + } else { + throw new RuntimeException("Create the same sleep token twice: " + token); + } return token; } - private void removeSleepToken(SleepTokenImpl token) { - mSleepTokens.remove(token); + void removeSleepToken(SleepToken token) { + if (!mSleepTokens.contains(token.mHashKey)) { + Slog.d(TAG, "Remove non-exist sleep token: " + token + " from " + Debug.getCallers(6)); + } + mSleepTokens.remove(token.mHashKey); final DisplayContent display = getDisplayContent(token.mDisplayId); if (display != null) { @@ -2716,7 +2729,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> if (sNdx >= taskDisplayArea.getStackCount()) { continue; } - final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + final Task stack = taskDisplayArea.getStackAt(sNdx); if (allowDelay) { result &= stack.goToSleepIfPossible(shuttingDown); } else { @@ -2787,7 +2800,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return false; } - ActivityStack getLaunchStack(@Nullable ActivityRecord r, + Task getLaunchStack(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable Task candidateTask, boolean onTop) { return getLaunchStack(r, options, candidateTask, onTop, null /* launchParams */, -1 /* no realCallingPid */, -1 /* no realCallingUid */); @@ -2805,7 +2818,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> * * @return The stack to use for the launch or INVALID_STACK_ID. */ - ActivityStack getLaunchStack(@Nullable ActivityRecord r, + Task getLaunchStack(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable Task candidateTask, boolean onTop, @Nullable LaunchParamsController.LaunchParams launchParams, int realCallingPid, int realCallingUid) { @@ -2831,12 +2844,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent> MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, options, onTop); options.setLaunchTaskId(taskId); if (task != null) { - return task.getStack(); + return task.getRootTask(); } } final int activityType = resolveActivityType(r, options, candidateTask); - ActivityStack stack = null; + Task stack = null; // Next preference for stack goes to the taskDisplayArea candidate. if (launchParams != null && launchParams.mPreferredTaskDisplayArea != null) { @@ -2858,7 +2871,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> realCallingPid, realCallingUid, r.info); if (canLaunchOnDisplayFromStartRequest || canLaunchOnDisplay(r, tdaDisplayId)) { if (r != null) { - final ActivityStack result = getValidLaunchStackInTaskDisplayArea( + final Task result = getValidLaunchStackInTaskDisplayArea( taskDisplayArea, r, candidateTask, options, launchParams); if (result != null) { return result; @@ -2878,7 +2891,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // mode we want to launch into. TaskDisplayArea container = null; if (candidateTask != null) { - stack = candidateTask.getStack(); + stack = candidateTask.getRootTask(); } if (stack == null && r != null) { stack = r.getRootTask(); @@ -2940,7 +2953,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> * @return Existing stack if there is a valid one, new dynamic stack if it is valid or null. */ @VisibleForTesting - ActivityStack getValidLaunchStackInTaskDisplayArea(@NonNull TaskDisplayArea taskDisplayArea, + Task getValidLaunchStackInTaskDisplayArea(@NonNull TaskDisplayArea taskDisplayArea, @NonNull ActivityRecord r, @Nullable Task candidateTask, @Nullable ActivityOptions options, @Nullable LaunchParamsController.LaunchParams launchParams) { @@ -2956,12 +2969,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent> final TaskDisplayArea attachedTaskDisplayArea = r.getTask() != null ? r.getTask().getDisplayArea() : r.getDisplayArea(); if (attachedTaskDisplayArea == null || attachedTaskDisplayArea == taskDisplayArea) { - return candidateTask.getStack(); + return candidateTask.getRootTask(); } // Or the candidate task is already a root task that can be reused by reparenting // it to the target display. if (candidateTask.isRootTask()) { - final ActivityStack stack = candidateTask.getStack(); + final Task stack = candidateTask.getRootTask(); stack.reparent(taskDisplayArea, true /* onTop */); return stack; } @@ -2982,7 +2995,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // Return the topmost valid stack on the display. for (int i = taskDisplayArea.getStackCount() - 1; i >= 0; --i) { - final ActivityStack stack = taskDisplayArea.getStackAt(i); + final Task stack = taskDisplayArea.getStackAt(i); if (isValidLaunchStack(stack, r, windowingMode)) { return stack; } @@ -3002,7 +3015,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } // TODO: Can probably be consolidated into getLaunchStack()... - private boolean isValidLaunchStack(ActivityStack stack, ActivityRecord r, int windowingMode) { + private boolean isValidLaunchStack(Task stack, ActivityRecord r, int windowingMode) { switch (stack.getActivityType()) { case ACTIVITY_TYPE_HOME: return r.isActivityTypeHome(); case ACTIVITY_TYPE_RECENTS: return r.isActivityTypeRecents(); @@ -3050,9 +3063,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> * @param currentFocus The stack that previously had focus. * @param ignoreCurrent If we should ignore {@param currentFocus} when searching for next * candidate. - * @return Next focusable {@link ActivityStack}, {@code null} if not found. + * @return Next focusable {@link Task}, {@code null} if not found. */ - ActivityStack getNextFocusableStack(@NonNull ActivityStack currentFocus, + Task getNextFocusableStack(@NonNull Task currentFocus, boolean ignoreCurrent) { // First look for next focusable stack on the same display TaskDisplayArea preferredDisplayArea = currentFocus.getDisplayArea(); @@ -3062,7 +3075,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> preferredDisplayArea = getDisplayContent(currentFocus.mPrevDisplayId) .getDefaultTaskDisplayArea(); } - final ActivityStack preferredFocusableStack = preferredDisplayArea.getNextFocusableStack( + final Task preferredFocusableStack = preferredDisplayArea.getNextFocusableStack( currentFocus, ignoreCurrent); if (preferredFocusableStack != null) { return preferredFocusableStack; @@ -3081,7 +3094,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // We've already checked this one continue; } - final ActivityStack nextFocusableStack = display.getDefaultTaskDisplayArea() + final Task nextFocusableStack = display.getDefaultTaskDisplayArea() .getNextFocusableStack(currentFocus, ignoreCurrent); if (nextFocusableStack != null) { return nextFocusableStack; @@ -3092,9 +3105,15 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } boolean handleAppDied(WindowProcessController app) { + if (app.isRemoved()) { + // The package of the died process should be force-stopped, so make its activities as + // finishing to prevent the process from being started again if the next top (or being + // visible) activity also resides in the same process. + app.makeFinishingForProcessRemoved(); + } return reduceOnAllTaskDisplayAreas((taskDisplayArea, result) -> { for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + final Task stack = taskDisplayArea.getStackAt(sNdx); result |= stack.handleAppDied(app); } return result; @@ -3129,24 +3148,26 @@ class RootWindowContainer extends WindowContainer<DisplayContent> private boolean mDoit; private boolean mEvenPersistent; private int mUserId; + private boolean mOnlyRemoveNoProcess; private Task mLastTask; private ComponentName mHomeActivity; private void reset(String packageName, Set<String> filterByClasses, - boolean doit, boolean evenPersistent, int userId) { + boolean doit, boolean evenPersistent, int userId, boolean onlyRemoveNoProcess) { mDidSomething = false; mPackageName = packageName; mFilterByClasses = filterByClasses; mDoit = doit; mEvenPersistent = evenPersistent; mUserId = userId; + mOnlyRemoveNoProcess = onlyRemoveNoProcess; mLastTask = null; mHomeActivity = null; } boolean process(String packageName, Set<String> filterByClasses, - boolean doit, boolean evenPersistent, int userId) { - reset(packageName, filterByClasses, doit, evenPersistent, userId); + boolean doit, boolean evenPersistent, int userId, boolean onlyRemoveNoProcess) { + reset(packageName, filterByClasses, doit, evenPersistent, userId, onlyRemoveNoProcess); final PooledFunction f = PooledLambda.obtainFunction( FinishDisabledPackageActivitiesHelper::processActivity, this, @@ -3161,9 +3182,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent> (r.packageName.equals(mPackageName) && (mFilterByClasses == null || mFilterByClasses.contains(r.mActivityComponent.getClassName()))) || (mPackageName == null && r.mUserId == mUserId); + final boolean noProcess = !r.hasProcess(); if ((mUserId == UserHandle.USER_ALL || r.mUserId == mUserId) && (sameComponent || r.getTask() == mLastTask) - && (r.app == null || mEvenPersistent || !r.app.isPersistent())) { + && (noProcess || mEvenPersistent || !r.app.isPersistent())) { if (!mDoit) { if (r.finishing) { // If this activity is just finishing, then it is not @@ -3180,10 +3202,19 @@ class RootWindowContainer extends WindowContainer<DisplayContent> mHomeActivity = r.mActivityComponent; } } - mDidSomething = true; - Slog.i(TAG, " Force finishing activity " + r); + if (mOnlyRemoveNoProcess) { + if (noProcess) { + mDidSomething = true; + Slog.i(TAG, " Force removing " + r); + r.cleanUp(false /* cleanServices */, false /* setState */); + r.removeFromHistory("force-stop"); + } + } else { + mDidSomething = true; + Slog.i(TAG, " Force finishing " + r); + r.finishIfPossible("force-stop", true /* oomAdj */); + } mLastTask = r.getTask(); - r.finishIfPossible("force-stop", true); } return false; @@ -3192,9 +3223,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> /** @return true if some activity was finished (or would have finished if doit were true). */ boolean finishDisabledPackageActivities(String packageName, Set<String> filterByClasses, - boolean doit, boolean evenPersistent, int userId) { + boolean doit, boolean evenPersistent, int userId, boolean onlyRemoveNoProcess) { return mFinishDisabledPackageActivitiesHelper.process(packageName, filterByClasses, doit, - evenPersistent, userId); + evenPersistent, userId, onlyRemoveNoProcess); } void updateActivityApplicationInfo(ApplicationInfo aInfo) { @@ -3218,7 +3249,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> forAllTaskDisplayAreas(taskDisplayArea -> { final int numStacks = taskDisplayArea.getStackCount(); for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = taskDisplayArea.getStackAt(stackNdx); + final Task stack = taskDisplayArea.getStackAt(stackNdx); stack.finishVoiceTask(session); } }); @@ -3261,7 +3292,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // If the focused stack is not null or not empty, there should have some activities // resuming or resumed. Make sure these activities are idle. - final ActivityStack stack = display.getFocusedStack(); + final Task stack = display.getFocusedStack(); if (stack == null || !stack.hasActivity()) { continue; } @@ -3284,7 +3315,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> final boolean foundInvisibleResumedActivity = forAllTaskDisplayAreas( taskDisplayArea -> { for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + final Task stack = taskDisplayArea.getStackAt(sNdx); final ActivityRecord r = stack.getResumedActivity(); if (r != null) { if (!r.nowVisible) { @@ -3306,7 +3337,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> final boolean hasActivityNotCompleted = forAllTaskDisplayAreas( taskDisplayArea -> { for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + final Task stack = taskDisplayArea.getStackAt(sNdx); final ActivityRecord r = stack.mPausingActivity; if (r != null && !r.isState(PAUSED, STOPPED, STOPPING, FINISHING)) { if (DEBUG_STATES) { @@ -3412,9 +3443,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> if (aOptions != null) { // Resolve the stack the task should be placed in now based on options // and reparent if needed. - final ActivityStack launchStack = + final Task launchStack = getLaunchStack(null, aOptions, task, onTop); - if (launchStack != null && task.getStack() != launchStack) { + if (launchStack != null && task.getRootTask() != launchStack) { final int reparentMode = onTop ? REPARENT_MOVE_STACK_TO_FRONT : REPARENT_LEAVE_STACK_IN_PLACE; task.reparent(launchStack, onTop, reparentMode, ANIMATE, DEFER_RESUME, @@ -3497,7 +3528,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } if (sendPowerModeLaunch && mService.mPowerManagerInternal != null) { - mService.mPowerManagerInternal.powerHint(PowerHint.LAUNCH, 1); + mService.mPowerManagerInternal.setPowerMode(Mode.LAUNCH, true); mPowerModeLaunchStarted = true; } } @@ -3505,7 +3536,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> void endPowerModeLaunchIfNeeded() { // Trigger launch power mode off if activity is launched if (mPowerModeLaunchStarted && mService.mPowerManagerInternal != null) { - mService.mPowerManagerInternal.powerHint(PowerHint.LAUNCH, 0); + mService.mPowerManagerInternal.setPowerMode(Mode.LAUNCH, false); mPowerModeLaunchStarted = false; } } @@ -3526,7 +3557,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> ArrayList<ActivityRecord> getDumpActivities(String name, boolean dumpVisibleStacksOnly, boolean dumpFocusedStackOnly) { if (dumpFocusedStackOnly) { - final ActivityStack topFocusedStack = getTopDisplayFocusedStack(); + final Task topFocusedStack = getTopDisplayFocusedStack(); if (topFocusedStack != null) { return topFocusedStack.getDumpActivitiesLocked(name); } else { @@ -3536,7 +3567,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> ArrayList<ActivityRecord> activities = new ArrayList<>(); forAllTaskDisplayAreas(taskDisplayArea -> { for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + final Task stack = taskDisplayArea.getStackAt(sNdx); if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) { activities.addAll(stack.getDumpActivitiesLocked(name)); } @@ -3585,7 +3616,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> pw.println(" (activities from top to bottom):"); displayContent.forAllTaskDisplayAreas(taskDisplayArea -> { for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + final Task stack = taskDisplayArea.getStackAt(sNdx); if (needSep[0]) { pw.println(); } @@ -3613,22 +3644,22 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return printed[0]; } - private final class SleepTokenImpl extends ActivityTaskManagerInternal.SleepToken { + private static int makeSleepTokenKey(String tag, int displayId) { + final String tokenKey = tag + displayId; + return tokenKey.hashCode(); + } + + static final class SleepToken { private final String mTag; private final long mAcquireTime; private final int mDisplayId; + final int mHashKey; - public SleepTokenImpl(String tag, int displayId) { + SleepToken(String tag, int displayId) { mTag = tag; mDisplayId = displayId; mAcquireTime = SystemClock.uptimeMillis(); - } - - @Override - public void release() { - synchronized (mService.mGlobalLock) { - removeSleepToken(this); - } + mHashKey = makeSleepTokenKey(mTag, mDisplayId); } @Override diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java index 3509ba72d058..6cf9432089b4 100644 --- a/services/core/java/com/android/server/wm/RunningTasks.java +++ b/services/core/java/com/android/server/wm/RunningTasks.java @@ -48,7 +48,7 @@ class RunningTasks { private ArraySet<Integer> mProfileIds; private boolean mAllowed; private boolean mFilterOnlyVisibleRecents; - private ActivityStack mTopDisplayFocusStack; + private Task mTopDisplayFocusStack; private RecentTasks mRecentTasks; void getTasks(int maxNum, List<RunningTaskInfo> list, boolean filterOnlyVisibleRecents, @@ -114,7 +114,7 @@ class RunningTasks { return; } - final ActivityStack stack = task.getStack(); + final Task stack = task.getRootTask(); if (stack == mTopDisplayFocusStack && stack.getTopMostTask() == task) { // For the focused stack top task, update the last stack active time so that it can be // used to determine the order of the tasks (it may not be set for newly created tasks) diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java index 837f1b523b68..34d084a3f9f8 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java @@ -26,7 +26,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.Nullable; -import android.hardware.power.V1_0.PowerHint; +import android.hardware.power.Boost; import android.os.Handler; import android.os.PowerManagerInternal; import android.util.ArrayMap; @@ -246,7 +246,7 @@ class SurfaceAnimationRunner { synchronized (mLock) { startPendingAnimationsLocked(); } - mPowerManagerInternal.powerHint(PowerHint.INTERACTION, 0); + mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, 0); } private void scheduleApplyTransaction() { diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 970520aff81f..e6e92ea9e489 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.ActivityTaskManager.RESIZE_MODE_FORCED; import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION; +import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; @@ -28,6 +29,7 @@ import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN import static android.app.WindowConfiguration.ROTATION_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; @@ -37,7 +39,10 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; +import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT; import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY; +import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING; +import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS; import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT; import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED; @@ -55,36 +60,91 @@ import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.provider.Settings.Secure.USER_SETUP_COMPLETE; +import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; import static android.view.Display.INVALID_DISPLAY; import static android.view.SurfaceControl.METADATA_TASK_ID; +import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE; +import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN; +import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE; +import static android.view.WindowManager.TRANSIT_NONE; +import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY; import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE; +import static android.view.WindowManager.TRANSIT_TASK_CLOSE; +import static android.view.WindowManager.TRANSIT_TASK_OPEN; +import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND; +import static android.view.WindowManager.TRANSIT_TASK_TO_BACK; +import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT; import static com.android.internal.policy.DecorView.DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP; import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP; import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN; -import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; -import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE; -import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; -import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; +import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS; +import static com.android.server.wm.ActivityStackSupervisor.dumpHistoryList; +import static com.android.server.wm.ActivityStackSupervisor.printThisActivity; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_APP; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_APP; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CLEANUP; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATES; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TRANSITION; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_USER_LEAVING; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK; +import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_STACK_MSG; +import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; +import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; import static com.android.server.wm.IdentifierProto.HASH_CODE; import static com.android.server.wm.IdentifierProto.TITLE; import static com.android.server.wm.IdentifierProto.USER_ID; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; +import static com.android.server.wm.Task.ActivityState.PAUSED; +import static com.android.server.wm.Task.ActivityState.PAUSING; +import static com.android.server.wm.Task.ActivityState.RESUMED; +import static com.android.server.wm.Task.ActivityState.STARTED; +import static com.android.server.wm.Task.ActivityState.STOPPED; +import static com.android.server.wm.Task.ActivityState.STOPPING; +import static com.android.server.wm.TaskProto.ACTIVITY_TYPE; +import static com.android.server.wm.TaskProto.ANIMATING_BOUNDS; +import static com.android.server.wm.TaskProto.BOUNDS; +import static com.android.server.wm.TaskProto.CREATED_BY_ORGANIZER; +import static com.android.server.wm.TaskProto.DISPLAY_ID; +import static com.android.server.wm.TaskProto.FILLS_PARENT; +import static com.android.server.wm.TaskProto.LAST_NON_FULLSCREEN_BOUNDS; +import static com.android.server.wm.TaskProto.MIN_HEIGHT; +import static com.android.server.wm.TaskProto.MIN_WIDTH; +import static com.android.server.wm.TaskProto.ORIG_ACTIVITY; +import static com.android.server.wm.TaskProto.REAL_ACTIVITY; +import static com.android.server.wm.TaskProto.RESIZE_MODE; +import static com.android.server.wm.TaskProto.RESUMED_ACTIVITY; +import static com.android.server.wm.TaskProto.ROOT_TASK_ID; +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.WindowContainerChildProto.TASK; @@ -103,11 +163,20 @@ import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.TaskDescription; import android.app.ActivityManager.TaskSnapshot; +import android.app.ActivityManagerInternal; import android.app.ActivityOptions; import android.app.ActivityTaskManager; import android.app.AppGlobals; +import android.app.IActivityController; +import android.app.RemoteAction; +import android.app.ResultInfo; import android.app.TaskInfo; import android.app.WindowConfiguration; +import android.app.servertransaction.ActivityResultItem; +import android.app.servertransaction.ClientTransaction; +import android.app.servertransaction.NewIntentItem; +import android.app.servertransaction.PauseActivityItem; +import android.app.servertransaction.ResumeActivityItem; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -117,8 +186,12 @@ import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; +import android.os.Binder; import android.os.Debug; +import android.os.Handler; import android.os.IBinder; +import android.os.Looper; +import android.os.Message; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; @@ -127,8 +200,10 @@ import android.provider.Settings; import android.service.voice.IVoiceInteractionSession; import android.util.ArraySet; import android.util.DisplayMetrics; +import android.util.Log; import android.util.Slog; import android.util.proto.ProtoOutputStream; +import android.view.Display; import android.view.DisplayInfo; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; @@ -137,36 +212,54 @@ import android.view.SurfaceControl; import android.view.WindowManager; import android.window.ITaskOrganizer; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceInteractor; +import com.android.internal.os.logging.MetricsLoggerWrapper; import com.android.internal.util.XmlUtils; import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledFunction; import com.android.internal.util.function.pooled.PooledLambda; import com.android.internal.util.function.pooled.PooledPredicate; +import com.android.server.Watchdog; +import com.android.server.am.ActivityManagerService; +import com.android.server.am.AppTimeTracker; import com.android.server.protolog.common.ProtoLog; -import com.android.server.wm.ActivityStack.ActivityState; +import com.android.server.uri.NeededUriGrants; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; +import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.List; import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; class Task extends WindowContainer<WindowContainer> { private static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_ATM; - private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE; + static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE; private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS; private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK; - private static final String TAG_TASKS = TAG + POSTFIX_TASKS; + static final String TAG_TASKS = TAG + POSTFIX_TASKS; + private static final String TAG_APP = TAG + POSTFIX_APP; + static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP; + private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE; + private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS; + private static final String TAG_STACK = TAG + POSTFIX_STACK; + private static final String TAG_STATES = TAG + POSTFIX_STATES; + private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH; + private static final String TAG_TRANSITION = TAG + POSTFIX_TRANSITION; + private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING; + static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY; private static final String ATTR_TASKID = "task_id"; private static final String TAG_INTENT = "intent"; @@ -202,6 +295,14 @@ class Task extends WindowContainer<WindowContainer> { private static final String ATTR_PERSIST_TASK_VERSION = "persist_task_version"; private static final String ATTR_WINDOW_LAYOUT_AFFINITY = "window_layout_affinity"; + // Set to false to disable the preview that is shown while a new activity + // is being started. + private static final boolean SHOW_APP_STARTING_PREVIEW = true; + + // How long to wait for all background Activities to redraw following a call to + // convertToTranslucent(). + private static final long TRANSLUCENT_CONVERSION_TIMEOUT = 2000; + // Current version of the task record we persist. Used to check if we need to run any upgrade // code. static final int PERSIST_TASK_VERSION = 1; @@ -226,6 +327,58 @@ class Task extends WindowContainer<WindowContainer> { // Do not move the stack as a part of reparenting static final int REPARENT_LEAVE_STACK_IN_PLACE = 2; + @IntDef(prefix = {"STACK_VISIBILITY"}, value = { + STACK_VISIBILITY_VISIBLE, + STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, + STACK_VISIBILITY_INVISIBLE, + }) + @interface StackVisibility {} + + /** Stack is visible. No other stacks on top that fully or partially occlude it. */ + static final int STACK_VISIBILITY_VISIBLE = 0; + + /** Stack is partially occluded by other translucent stack(s) on top of it. */ + static final int STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT = 1; + + /** Stack is completely invisible. */ + static final int STACK_VISIBILITY_INVISIBLE = 2; + + enum ActivityState { + INITIALIZING, + STARTED, + RESUMED, + PAUSING, + PAUSED, + STOPPING, + STOPPED, + FINISHING, + DESTROYING, + DESTROYED, + RESTARTING_PROCESS + } + + // The topmost Activity passed to convertToTranslucent(). When non-null it means we are + // waiting for all Activities in mUndrawnActivitiesBelowTopTranslucent to be removed as they + // are drawn. When the last member of mUndrawnActivitiesBelowTopTranslucent is removed the + // Activity in mTranslucentActivityWaiting is notified via + // Activity.onTranslucentConversionComplete(false). If a timeout occurs prior to the last + // background activity being drawn then the same call will be made with a true value. + ActivityRecord mTranslucentActivityWaiting = null; + ArrayList<ActivityRecord> mUndrawnActivitiesBelowTopTranslucent = new ArrayList<>(); + + /** + * Set when we know we are going to be calling updateConfiguration() + * soon, so want to skip intermediate config checks. + */ + boolean mConfigWillChange; + + /** + * Used to keep resumeTopActivityUncheckedLocked() from being entered recursively + */ + boolean mInResumeTopActivity = false; + + int mCurrentUser; + String affinity; // The affinity name for this task, or null; may change identity. String rootAffinity; // Initial base affinity, or null; does not change from initial root. String mWindowLayoutAffinity; // Launch param affinity of this task or null. Used when saving @@ -447,6 +600,268 @@ class Task extends WindowContainer<WindowContainer> { SurfaceControl.Transaction mMainWindowSizeChangeTransaction; Task mMainWindowSizeChangeTask; + // If this is true, we are in the bounds animating mode. The task will be down or upscaled to + // perfectly fit the region it would have been cropped to. We may also avoid certain logic we + // would otherwise apply while resizing, while resizing in the bounds animating mode. + private boolean mBoundsAnimating = false; + // Set when an animation has been requested but has not yet started from the UI thread. This is + // cleared when the animation actually starts. + private boolean mBoundsAnimatingRequested = false; + private Rect mBoundsAnimationTarget = new Rect(); + private Rect mBoundsAnimationSourceHintBounds = new Rect(); + + Rect mPreAnimationBounds = new Rect(); + + private final AnimatingActivityRegistry mAnimatingActivityRegistry = + new AnimatingActivityRegistry(); + + private boolean mTopActivityOccludesKeyguard; + private ActivityRecord mTopDismissingKeyguardActivity; + + private static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 1; + + private final Handler mHandler; + + private class ActivityStackHandler extends Handler { + + ActivityStackHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case TRANSLUCENT_TIMEOUT_MSG: { + synchronized (mAtmService.mGlobalLock) { + notifyActivityDrawnLocked(null); + } + } break; + } + } + } + + private static final ResetTargetTaskHelper sResetTargetTaskHelper = new ResetTargetTaskHelper(); + private final EnsureActivitiesVisibleHelper mEnsureActivitiesVisibleHelper = + new EnsureActivitiesVisibleHelper(this); + private final EnsureVisibleActivitiesConfigHelper mEnsureVisibleActivitiesConfigHelper = + new EnsureVisibleActivitiesConfigHelper(); + private class EnsureVisibleActivitiesConfigHelper { + private boolean mUpdateConfig; + private boolean mPreserveWindow; + private boolean mBehindFullscreen; + + void reset(boolean preserveWindow) { + mPreserveWindow = preserveWindow; + mUpdateConfig = false; + mBehindFullscreen = false; + } + + void process(ActivityRecord start, boolean preserveWindow) { + if (start == null || !start.mVisibleRequested) { + return; + } + reset(preserveWindow); + + final PooledFunction f = PooledLambda.obtainFunction( + EnsureVisibleActivitiesConfigHelper::processActivity, this, + PooledLambda.__(ActivityRecord.class)); + forAllActivities(f, start, true /*includeBoundary*/, true /*traverseTopToBottom*/); + f.recycle(); + + if (mUpdateConfig) { + // Ensure the resumed state of the focus activity if we updated the configuration of + // any activity. + mRootWindowContainer.resumeFocusedStacksTopActivities(); + } + } + + boolean processActivity(ActivityRecord r) { + mUpdateConfig |= r.ensureActivityConfiguration(0 /*globalChanges*/, mPreserveWindow); + mBehindFullscreen |= r.occludesParent(); + return mBehindFullscreen; + } + } + + private final CheckBehindFullscreenActivityHelper mCheckBehindFullscreenActivityHelper = + new CheckBehindFullscreenActivityHelper(); + private class CheckBehindFullscreenActivityHelper { + private boolean mAboveTop; + private boolean mBehindFullscreenActivity; + private ActivityRecord mToCheck; + private Consumer<ActivityRecord> mHandleBehindFullscreenActivity; + private boolean mHandlingOccluded; + + private void reset(ActivityRecord toCheck, + Consumer<ActivityRecord> handleBehindFullscreenActivity) { + mToCheck = toCheck; + mHandleBehindFullscreenActivity = handleBehindFullscreenActivity; + mAboveTop = true; + mBehindFullscreenActivity = false; + + if (!shouldBeVisible(null)) { + // The stack is not visible, so no activity in it should be displaying a starting + // window. Mark all activities below top and behind fullscreen. + mAboveTop = false; + mBehindFullscreenActivity = true; + } + + mHandlingOccluded = mToCheck == null && mHandleBehindFullscreenActivity != null; + } + + boolean process(ActivityRecord toCheck, + Consumer<ActivityRecord> handleBehindFullscreenActivity) { + reset(toCheck, handleBehindFullscreenActivity); + + if (!mHandlingOccluded && mBehindFullscreenActivity) { + return true; + } + + final ActivityRecord topActivity = topRunningActivity(); + final PooledFunction f = PooledLambda.obtainFunction( + CheckBehindFullscreenActivityHelper::processActivity, this, + PooledLambda.__(ActivityRecord.class), topActivity); + forAllActivities(f); + f.recycle(); + + return mBehindFullscreenActivity; + } + + /** Returns {@code true} to stop the outer loop and indicate the result is computed. */ + private boolean processActivity(ActivityRecord r, ActivityRecord topActivity) { + if (mAboveTop) { + if (r == topActivity) { + if (r == mToCheck) { + // It is the top activity in a visible stack. + mBehindFullscreenActivity = false; + return true; + } + mAboveTop = false; + } + mBehindFullscreenActivity |= r.occludesParent(); + return false; + } + + if (mHandlingOccluded) { + // Iterating through all occluded activities. + if (mBehindFullscreenActivity) { + mHandleBehindFullscreenActivity.accept(r); + } + } else if (r == mToCheck) { + return true; + } else if (mBehindFullscreenActivity) { + // It is occluded before {@param toCheck} is found. + return true; + } + mBehindFullscreenActivity |= r.occludesParent(); + return false; + } + } + + // TODO: Can we just loop through WindowProcessController#mActivities instead of doing this? + private final RemoveHistoryRecordsForApp mRemoveHistoryRecordsForApp = + new RemoveHistoryRecordsForApp(); + private class RemoveHistoryRecordsForApp { + private boolean mHasVisibleActivities; + private boolean mIsProcessRemoved; + private WindowProcessController mApp; + private ArrayList<ActivityRecord> mToRemove = new ArrayList<>(); + + boolean process(WindowProcessController app) { + mToRemove.clear(); + mHasVisibleActivities = false; + mApp = app; + mIsProcessRemoved = app.isRemoved(); + + final PooledConsumer c = PooledLambda.obtainConsumer( + RemoveHistoryRecordsForApp::addActivityToRemove, this, + PooledLambda.__(ActivityRecord.class)); + forAllActivities(c); + c.recycle(); + + while (!mToRemove.isEmpty()) { + processActivity(mToRemove.remove(0)); + } + + mApp = null; + return mHasVisibleActivities; + } + + private void addActivityToRemove(ActivityRecord r) { + if (r.app == mApp) { + mToRemove.add(r); + } + } + + private void processActivity(ActivityRecord r) { + if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP, "Record " + r + ": app=" + r.app); + + if (r.app != mApp) { + return; + } + if (r.isVisible() || r.mVisibleRequested) { + // While an activity launches a new activity, it's possible that the old + // activity is already requested to be hidden (mVisibleRequested=false), but + // this visibility is not yet committed, so isVisible()=true. + mHasVisibleActivities = true; + } + final boolean remove; + if ((r.mRelaunchReason == RELAUNCH_REASON_WINDOWING_MODE_RESIZE + || r.mRelaunchReason == RELAUNCH_REASON_FREE_RESIZE) + && r.launchCount < 3 && !r.finishing) { + // If the process crashed during a resize, always try to relaunch it, unless + // it has failed more than twice. Skip activities that's already finishing + // cleanly by itself. + remove = false; + } else if ((!r.hasSavedState() && !r.stateNotNeeded + && !r.isState(ActivityState.RESTARTING_PROCESS)) || r.finishing) { + // Don't currently have state for the activity, or + // it is finishing -- always remove it. + remove = true; + } else if (!r.mVisibleRequested && r.launchCount > 2 + && r.lastLaunchTime > (SystemClock.uptimeMillis() - 60000)) { + // We have launched this activity too many times since it was + // able to run, so give up and remove it. + // (Note if the activity is visible, we don't remove the record. + // We leave the dead window on the screen but the process will + // not be restarted unless user explicitly tap on it.) + remove = true; + } else { + // The process may be gone, but the activity lives on! + remove = false; + } + if (remove) { + if (DEBUG_ADD_REMOVE || DEBUG_CLEANUP) Slog.i(TAG_ADD_REMOVE, + "Removing activity " + r + " from stack " + + ": hasSavedState=" + r.hasSavedState() + + " stateNotNeeded=" + r.stateNotNeeded + + " finishing=" + r.finishing + + " state=" + r.getState() + " callers=" + Debug.getCallers(5)); + if (!r.finishing || mIsProcessRemoved) { + Slog.w(TAG, "Force removing " + r + ": app died, no saved state"); + EventLogTags.writeWmFinishActivity(r.mUserId, + System.identityHashCode(r), r.getTask().mTaskId, + r.shortComponentName, "proc died without state saved"); + } + } else { + // We have the current state for this activity, so + // it can be restarted later when needed. + if (DEBUG_ALL) Slog.v(TAG, "Keeping entry, setting app to null"); + if (DEBUG_APP) Slog.v(TAG_APP, + "Clearing app during removeHistory for activity " + r); + r.app = null; + // Set nowVisible to previous visible state. If the app was visible while + // it died, we leave the dead window on screen so it's basically visible. + // This is needed when user later tap on the dead window, we need to stop + // other apps when user transfers focus to the restarted activity. + r.nowVisible = r.mVisibleRequested; + } + r.cleanUp(true /* cleanServices */, true /* setState */); + if (remove) { + r.removeFromHistory("appDied"); + } + } + } + private final FindRootHelper mFindRootHelper = new FindRootHelper(); private class FindRootHelper { private ActivityRecord mRoot; @@ -507,12 +922,22 @@ class Task extends WindowContainer<WindowContainer> { boolean mCreatedByOrganizer; /** - * Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int, - * ActivityInfo, Intent, TaskDescription)} instead. + * Don't use constructor directly. Use {@link TaskDisplayArea#createStackUnchecked()} instead. + */ + Task(ActivityTaskManagerService atmService, int id, int activityType, + ActivityInfo info, Intent intent, boolean createdByOrganizer) { + this(atmService, id, info, intent, null /*voiceSession*/, null /*voiceInteractor*/, + null /*taskDescription*/, null /*stack*/); + mCreatedByOrganizer = createdByOrganizer; + setActivityType(activityType); + } + + /** + * Don't use constructor directly. Use {@link Task#reuseOrCreateTask()} instead. */ Task(ActivityTaskManagerService atmService, int _taskId, ActivityInfo info, Intent _intent, IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, - TaskDescription _taskDescription, ActivityStack stack) { + TaskDescription _taskDescription, Task stack) { this(atmService, _taskId, _intent, null /*_affinityIntent*/, null /*_affinity*/, null /*_rootAffinity*/, null /*_realActivity*/, null /*_origActivity*/, false /*_rootWasReset*/, false /*_autoRemoveRecents*/, false /*_askedCompatMode*/, @@ -538,7 +963,7 @@ class Task extends WindowContainer<WindowContainer> { @Nullable String callingFeatureId, int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended, boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info, IVoiceInteractionSession _voiceSession, - IVoiceInteractor _voiceInteractor, ActivityStack stack) { + IVoiceInteractor _voiceInteractor, Task stack) { super(atmService.mWindowManager); EventLogTags.writeWmTaskCreated(_taskId, stack != null ? getRootTaskId() : INVALID_TASK_ID); @@ -587,6 +1012,8 @@ class Task extends WindowContainer<WindowContainer> { mMinHeight = minHeight; } mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity); + mHandler = new ActivityStackHandler(mStackSupervisor.mLooper); + mCurrentUser = mAtmService.mAmInternal.getCurrentUserId(); } Task reuseAsLeafTask(IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, @@ -727,7 +1154,7 @@ class Task extends WindowContainer<WindowContainer> { } /** Convenience method to reparent a task to the top or bottom position of the stack. */ - boolean reparent(ActivityStack preferredStack, boolean toTop, + boolean reparent(Task preferredStack, boolean toTop, @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, String reason) { return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate, deferResume, @@ -738,7 +1165,7 @@ class Task extends WindowContainer<WindowContainer> { * Convenience method to reparent a task to the top or bottom position of the stack, with * an option to skip scheduling the picture-in-picture mode change. */ - boolean reparent(ActivityStack preferredStack, boolean toTop, + boolean reparent(Task preferredStack, boolean toTop, @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, boolean schedulePictureInPictureModeChange, String reason) { return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate, @@ -746,7 +1173,7 @@ class Task extends WindowContainer<WindowContainer> { } /** Convenience method to reparent a task to a specific position of the stack. */ - boolean reparent(ActivityStack preferredStack, int position, + boolean reparent(Task preferredStack, int position, @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, String reason) { return reparent(preferredStack, position, moveStackMode, animate, deferResume, @@ -772,14 +1199,14 @@ class Task extends WindowContainer<WindowContainer> { */ // TODO: Inspect all call sites and change to just changing windowing mode of the stack vs. // re-parenting the task. Can only be done when we are no longer using static stack Ids. - boolean reparent(ActivityStack preferredStack, int position, + boolean reparent(Task preferredStack, int position, @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, boolean schedulePictureInPictureModeChange, String reason) { final ActivityStackSupervisor supervisor = mStackSupervisor; final RootWindowContainer root = mRootWindowContainer; final WindowManagerService windowManager = mAtmService.mWindowManager; - final ActivityStack sourceStack = getStack(); - final ActivityStack toStack = supervisor.getReparentTargetStack(this, preferredStack, + final Task sourceStack = getRootTask(); + final Task toStack = supervisor.getReparentTargetStack(this, preferredStack, position == MAX_VALUE); if (toStack == sourceStack) { return false; @@ -1172,6 +1599,12 @@ class Task extends WindowContainer<WindowContainer> { } mRootWindowContainer.updateUIDsPresentOnDisplay(); + + // Resume next focusable stack after reparenting to another display if we aren't removing + // the prevous display. + if (oldDisplay != null && oldDisplay.isRemoving()) { + postReparent(); + } } void cleanUpActivityReferences(ActivityRecord r) { @@ -1370,7 +1803,7 @@ class Task extends WindowContainer<WindowContainer> { // A rootable task that is now being added to be the child of an organized task. Making // sure the stack references is keep updated. if (mTaskOrganizer != null && mCreatedByOrganizer && child.asTask() != null) { - getDisplayArea().addStackReferenceIfNeeded((ActivityStack) child); + getDisplayArea().addStackReferenceIfNeeded((Task) child); } // Make sure the list of display UID whitelists is updated @@ -1420,7 +1853,7 @@ class Task extends WindowContainer<WindowContainer> { // A rootable child task that is now being removed from an organized task. Making sure // the stack references is keep updated. if (mCreatedByOrganizer && r.asTask() != null) { - getDisplayArea().removeStackReferenceIfNeeded((ActivityStack) r); + getDisplayArea().removeStackReferenceIfNeeded((Task) r); } if (!mChildren.contains(r)) { Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this); @@ -1460,7 +1893,7 @@ class Task extends WindowContainer<WindowContainer> { // Remove entire task if it doesn't have any activity left and it isn't marked for reuse // or created by task organizer. if (!isRootTask()) { - getStack().removeChild(this, reason); + getRootTask().removeChild(this, reason); } EventLogTags.writeWmTaskRemoved(mTaskId, "removeChild: last r=" + r + " in t=" + this); @@ -1502,7 +1935,7 @@ class Task extends WindowContainer<WindowContainer> { /** Completely remove all activities associated with an existing task. */ void performClearTask(String reason) { // Broken down into to cases to avoid object create due to capturing mStack. - if (getStack() == null) { + if (getRootTask() == null) { forAllActivities((r) -> { if (r.finishing) return; // Task was restored from persistent storage. @@ -1881,8 +2314,7 @@ class Task extends WindowContainer<WindowContainer> { } } - @Override - public void onConfigurationChanged(Configuration newParentConfig) { + private void onConfigurationChangedInner(Configuration newParentConfig) { // Check if the new configuration supports persistent bounds (eg. is Freeform) and if so // restore the last recorded non-fullscreen bounds. final boolean prevPersistTaskBounds = getWindowConfiguration().persistTaskBounds(); @@ -1910,7 +2342,7 @@ class Task extends WindowContainer<WindowContainer> { final boolean pipChanging = wasInPictureInPicture != inPinnedWindowingMode(); if (pipChanging) { - mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, getStack()); + mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, getRootTask()); } else if (wasInMultiWindowMode != inMultiWindowMode()) { mStackSupervisor.scheduleUpdateMultiWindowMode(this); } @@ -1959,6 +2391,78 @@ class Task extends WindowContainer<WindowContainer> { } } + @Override + public void onConfigurationChanged(Configuration newParentConfig) { + // Calling Task#onConfigurationChanged() for leaf task since the ops in this method are + // particularly for ActivityStack, like preventing bounds changes when inheriting certain + // windowing mode. + if (!isRootTask()) { + onConfigurationChangedInner(newParentConfig); + return; + } + + final int prevWindowingMode = getWindowingMode(); + final boolean prevIsAlwaysOnTop = isAlwaysOnTop(); + final int prevRotation = getWindowConfiguration().getRotation(); + final Rect newBounds = mTmpRect; + // Initialize the new bounds by previous bounds as the input and output for calculating + // override bounds in pinned (pip) or split-screen mode. + getBounds(newBounds); + + onConfigurationChangedInner(newParentConfig); + + final TaskDisplayArea taskDisplayArea = getDisplayArea(); + if (taskDisplayArea == null) { + return; + } + + if (prevWindowingMode != getWindowingMode()) { + taskDisplayArea.onStackWindowingModeChanged(this); + } + + final DisplayContent display = getDisplay(); + if (display == null ) { + return; + } + + final boolean windowingModeChanged = prevWindowingMode != getWindowingMode(); + final int overrideWindowingMode = getRequestedOverrideWindowingMode(); + // Update bounds if applicable + boolean hasNewOverrideBounds = false; + // Use override windowing mode to prevent extra bounds changes if inheriting the mode. + if ((overrideWindowingMode != WINDOWING_MODE_PINNED) + && !getRequestedOverrideBounds().isEmpty()) { + // If the parent (display) has rotated, rotate our bounds to best-fit where their + // bounds were on the pre-rotated display. + final int newRotation = getWindowConfiguration().getRotation(); + final boolean rotationChanged = prevRotation != newRotation; + if (rotationChanged) { + display.mDisplayContent.rotateBounds( + newParentConfig.windowConfiguration.getBounds(), prevRotation, newRotation, + newBounds); + hasNewOverrideBounds = true; + } + } + + if (windowingModeChanged) { + taskDisplayArea.onStackWindowingModeChanged(this); + } + if (hasNewOverrideBounds) { + if (inSplitScreenWindowingMode()) { + setBounds(newBounds); + } else if (overrideWindowingMode != WINDOWING_MODE_PINNED) { + // For pinned stack, resize is now part of the {@link WindowContainerTransaction} + resize(new Rect(newBounds), PRESERVE_WINDOWS, true /* deferResume */); + } + } + if (prevIsAlwaysOnTop != isAlwaysOnTop()) { + // Since always on top is only on when the stack is freeform or pinned, the state + // can be toggled when the windowing mode changes. We must make sure the stack is + // placed properly when always on top state changes. + taskDisplayArea.positionStackAtTop(this, false /* includingParents */); + } + } + /** * Initializes a change transition. See {@link SurfaceFreezer} for more information. */ @@ -2191,10 +2695,11 @@ class Task extends WindowContainer<WindowContainer> { DisplayInfo displayInfo) { outNonDecorBounds.set(bounds); outStableBounds.set(bounds); - if (getStack() == null || getStack().getDisplay() == null) { + final Task rootTask = getRootTask(); + if (rootTask == null || rootTask.getDisplay() == null) { return; } - DisplayPolicy policy = getStack().getDisplay().mDisplayContent.getDisplayPolicy(); + DisplayPolicy policy = rootTask.getDisplay().mDisplayContent.getDisplayPolicy(); if (policy == null) { return; } @@ -2533,8 +3038,8 @@ class Task extends WindowContainer<WindowContainer> { /** Updates the task's bounds and override configuration to match what is expected for the * input stack. */ - void updateOverrideConfigurationForStack(ActivityStack inStack) { - final ActivityStack stack = getStack(); + void updateOverrideConfigurationForStack(Task inStack) { + final Task stack = getRootTask(); if (stack != null && stack == inStack) { return; @@ -2547,7 +3052,7 @@ class Task extends WindowContainer<WindowContainer> { /** Returns the bounds that should be used to launch this task. */ Rect getLaunchBounds() { - final ActivityStack stack = getStack(); + final Task stack = getRootTask(); if (stack == null) { return null; } @@ -2582,7 +3087,7 @@ class Task extends WindowContainer<WindowContainer> { @Override DisplayContent getDisplayContent() { // TODO: Why aren't we just using our own display content vs. parent's??? - final ActivityStack stack = getStack(); + final Task stack = getRootTask(); return stack != null && stack != this ? stack.getDisplayContent() : super.getDisplayContent(); } @@ -2592,11 +3097,6 @@ class Task extends WindowContainer<WindowContainer> { return dc != null ? dc.mDisplayId : INVALID_DISPLAY; } - // TODO: Migrate callers to getRootTask() - ActivityStack getStack() { - return (ActivityStack) getRootTask(); - } - /** @return Id of root task. */ int getRootTaskId() { return getRootTask().mTaskId; @@ -2637,7 +3137,7 @@ class Task extends WindowContainer<WindowContainer> { * Find next proper focusable stack and make it focused. * @return The stack that now got the focus, {@code null} if none found. */ - ActivityStack adjustFocusToNextFocusableTask(String reason) { + Task adjustFocusToNextFocusableTask(String reason) { return adjustFocusToNextFocusableTask(reason, false /* allowFocusSelf */, true /* moveDisplayToTop */); } @@ -2650,7 +3150,7 @@ class Task extends WindowContainer<WindowContainer> { } final Task focusableTask = parent.getTask((task) -> (allowFocusSelf || task != this) - && ((ActivityStack) task).isFocusableAndVisible()); + && ((Task) task).isFocusableAndVisible()); if (focusableTask == null && parent.asTask() != null) { return parent.asTask().getNextFocusableTask(allowFocusSelf); } else { @@ -2665,18 +3165,17 @@ class Task extends WindowContainer<WindowContainer> { * @param moveDisplayToTop Whether to move display to top while making the task focused. * @return The root task that now got the focus, {@code null} if none found. */ - ActivityStack adjustFocusToNextFocusableTask(String reason, boolean allowFocusSelf, + Task adjustFocusToNextFocusableTask(String reason, boolean allowFocusSelf, boolean moveDisplayToTop) { - ActivityStack focusableTask = (ActivityStack) getNextFocusableTask(allowFocusSelf); + Task focusableTask = getNextFocusableTask(allowFocusSelf); if (focusableTask == null) { - focusableTask = mRootWindowContainer.getNextFocusableStack((ActivityStack) this, - !allowFocusSelf); + focusableTask = mRootWindowContainer.getNextFocusableStack(this, !allowFocusSelf); } if (focusableTask == null) { return null; } - final ActivityStack rootTask = (ActivityStack) focusableTask.getRootTask(); + final Task rootTask = focusableTask.getRootTask(); if (!moveDisplayToTop) { // There may be multiple task layers above this task, so when relocating the task to the // top, we should move this task and each of its parent task that below display area to @@ -2807,7 +3306,7 @@ class Task extends WindowContainer<WindowContainer> { // No reason to defer removal of a Task that doesn't have any child. return false; } - return hasWindowsAlive() && getStack().isAnimating(TRANSITION | CHILDREN); + return hasWindowsAlive() && getRootTask().isAnimating(TRANSITION | CHILDREN); } @Override @@ -2826,9 +3325,9 @@ class Task extends WindowContainer<WindowContainer> { } // TODO: Consolidate this with Task.reparent() - void reparent(ActivityStack stack, int position, boolean moveParents, String reason) { + void reparent(Task stack, int position, boolean moveParents, String reason) { if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId - + " from stack=" + getStack()); + + " from stack=" + getRootTask()); EventLogTags.writeWmTaskRemoved(mTaskId, "reParentTask:" + reason); reparent(stack, position); @@ -2855,9 +3354,13 @@ class Task extends WindowContainer<WindowContainer> { /** Set the task bounds. Passing in null sets the bounds to fullscreen. */ @Override public int setBounds(Rect bounds) { + if (isRootTask()) { + return setBounds(getRequestedOverrideBounds(), bounds); + } + int rotation = Surface.ROTATION_0; - final DisplayContent displayContent = getStack() != null - ? getStack().getDisplayContent() : null; + final DisplayContent displayContent = getRootTask() != null + ? getRootTask().getDisplayContent() : null; if (displayContent != null) { rotation = displayContent.getDisplayInfo().rotation; } @@ -2869,6 +3372,17 @@ class Task extends WindowContainer<WindowContainer> { } @Override + public boolean isCompatible(int windowingMode, int activityType) { + // TODO: Should we just move this to ConfigurationContainer? + if (activityType == ACTIVITY_TYPE_UNDEFINED) { + // Undefined activity types end up in a standard stack once the stack is created on a + // display, so they should be considered compatible. + activityType = ACTIVITY_TYPE_STANDARD; + } + return super.isCompatible(windowingMode, activityType); + } + + @Override public boolean onDescendantOrientationChanged(IBinder freezeDisplayToken, ConfigurationContainer requestingContainer) { if (super.onDescendantOrientationChanged(freezeDisplayToken, requestingContainer)) { @@ -2902,6 +3416,9 @@ class Task extends WindowContainer<WindowContainer> { mWmService.mAtmService.getTaskChangeNotificationController().notifyTaskDisplayChanged( mTaskId, displayId); } + if (isRootTask()) { + updateSurfaceBounds(); + } } boolean isResizeable(boolean checkSupportsPip) { @@ -2992,7 +3509,13 @@ class Task extends WindowContainer<WindowContainer> { /** Bounds of the task to be used for dimming, as well as touch related tests. */ void getDimBounds(Rect out) { - final DisplayContent displayContent = getStack().getDisplayContent(); + if (isRootTask()) { + getBounds(out); + return; + } + + final Task rootTask = getRootTask(); + final DisplayContent displayContent = rootTask.getDisplayContent(); // It doesn't matter if we in particular are part of the resize, since we couldn't have // a DimLayer anyway if we weren't visible. final boolean dockedResizing = displayContent != null @@ -3016,9 +3539,9 @@ class Task extends WindowContainer<WindowContainer> { // stack bounds and so we don't even want to use them. Even if the app should not be // resized the Dim should keep up with the divider. if (dockedResizing) { - getStack().getBounds(out); + rootTask.getBounds(out); } else { - getStack().getBounds(mTmpRect); + rootTask.getBounds(mTmpRect); mTmpRect.intersect(getBounds()); out.set(mTmpRect); } @@ -3031,7 +3554,8 @@ class Task extends WindowContainer<WindowContainer> { void setDragResizing(boolean dragResizing, int dragResizeMode) { if (mDragResizing != dragResizing) { // No need to check if the mode is allowed if it's leaving dragResize - if (dragResizing && !DragResizeMode.isModeAllowedForStack(getStack(), dragResizeMode)) { + if (dragResizing + && !DragResizeMode.isModeAllowedForStack(getRootTask(), dragResizeMode)) { throw new IllegalArgumentException("Drag resize mode not allow for stack stackId=" + getRootTaskId() + " dragResizeMode=" + dragResizeMode); } @@ -3221,9 +3745,9 @@ class Task extends WindowContainer<WindowContainer> { @Override Rect getAnimationBounds(int appStackClipMode) { // TODO(b/131661052): we should remove appStackClipMode with hierarchical animations. - if (appStackClipMode == STACK_CLIP_BEFORE_ANIM && getStack() != null) { + if (appStackClipMode == STACK_CLIP_BEFORE_ANIM && getRootTask() != null) { // Using the stack bounds here effectively applies the clipping before animation. - return getStack().getBounds(); + return getRootTask().getBounds(); } return super.getAnimationBounds(appStackClipMode); } @@ -3573,6 +4097,20 @@ class Task extends WindowContainer<WindowContainer> { child.dump(pw, doublePrefix, dumpAll); } } + + if (!mExitingActivities.isEmpty()) { + pw.println(); + pw.println(prefix + "Exiting application tokens:"); + for (int i = mExitingActivities.size() - 1; i >= 0; i--) { + WindowToken token = mExitingActivities.get(i); + pw.print(doublePrefix + "Exiting App #" + i); + pw.print(' '); pw.print(token); + pw.println(':'); + token.dump(pw, doublePrefix, dumpAll); + } + pw.println(); + } + mAnimatingActivityRegistry.dump(pw, "AnimatingApps:", prefix); } @@ -3668,7 +4206,7 @@ class Task extends WindowContainer<WindowContainer> { * * @param starting The currently starting activity or null if there is none. */ - @ActivityStack.StackVisibility + @Task.StackVisibility int getVisibility(ActivityRecord starting) { if (!isAttached() || isForceHidden()) { return STACK_VISIBILITY_INVISIBLE; @@ -4289,7 +4827,7 @@ class Task extends WindowContainer<WindowContainer> { } } - final Task task = new ActivityStack(stackSupervisor.mService, taskId, intent, + final Task task = new Task(stackSupervisor.mService, taskId, intent, affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset, autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription, lastTimeOnTop, neverRelinquishIdentity, taskDescription, taskAffiliation, @@ -4604,4 +5142,2653 @@ class Task extends WindowContainer<WindowContainer> { return TASK; } + @Override + public void setWindowingMode(int windowingMode) { + // Reset the cached result of toString() + stringName = null; + + // Calling Task#setWindowingMode() for leaf task since this is the a specialization of + // {@link #setWindowingMode(int)} for ActivityStack. + if (!isRootTask()) { + super.setWindowingMode(windowingMode); + return; + } + + setWindowingMode(windowingMode, false /* creating */); + } + + /** + * Specialization of {@link #setWindowingMode(int)} for this subclass. + * + * @param preferredWindowingMode the preferred windowing mode. This may not be honored depending + * on the state of things. For example, WINDOWING_MODE_UNDEFINED will resolve to the + * previous non-transient mode if this stack is currently in a transient mode. + * @param creating {@code true} if this is being run during ActivityStack construction. + */ + void setWindowingMode(int preferredWindowingMode, boolean creating) { + mWmService.inSurfaceTransaction(() -> setWindowingModeInSurfaceTransaction( + preferredWindowingMode, creating)); + } + + private void setWindowingModeInSurfaceTransaction(int preferredWindowingMode, + boolean creating) { + final TaskDisplayArea taskDisplayArea = getDisplayArea(); + if (taskDisplayArea == null) { + Slog.d(TAG, "taskDisplayArea is null, bail early"); + return; + } + final int currentMode = getWindowingMode(); + final int currentOverrideMode = getRequestedOverrideWindowingMode(); + final Task topTask = getTopMostTask(); + int windowingMode = preferredWindowingMode; + + // Need to make sure windowing mode is supported. If we in the process of creating the stack + // no need to resolve the windowing mode again as it is already resolved to the right mode. + if (!creating) { + if (!taskDisplayArea.isValidWindowingMode(windowingMode, null /* ActivityRecord */, + topTask, getActivityType())) { + windowingMode = WINDOWING_MODE_UNDEFINED; + } + } + + final boolean alreadyInSplitScreenMode = taskDisplayArea.isSplitScreenModeActivated(); + + if (creating && alreadyInSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN + && isActivityTypeStandardOrUndefined()) { + // If the stack is being created explicitly in fullscreen mode, dismiss split-screen + // and display a warning toast about it. + mAtmService.getTaskChangeNotificationController() + .notifyActivityDismissingDockedStack(); + taskDisplayArea.onSplitScreenModeDismissed(this); + } + + if (currentMode == windowingMode) { + // You are already in the window mode, so we can skip most of the work below. However, + // it's possible that we have inherited the current windowing mode from a parent. So, + // fulfill this method's contract by setting the override mode directly. + getRequestedOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode); + return; + } + + final ActivityRecord topActivity = getTopNonFinishingActivity(); + + // For now, assume that the Stack's windowing mode is what will actually be used + // by it's activities. In the future, there may be situations where this doesn't + // happen; so at that point, this message will need to handle that. + int likelyResolvedMode = windowingMode; + if (windowingMode == WINDOWING_MODE_UNDEFINED) { + final ConfigurationContainer parent = getParent(); + likelyResolvedMode = parent != null ? parent.getWindowingMode() + : WINDOWING_MODE_FULLSCREEN; + } + if (currentMode == WINDOWING_MODE_PINNED) { + mAtmService.getTaskChangeNotificationController().notifyActivityUnpinned(); + } + if (likelyResolvedMode == WINDOWING_MODE_PINNED + && taskDisplayArea.getRootPinnedTask() != null) { + // Can only have 1 pip at a time, so replace an existing pip + taskDisplayArea.getRootPinnedTask().dismissPip(); + } + if (likelyResolvedMode != WINDOWING_MODE_FULLSCREEN + && topActivity != null && !topActivity.noDisplay + && topActivity.isNonResizableOrForcedResizable(likelyResolvedMode)) { + // Inform the user that they are starting an app that may not work correctly in + // multi-window mode. + final String packageName = topActivity.info.applicationInfo.packageName; + mAtmService.getTaskChangeNotificationController().notifyActivityForcedResizable( + topTask.mTaskId, FORCED_RESIZEABLE_REASON_SPLIT_SCREEN, packageName); + } + + mAtmService.deferWindowLayout(); + try { + if (topActivity != null) { + mStackSupervisor.mNoAnimActivities.add(topActivity); + } + super.setWindowingMode(windowingMode); + // setWindowingMode triggers an onConfigurationChanged cascade which can result in a + // different resolved windowing mode (usually when preferredWindowingMode is UNDEFINED). + windowingMode = getWindowingMode(); + + if (creating) { + // Nothing else to do if we don't have a window container yet. E.g. call from ctor. + return; + } + + if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && alreadyInSplitScreenMode) { + // We already have a split-screen stack in this display, so just move the tasks over. + // TODO: Figure-out how to do all the stuff in + // AMS.setTaskWindowingModeSplitScreenPrimary + throw new IllegalArgumentException("Setting primary split-screen windowing mode" + + " while there is already one isn't currently supported"); + //return; + } + } finally { + mAtmService.continueWindowLayout(); + } + + mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); + mRootWindowContainer.resumeFocusedStacksTopActivities(); + } + + /** Resume next focusable stack after reparenting to another display. */ + void postReparent() { + adjustFocusToNextFocusableTask("reparent", true /* allowFocusSelf */, + true /* moveDisplayToTop */); + mRootWindowContainer.resumeFocusedStacksTopActivities(); + // Update visibility of activities before notifying WM. This way it won't try to resize + // windows that are no longer visible. + mRootWindowContainer.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, + !PRESERVE_WINDOWS); + } + + DisplayContent getDisplay() { + return getDisplayContent(); + } + + /** @return true if the stack can only contain one task */ + boolean isSingleTaskInstance() { + final DisplayContent display = getDisplay(); + return display != null && display.isSingleTaskInstance(); + } + + final boolean isHomeOrRecentsStack() { + return isActivityTypeHome() || isActivityTypeRecents(); + } + + final boolean isOnHomeDisplay() { + return getDisplayId() == DEFAULT_DISPLAY; + } + + void moveToFront(String reason) { + moveToFront(reason, null); + } + + /** + * @param reason The reason for moving the stack to the front. + * @param task If non-null, the task will be moved to the top of the stack. + */ + void moveToFront(String reason, Task task) { + if (!isAttached()) { + return; + } + + final TaskDisplayArea taskDisplayArea = getDisplayArea(); + + if (inSplitScreenSecondaryWindowingMode()) { + // If the stack is in split-screen secondary mode, we need to make sure we move the + // primary split-screen stack forward in the case it is currently behind a fullscreen + // stack so both halves of the split-screen appear on-top and the fullscreen stack isn't + // cutting between them. + // TODO(b/70677280): This is a workaround until we can fix as part of b/70677280. + final Task topFullScreenStack = + taskDisplayArea.getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN); + if (topFullScreenStack != null) { + final Task primarySplitScreenStack = + taskDisplayArea.getRootSplitScreenPrimaryTask(); + if (primarySplitScreenStack != null + && taskDisplayArea.getIndexOf(topFullScreenStack) + > taskDisplayArea.getIndexOf(primarySplitScreenStack)) { + primarySplitScreenStack.moveToFront(reason + " splitScreenToTop"); + } + } + } + + if (!isActivityTypeHome() && returnsToHomeStack()) { + // Make sure the home stack is behind this stack since that is where we should return to + // when this stack is no longer visible. + taskDisplayArea.moveHomeStackToFront(reason + " returnToHome"); + } + + if (isRootTask()) { + taskDisplayArea.positionStackAtTop(this, false /* includingParents */, reason); + } + if (task == null) { + task = this; + } + task.getParent().positionChildAt(POSITION_TOP, task, true /* includingParents */); + } + + /** + * This moves 'task' to the back of this task and also recursively moves this task to the back + * of its parents (if applicable). + * + * @param reason The reason for moving the stack to the back. + * @param task If non-null, the task will be moved to the bottom of the stack. + **/ + void moveToBack(String reason, Task task) { + if (!isAttached()) { + return; + } + final TaskDisplayArea displayArea = getDisplayArea(); + if (!mCreatedByOrganizer) { + // If this is just a normal task, so move to back of parent and then move 'task' to + // back of this. + final WindowContainer parent = getParent(); + final Task parentTask = parent != null ? parent.asTask() : null; + if (parentTask != null) { + parentTask.moveToBack(reason, this); + } else { + displayArea.positionStackAtBottom(this, reason); + } + if (task != null && task != this) { + positionChildAtBottom(task); + } + return; + } + if (task == null || task == this) { + return; + } + // This is a created-by-organizer task. In this case, let the organizer deal with this + // task's ordering. However, we still need to move 'task' to back. The intention is that + // this ends up behind the home-task so that it is made invisible; so, if the home task + // is not a child of this, reparent 'task' to the back of the home task's actual parent. + displayArea.positionTaskBehindHome(task); + } + + // TODO: Should each user have there own stacks? + @Override + void switchUser(int userId) { + if (mCurrentUser == userId) { + return; + } + mCurrentUser = userId; + + super.switchUser(userId); + if (isLeafTask() && showToCurrentUser()) { + getParent().positionChildAt(POSITION_TOP, this, false /*includeParents*/); + } + } + + void minimalResumeActivityLocked(ActivityRecord r) { + if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + r + " (starting new instance)" + + " callers=" + Debug.getCallers(5)); + r.setState(RESUMED, "minimalResumeActivityLocked"); + r.completeResumeLocked(); + } + + private void clearLaunchTime(ActivityRecord r) { + // Make sure that there is no activity waiting for this to launch. + if (!mStackSupervisor.mWaitingActivityLaunched.isEmpty()) { + mStackSupervisor.removeIdleTimeoutForActivity(r); + mStackSupervisor.scheduleIdleTimeout(r); + } + } + + void awakeFromSleepingLocked() { + // Ensure activities are no longer sleeping. + forAllActivities((Consumer<ActivityRecord>) (r) -> r.setSleeping(false)); + if (mPausingActivity != null) { + Slog.d(TAG, "awakeFromSleepingLocked: previously pausing activity didn't pause"); + mPausingActivity.activityPaused(true); + } + } + + void checkReadyForSleep() { + if (shouldSleepActivities() && goToSleepIfPossible(false /* shuttingDown */)) { + mStackSupervisor.checkReadyForSleepLocked(true /* allowDelay */); + } + } + + /** + * Tries to put the activities in the stack to sleep. + * + * If the stack is not in a state where its activities can be put to sleep, this function will + * start any necessary actions to move the stack into such a state. It is expected that this + * function get called again when those actions complete. + * + * @param shuttingDown true when the called because the device is shutting down. + * @return true if the stack finished going to sleep, false if the stack only started the + * process of going to sleep (checkReadyForSleep will be called when that process finishes). + */ + boolean goToSleepIfPossible(boolean shuttingDown) { + boolean shouldSleep = true; + + if (mResumedActivity != null) { + // Still have something resumed; can't sleep until it is paused. + if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep needs to pause " + mResumedActivity); + if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING, + "Sleep => pause with userLeaving=false"); + + startPausingLocked(false /* userLeaving */, true /* uiSleeping */, null /* resuming */); + shouldSleep = false ; + } else if (mPausingActivity != null) { + // Still waiting for something to pause; can't sleep yet. + if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still waiting to pause " + mPausingActivity); + shouldSleep = false; + } + + if (!shuttingDown) { + if (containsActivityFromStack(mStackSupervisor.mStoppingActivities)) { + // Still need to tell some activities to stop; can't sleep yet. + if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to stop " + + mStackSupervisor.mStoppingActivities.size() + " activities"); + + mStackSupervisor.scheduleIdle(); + shouldSleep = false; + } + } + + if (shouldSleep) { + goToSleep(); + } + + return shouldSleep; + } + + void goToSleep() { + // Make sure all visible activities are now sleeping. This will update the activity's + // visibility and onStop() will be called. + forAllActivities((r) -> { + if (r.isState(STARTED, RESUMED, PAUSING, PAUSED, STOPPING, STOPPED)) { + r.setSleeping(true); + } + }); + + // Ensure visibility after updating sleep states without updating configuration, + // as activities are about to be sent to sleep. + ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, + !PRESERVE_WINDOWS); + } + + private boolean containsActivityFromStack(List<ActivityRecord> rs) { + for (ActivityRecord r : rs) { + if (r.getRootTask() == this) { + return true; + } + } + return false; + } + + /** + * Start pausing the currently resumed activity. It is an error to call this if there + * is already an activity being paused or there is no resumed activity. + * + * @param userLeaving True if this should result in an onUserLeaving to the current activity. + * @param uiSleeping True if this is happening with the user interface going to sleep (the + * screen turning off). + * @param resuming The activity we are currently trying to resume or null if this is not being + * called as part of resuming the top activity, so we shouldn't try to instigate + * a resume here if not null. + * @return Returns true if an activity now is in the PAUSING state, and we are waiting for + * it to tell us when it is done. + */ + final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, + ActivityRecord resuming) { + if (mPausingActivity != null) { + Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity + + " state=" + mPausingActivity.getState()); + if (!shouldSleepActivities()) { + // Avoid recursion among check for sleep and complete pause during sleeping. + // Because activity will be paused immediately after resume, just let pause + // be completed by the order of activity paused from clients. + completePauseLocked(false, resuming); + } + } + ActivityRecord prev = mResumedActivity; + + if (prev == null) { + if (resuming == null) { + Slog.wtf(TAG, "Trying to pause when nothing is resumed"); + mRootWindowContainer.resumeFocusedStacksTopActivities(); + } + return false; + } + + if (prev == resuming) { + Slog.wtf(TAG, "Trying to pause activity that is in process of being resumed"); + return false; + } + + if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSING: " + prev); + else if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Start pausing: " + prev); + mPausingActivity = prev; + mLastPausedActivity = prev; + mLastNoHistoryActivity = prev.isNoHistory() ? prev : null; + prev.setState(PAUSING, "startPausingLocked"); + prev.getTask().touchActiveTime(); + clearLaunchTime(prev); + + mAtmService.updateCpuStats(); + + boolean pauseImmediately = false; + if (resuming != null && (resuming.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0) { + // If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous + // activity to be paused, while at the same time resuming the new resume activity + // only if the previous activity can't go into Pip since we want to give Pip + // activities a chance to enter Pip before resuming the next activity. + final boolean lastResumedCanPip = prev != null && prev.checkEnterPictureInPictureState( + "shouldResumeWhilePausing", userLeaving); + if (!lastResumedCanPip) { + pauseImmediately = true; + } + } + + if (prev.attachedToProcess()) { + if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev); + try { + EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev), + prev.shortComponentName, "userLeaving=" + userLeaving); + + mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(), + prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving, + prev.configChangeFlags, pauseImmediately)); + } catch (Exception e) { + // Ignore exception, if process died other code will cleanup. + Slog.w(TAG, "Exception thrown during pause", e); + mPausingActivity = null; + mLastPausedActivity = null; + mLastNoHistoryActivity = null; + } + } else { + mPausingActivity = null; + mLastPausedActivity = null; + mLastNoHistoryActivity = null; + } + + // If we are not going to sleep, we want to ensure the device is + // awake until the next activity is started. + if (!uiSleeping && !mAtmService.isSleepingOrShuttingDownLocked()) { + mStackSupervisor.acquireLaunchWakelock(); + } + + if (mPausingActivity != null) { + // Have the window manager pause its key dispatching until the new + // activity has started. If we're pausing the activity just because + // the screen is being turned off and the UI is sleeping, don't interrupt + // key dispatch; the same activity will pick it up again on wakeup. + if (!uiSleeping) { + prev.pauseKeyDispatchingLocked(); + } else if (DEBUG_PAUSE) { + Slog.v(TAG_PAUSE, "Key dispatch not paused for screen off"); + } + + if (pauseImmediately) { + // If the caller said they don't want to wait for the pause, then complete + // the pause now. + completePauseLocked(false, resuming); + return false; + + } else { + prev.schedulePauseTimeout(); + return true; + } + + } else { + // This activity failed to schedule the + // pause, so just treat it as being paused now. + if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Activity not running, resuming next."); + if (resuming == null) { + mRootWindowContainer.resumeFocusedStacksTopActivities(); + } + return false; + } + } + + @VisibleForTesting + void completePauseLocked(boolean resumeNext, ActivityRecord resuming) { + ActivityRecord prev = mPausingActivity; + if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Complete pause: " + prev); + + if (prev != null) { + prev.setWillCloseOrEnterPip(false); + final boolean wasStopping = prev.isState(STOPPING); + prev.setState(PAUSED, "completePausedLocked"); + if (prev.finishing) { + if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev); + prev = prev.completeFinishing("completePausedLocked"); + } else if (prev.hasProcess()) { + if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev + + " wasStopping=" + wasStopping + + " visibleRequested=" + prev.mVisibleRequested); + if (prev.deferRelaunchUntilPaused) { + // Complete the deferred relaunch that was waiting for pause to complete. + if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Re-launching after pause: " + prev); + prev.relaunchActivityLocked(prev.preserveWindowOnDeferredRelaunch); + } else if (wasStopping) { + // We are also stopping, the stop request must have gone soon after the pause. + // We can't clobber it, because the stop confirmation will not be handled. + // We don't need to schedule another stop, we only need to let it happen. + prev.setState(STOPPING, "completePausedLocked"); + } else if (!prev.mVisibleRequested || shouldSleepOrShutDownActivities()) { + // Clear out any deferred client hide we might currently have. + prev.setDeferHidingClient(false); + // If we were visible then resumeTopActivities will release resources before + // stopping. + prev.addToStopping(true /* scheduleIdle */, false /* idleDelayed */, + "completePauseLocked"); + } + } else { + if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "App died during pause, not stopping: " + prev); + prev = null; + } + // It is possible the activity was freezing the screen before it was paused. + // In that case go ahead and remove the freeze this activity has on the screen + // since it is no longer visible. + if (prev != null) { + prev.stopFreezingScreenLocked(true /*force*/); + } + mPausingActivity = null; + } + + if (resumeNext) { + final Task topStack = mRootWindowContainer.getTopDisplayFocusedStack(); + if (topStack != null && !topStack.shouldSleepOrShutDownActivities()) { + mRootWindowContainer.resumeFocusedStacksTopActivities(topStack, prev, null); + } else { + checkReadyForSleep(); + final ActivityRecord top = topStack != null ? topStack.topRunningActivity() : null; + if (top == null || (prev != null && top != prev)) { + // If there are no more activities available to run, do resume anyway to start + // something. Also if the top activity on the stack is not the just paused + // activity, we need to go ahead and resume it to ensure we complete an + // in-flight app switch. + mRootWindowContainer.resumeFocusedStacksTopActivities(); + } + } + } + + if (prev != null) { + prev.resumeKeyDispatchingLocked(); + + if (prev.hasProcess() && prev.cpuTimeAtResume > 0) { + final long diff = prev.app.getCpuTime() - prev.cpuTimeAtResume; + if (diff > 0) { + final Runnable r = PooledLambda.obtainRunnable( + ActivityManagerInternal::updateForegroundTimeIfOnBattery, + mAtmService.mAmInternal, prev.info.packageName, + prev.info.applicationInfo.uid, + diff); + mAtmService.mH.post(r); + } + } + prev.cpuTimeAtResume = 0; // reset it + } + + mRootWindowContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS); + + // Notify when the task stack has changed, but only if visibilities changed (not just + // focus). Also if there is an active pinned stack - we always want to notify it about + // task stack changes, because its positioning may depend on it. + if (mStackSupervisor.mAppVisibilitiesChangedSinceLastPause + || (getDisplayArea() != null && getDisplayArea().hasPinnedTask())) { + mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged(); + mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = false; + } + } + + boolean isTopStackInDisplayArea() { + final TaskDisplayArea taskDisplayArea = getDisplayArea(); + return taskDisplayArea != null && taskDisplayArea.isTopStack(this); + } + + /** + * @return {@code true} if this is the focused stack on its current display, {@code false} + * otherwise. + */ + boolean isFocusedStackOnDisplay() { + final DisplayContent display = getDisplay(); + return display != null && this == display.getFocusedStack(); + } + + /** + * Make sure that all activities that need to be visible in the stack (that is, they + * currently can be seen by the user) actually are and update their configuration. + * @param starting The top most activity in the task. + * The activity is either starting or resuming. + * Caller should ensure starting activity is visible. + * @param preserveWindows Flag indicating whether windows should be preserved when updating + * configuration in {@link mEnsureActivitiesVisibleHelper}. + * @param configChanges Parts of the configuration that changed for this activity for evaluating + * if the screen should be frozen as part of + * {@link mEnsureActivitiesVisibleHelper}. + * + */ + void ensureActivitiesVisible(@Nullable ActivityRecord starting, int configChanges, + boolean preserveWindows) { + ensureActivitiesVisible(starting, configChanges, preserveWindows, true /* notifyClients */); + } + + /** + * Ensure visibility with an option to also update the configuration of visible activities. + * @see #ensureActivitiesVisible(ActivityRecord, int, boolean) + * @see RootWindowContainer#ensureActivitiesVisible(ActivityRecord, int, boolean) + * @param starting The top most activity in the task. + * The activity is either starting or resuming. + * Caller should ensure starting activity is visible. + * @param notifyClients Flag indicating whether the visibility updates should be sent to the + * clients in {@link mEnsureActivitiesVisibleHelper}. + * @param preserveWindows Flag indicating whether windows should be preserved when updating + * configuration in {@link mEnsureActivitiesVisibleHelper}. + * @param configChanges Parts of the configuration that changed for this activity for evaluating + * if the screen should be frozen as part of + * {@link mEnsureActivitiesVisibleHelper}. + */ + // TODO: Should be re-worked based on the fact that each task as a stack in most cases. + void ensureActivitiesVisible(@Nullable ActivityRecord starting, int configChanges, + boolean preserveWindows, boolean notifyClients) { + mTopActivityOccludesKeyguard = false; + mTopDismissingKeyguardActivity = null; + mStackSupervisor.beginActivityVisibilityUpdate(); + try { + mEnsureActivitiesVisibleHelper.process( + starting, configChanges, preserveWindows, notifyClients); + + if (mTranslucentActivityWaiting != null && + mUndrawnActivitiesBelowTopTranslucent.isEmpty()) { + // Nothing is getting drawn or everything was already visible, don't wait for timeout. + notifyActivityDrawnLocked(null); + } + } finally { + mStackSupervisor.endActivityVisibilityUpdate(); + } + } + + /** + * @return true if the top visible activity wants to occlude the Keyguard, false otherwise + */ + boolean topActivityOccludesKeyguard() { + return mTopActivityOccludesKeyguard; + } + + /** + * Returns true if this stack should be resized to match the bounds specified by + * {@link ActivityOptions#setLaunchBounds} when launching an activity into the stack. + */ + boolean shouldResizeStackWithLaunchBounds() { + return inPinnedWindowingMode(); + } + + // TODO(NOW!) + /** + * Returns {@code true} if this is the top-most split-screen-primary or + * split-screen-secondary stack, {@code false} otherwise. + */ + boolean isTopSplitScreenStack() { + return inSplitScreenWindowingMode() + && this == getDisplayArea().getTopStackInWindowingMode(getWindowingMode()); + } + + /** + * @return the top most visible activity that wants to dismiss Keyguard + */ + ActivityRecord getTopDismissingKeyguardActivity() { + return mTopDismissingKeyguardActivity; + } + + /** + * Checks whether {@param r} should be visible depending on Keyguard state and updates + * {@link #mTopActivityOccludesKeyguard} and {@link #mTopDismissingKeyguardActivity} if + * necessary. + * + * @return true if {@param r} is visible taken Keyguard state into account, false otherwise + */ + boolean checkKeyguardVisibility(ActivityRecord r, boolean shouldBeVisible, boolean isTop) { + int displayId = getDisplayId(); + if (displayId == INVALID_DISPLAY) displayId = DEFAULT_DISPLAY; + + final boolean keyguardOrAodShowing = mStackSupervisor.getKeyguardController() + .isKeyguardOrAodShowing(displayId); + final boolean keyguardLocked = mStackSupervisor.getKeyguardController().isKeyguardLocked(); + final boolean showWhenLocked = r.canShowWhenLocked(); + final boolean dismissKeyguard = r.containsDismissKeyguardWindow(); + if (shouldBeVisible) { + if (dismissKeyguard && mTopDismissingKeyguardActivity == null) { + mTopDismissingKeyguardActivity = r; + } + + // Only the top activity may control occluded, as we can't occlude the Keyguard if the + // top app doesn't want to occlude it. + if (isTop) { + mTopActivityOccludesKeyguard |= showWhenLocked; + } + + final boolean canShowWithKeyguard = canShowWithInsecureKeyguard() + && mStackSupervisor.getKeyguardController().canDismissKeyguard(); + if (canShowWithKeyguard) { + return true; + } + } + if (keyguardOrAodShowing) { + // If keyguard is showing, nothing is visible, except if we are able to dismiss Keyguard + // right away and AOD isn't visible. + return shouldBeVisible && mStackSupervisor.getKeyguardController() + .canShowActivityWhileKeyguardShowing(r, dismissKeyguard); + } else if (keyguardLocked) { + return shouldBeVisible && mStackSupervisor.getKeyguardController().canShowWhileOccluded( + dismissKeyguard, showWhenLocked); + } else { + return shouldBeVisible; + } + } + + /** + * Check if the display to which this stack is attached has + * {@link Display#FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD} applied. + */ + boolean canShowWithInsecureKeyguard() { + final DisplayContent displayContent = getDisplay(); + if (displayContent == null) { + throw new IllegalStateException("Stack is not attached to any display, stackId=" + + getRootTaskId()); + } + + final int flags = displayContent.mDisplay.getFlags(); + return (flags & FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0; + } + + void checkTranslucentActivityWaiting(ActivityRecord top) { + if (mTranslucentActivityWaiting != top) { + mUndrawnActivitiesBelowTopTranslucent.clear(); + if (mTranslucentActivityWaiting != null) { + // Call the callback with a timeout indication. + notifyActivityDrawnLocked(null); + mTranslucentActivityWaiting = null; + } + mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG); + } + } + + void convertActivityToTranslucent(ActivityRecord r) { + mTranslucentActivityWaiting = r; + mUndrawnActivitiesBelowTopTranslucent.clear(); + mHandler.sendEmptyMessageDelayed(TRANSLUCENT_TIMEOUT_MSG, TRANSLUCENT_CONVERSION_TIMEOUT); + } + + /** + * Called as activities below the top translucent activity are redrawn. When the last one is + * redrawn notify the top activity by calling + * {@link Activity#onTranslucentConversionComplete}. + * + * @param r The most recent background activity to be drawn. Or, if r is null then a timeout + * occurred and the activity will be notified immediately. + */ + void notifyActivityDrawnLocked(ActivityRecord r) { + if ((r == null) + || (mUndrawnActivitiesBelowTopTranslucent.remove(r) && + mUndrawnActivitiesBelowTopTranslucent.isEmpty())) { + // The last undrawn activity below the top has just been drawn. If there is an + // opaque activity at the top, notify it that it can become translucent safely now. + final ActivityRecord waitingActivity = mTranslucentActivityWaiting; + mTranslucentActivityWaiting = null; + mUndrawnActivitiesBelowTopTranslucent.clear(); + mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG); + + if (waitingActivity != null) { + mWmService.setWindowOpaqueLocked(waitingActivity.appToken, false); + if (waitingActivity.attachedToProcess()) { + try { + waitingActivity.app.getThread().scheduleTranslucentConversionComplete( + waitingActivity.appToken, r != null); + } catch (RemoteException e) { + } + } + } + } + } + + /** @see ActivityRecord#cancelInitializing() */ + void cancelInitializingActivities() { + // We don't want to clear starting window for activities that aren't behind fullscreen + // activities as we need to display their starting window until they are done initializing. + checkBehindFullscreenActivity(null /* toCheck */, ActivityRecord::cancelInitializing); + } + + /** + * If an activity {@param toCheck} is given, this method returns {@code true} if the activity + * is occluded by any fullscreen activity. If there is no {@param toCheck} and the handling + * function {@param handleBehindFullscreenActivity} is given, this method will pass all occluded + * activities to the function. + */ + boolean checkBehindFullscreenActivity(ActivityRecord toCheck, + Consumer<ActivityRecord> handleBehindFullscreenActivity) { + return mCheckBehindFullscreenActivityHelper.process( + toCheck, handleBehindFullscreenActivity); + } + + /** + * Ensure that the top activity in the stack is resumed. + * + * @param prev The previously resumed activity, for when in the process + * of pausing; can be null to call from elsewhere. + * @param options Activity options. + * + * @return Returns true if something is being resumed, or false if + * nothing happened. + * + * NOTE: It is not safe to call this method directly as it can cause an activity in a + * non-focused stack to be resumed. + * Use {@link RootWindowContainer#resumeFocusedStacksTopActivities} to resume the + * right activity for the current system state. + */ + @GuardedBy("mService") + boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) { + if (mInResumeTopActivity) { + // Don't even start recursing. + return false; + } + + boolean result = false; + try { + // Protect against recursion. + mInResumeTopActivity = true; + result = resumeTopActivityInnerLocked(prev, options); + + // When resuming the top activity, it may be necessary to pause the top activity (for + // example, returning to the lock screen. We suppress the normal pause logic in + // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the + // end. We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here + // to ensure any necessary pause logic occurs. In the case where the Activity will be + // shown regardless of the lock screen, the call to + // {@link ActivityStackSupervisor#checkReadyForSleepLocked} is skipped. + final ActivityRecord next = topRunningActivity(true /* focusableOnly */); + if (next == null || !next.canTurnScreenOn()) { + checkReadyForSleep(); + } + } finally { + mInResumeTopActivity = false; + } + + return result; + } + + @GuardedBy("mService") + private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) { + if (!mAtmService.isBooting() && !mAtmService.isBooted()) { + // Not ready yet! + return false; + } + + // Find the next top-most activity to resume in this stack that is not finishing and is + // focusable. If it is not focusable, we will fall into the case below to resume the + // top activity in the next focusable task. + ActivityRecord next = topRunningActivity(true /* focusableOnly */); + + final boolean hasRunningActivity = next != null; + + // TODO: Maybe this entire condition can get removed? + if (hasRunningActivity && !isAttached()) { + return false; + } + + mRootWindowContainer.cancelInitializingActivities(); + + // Remember how we'll process this pause/resume situation, and ensure + // that the state is reset however we wind up proceeding. + boolean userLeaving = mStackSupervisor.mUserLeaving; + mStackSupervisor.mUserLeaving = false; + + if (!hasRunningActivity) { + // There are no activities left in the stack, let's look somewhere else. + return resumeNextFocusableActivityWhenStackIsEmpty(prev, options); + } + + next.delayedResume = false; + final TaskDisplayArea taskDisplayArea = getDisplayArea(); + + // If the top activity is the resumed one, nothing to do. + if (mResumedActivity == next && next.isState(RESUMED) + && taskDisplayArea.allResumedActivitiesComplete()) { + // Make sure we have executed any pending transitions, since there + // should be nothing left to do at this point. + executeAppTransition(options); + if (DEBUG_STATES) Slog.d(TAG_STATES, + "resumeTopActivityLocked: Top activity resumed " + next); + return false; + } + + if (!next.canResumeByCompat()) { + return false; + } + + // If we are currently pausing an activity, then don't do anything until that is done. + final boolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete(); + if (!allPausedComplete) { + if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) { + Slog.v(TAG_PAUSE, "resumeTopActivityLocked: Skip resume: some activity pausing."); + } + return false; + } + + // If we are sleeping, and there is no resumed activity, and the top activity is paused, + // well that is the state we want. + if (shouldSleepOrShutDownActivities() + && mLastPausedActivity == next + && mRootWindowContainer.allPausedActivitiesComplete()) { + // If the current top activity may be able to occlude keyguard but the occluded state + // has not been set, update visibility and check again if we should continue to resume. + boolean nothingToResume = true; + if (!mAtmService.mShuttingDown) { + final boolean canShowWhenLocked = !mTopActivityOccludesKeyguard + && next.canShowWhenLocked(); + final boolean mayDismissKeyguard = mTopDismissingKeyguardActivity != next + && next.containsDismissKeyguardWindow(); + + if (canShowWhenLocked || mayDismissKeyguard) { + ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, + !PRESERVE_WINDOWS); + nothingToResume = shouldSleepActivities(); + } else if (next.currentLaunchCanTurnScreenOn() && next.canTurnScreenOn()) { + nothingToResume = false; + } + } + if (nothingToResume) { + // Make sure we have executed any pending transitions, since there + // should be nothing left to do at this point. + executeAppTransition(options); + if (DEBUG_STATES) Slog.d(TAG_STATES, + "resumeTopActivityLocked: Going to sleep and all paused"); + return false; + } + } + + // Make sure that the user who owns this activity is started. If not, + // we will just leave it as is because someone should be bringing + // another user's activities to the top of the stack. + if (!mAtmService.mAmInternal.hasStartedUserState(next.mUserId)) { + Slog.w(TAG, "Skipping resume of top activity " + next + + ": user " + next.mUserId + " is stopped"); + return false; + } + + // The activity may be waiting for stop, but that is no longer + // appropriate for it. + mStackSupervisor.mStoppingActivities.remove(next); + next.setSleeping(false); + + if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next); + + // If we are currently pausing an activity, then don't do anything until that is done. + if (!mRootWindowContainer.allPausedActivitiesComplete()) { + if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE, + "resumeTopActivityLocked: Skip resume: some activity pausing."); + + return false; + } + + mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid); + + ActivityRecord lastResumed = null; + final Task lastFocusedStack = taskDisplayArea.getLastFocusedStack(); + if (lastFocusedStack != null && lastFocusedStack != this) { + // So, why aren't we using prev here??? See the param comment on the method. prev + // doesn't represent the last resumed activity. However, the last focus stack does if + // it isn't null. + lastResumed = lastFocusedStack.mResumedActivity; + if (userLeaving && inMultiWindowMode() && lastFocusedStack.shouldBeVisible(next)) { + // The user isn't leaving if this stack is the multi-window mode and the last + // focused stack should still be visible. + if(DEBUG_USER_LEAVING) Slog.i(TAG_USER_LEAVING, "Overriding userLeaving to false" + + " next=" + next + " lastResumed=" + lastResumed); + userLeaving = false; + } + } + + boolean pausing = taskDisplayArea.pauseBackStacks(userLeaving, next); + if (mResumedActivity != null) { + if (DEBUG_STATES) Slog.d(TAG_STATES, + "resumeTopActivityLocked: Pausing " + mResumedActivity); + pausing |= startPausingLocked(userLeaving, false /* uiSleeping */, next); + } + if (pausing) { + if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG_STATES, + "resumeTopActivityLocked: Skip resume: need to start pausing"); + // At this point we want to put the upcoming activity's process + // at the top of the LRU list, since we know we will be needing it + // very soon and it would be a waste to let it get killed if it + // happens to be sitting towards the end. + if (next.attachedToProcess()) { + next.app.updateProcessInfo(false /* updateServiceConnectionActivities */, + true /* activityChange */, false /* updateOomAdj */, + false /* addPendingTopUid */); + } else if (!next.isProcessRunning()) { + // Since the start-process is asynchronous, if we already know the process of next + // activity isn't running, we can start the process earlier to save the time to wait + // for the current activity to be paused. + final boolean isTop = this == taskDisplayArea.getFocusedStack(); + mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop, + isTop ? "pre-top-activity" : "pre-activity"); + } + if (lastResumed != null) { + lastResumed.setWillCloseOrEnterPip(true); + } + return true; + } else if (mResumedActivity == next && next.isState(RESUMED) + && taskDisplayArea.allResumedActivitiesComplete()) { + // It is possible for the activity to be resumed when we paused back stacks above if the + // next activity doesn't have to wait for pause to complete. + // So, nothing else to-do except: + // Make sure we have executed any pending transitions, since there + // should be nothing left to do at this point. + executeAppTransition(options); + if (DEBUG_STATES) Slog.d(TAG_STATES, + "resumeTopActivityLocked: Top activity resumed (dontWaitForPause) " + next); + return true; + } + + // If the most recent activity was noHistory but was only stopped rather + // than stopped+finished because the device went to sleep, we need to make + // sure to finish it as we're making a new activity topmost. + if (shouldSleepActivities() && mLastNoHistoryActivity != null && + !mLastNoHistoryActivity.finishing) { + if (DEBUG_STATES) Slog.d(TAG_STATES, + "no-history finish of " + mLastNoHistoryActivity + " on new resume"); + mLastNoHistoryActivity.finishIfPossible("resume-no-history", false /* oomAdj */); + mLastNoHistoryActivity = null; + } + + if (prev != null && prev != next && next.nowVisible) { + + // The next activity is already visible, so hide the previous + // activity's windows right now so we can show the new one ASAP. + // We only do this if the previous is finishing, which should mean + // it is on top of the one being resumed so hiding it quickly + // is good. Otherwise, we want to do the normal route of allowing + // the resumed activity to be shown so we can decide if the + // previous should actually be hidden depending on whether the + // new one is found to be full-screen or not. + if (prev.finishing) { + prev.setVisibility(false); + if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, + "Not waiting for visible to hide: " + prev + + ", nowVisible=" + next.nowVisible); + } else { + if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, + "Previous already visible but still waiting to hide: " + prev + + ", nowVisible=" + next.nowVisible); + } + + } + + // Launching this app's activity, make sure the app is no longer + // considered stopped. + try { + mAtmService.getPackageManager().setPackageStoppedState( + next.packageName, false, next.mUserId); /* TODO: Verify if correct userid */ + } catch (RemoteException e1) { + } catch (IllegalArgumentException e) { + Slog.w(TAG, "Failed trying to unstop package " + + next.packageName + ": " + e); + } + + // We are starting up the next activity, so tell the window manager + // that the previous one will be hidden soon. This way it can know + // to ignore it when computing the desired screen orientation. + boolean anim = true; + final DisplayContent dc = taskDisplayArea.mDisplayContent; + if (prev != null) { + if (prev.finishing) { + if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, + "Prepare close transition: prev=" + prev); + if (mStackSupervisor.mNoAnimActivities.contains(prev)) { + anim = false; + dc.prepareAppTransition(TRANSIT_NONE, false); + } else { + dc.prepareAppTransition( + prev.getTask() == next.getTask() ? TRANSIT_ACTIVITY_CLOSE + : TRANSIT_TASK_CLOSE, false); + } + prev.setVisibility(false); + } else { + if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, + "Prepare open transition: prev=" + prev); + if (mStackSupervisor.mNoAnimActivities.contains(next)) { + anim = false; + dc.prepareAppTransition(TRANSIT_NONE, false); + } else { + dc.prepareAppTransition( + prev.getTask() == next.getTask() ? TRANSIT_ACTIVITY_OPEN + : next.mLaunchTaskBehind ? TRANSIT_TASK_OPEN_BEHIND + : TRANSIT_TASK_OPEN, false); + } + } + } else { + if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous"); + if (mStackSupervisor.mNoAnimActivities.contains(next)) { + anim = false; + dc.prepareAppTransition(TRANSIT_NONE, false); + } else { + dc.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false); + } + } + + if (anim) { + next.applyOptionsLocked(); + } else { + next.clearOptionsLocked(); + } + + mStackSupervisor.mNoAnimActivities.clear(); + + if (next.attachedToProcess()) { + if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next + + " stopped=" + next.stopped + + " visibleRequested=" + next.mVisibleRequested); + + // If the previous activity is translucent, force a visibility update of + // the next activity, so that it's added to WM's opening app list, and + // transition animation can be set up properly. + // For example, pressing Home button with a translucent activity in focus. + // Launcher is already visible in this case. If we don't add it to opening + // apps, maybeUpdateTransitToWallpaper() will fail to identify this as a + // TRANSIT_WALLPAPER_OPEN animation, and run some funny animation. + final boolean lastActivityTranslucent = lastFocusedStack != null + && (lastFocusedStack.inMultiWindowMode() + || (lastFocusedStack.mLastPausedActivity != null + && !lastFocusedStack.mLastPausedActivity.occludesParent())); + + // This activity is now becoming visible. + if (!next.mVisibleRequested || next.stopped || lastActivityTranslucent) { + next.setVisibility(true); + } + + // schedule launch ticks to collect information about slow apps. + next.startLaunchTickingLocked(); + + ActivityRecord lastResumedActivity = + lastFocusedStack == null ? null : lastFocusedStack.mResumedActivity; + final ActivityState lastState = next.getState(); + + mAtmService.updateCpuStats(); + + if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + next + + " (in existing)"); + + next.setState(RESUMED, "resumeTopActivityInnerLocked"); + + next.app.updateProcessInfo(false /* updateServiceConnectionActivities */, + true /* activityChange */, true /* updateOomAdj */, + true /* addPendingTopUid */); + + // Have the window manager re-evaluate the orientation of + // the screen based on the new activity order. + boolean notUpdated = true; + + // Activity should also be visible if set mLaunchTaskBehind to true (see + // ActivityRecord#shouldBeVisibleIgnoringKeyguard()). + if (shouldBeVisible(next)) { + // We have special rotation behavior when here is some active activity that + // requests specific orientation or Keyguard is locked. Make sure all activity + // visibilities are set correctly as well as the transition is updated if needed + // to get the correct rotation behavior. Otherwise the following call to update + // the orientation may cause incorrect configurations delivered to client as a + // result of invisible window resize. + // TODO: Remove this once visibilities are set correctly immediately when + // starting an activity. + notUpdated = !mRootWindowContainer.ensureVisibilityAndConfig(next, getDisplayId(), + true /* markFrozenIfConfigChanged */, false /* deferResume */); + } + + if (notUpdated) { + // The configuration update wasn't able to keep the existing + // instance of the activity, and instead started a new one. + // We should be all done, but let's just make sure our activity + // is still at the top and schedule another run if something + // weird happened. + ActivityRecord nextNext = topRunningActivity(); + if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_STATES, + "Activity config changed during resume: " + next + + ", new next: " + nextNext); + if (nextNext != next) { + // Do over! + mStackSupervisor.scheduleResumeTopActivities(); + } + if (!next.mVisibleRequested || next.stopped) { + next.setVisibility(true); + } + next.completeResumeLocked(); + return true; + } + + try { + final ClientTransaction transaction = + ClientTransaction.obtain(next.app.getThread(), next.appToken); + // Deliver all pending results. + ArrayList<ResultInfo> a = next.results; + if (a != null) { + final int N = a.size(); + if (!next.finishing && N > 0) { + if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, + "Delivering results to " + next + ": " + a); + transaction.addCallback(ActivityResultItem.obtain(a)); + } + } + + if (next.newIntents != null) { + transaction.addCallback( + NewIntentItem.obtain(next.newIntents, true /* resume */)); + } + + // Well the app will no longer be stopped. + // Clear app token stopped state in window manager if needed. + next.notifyAppResumed(next.stopped); + + EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next), + next.getTask().mTaskId, next.shortComponentName); + + next.setSleeping(false); + mAtmService.getAppWarningsLocked().onResumeActivity(next); + next.app.setPendingUiCleanAndForceProcessStateUpTo(mAtmService.mTopProcessState); + next.clearOptionsLocked(); + transaction.setLifecycleStateRequest( + ResumeActivityItem.obtain(next.app.getReportedProcState(), + dc.isNextTransitionForward())); + mAtmService.getLifecycleManager().scheduleTransaction(transaction); + + if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed " + + next); + } catch (Exception e) { + // Whoops, need to restart this activity! + if (DEBUG_STATES) Slog.v(TAG_STATES, "Resume failed; resetting state to " + + lastState + ": " + next); + next.setState(lastState, "resumeTopActivityInnerLocked"); + + // lastResumedActivity being non-null implies there is a lastStack present. + if (lastResumedActivity != null) { + lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked"); + } + + Slog.i(TAG, "Restarting because process died: " + next); + if (!next.hasBeenLaunched) { + next.hasBeenLaunched = true; + } else if (SHOW_APP_STARTING_PREVIEW && lastFocusedStack != null + && lastFocusedStack.isTopStackInDisplayArea()) { + next.showStartingWindow(null /* prev */, false /* newTask */, + false /* taskSwitch */); + } + mStackSupervisor.startSpecificActivity(next, true, false); + return true; + } + + // From this point on, if something goes wrong there is no way + // to recover the activity. + try { + next.completeResumeLocked(); + } catch (Exception e) { + // If any exception gets thrown, toss away this + // activity and try the next one. + Slog.w(TAG, "Exception thrown during resume of " + next, e); + next.finishIfPossible("resume-exception", true /* oomAdj */); + return true; + } + } else { + // Whoops, need to restart this activity! + if (!next.hasBeenLaunched) { + next.hasBeenLaunched = true; + } else { + if (SHOW_APP_STARTING_PREVIEW) { + next.showStartingWindow(null /* prev */, false /* newTask */, + false /* taskSwich */); + } + if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next); + } + if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Restarting " + next); + mStackSupervisor.startSpecificActivity(next, true, true); + } + + return true; + } + + /** + * Resume the next eligible activity in a focusable stack when this one does not have any + * running activities left. The focus will be adjusted to the next focusable stack and + * top running activities will be resumed in all focusable stacks. However, if the current stack + * is a home stack - we have to keep it focused, start and resume a home activity on the current + * display instead to make sure that the display is not empty. + */ + private boolean resumeNextFocusableActivityWhenStackIsEmpty(ActivityRecord prev, + ActivityOptions options) { + final String reason = "noMoreActivities"; + + if (!isActivityTypeHome()) { + final Task nextFocusedStack = adjustFocusToNextFocusableTask(reason); + if (nextFocusedStack != null) { + // Try to move focus to the next visible stack with a running activity if this + // stack is not covering the entire screen or is on a secondary display with no home + // stack. + return mRootWindowContainer.resumeFocusedStacksTopActivities(nextFocusedStack, + prev, null /* targetOptions */); + } + } + + // If the current stack is a home stack, or if focus didn't switch to a different stack - + // just start up the Launcher... + ActivityOptions.abort(options); + if (DEBUG_STATES) Slog.d(TAG_STATES, + "resumeNextFocusableActivityWhenStackIsEmpty: " + reason + ", go home"); + return mRootWindowContainer.resumeHomeActivity(prev, reason, getDisplayArea()); + } + + void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity, + boolean newTask, boolean keepCurTransition, ActivityOptions options) { + Task rTask = r.getTask(); + final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront(); + final boolean isOrhasTask = rTask == this || hasChild(rTask); + // mLaunchTaskBehind tasks get placed at the back of the task stack. + if (!r.mLaunchTaskBehind && allowMoveToFront && (!isOrhasTask || newTask)) { + // Last activity in task had been removed or ActivityManagerService is reusing task. + // Insert or replace. + // Might not even be in. + positionChildAtTop(rTask); + } + Task task = null; + if (!newTask && isOrhasTask) { + // Starting activity cannot be occluding activity, otherwise starting window could be + // remove immediately without transferring to starting activity. + final ActivityRecord occludingActivity = getOccludingActivityAbove(r); + if (occludingActivity != null) { + // Here it is! Now, if this is not yet visible (occluded by another task) to the + // user, then just add it without starting; it will get started when the user + // navigates back to it. + if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task " + task, + new RuntimeException("here").fillInStackTrace()); + rTask.positionChildAtTop(r); + ActivityOptions.abort(options); + return; + } + } + + // Place a new activity at top of stack, so it is next to interact with the user. + + // If we are not placing the new activity frontmost, we do not want to deliver the + // onUserLeaving callback to the actual frontmost activity + final Task activityTask = r.getTask(); + if (task == activityTask && mChildren.indexOf(task) != (getChildCount() - 1)) { + mStackSupervisor.mUserLeaving = false; + if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING, + "startActivity() behind front, mUserLeaving=false"); + } + + task = activityTask; + + // Slot the activity into the history stack and proceed + if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task, + new RuntimeException("here").fillInStackTrace()); + task.positionChildAtTop(r); + + // The transition animation and starting window are not needed if {@code allowMoveToFront} + // is false, because the activity won't be visible. + if ((!isHomeOrRecentsStack() || hasActivity()) && allowMoveToFront) { + final DisplayContent dc = getDisplay().mDisplayContent; + if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, + "Prepare open transition: starting " + r); + if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) { + dc.prepareAppTransition(TRANSIT_NONE, keepCurTransition); + mStackSupervisor.mNoAnimActivities.add(r); + } else { + int transit = TRANSIT_ACTIVITY_OPEN; + if (newTask) { + if (r.mLaunchTaskBehind) { + transit = TRANSIT_TASK_OPEN_BEHIND; + } else if (getDisplay().isSingleTaskInstance()) { + // If a new task is being launched in a single task display, we don't need + // to play normal animation, but need to trigger a callback when an app + // transition is actually handled. So ignore already prepared activity, and + // override it. + transit = TRANSIT_SHOW_SINGLE_TASK_DISPLAY; + keepCurTransition = false; + } else { + // If a new task is being launched, then mark the existing top activity as + // supporting picture-in-picture while pausing only if the starting activity + // would not be considered an overlay on top of the current activity + // (eg. not fullscreen, or the assistant) + if (canEnterPipOnTaskSwitch(focusedTopActivity, + null /* toFrontTask */, r, options)) { + focusedTopActivity.supportsEnterPipOnTaskSwitch = true; + } + transit = TRANSIT_TASK_OPEN; + } + } + dc.prepareAppTransition(transit, keepCurTransition); + mStackSupervisor.mNoAnimActivities.remove(r); + } + boolean doShow = true; + if (newTask) { + // Even though this activity is starting fresh, we still need + // to reset it to make sure we apply affinities to move any + // existing activities from other tasks in to it. + // If the caller has requested that the target task be + // reset, then do so. + if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { + resetTaskIfNeeded(r, r); + doShow = topRunningNonDelayedActivityLocked(null) == r; + } + } else if (options != null && options.getAnimationType() + == ActivityOptions.ANIM_SCENE_TRANSITION) { + doShow = false; + } + if (r.mLaunchTaskBehind) { + // Don't do a starting window for mLaunchTaskBehind. More importantly make sure we + // tell WindowManager that r is visible even though it is at the back of the stack. + r.setVisibility(true); + ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); + // Go ahead to execute app transition for this activity since the app transition + // will not be triggered through the resume channel. + getDisplay().mDisplayContent.executeAppTransition(); + } else if (SHOW_APP_STARTING_PREVIEW && doShow) { + // Figure out if we are transitioning from another activity that is + // "has the same starting icon" as the next one. This allows the + // window manager to keep the previous window it had previously + // created, if it still had one. + Task prevTask = r.getTask(); + ActivityRecord prev = prevTask.topActivityWithStartingWindow(); + if (prev != null) { + // We don't want to reuse the previous starting preview if: + // (1) The current activity is in a different task. + if (prev.getTask() != prevTask) { + prev = null; + } + // (2) The current activity is already displayed. + else if (prev.nowVisible) { + prev = null; + } + } + r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity)); + } + } else { + // If this is the first activity, don't do any fancy animations, + // because there is nothing for it to animate on top of. + ActivityOptions.abort(options); + } + } + + /** + * @return Whether the switch to another task can trigger the currently running activity to + * enter PiP while it is pausing (if supported). Only one of {@param toFrontTask} or + * {@param toFrontActivity} should be set. + */ + private boolean canEnterPipOnTaskSwitch(ActivityRecord pipCandidate, + Task toFrontTask, ActivityRecord toFrontActivity, ActivityOptions opts) { + if (opts != null && opts.disallowEnterPictureInPictureWhileLaunching()) { + // Ensure the caller has requested not to trigger auto-enter PiP + return false; + } + if (pipCandidate == null || pipCandidate.inPinnedWindowingMode()) { + // Ensure that we do not trigger entering PiP an activity on the pinned stack + return false; + } + final Task targetStack = toFrontTask != null + ? toFrontTask.getRootTask() : toFrontActivity.getRootTask(); + if (targetStack != null && targetStack.isActivityTypeAssistant()) { + // Ensure the task/activity being brought forward is not the assistant + return false; + } + return true; + } + + private boolean isTaskSwitch(ActivityRecord r, ActivityRecord topFocusedActivity) { + return topFocusedActivity != null && r.getTask() != topFocusedActivity.getTask(); + } + + /** + * Reset the task by reparenting the activities that have same affinity to the task or + * reparenting the activities that have different affinityies out of the task, while these + * activities allow task reparenting. + * + * @param taskTop Top activity of the task might be reset. + * @param newActivity The activity that going to be started. + * @return The non-finishing top activity of the task after reset or the original task top + * activity if all activities within the task are finishing. + */ + ActivityRecord resetTaskIfNeeded(ActivityRecord taskTop, ActivityRecord newActivity) { + final boolean forceReset = + (newActivity.info.flags & ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0; + final Task task = taskTop.getTask(); + + // If ActivityOptions are moved out and need to be aborted or moved to taskTop. + final ActivityOptions topOptions = sResetTargetTaskHelper.process(task, forceReset); + + if (mChildren.contains(task)) { + final ActivityRecord newTop = task.getTopNonFinishingActivity(); + if (newTop != null) { + taskTop = newTop; + } + } + + if (topOptions != null) { + // If we got some ActivityOptions from an activity on top that + // was removed from the task, propagate them to the new real top. + taskTop.updateOptionsLocked(topOptions); + } + + return taskTop; + } + + /** + * Finish the topmost activity that belongs to the crashed app. We may also finish the activity + * that requested launch of the crashed one to prevent launch-crash loop. + * @param app The app that crashed. + * @param reason Reason to perform this action. + * @return The task that was finished in this stack, {@code null} if top running activity does + * not belong to the crashed app. + */ + final Task finishTopCrashedActivityLocked(WindowProcessController app, String reason) { + final ActivityRecord r = topRunningActivity(); + if (r == null || r.app != app) { + return null; + } + if (r.isActivityTypeHome() && mAtmService.mHomeProcess == app) { + // Home activities should not be force-finished as we have nothing else to go + // back to. AppErrors will get to it after two crashes in MIN_CRASH_INTERVAL. + Slog.w(TAG, " Not force finishing home activity " + + r.intent.getComponent().flattenToShortString()); + return null; + } + Slog.w(TAG, " Force finishing activity " + + r.intent.getComponent().flattenToShortString()); + Task finishedTask = r.getTask(); + getDisplay().mDisplayContent.prepareAppTransition( + TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */); + r.finishIfPossible(reason, false /* oomAdj */); + + // Also terminate any activities below it that aren't yet stopped, to avoid a situation + // where one will get re-start our crashing activity once it gets resumed again. + final ActivityRecord activityBelow = getActivityBelow(r); + if (activityBelow != null) { + if (activityBelow.isState(STARTED, RESUMED, PAUSING, PAUSED)) { + if (!activityBelow.isActivityTypeHome() + || mAtmService.mHomeProcess != activityBelow.app) { + Slog.w(TAG, " Force finishing activity " + + activityBelow.intent.getComponent().flattenToShortString()); + activityBelow.finishIfPossible(reason, false /* oomAdj */); + } + } + } + + return finishedTask; + } + + void finishVoiceTask(IVoiceInteractionSession session) { + final PooledConsumer c = PooledLambda.obtainConsumer(Task::finishIfVoiceTask, + PooledLambda.__(Task.class), session.asBinder()); + forAllLeafTasks(c, true /* traverseTopToBottom */); + c.recycle(); + } + + private static void finishIfVoiceTask(Task tr, IBinder binder) { + if (tr.voiceSession != null && tr.voiceSession.asBinder() == binder) { + tr.forAllActivities((r) -> { + if (r.finishing) return; + r.finishIfPossible("finish-voice", false /* oomAdj */); + tr.mAtmService.updateOomAdj(); + }); + } else { + // Check if any of the activities are using voice + final PooledFunction f = PooledLambda.obtainFunction( + Task::finishIfVoiceActivity, PooledLambda.__(ActivityRecord.class), + binder); + tr.forAllActivities(f); + f.recycle(); + } + } + + private static boolean finishIfVoiceActivity(ActivityRecord r, IBinder binder) { + if (r.voiceSession == null || r.voiceSession.asBinder() != binder) return false; + // Inform of cancellation + r.clearVoiceSessionLocked(); + try { + r.app.getThread().scheduleLocalVoiceInteractionStarted(r.appToken, null); + } catch (RemoteException re) { + // Ok Boomer... + } + r.mAtmService.finishRunningVoiceLocked(); + return true; + } + + /** Finish all activities in the stack without waiting. */ + void finishAllActivitiesImmediately() { + if (!hasChild()) { + removeIfPossible(); + return; + } + forAllActivities((r) -> { + Slog.d(TAG, "finishAllActivitiesImmediatelyLocked: finishing " + r); + r.destroyIfPossible("finishAllActivitiesImmediately"); + }); + } + + /** @return true if the stack behind this one is a standard activity type. */ + private boolean inFrontOfStandardStack() { + final TaskDisplayArea taskDisplayArea = getDisplayArea(); + if (taskDisplayArea == null) { + return false; + } + final int index = taskDisplayArea.getIndexOf(this); + if (index == 0) { + return false; + } + final Task stackBehind = taskDisplayArea.getChildAt(index - 1); + return stackBehind.isActivityTypeStandard(); + } + + boolean shouldUpRecreateTaskLocked(ActivityRecord srec, String destAffinity) { + // Basic case: for simple app-centric recents, we need to recreate + // the task if the affinity has changed. + + final String affinity = ActivityRecord.getTaskAffinityWithUid(destAffinity, srec.getUid()); + if (srec == null || srec.getTask().affinity == null + || !srec.getTask().affinity.equals(affinity)) { + return true; + } + // Document-centric case: an app may be split in to multiple documents; + // they need to re-create their task if this current activity is the root + // of a document, unless simply finishing it will return them to the + // correct app behind. + final Task task = srec.getTask(); + if (srec.isRootOfTask() && task.getBaseIntent() != null + && task.getBaseIntent().isDocument()) { + // Okay, this activity is at the root of its task. What to do, what to do... + if (!inFrontOfStandardStack()) { + // Finishing won't return to an application, so we need to recreate. + return true; + } + // We now need to get the task below it to determine what to do. + final Task prevTask = getTaskBelow(task); + if (prevTask == null) { + Slog.w(TAG, "shouldUpRecreateTask: task not in history for " + srec); + return false; + } + if (!task.affinity.equals(prevTask.affinity)) { + // These are different apps, so need to recreate. + return true; + } + } + return false; + } + + boolean navigateUpTo(ActivityRecord srec, Intent destIntent, NeededUriGrants destGrants, + int resultCode, Intent resultData, NeededUriGrants resultGrants) { + if (!srec.attachedToProcess()) { + // Nothing to do if the caller is not attached, because this method should be called + // from an alive activity. + return false; + } + final Task task = srec.getTask(); + if (!srec.isDescendantOf(this)) { + return false; + } + + ActivityRecord parent = task.getActivityBelow(srec); + boolean foundParentInTask = false; + final ComponentName dest = destIntent.getComponent(); + if (task.getBottomMostActivity() != srec && dest != null) { + final ActivityRecord candidate = task.getActivity( + (ar) -> ar.info.packageName.equals(dest.getPackageName()) + && ar.info.name.equals(dest.getClassName()), srec, + false /*includeBoundary*/, true /*traverseTopToBottom*/); + if (candidate != null) { + parent = candidate; + foundParentInTask = true; + } + } + + // TODO: There is a dup. of this block of code in ActivityTaskManagerService.finishActivity + // We should consolidate. + IActivityController controller = mAtmService.mController; + if (controller != null) { + ActivityRecord next = topRunningActivity(srec.appToken, INVALID_TASK_ID); + if (next != null) { + // ask watcher if this is allowed + boolean resumeOK = true; + try { + resumeOK = controller.activityResuming(next.packageName); + } catch (RemoteException e) { + mAtmService.mController = null; + Watchdog.getInstance().setActivityController(null); + } + + if (!resumeOK) { + return false; + } + } + } + final long origId = Binder.clearCallingIdentity(); + + final int[] resultCodeHolder = new int[1]; + resultCodeHolder[0] = resultCode; + final Intent[] resultDataHolder = new Intent[1]; + resultDataHolder[0] = resultData; + final NeededUriGrants[] resultGrantsHolder = new NeededUriGrants[1]; + resultGrantsHolder[0] = resultGrants; + final ActivityRecord finalParent = parent; + task.forAllActivities((ar) -> { + if (ar == finalParent) return true; + + ar.finishIfPossible(resultCodeHolder[0], resultDataHolder[0], resultGrantsHolder[0], + "navigate-up", true /* oomAdj */); + // Only return the supplied result for the first activity finished + resultCodeHolder[0] = Activity.RESULT_CANCELED; + resultDataHolder[0] = null; + return false; + }, srec, true, true); + resultCode = resultCodeHolder[0]; + resultData = resultDataHolder[0]; + + if (parent != null && foundParentInTask) { + final int callingUid = srec.info.applicationInfo.uid; + final int parentLaunchMode = parent.info.launchMode; + final int destIntentFlags = destIntent.getFlags(); + if (parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE || + parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK || + parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP || + (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) { + parent.deliverNewIntentLocked(callingUid, destIntent, destGrants, srec.packageName); + } else { + try { + ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo( + destIntent.getComponent(), ActivityManagerService.STOCK_PM_FLAGS, + srec.mUserId); + // TODO(b/64750076): Check if calling pid should really be -1. + final int res = mAtmService.getActivityStartController() + .obtainStarter(destIntent, "navigateUpTo") + .setCaller(srec.app.getThread()) + .setActivityInfo(aInfo) + .setResultTo(parent.appToken) + .setCallingPid(-1) + .setCallingUid(callingUid) + .setCallingPackage(srec.packageName) + .setCallingFeatureId(parent.launchedFromFeatureId) + .setRealCallingPid(-1) + .setRealCallingUid(callingUid) + .setComponentSpecified(true) + .execute(); + foundParentInTask = res == ActivityManager.START_SUCCESS; + } catch (RemoteException e) { + foundParentInTask = false; + } + parent.finishIfPossible(resultCode, resultData, resultGrants, + "navigate-top", true /* oomAdj */); + } + } + Binder.restoreCallingIdentity(origId); + return foundParentInTask; + } + + void removeLaunchTickMessages() { + forAllActivities(ActivityRecord::removeLaunchTickRunnable); + } + + private void updateTransitLocked(int transit, ActivityOptions options, boolean forceOverride) { + if (options != null) { + ActivityRecord r = topRunningActivity(); + if (r != null && !r.isState(RESUMED)) { + r.updateOptionsLocked(options); + } else { + ActivityOptions.abort(options); + } + } + getDisplay().mDisplayContent.prepareAppTransition(transit, false, + 0 /* flags */, forceOverride); + } + + final void moveTaskToFront(Task tr, boolean noAnimation, ActivityOptions options, + AppTimeTracker timeTracker, String reason) { + moveTaskToFront(tr, noAnimation, options, timeTracker, !DEFER_RESUME, reason); + } + + final void moveTaskToFront(Task tr, boolean noAnimation, ActivityOptions options, + AppTimeTracker timeTracker, boolean deferResume, String reason) { + if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr); + + final Task topStack = getDisplayArea().getTopStack(); + final ActivityRecord topActivity = topStack != null + ? topStack.getTopNonFinishingActivity() : null; + + if (tr != this && !tr.isDescendantOf(this)) { + // nothing to do! + if (noAnimation) { + ActivityOptions.abort(options); + } else if (isSingleTaskInstance()) { + // When a task is moved front on the display which can only contain one task, start + // a special transition. + // {@link AppTransitionController#handleAppTransitionReady} later picks up the + // transition, and schedules + // {@link ITaskStackListener#onSingleTaskDisplayDrawn} callback which is triggered + // after contents are drawn on the display. + updateTransitLocked(TRANSIT_SHOW_SINGLE_TASK_DISPLAY, options, + true /* forceOverride */); + } else { + updateTransitLocked(TRANSIT_TASK_TO_FRONT, options, false /* forceOverride */); + } + return; + } + + if (timeTracker != null) { + // The caller wants a time tracker associated with this task. + final PooledConsumer c = PooledLambda.obtainConsumer(ActivityRecord::setAppTimeTracker, + PooledLambda.__(ActivityRecord.class), timeTracker); + tr.forAllActivities(c); + c.recycle(); + } + + try { + // Defer updating the IME target since the new IME target will try to get computed + // before updating all closing and opening apps, which can cause the ime target to + // get calculated incorrectly. + getDisplay().deferUpdateImeTarget(); + + // Shift all activities with this task up to the top + // of the stack, keeping them in the same internal order. + positionChildAtTop(tr); + + // Don't refocus if invisible to current user + final ActivityRecord top = tr.getTopNonFinishingActivity(); + if (top == null || !top.okToShowLocked()) { + if (top != null) { + mStackSupervisor.mRecentTasks.add(top.getTask()); + } + ActivityOptions.abort(options); + return; + } + + // Set focus to the top running activity of this stack. + final ActivityRecord r = topRunningActivity(); + if (r != null) { + r.moveFocusableActivityToTop(reason); + } + + if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr); + if (noAnimation) { + getDisplay().mDisplayContent.prepareAppTransition(TRANSIT_NONE, false); + if (r != null) { + mStackSupervisor.mNoAnimActivities.add(r); + } + ActivityOptions.abort(options); + } else if (isSingleTaskInstance()) { + updateTransitLocked(TRANSIT_SHOW_SINGLE_TASK_DISPLAY, options, + true /* forceOverride */); + } else { + updateTransitLocked(TRANSIT_TASK_TO_FRONT, options, false /* forceOverride */); + } + + // If a new task is moved to the front, then mark the existing top activity as + // supporting + + // picture-in-picture while paused only if the task would not be considered an oerlay + // on top + // of the current activity (eg. not fullscreen, or the assistant) + if (canEnterPipOnTaskSwitch(topActivity, tr, null /* toFrontActivity */, + options)) { + topActivity.supportsEnterPipOnTaskSwitch = true; + } + + if (!deferResume) { + mRootWindowContainer.resumeFocusedStacksTopActivities(); + } + EventLogTags.writeWmTaskToFront(tr.mUserId, tr.mTaskId); + mAtmService.getTaskChangeNotificationController() + .notifyTaskMovedToFront(tr.getTaskInfo()); + } finally { + getDisplay().continueUpdateImeTarget(); + } + } + + /** + * Worker method for rearranging history stack. Implements the function of moving all + * activities for a specific task (gathering them if disjoint) into a single group at the + * bottom of the stack. + * + * If a watcher is installed, the action is preflighted and the watcher has an opportunity + * to premeptively cancel the move. + * + * @param tr The task to collect and move to the bottom. + * @return Returns true if the move completed, false if not. + */ + boolean moveTaskToBack(Task tr) { + Slog.i(TAG, "moveTaskToBack: " + tr); + + // In LockTask mode, moving a locked task to the back of the stack may expose unlocked + // ones. Therefore we need to check if this operation is allowed. + if (!mAtmService.getLockTaskController().canMoveTaskToBack(tr)) { + return false; + } + + // If we have a watcher, preflight the move before committing to it. First check + // for *other* available tasks, but if none are available, then try again allowing the + // current task to be selected. + if (isTopStackInDisplayArea() && mAtmService.mController != null) { + ActivityRecord next = topRunningActivity(null, tr.mTaskId); + if (next == null) { + next = topRunningActivity(null, INVALID_TASK_ID); + } + if (next != null) { + // ask watcher if this is allowed + boolean moveOK = true; + try { + moveOK = mAtmService.mController.activityResuming(next.packageName); + } catch (RemoteException e) { + mAtmService.mController = null; + Watchdog.getInstance().setActivityController(null); + } + if (!moveOK) { + return false; + } + } + } + + if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to back transition: task=" + + tr.mTaskId); + + getDisplay().mDisplayContent.prepareAppTransition(TRANSIT_TASK_TO_BACK, false); + moveToBack("moveTaskToBackLocked", tr); + + if (inPinnedWindowingMode()) { + mStackSupervisor.removeStack(this); + return true; + } + + mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */, + getDisplay().mDisplayId, false /* markFrozenIfConfigChanged */, + false /* deferResume */); + + ActivityRecord topActivity = getDisplayArea().topRunningActivity(); + Task topStack = topActivity.getRootTask(); + if (topStack != null && topStack != this && topActivity.isState(RESUMED)) { + // Usually resuming a top activity triggers the next app transition, but nothing's got + // resumed in this case, so we need to execute it explicitly. + getDisplay().mDisplayContent.executeAppTransition(); + } else { + mRootWindowContainer.resumeFocusedStacksTopActivities(); + } + return true; + } + + /** + * Ensures all visible activities at or below the input activity have the right configuration. + */ + void ensureVisibleActivitiesConfiguration(ActivityRecord start, boolean preserveWindow) { + mEnsureVisibleActivitiesConfigHelper.process(start, preserveWindow); + } + + // TODO: Can only be called from special methods in ActivityStackSupervisor. + // Need to consolidate those calls points into this resize method so anyone can call directly. + void resize(Rect displayedBounds, boolean preserveWindows, boolean deferResume) { + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "stack.resize_" + getRootTaskId()); + mAtmService.deferWindowLayout(); + try { + // TODO: Why not just set this on the stack directly vs. on each tasks? + // Update override configurations of all tasks in the stack. + final PooledConsumer c = PooledLambda.obtainConsumer( + Task::processTaskResizeBounds, PooledLambda.__(Task.class), + displayedBounds); + forAllTasks(c, true /* traverseTopToBottom */); + c.recycle(); + + if (mBoundsAnimating) { + // Force to update task surface bounds and relayout windows, since configBounds + // remains unchanged during bounds animation. + updateSurfaceBounds(); + getDisplay().setLayoutNeeded(); + mWmService.requestTraversal(); + } + + if (!deferResume) { + ensureVisibleActivitiesConfiguration(topRunningActivity(), preserveWindows); + } + } finally { + mAtmService.continueWindowLayout(); + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); + } + } + + private static void processTaskResizeBounds(Task task, Rect displayedBounds) { + if (!task.isResizeable()) return; + + task.setBounds(displayedBounds); + } + + /** + * Until we can break this "set task bounds to same as stack bounds" behavior, this + * basically resizes both stack and task bounds to the same bounds. + */ + private void setTaskBounds(Rect bounds) { + final PooledConsumer c = PooledLambda.obtainConsumer(Task::setTaskBoundsInner, + PooledLambda.__(Task.class), bounds); + forAllLeafTasks(c, true /* traverseTopToBottom */); + c.recycle(); + } + + private static void setTaskBoundsInner(Task task, Rect bounds) { + task.setBounds(task.isResizeable() ? bounds : null); + } + + boolean willActivityBeVisible(IBinder token) { + final ActivityRecord r = ActivityRecord.forTokenLocked(token); + if (r == null) { + return false; + } + + // See if there is an occluding activity on-top of this one. + final ActivityRecord occludingActivity = getOccludingActivityAbove(r); + if (occludingActivity != null) return false; + + if (r.finishing) Slog.e(TAG, "willActivityBeVisible: Returning false," + + " would have returned true for r=" + r); + return !r.finishing; + } + + void unhandledBackLocked() { + final ActivityRecord topActivity = getTopMostActivity(); + if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, + "Performing unhandledBack(): top activity: " + topActivity); + if (topActivity != null) { + topActivity.finishIfPossible("unhandled-back", true /* oomAdj */); + } + } + + /** + * Reset local parameters because an app's activity died. + * @param app The app of the activity that died. + * @return result from removeHistoryRecordsForAppLocked. + */ + boolean handleAppDied(WindowProcessController app) { + if (mPausingActivity != null && mPausingActivity.app == app) { + if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG_PAUSE, + "App died while pausing: " + mPausingActivity); + mPausingActivity = null; + } + if (mLastPausedActivity != null && mLastPausedActivity.app == app) { + mLastPausedActivity = null; + mLastNoHistoryActivity = null; + } + + mStackSupervisor.removeHistoryRecords(app); + return mRemoveHistoryRecordsForApp.process(app); + } + + boolean dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient, + String dumpPackage, final boolean needSep) { + Runnable headerPrinter = () -> { + if (needSep) { + pw.println(); + } + pw.println(" Stack #" + getRootTaskId() + + ": type=" + activityTypeToString(getActivityType()) + + " mode=" + windowingModeToString(getWindowingMode())); + pw.println(" isSleeping=" + shouldSleepActivities()); + pw.println(" mBounds=" + getRequestedOverrideBounds()); + }; + + boolean printed = false; + + if (dumpPackage == null) { + // If we are not filtering by package, we want to print absolutely everything, + // so always print the header even if there are no tasks/activities inside. + headerPrinter.run(); + headerPrinter = null; + printed = true; + } + + printed |= printThisActivity(pw, mPausingActivity, dumpPackage, false, + " mPausingActivity: ", null); + printed |= printThisActivity(pw, getResumedActivity(), dumpPackage, false, + " mResumedActivity: ", null); + if (dumpAll) { + printed |= printThisActivity(pw, mLastPausedActivity, dumpPackage, false, + " mLastPausedActivity: ", null); + printed |= printThisActivity(pw, mLastNoHistoryActivity, dumpPackage, + false, " mLastNoHistoryActivity: ", null); + } + + printed |= dumpActivities(fd, pw, dumpAll, dumpClient, dumpPackage, false, headerPrinter); + + return printed; + } + + private boolean dumpActivities(FileDescriptor fd, PrintWriter pw, boolean dumpAll, + boolean dumpClient, String dumpPackage, boolean needSep, Runnable header) { + if (!hasChild()) { + return false; + } + final AtomicBoolean printedHeader = new AtomicBoolean(false); + final AtomicBoolean printed = new AtomicBoolean(false); + forAllLeafTasks((task) -> { + final String prefix = " "; + Runnable headerPrinter = () -> { + printed.set(true); + if (!printedHeader.get()) { + if (needSep) { + pw.println(""); + } + if (header != null) { + header.run(); + } + printedHeader.set(true); + } + pw.print(prefix); pw.print("* "); pw.println(task); + pw.print(prefix); pw.print(" mBounds="); + pw.println(task.getRequestedOverrideBounds()); + pw.print(prefix); pw.print(" mMinWidth="); pw.print(task.mMinWidth); + pw.print(" mMinHeight="); pw.println(task.mMinHeight); + if (mLastNonFullscreenBounds != null) { + pw.print(prefix); + pw.print(" mLastNonFullscreenBounds="); + pw.println(task.mLastNonFullscreenBounds); + } + task.dump(pw, prefix + " "); + }; + if (dumpPackage == null) { + // If we are not filtering by package, we want to print absolutely everything, + // so always print the header even if there are no activities inside. + headerPrinter.run(); + headerPrinter = null; + } + final ArrayList<ActivityRecord> activities = new ArrayList<>(); + // Add activities by traversing the hierarchy from bottom to top, since activities + // are dumped in reverse order in {@link ActivityStackSupervisor#dumpHistoryList()}. + task.forAllActivities((Consumer<ActivityRecord>) activities::add, + false /* traverseTopToBottom */); + dumpHistoryList(fd, pw, activities, prefix, "Hist", true, !dumpAll, dumpClient, + dumpPackage, false, headerPrinter, task); + }, true /* traverseTopToBottom */); + return printed.get(); + } + + ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) { + ArrayList<ActivityRecord> activities = new ArrayList<>(); + + if ("all".equals(name)) { + forAllActivities((Consumer<ActivityRecord>) activities::add); + } else if ("top".equals(name)) { + final ActivityRecord topActivity = getTopMostActivity(); + if (topActivity != null) { + activities.add(topActivity); + } + } else { + ActivityManagerService.ItemMatcher matcher = new ActivityManagerService.ItemMatcher(); + matcher.build(name); + + forAllActivities((r) -> { + if (matcher.match(r, r.intent.getComponent())) { + activities.add(r); + } + }); + } + + return activities; + } + + ActivityRecord restartPackage(String packageName) { + ActivityRecord starting = topRunningActivity(); + + // All activities that came from the package must be + // restarted as if there was a config change. + PooledConsumer c = PooledLambda.obtainConsumer(Task::restartPackage, + PooledLambda.__(ActivityRecord.class), starting, packageName); + forAllActivities(c); + c.recycle(); + + return starting; + } + + private static void restartPackage( + ActivityRecord r, ActivityRecord starting, String packageName) { + if (r.info.packageName.equals(packageName)) { + r.forceNewConfig = true; + if (starting != null && r == starting && r.mVisibleRequested) { + r.startFreezingScreenLocked(CONFIG_SCREEN_LAYOUT); + } + } + } + + Task reuseOrCreateTask(ActivityInfo info, Intent intent, boolean toTop) { + return reuseOrCreateTask(info, intent, null /*voiceSession*/, null /*voiceInteractor*/, + toTop, null /*activity*/, null /*source*/, null /*options*/); + } + // TODO: Can be removed once we change callpoints creating stacks to be creating tasks. + /** Either returns this current task to be re-used or creates a new child task. */ + Task reuseOrCreateTask(ActivityInfo info, Intent intent, IVoiceInteractionSession voiceSession, + IVoiceInteractor voiceInteractor, boolean toTop, ActivityRecord activity, + ActivityRecord source, ActivityOptions options) { + + Task task; + if (DisplayContent.alwaysCreateStack(getWindowingMode(), getActivityType())) { + // This stack will only contain one task, so just return itself since all stacks ara now + // tasks and all tasks are now stacks. + task = reuseAsLeafTask(voiceSession, voiceInteractor, intent, info, activity); + } else { + // Create child task since this stack can contain multiple tasks. + final int taskId = activity != null + ? mStackSupervisor.getNextTaskIdForUser(activity.mUserId) + : mStackSupervisor.getNextTaskIdForUser(); + task = new Task(mAtmService, taskId, info, intent, voiceSession, + voiceInteractor, null /* taskDescription */, this); + + // add the task to stack first, mTaskPositioner might need the stack association + addChild(task, toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0); + } + + int displayId = getDisplayId(); + if (displayId == INVALID_DISPLAY) displayId = DEFAULT_DISPLAY; + final boolean isLockscreenShown = mAtmService.mStackSupervisor.getKeyguardController() + .isKeyguardOrAodShowing(displayId); + if (!mStackSupervisor.getLaunchParamsController() + .layoutTask(task, info.windowLayout, activity, source, options) + && !getRequestedOverrideBounds().isEmpty() + && task.isResizeable() && !isLockscreenShown) { + task.setBounds(getRequestedOverrideBounds()); + } + + return task; + } + + void addChild(WindowContainer child, final boolean toTop, boolean showForAllUsers) { + if (isSingleTaskInstance() && hasChild()) { + throw new IllegalStateException("Can only have one child on stack=" + this); + } + + Task task = child.asTask(); + try { + + if (task != null) { + task.setForceShowForAllUsers(showForAllUsers); + } + // We only want to move the parents to the parents if we are creating this task at the + // top of its stack. + addChild(child, toTop ? MAX_VALUE : 0, toTop /*moveParents*/); + } finally { + if (task != null) { + task.setForceShowForAllUsers(false); + } + } + } + + void positionChildAt(Task task, int position) { + if (task.getRootTask() != this) { + throw new IllegalArgumentException("AS.positionChildAt: task=" + task + + " is not a child of stack=" + this + " current parent=" + task.getRootTask()); + } + + task.updateOverrideConfigurationForStack(this); + + final ActivityRecord topRunningActivity = task.topRunningActivityLocked(); + final boolean wasResumed = topRunningActivity == task.getRootTask().mResumedActivity; + + boolean toTop = position >= getChildCount(); + boolean includingParents = toTop || getDisplayArea().getNextFocusableStack(this, + true /* ignoreCurrent */) == null; + if (WindowManagerDebugConfig.DEBUG_STACK) { + Slog.i(TAG_WM, "positionChildAt: positioning task=" + task + " at " + position); + } + positionChildAt(position, task, includingParents); + task.updateTaskMovement(toTop); + getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); + + + // TODO: Investigate if this random code is really needed. + if (task.voiceSession != null) { + try { + task.voiceSession.taskStarted(task.intent, task.mTaskId); + } catch (RemoteException e) { + } + } + + if (wasResumed) { + if (mResumedActivity != null) { + Log.wtf(TAG, "mResumedActivity was already set when moving mResumedActivity from" + + " other stack to this stack mResumedActivity=" + mResumedActivity + + " other mResumedActivity=" + topRunningActivity); + } + topRunningActivity.setState(RESUMED, "positionChildAt"); + } + + // The task might have already been running and its visibility needs to be synchronized with + // the visibility of the stack / windows. + ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); + mRootWindowContainer.resumeFocusedStacksTopActivities(); + } + + public void setAlwaysOnTop(boolean alwaysOnTop) { + if (isAlwaysOnTop() == alwaysOnTop) { + return; + } + super.setAlwaysOnTop(alwaysOnTop); + final TaskDisplayArea taskDisplayArea = getDisplayArea(); + // positionChildAtTop() must be called even when always on top gets turned off because we + // need to make sure that the stack is moved from among always on top windows to below other + // always on top windows. Since the position the stack should be inserted into is calculated + // properly in {@link DisplayContent#getTopInsertPosition()} in both cases, we can just + // request that the stack is put at top here. + taskDisplayArea.positionStackAtTop(this, false /* includingParents */); + } + + /** NOTE: Should only be called from {@link Task#reparent}. */ + void moveToFrontAndResumeStateIfNeeded(ActivityRecord r, boolean moveToFront, boolean setResume, + boolean setPause, String reason) { + if (!moveToFront) { + return; + } + + final ActivityState origState = r.getState(); + // If the activity owns the last resumed activity, transfer that together, + // so that we don't resume the same activity again in the new stack. + // Apps may depend on onResume()/onPause() being called in pairs. + if (setResume) { + r.setState(RESUMED, "moveToFrontAndResumeStateIfNeeded"); + } + // If the activity was previously pausing, then ensure we transfer that as well + if (setPause) { + mPausingActivity = r; + r.schedulePauseTimeout(); + } + // Move the stack in which we are placing the activity to the front. + moveToFront(reason); + // If the original state is resumed, there is no state change to update focused app. + // So here makes sure the activity focus is set if it is the top. + if (origState == RESUMED && r == mRootWindowContainer.getTopResumedActivity()) { + mAtmService.setResumedActivityUncheckLocked(r, reason); + } + } + + void dismissPip() { + if (!isActivityTypeStandardOrUndefined()) { + throw new IllegalArgumentException( + "You can't move tasks from non-standard stacks."); + } + if (getWindowingMode() != WINDOWING_MODE_PINNED) { + throw new IllegalArgumentException( + "Can't exit pinned mode if it's not pinned already."); + } + + mWmService.inSurfaceTransaction(() -> { + final Task task = getBottomMostTask(); + setWindowingMode(WINDOWING_MODE_UNDEFINED); + + getDisplayArea().positionStackAtTop(this, false /* includingParents */); + + mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, this); + MetricsLoggerWrapper.logPictureInPictureFullScreen(mAtmService.mContext, + task.effectiveUid, task.realActivity.flattenToString()); + }); + } + + void prepareFreezingTaskBounds() { + forAllLeafTasks(Task::prepareFreezingBounds, true /* traverseTopToBottom */); + } + + private int setBounds(Rect existing, Rect bounds) { + if (equivalentBounds(existing, bounds)) { + return BOUNDS_CHANGE_NONE; + } + + final int result = super.setBounds(!inMultiWindowMode() ? null : bounds); + + updateSurfaceBounds(); + return result; + } + + @Override + public void getBounds(Rect bounds) { + bounds.set(getBounds()); + } + + /** + * @return the final bounds for the bounds animation. + */ + void getFinalAnimationBounds(Rect outBounds) { + outBounds.set(mBoundsAnimationTarget); + } + + /** + * @return the final source bounds for the bounds animation. + */ + void getFinalAnimationSourceHintBounds(Rect outBounds) { + outBounds.set(mBoundsAnimationSourceHintBounds); + } + + /** + * Put a Task in this stack. Used for adding only. + * When task is added to top of the stack, the entire branch of the hierarchy (including stack + * and display) will be brought to top. + * @param child The child to add. + * @param position Target position to add the task to. + */ + private void addChild(WindowContainer child, int position, boolean moveParents) { + // Add child task. + addChild(child, null); + + // Move child to a proper position, as some restriction for position might apply. + positionChildAt(position, child, moveParents /* includingParents */); + } + + void positionChildAtTop(Task child) { + if (child == null) { + // TODO: Fix the call-points that cause this to happen. + return; + } + + if (child == this) { + // TODO: Fix call-points + moveToFront("positionChildAtTop"); + return; + } + + positionChildAt(POSITION_TOP, child, true /* includingParents */); + child.updateTaskMovement(true); + + final DisplayContent displayContent = getDisplayContent(); + displayContent.layoutAndAssignWindowLayersIfNeeded(); + } + + void positionChildAtBottom(Task child) { + // If there are other focusable stacks on the display, the z-order of the display should not + // be changed just because a task was placed at the bottom. E.g. if it is moving the topmost + // task to bottom, the next focusable stack on the same display should be focused. + final Task nextFocusableStack = getDisplayArea().getNextFocusableStack( + child.getRootTask(), true /* ignoreCurrent */); + positionChildAtBottom(child, nextFocusableStack == null /* includingParents */); + child.updateTaskMovement(true); + } + + @VisibleForTesting + void positionChildAtBottom(Task child, boolean includingParents) { + if (child == null) { + // TODO: Fix the call-points that cause this to happen. + return; + } + + positionChildAt(POSITION_BOTTOM, child, includingParents); + getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); + } + + @Override + void onChildPositionChanged(WindowContainer child) { + if (isOrganized()) { + mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, false /* force */); + } + + if (!mChildren.contains(child)) { + return; + } + + final boolean isTop = getTopChild() == child; + + final Task task = child.asTask(); + if (task != null) { + task.updateTaskMovement(isTop); + } + + if (isTop) { + final DisplayContent displayContent = getDisplayContent(); + displayContent.layoutAndAssignWindowLayersIfNeeded(); + } + } + + void reparent(TaskDisplayArea newParent, boolean onTop) { + reparent(newParent, onTop ? POSITION_TOP : POSITION_BOTTOM); + } + + private void updateSurfaceBounds() { + updateSurfaceSize(getSyncTransaction()); + updateSurfacePosition(); + scheduleAnimation(); + } + + @Override + void getRelativePosition(Point outPos) { + super.getRelativePosition(outPos); + final int outset = getTaskOutset(); + outPos.x -= outset; + outPos.y -= outset; + } + + boolean shouldIgnoreInput() { + if (inSplitScreenPrimaryWindowingMode() && !isFocusable()) { + return true; + } + if (mAtmService.mHasLeanbackFeature && inPinnedWindowingMode() + && !isFocusedStackOnDisplay()) { + // Preventing Picture-in-Picture stack from receiving input on TVs. + return true; + } + return false; + } + + /** + * Sets the current picture-in-picture aspect ratio. + */ + void setPictureInPictureAspectRatio(float aspectRatio) { + if (!mWmService.mAtmService.mSupportsPictureInPicture) { + return; + } + + final DisplayContent displayContent = getDisplayContent(); + if (displayContent == null) { + return; + } + + if (!inPinnedWindowingMode()) { + return; + } + + final PinnedStackController pinnedStackController = + getDisplayContent().getPinnedStackController(); + + if (Float.compare(aspectRatio, pinnedStackController.getAspectRatio()) == 0) { + return; + } + + // Notify the pinned stack controller about aspect ratio change. + // This would result a callback delivered from SystemUI to WM to start animation, + // if the bounds are ought to be altered due to aspect ratio change. + pinnedStackController.setAspectRatio( + pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio) + ? aspectRatio : -1f); + } + + /** + * Sets the current picture-in-picture actions. + */ + void setPictureInPictureActions(List<RemoteAction> actions) { + if (!mWmService.mAtmService.mSupportsPictureInPicture) { + return; + } + + if (!inPinnedWindowingMode()) { + return; + } + + getDisplayContent().getPinnedStackController().setActions(actions); + } + + public boolean isForceScaled() { + return mBoundsAnimating; + } + + /** Returns true if a removal action is still being deferred. */ + boolean handleCompleteDeferredRemoval() { + if (isAnimating(TRANSITION | CHILDREN)) { + return true; + } + + return super.handleCompleteDeferredRemoval(); + } + + public DisplayInfo getDisplayInfo() { + return mDisplayContent.getDisplayInfo(); + } + + AnimatingActivityRegistry getAnimatingActivityRegistry() { + return mAnimatingActivityRegistry; + } + + void executeAppTransition(ActivityOptions options) { + getDisplay().mDisplayContent.executeAppTransition(); + ActivityOptions.abort(options); + } + + boolean shouldSleepActivities() { + final DisplayContent display = getDisplay(); + + // Do not sleep activities in this stack if we're marked as focused and the keyguard + // is in the process of going away. + if (isFocusedStackOnDisplay() + && mStackSupervisor.getKeyguardController().isKeyguardGoingAway()) { + return false; + } + + return display != null ? display.isSleeping() : mAtmService.isSleepingLocked(); + } + + boolean shouldSleepOrShutDownActivities() { + return shouldSleepActivities() || mAtmService.mShuttingDown; + } + + /** Bounds of the stack without adjusting for other factors in the system like visibility + * of docked stack. + * Most callers should be using {@link ConfigurationContainer#getRequestedOverrideBounds} a + * it takes into consideration other system factors. */ + void getRawBounds(Rect out) { + out.set(getRawBounds()); + } + + private Rect getRawBounds() { + return super.getBounds(); + } + + @Override + public void dumpDebug(ProtoOutputStream proto, long fieldId, + @WindowTraceLogLevel int logLevel) { + if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) { + return; + } + + final long token = proto.start(fieldId); + super.dumpDebug(proto, WINDOW_CONTAINER, logLevel); + + proto.write(TaskProto.ID, mTaskId); + proto.write(DISPLAY_ID, getDisplayId()); + proto.write(ROOT_TASK_ID, getRootTaskId()); + + if (mResumedActivity != null) { + mResumedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY); + } + if (realActivity != null) { + proto.write(REAL_ACTIVITY, realActivity.flattenToShortString()); + } + if (origActivity != null) { + proto.write(ORIG_ACTIVITY, origActivity.flattenToShortString()); + } + proto.write(ACTIVITY_TYPE, getActivityType()); + proto.write(RESIZE_MODE, mResizeMode); + proto.write(MIN_WIDTH, mMinWidth); + proto.write(MIN_HEIGHT, mMinHeight); + + proto.write(FILLS_PARENT, matchParentBounds()); + getRawBounds().dumpDebug(proto, BOUNDS); + + if (mLastNonFullscreenBounds != null) { + mLastNonFullscreenBounds.dumpDebug(proto, LAST_NON_FULLSCREEN_BOUNDS); + } + + proto.write(ANIMATING_BOUNDS, mBoundsAnimating); + + if (mSurfaceControl != null) { + proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth()); + proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight()); + } + + proto.write(CREATED_BY_ORGANIZER, mCreatedByOrganizer); + + proto.end(token); + } } diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index aba5b99f7481..4473bd69681b 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -32,8 +32,6 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; -import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; -import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; @@ -42,6 +40,8 @@ import static com.android.server.wm.DisplayContent.alwaysCreateStack; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.RootWindowContainer.TAG_STATES; +import static com.android.server.wm.Task.ActivityState.RESUMED; +import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -73,7 +73,7 @@ import java.util.function.Function; /** * {@link DisplayArea} that represents a section of a screen that contains app window containers. */ -final class TaskDisplayArea extends DisplayArea<ActivityStack> { +final class TaskDisplayArea extends DisplayArea<Task> { DisplayContent mDisplayContent; @@ -100,16 +100,16 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { // Cached reference to some special tasks we tend to get a lot so we don't need to loop // through the list to find them. - private ActivityStack mRootHomeTask; - private ActivityStack mRootPinnedTask; - private ActivityStack mRootSplitScreenPrimaryTask; + private Task mRootHomeTask; + private Task mRootPinnedTask; + private Task mRootSplitScreenPrimaryTask; // TODO(b/159029784): Remove when getStack() behavior is cleaned-up - private ActivityStack mRootRecentsTask; + private Task mRootRecentsTask; - private final ArrayList<ActivityStack> mTmpAlwaysOnTopStacks = new ArrayList<>(); - private final ArrayList<ActivityStack> mTmpNormalStacks = new ArrayList<>(); - private final ArrayList<ActivityStack> mTmpHomeStacks = new ArrayList<>(); + private final ArrayList<Task> mTmpAlwaysOnTopStacks = new ArrayList<>(); + private final ArrayList<Task> mTmpNormalStacks = new ArrayList<>(); + private final ArrayList<Task> mTmpHomeStacks = new ArrayList<>(); private final IntArray mTmpNeedsZBoostIndexes = new IntArray(); private int mTmpLayerForSplitScreenDividerAnchor; private int mTmpLayerForAnimationLayer; @@ -128,7 +128,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { * have the topmost index, it is used as a preferred candidate to prevent being unable to resume * target stack properly when there are other focusable always-on-top stacks. */ - ActivityStack mPreferredTopFocusableStack; + Task mPreferredTopFocusableStack; private final RootWindowContainer.FindTaskResult mTmpFindTaskResult = new RootWindowContainer.FindTaskResult(); @@ -138,7 +138,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { * stack has been resumed. If stacks are changing position this will hold the old stack until * the new stack becomes resumed after which it will be set to current focused stack. */ - ActivityStack mLastFocusedStack; + Task mLastFocusedStack; /** * All of the stacks on this display. Order matters, topmost stack is in front of all other * stacks, bottommost behind. Accessed directly by ActivityManager package classes. Any calls @@ -164,7 +164,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { * Returns the topmost stack on the display that is compatible with the input windowing mode * and activity type. Null is no compatible stack on the display. */ - ActivityStack getStack(int windowingMode, int activityType) { + Task getStack(int windowingMode, int activityType) { if (activityType == ACTIVITY_TYPE_HOME) { return mRootHomeTask; } else if (activityType == ACTIVITY_TYPE_RECENTS) { @@ -176,7 +176,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { return mRootSplitScreenPrimaryTask; } for (int i = getChildCount() - 1; i >= 0; --i) { - final ActivityStack stack = getChildAt(i); + final Task stack = getChildAt(i); if (activityType == ACTIVITY_TYPE_UNDEFINED && windowingMode == stack.getWindowingMode()) { // Passing in undefined type means we want to match the topmost stack with the @@ -191,33 +191,33 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { } @VisibleForTesting - ActivityStack getTopStack() { + Task getTopStack() { final int count = getChildCount(); return count > 0 ? getChildAt(count - 1) : null; } // TODO: Figure-out a way to remove since it might be a source of confusion. - int getIndexOf(ActivityStack stack) { - return mChildren.indexOf(stack); + int getIndexOf(Task task) { + return mChildren.indexOf(task); } - @Nullable ActivityStack getRootHomeTask() { + @Nullable Task getRootHomeTask() { return mRootHomeTask; } - @Nullable ActivityStack getRootRecentsTask() { + @Nullable Task getRootRecentsTask() { return mRootRecentsTask; } - ActivityStack getRootPinnedTask() { + Task getRootPinnedTask() { return mRootPinnedTask; } - ActivityStack getRootSplitScreenPrimaryTask() { + Task getRootSplitScreenPrimaryTask() { return mRootSplitScreenPrimaryTask; } - ActivityStack getRootSplitScreenSecondaryTask() { + Task getRootSplitScreenSecondaryTask() { for (int i = mChildren.size() - 1; i >= 0; --i) { if (mChildren.get(i).inSplitScreenSecondaryWindowingMode()) { return mChildren.get(i); @@ -236,7 +236,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { return visibleTasks; } - void onStackWindowingModeChanged(ActivityStack stack) { + void onStackWindowingModeChanged(Task stack) { removeStackReferenceIfNeeded(stack); addStackReferenceIfNeeded(stack); if (stack == mRootPinnedTask && getTopStack() != stack) { @@ -245,7 +245,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { } } - void addStackReferenceIfNeeded(ActivityStack stack) { + void addStackReferenceIfNeeded(Task stack) { if (stack.isActivityTypeHome()) { if (mRootHomeTask != null) { if (!stack.isDescendantOf(mRootHomeTask)) { @@ -290,7 +290,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { } } - void removeStackReferenceIfNeeded(ActivityStack stack) { + void removeStackReferenceIfNeeded(Task stack) { if (stack == mRootHomeTask) { mRootHomeTask = null; } else if (stack == mRootRecentsTask) { @@ -303,7 +303,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { } @Override - void addChild(ActivityStack stack, int position) { + void addChild(Task stack, int position) { if (DEBUG_STACK) Slog.d(TAG_WM, "Set stack=" + stack + " on taskDisplayArea=" + this); addStackReferenceIfNeeded(stack); position = findPositionForStack(position, stack, true /* adding */); @@ -315,7 +315,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { } @Override - protected void removeChild(ActivityStack stack) { + protected void removeChild(Task stack) { super.removeChild(stack); onStackRemoved(stack); mAtmService.updateSleepIfNeededLocked(); @@ -329,7 +329,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { } @Override - void positionChildAt(int position, ActivityStack child, boolean includingParents) { + void positionChildAt(int position, Task child, boolean includingParents) { final boolean moveToTop = position >= getChildCount() - 1; final boolean moveToBottom = position <= 0; @@ -408,7 +408,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { * * @return the priority of the stack */ - private int getPriority(ActivityStack stack) { + private int getPriority(Task stack) { if (mWmService.mAssistantOnTopOfDream && stack.isActivityTypeAssistant()) return 4; if (stack.isActivityTypeDream()) return 3; if (stack.inPinnedWindowingMode()) return 2; @@ -416,7 +416,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { return 0; } - private int findMinPositionForStack(ActivityStack stack) { + private int findMinPositionForStack(Task stack) { int minPosition = POSITION_BOTTOM; for (int i = 0; i < mChildren.size(); ++i) { if (getPriority(getStackAt(i)) < getPriority(stack)) { @@ -438,9 +438,9 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { return minPosition; } - private int findMaxPositionForStack(ActivityStack stack) { + private int findMaxPositionForStack(Task stack) { for (int i = mChildren.size() - 1; i >= 0; --i) { - final ActivityStack curr = getStackAt(i); + final Task curr = getStackAt(i); // Since a stack could be repositioned while still being one of the children, we check // if 'curr' is the same stack and skip it if so final boolean sameStack = curr == stack; @@ -470,7 +470,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { * @param adding Flag indicates whether we're adding a new stack or positioning an existing. * @return The proper position for the stack. */ - private int findPositionForStack(int requestedPosition, ActivityStack stack, boolean adding) { + private int findPositionForStack(int requestedPosition, Task stack, boolean adding) { // The max possible position we can insert the stack at. int maxPosition = findMaxPositionForStack(stack); // The min possible position we can insert the stack at. @@ -632,7 +632,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { assignStackOrdering(t); for (int i = 0; i < mChildren.size(); i++) { - final ActivityStack s = mChildren.get(i); + final Task s = mChildren.get(i); s.assignChildLayers(t); } } @@ -645,7 +645,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { mTmpHomeStacks.clear(); mTmpNormalStacks.clear(); for (int i = 0; i < mChildren.size(); ++i) { - final ActivityStack s = mChildren.get(i); + final Task s = mChildren.get(i); if (s.isAlwaysOnTop()) { mTmpAlwaysOnTopStacks.add(s); } else if (s.isActivityTypeHome()) { @@ -675,7 +675,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { t.setLayer(mBoostedAppAnimationLayer, layerForBoostedAnimationLayer); } - private int adjustNormalStackLayer(ActivityStack s, int layer) { + private int adjustNormalStackLayer(Task s, int layer) { if (s.inSplitScreenWindowingMode()) { // The split screen divider anchor is located above the split screen window. mTmpLayerForSplitScreenDividerAnchor = layer++; @@ -696,12 +696,12 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { * @param normalStacks Set {@code true} if this group is neither home nor always on top. * @return The adjusted layer value. */ - private int adjustRootTaskLayer(SurfaceControl.Transaction t, ArrayList<ActivityStack> stacks, + private int adjustRootTaskLayer(SurfaceControl.Transaction t, ArrayList<Task> stacks, int startLayer, boolean normalStacks) { mTmpNeedsZBoostIndexes.clear(); final int stackSize = stacks.size(); for (int i = 0; i < stackSize; i++) { - final ActivityStack stack = stacks.get(i); + final Task stack = stacks.get(i); if (!stack.needsZBoost()) { stack.assignLayer(t, startLayer++); if (normalStacks) { @@ -714,7 +714,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { final int zBoostSize = mTmpNeedsZBoostIndexes.size(); for (int i = 0; i < zBoostSize; i++) { - final ActivityStack stack = stacks.get(mTmpNeedsZBoostIndexes.get(i)); + final Task stack = stacks.get(mTmpNeedsZBoostIndexes.get(i)); stack.assignLayer(t, startLayer++); if (normalStacks) { startLayer = adjustNormalStackLayer(stack, startLayer); @@ -781,7 +781,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { } } - void onStackRemoved(ActivityStack stack) { + void onStackRemoved(Task stack) { if (ActivityTaskManagerDebugConfig.DEBUG_STACK) { Slog.v(TAG_STACK, "removeStack: detaching " + stack + " from displayId=" + mDisplayContent.mDisplayId); @@ -800,40 +800,40 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { } } - void positionStackAt(int position, ActivityStack child, boolean includingParents) { + void positionStackAt(int position, Task child, boolean includingParents) { positionChildAt(position, child, includingParents); mDisplayContent.layoutAndAssignWindowLayersIfNeeded(); } - void positionStackAtTop(ActivityStack stack, boolean includingParents) { + void positionStackAtTop(Task stack, boolean includingParents) { positionStackAtTop(stack, includingParents, null /* updateLastFocusedStackReason */); } - void positionStackAtTop(ActivityStack stack, boolean includingParents, + void positionStackAtTop(Task stack, boolean includingParents, String updateLastFocusedStackReason) { positionStackAt(stack, getStackCount(), includingParents, updateLastFocusedStackReason); } - void positionStackAtBottom(ActivityStack stack) { + void positionStackAtBottom(Task stack) { positionStackAtBottom(stack, null /* updateLastFocusedStackReason */); } - void positionStackAtBottom(ActivityStack stack, String updateLastFocusedStackReason) { + void positionStackAtBottom(Task stack, String updateLastFocusedStackReason) { positionStackAt(stack, 0, false /* includingParents */, updateLastFocusedStackReason); } - void positionStackAt(ActivityStack stack, int position) { + void positionStackAt(Task stack, int position) { positionStackAt(stack, position, false /* includingParents */, null /* updateLastFocusedStackReason */); } - void positionStackAt(ActivityStack stack, int position, boolean includingParents, + void positionStackAt(Task stack, int position, boolean includingParents, String updateLastFocusedStackReason) { // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust // the position internally, also update the logic here - final ActivityStack prevFocusedStack = updateLastFocusedStackReason != null + final Task prevFocusedStack = updateLastFocusedStackReason != null ? getFocusedStack() : null; final boolean wasContained = mChildren.contains(stack); if (mDisplayContent.mSingleTaskInstance && getStackCount() == 1 && !wasContained) { @@ -846,7 +846,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { positionStackAt(position, stack, includingParents); if (updateLastFocusedStackReason != null) { - final ActivityStack currentFocusedStack = getFocusedStack(); + final Task currentFocusedStack = getFocusedStack(); if (currentFocusedStack != prevFocusedStack) { mLastFocusedStack = prevFocusedStack; EventLogTags.writeWmFocusedStack(mRootWindowContainer.mCurrentUser, @@ -865,8 +865,8 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { * when we just want to move a task to "the back" vs. a specific place. The primary use-case * is to make sure that moved-to-back apps go into secondary split when in split-screen mode. */ - void positionTaskBehindHome(ActivityStack task) { - final ActivityStack home = getOrCreateRootHomeTask(); + void positionTaskBehindHome(Task task) { + final Task home = getOrCreateRootHomeTask(); final WindowContainer homeParent = home.getParent(); final Task homeParentTask = homeParent != null ? homeParent.asTask() : null; if (homeParentTask == null) { @@ -878,17 +878,17 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { } } else if (homeParentTask == task.getParent()) { // Apparently reparent early-outs if same stack, so we have to explicitly reorder. - ((ActivityStack) homeParentTask).positionChildAtBottom(task); + homeParentTask.positionChildAtBottom(task); } else { - task.reparent((ActivityStack) homeParentTask, false /* toTop */, + task.reparent(homeParentTask, false /* toTop */, Task.REPARENT_LEAVE_STACK_IN_PLACE, false /* animate */, false /* deferResume */, "positionTaskBehindHome"); } } - ActivityStack getStack(int rootTaskId) { + Task getStack(int rootTaskId) { for (int i = getStackCount() - 1; i >= 0; --i) { - final ActivityStack stack = getStackAt(i); + final Task stack = getStackAt(i); if (stack.getRootTaskId() == rootTaskId) { return stack; } @@ -901,7 +901,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { * if a compatible stack doesn't exist. * @see #getOrCreateStack(int, int, boolean, Intent, Task) */ - ActivityStack getOrCreateStack(int windowingMode, int activityType, boolean onTop) { + Task getOrCreateStack(int windowingMode, int activityType, boolean onTop) { return getOrCreateStack(windowingMode, activityType, onTop, null /* intent */, null /* candidateTask */); } @@ -914,19 +914,19 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { * @see #getStack(int, int) * @see #createStack(int, int, boolean) */ - ActivityStack getOrCreateStack(int windowingMode, int activityType, boolean onTop, + Task getOrCreateStack(int windowingMode, int activityType, boolean onTop, Intent intent, Task candidateTask) { // Need to pass in a determined windowing mode to see if a new stack should be created, // so use its parent's windowing mode if it is undefined. if (!alwaysCreateStack( windowingMode != WINDOWING_MODE_UNDEFINED ? windowingMode : getWindowingMode(), activityType)) { - ActivityStack stack = getStack(windowingMode, activityType); + Task stack = getStack(windowingMode, activityType); if (stack != null) { return stack; } } else if (candidateTask != null) { - final ActivityStack stack = (ActivityStack) candidateTask; + final Task stack = candidateTask; final int position = onTop ? POSITION_TOP : POSITION_BOTTOM; Task launchRootTask = updateLaunchRootTask(windowingMode); @@ -958,7 +958,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { * if a compatible stack doesn't exist. * @see #getOrCreateStack(int, int, boolean) */ - ActivityStack getOrCreateStack(@Nullable ActivityRecord r, + Task getOrCreateStack(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable Task candidateTask, int activityType, boolean onTop) { // First preference is the windowing mode in the activity options if set. @@ -977,7 +977,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { return mAtmService.mStackSupervisor.getNextTaskIdForUser(); } - ActivityStack createStack(int windowingMode, int activityType, boolean onTop) { + Task createStack(int windowingMode, int activityType, boolean onTop) { return createStack(windowingMode, activityType, onTop, null /* info */, null /* intent */, false /* createdByOrganizer */); } @@ -997,7 +997,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { * otherwise. * @return The newly created stack. */ - ActivityStack createStack(int windowingMode, int activityType, boolean onTop, ActivityInfo info, + Task createStack(int windowingMode, int activityType, boolean onTop, ActivityInfo info, Intent intent, boolean createdByOrganizer) { if (mDisplayContent.mSingleTaskInstance && getStackCount() > 0) { // Create stack on default display instead since this display can only contain 1 stack. @@ -1016,7 +1016,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { if (activityType != ACTIVITY_TYPE_STANDARD && activityType != ACTIVITY_TYPE_UNDEFINED) { // For now there can be only one stack of a particular non-standard activity type on a // display. So, get that ignoring whatever windowing mode it is currently in. - ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType); + Task stack = getStack(WINDOWING_MODE_UNDEFINED, activityType); if (stack != null) { throw new IllegalArgumentException("Stack=" + stack + " of activityType=" + activityType + " already on display=" + this + ". Can't have multiple."); @@ -1068,7 +1068,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { } @VisibleForTesting - ActivityStack createStackUnchecked(int windowingMode, int activityType, int stackId, + Task createStackUnchecked(int windowingMode, int activityType, int stackId, boolean onTop, ActivityInfo info, Intent intent, boolean createdByOrganizer) { if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) { throw new IllegalArgumentException("Stack with windowing mode cannot with non standard " @@ -1086,12 +1086,12 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { windowingMode = WINDOWING_MODE_UNDEFINED; } - final ActivityStack stack = new ActivityStack(mAtmService, stackId, activityType, + final Task stack = new Task(mAtmService, stackId, activityType, info, intent, createdByOrganizer); if (launchRootTask != null) { launchRootTask.addChild(stack, onTop ? POSITION_TOP : POSITION_BOTTOM); if (onTop) { - positionStackAtTop((ActivityStack) launchRootTask, false /* includingParents */); + positionStackAtTop(launchRootTask, false /* includingParents */); } } else { addChild(stack, onTop ? POSITION_TOP : POSITION_BOTTOM); @@ -1104,13 +1104,13 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { * Get the preferred focusable stack in priority. If the preferred stack does not exist, find a * focusable and visible stack from the top of stacks in this display. */ - ActivityStack getFocusedStack() { + Task getFocusedStack() { if (mPreferredTopFocusableStack != null) { return mPreferredTopFocusableStack; } for (int i = getStackCount() - 1; i >= 0; --i) { - final ActivityStack stack = getStackAt(i); + final Task stack = getStackAt(i); if (stack.isFocusableAndVisible()) { return stack; } @@ -1119,13 +1119,13 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { return null; } - ActivityStack getNextFocusableStack(ActivityStack currentFocus, boolean ignoreCurrent) { + Task getNextFocusableStack(Task currentFocus, boolean ignoreCurrent) { final int currentWindowingMode = currentFocus != null ? currentFocus.getWindowingMode() : WINDOWING_MODE_UNDEFINED; - ActivityStack candidate = null; + Task candidate = null; for (int i = getStackCount() - 1; i >= 0; --i) { - final ActivityStack stack = getStackAt(i); + final Task stack = getStackAt(i); if (ignoreCurrent && stack == currentFocus) { continue; } @@ -1155,7 +1155,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { } ActivityRecord getFocusedActivity() { - final ActivityStack focusedStack = getFocusedStack(); + final Task focusedStack = getFocusedStack(); if (focusedStack == null) { return null; } @@ -1175,7 +1175,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { return resumedActivity; } - ActivityStack getLastFocusedStack() { + Task getLastFocusedStack() { return mLastFocusedStack; } @@ -1186,7 +1186,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { return false; } } - final ActivityStack currentFocusedStack = getFocusedStack(); + final Task currentFocusedStack = getFocusedStack(); if (ActivityTaskManagerDebugConfig.DEBUG_STACK) { Slog.d(TAG_STACK, "allResumedActivitiesComplete: mLastFocusedStack changing from=" + mLastFocusedStack + " to=" + currentFocusedStack); @@ -1208,7 +1208,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming) { boolean someActivityPaused = false; for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = getStackAt(stackNdx); + final Task stack = getStackAt(stackNdx); final ActivityRecord resumedActivity = stack.getResumedActivity(); if (resumedActivity != null && (stack.getVisibility(resuming) != STACK_VISIBILITY_VISIBLE @@ -1231,7 +1231,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { RootWindowContainer.FindTaskResult result) { mTmpFindTaskResult.clear(); for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = getStackAt(stackNdx); + final Task stack = getStackAt(stackNdx); if (!r.hasCompatibleActivityType(stack) && stack.isLeafTask()) { if (DEBUG_TASKS) { Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) " + stack); @@ -1271,11 +1271,11 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { // Collect the stacks that are necessary to be removed instead of performing the removal // by looping mStacks, so that we don't miss any stacks after the stack size changed or // stacks reordered. - final ArrayList<ActivityStack> stacks = new ArrayList<>(); + final ArrayList<Task> stacks = new ArrayList<>(); for (int j = windowingModes.length - 1; j >= 0; --j) { final int windowingMode = windowingModes[j]; for (int i = getStackCount() - 1; i >= 0; --i) { - final ActivityStack stack = getStackAt(i); + final Task stack = getStackAt(i); if (!stack.isActivityTypeStandardOrUndefined()) { continue; } @@ -1299,15 +1299,15 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { // Collect the stacks that are necessary to be removed instead of performing the removal // by looping mStacks, so that we don't miss any stacks after the stack size changed or // stacks reordered. - final ArrayList<ActivityStack> stacks = new ArrayList<>(); + final ArrayList<Task> stacks = new ArrayList<>(); for (int j = activityTypes.length - 1; j >= 0; --j) { final int activityType = activityTypes[j]; for (int i = getStackCount() - 1; i >= 0; --i) { - final ActivityStack stack = getStackAt(i); + final Task stack = getStackAt(i); // Collect the root tasks that are currently being organized. if (stack.mCreatedByOrganizer) { for (int k = stack.getChildCount() - 1; k >= 0; --k) { - final ActivityStack childStack = (ActivityStack) stack.getChildAt(k); + final Task childStack = (Task) stack.getChildAt(k); if (childStack.getActivityType() == activityType) { stacks.add(childStack); } @@ -1327,15 +1327,15 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { onSplitScreenModeDismissed(null /* toTop */); } - void onSplitScreenModeDismissed(ActivityStack toTop) { + void onSplitScreenModeDismissed(Task toTop) { mAtmService.deferWindowLayout(); try { mLaunchRootTask = null; moveSplitScreenTasksToFullScreen(); } finally { - final ActivityStack topFullscreenStack = toTop != null + final Task topFullscreenStack = toTop != null ? toTop : getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN); - final ActivityStack homeStack = getOrCreateRootHomeTask(); + final Task homeStack = getOrCreateRootHomeTask(); if (homeStack != null && ((topFullscreenStack != null && !isTopStack(homeStack)) || toTop != null)) { // Whenever split-screen is dismissed we want the home stack directly behind the @@ -1509,13 +1509,13 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { return windowingMode; } - boolean isTopStack(ActivityStack stack) { + boolean isTopStack(Task stack) { return stack == getTopStack(); } - boolean isTopNotPinnedStack(ActivityStack stack) { + boolean isTopNotPinnedStack(Task stack) { for (int i = getStackCount() - 1; i >= 0; --i) { - final ActivityStack current = getStackAt(i); + final Task current = getStackAt(i); if (!current.inPinnedWindowingMode()) { return current == stack; } @@ -1538,7 +1538,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { */ ActivityRecord topRunningActivity(boolean considerKeyguardState) { ActivityRecord topRunning = null; - final ActivityStack focusedStack = getFocusedStack(); + final Task focusedStack = getFocusedStack(); if (focusedStack != null) { topRunning = focusedStack.topRunningActivity(); } @@ -1546,7 +1546,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { // Look in other focusable stacks. if (topRunning == null) { for (int i = getStackCount() - 1; i >= 0; --i) { - final ActivityStack stack = getStackAt(i); + final Task stack = getStackAt(i); // Only consider focusable stacks other than the current focused one. if (stack == focusedStack || !stack.isTopActivityFocusable()) { continue; @@ -1574,12 +1574,12 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { return mChildren.size(); } - protected ActivityStack getStackAt(int index) { + protected Task getStackAt(int index) { return mChildren.get(index); } @Nullable - ActivityStack getOrCreateRootHomeTask() { + Task getOrCreateRootHomeTask() { return getOrCreateRootHomeTask(false /* onTop */); } @@ -1590,8 +1590,8 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { * be created at the top of the display, else at the bottom. */ @Nullable - ActivityStack getOrCreateRootHomeTask(boolean onTop) { - ActivityStack homeTask = getRootHomeTask(); + Task getOrCreateRootHomeTask(boolean onTop) { + Task homeTask = getRootHomeTask(); if (homeTask == null && mDisplayContent.supportsSystemDecorations()) { homeTask = createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, onTop); } @@ -1607,12 +1607,12 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { * Returns the topmost stack on the display that is compatible with the input windowing mode. * Null is no compatible stack on the display. */ - ActivityStack getTopStackInWindowingMode(int windowingMode) { + Task getTopStackInWindowingMode(int windowingMode) { return getStack(windowingMode, ACTIVITY_TYPE_UNDEFINED); } void moveHomeStackToFront(String reason) { - final ActivityStack homeStack = getOrCreateRootHomeTask(); + final Task homeStack = getOrCreateRootHomeTask(); if (homeStack != null) { homeStack.moveToFront(reason); } @@ -1638,7 +1638,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { @Nullable ActivityRecord getHomeActivityForUser(int userId) { - final ActivityStack homeStack = getRootHomeTask(); + final Task homeStack = getRootHomeTask(); if (homeStack == null) { return null; } @@ -1660,7 +1660,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { * Generally used in conjunction with {@link #moveStackBehindStack}. */ // TODO(b/151575894): Remove special stack movement methods. - void moveStackBehindBottomMostVisibleStack(ActivityStack stack) { + void moveStackBehindBottomMostVisibleStack(Task stack) { if (stack.shouldBeVisible(null)) { // Skip if the stack is already visible return; @@ -1677,8 +1677,8 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { // Find the next position where the stack should be placed final int numStacks = isRootTask ? getStackCount() : stack.getParent().getChildCount(); for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) { - final ActivityStack s = isRootTask ? getStackAt(stackNdx) - : (ActivityStack) stack.getParent().getChildAt(stackNdx); + final Task s = isRootTask ? getStackAt(stackNdx) + : (Task) stack.getParent().getChildAt(stackNdx); if (s == stack) { continue; } @@ -1703,7 +1703,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { * {@param behindStack} is not currently in the display, then then the stack is moved to the * back. Generally used in conjunction with {@link #moveStackBehindBottomMostVisibleStack}. */ - void moveStackBehindStack(ActivityStack stack, ActivityStack behindStack) { + void moveStackBehindStack(Task stack, Task behindStack) { if (behindStack == null || behindStack == stack) { return; } @@ -1737,19 +1737,19 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { * @return the stack currently above the {@param stack}. Can be null if the {@param stack} is * already top-most. */ - static ActivityStack getStackAbove(ActivityStack stack) { + static Task getStackAbove(Task stack) { final WindowContainer wc = stack.getParent(); final int index = wc.mChildren.indexOf(stack) + 1; - return (index < wc.mChildren.size()) ? (ActivityStack) wc.mChildren.get(index) : null; + return (index < wc.mChildren.size()) ? (Task) wc.mChildren.get(index) : null; } /** Returns true if the stack in the windowing mode is visible. */ boolean isStackVisible(int windowingMode) { - final ActivityStack stack = getTopStackInWindowingMode(windowingMode); + final Task stack = getTopStackInWindowingMode(windowingMode); return stack != null && stack.isVisible(); } - void removeStack(ActivityStack stack) { + void removeStack(Task stack) { removeChild(stack); } @@ -1783,7 +1783,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { * Notifies of a stack order change * @param stack The stack which triggered the order change */ - void onStackOrderChanged(ActivityStack stack) { + void onStackOrderChanged(Task stack) { for (int i = mStackOrderChangedCallbacks.size() - 1; i >= 0; i--) { mStackOrderChangedCallbacks.get(i).onStackOrderChanged(stack); } @@ -1798,7 +1798,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { * Callback for when the order of the stacks in the display changes. */ interface OnStackOrderChangedListener { - void onStackOrderChanged(ActivityStack stack); + void onStackOrderChanged(Task stack); } void ensureActivitiesVisible(ActivityRecord starting, int configChanges, @@ -1806,7 +1806,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { mAtmService.mStackSupervisor.beginActivityVisibilityUpdate(); try { for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = getStackAt(stackNdx); + final Task stack = getStackAt(stackNdx); stack.ensureActivitiesVisible(starting, configChanges, preserveWindows, notifyClients); } @@ -1817,7 +1817,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { void prepareFreezingTaskBounds() { for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = getChildAt(stackNdx); + final Task stack = getChildAt(stackNdx); stack.prepareFreezingTaskBounds(); } } @@ -1826,12 +1826,12 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { * Removes the stacks in the node applying the content removal node from the display. * @return last reparented stack, or {@code null} if the stacks had to be destroyed. */ - ActivityStack remove() { + Task remove() { mPreferredTopFocusableStack = null; // TODO(b/153090332): Allow setting content removal mode per task display area final boolean destroyContentOnRemoval = mDisplayContent.shouldDestroyContentOnRemove(); final TaskDisplayArea toDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - ActivityStack lastReparentedStack = null; + Task lastReparentedStack = null; // Stacks could be reparented from the removed display area to other display area. After // reparenting the last stack of the removed display area, the display area becomes ready to @@ -1842,10 +1842,10 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { int numStacks = getStackCount(); final boolean splitScreenActivated = toDisplayArea.isSplitScreenModeActivated(); - final ActivityStack rootStack = splitScreenActivated ? toDisplayArea + final Task rootStack = splitScreenActivated ? toDisplayArea .getTopStackInWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) : null; for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) { - final ActivityStack stack = getStackAt(stackNdx); + final Task stack = getStackAt(stackNdx); // Always finish non-standard type stacks. if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) { stack.finishAllActivitiesImmediately(); @@ -1895,7 +1895,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { final String triplePrefix = doublePrefix + " "; pw.println(doublePrefix + "Application tokens in top down Z order:"); for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = getChildAt(stackNdx); + final Task stack = getChildAt(stackNdx); pw.println(doublePrefix + "* " + stack); stack.dump(pw, triplePrefix, dumpAll); } diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java index 00ddf82d2ba3..9a818ce80872 100644 --- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java @@ -341,8 +341,8 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { } } - ActivityStack stack = (taskDisplayArea == null && task != null) - ? task.getStack() : null; + Task stack = (taskDisplayArea == null && task != null) + ? task.getRootTask() : null; if (stack != null) { if (DEBUG) appendLog("display-from-task=" + stack.getDisplayId()); taskDisplayArea = stack.getDisplayArea(); @@ -744,13 +744,13 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { display.forAllTaskDisplayAreas(taskDisplayArea -> { int numStacks = taskDisplayArea.getStackCount(); for (int sNdx = 0; sNdx < numStacks; ++sNdx) { - final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); - if (!stack.inFreeformWindowingMode()) { + final Task task = taskDisplayArea.getStackAt(sNdx); + if (!task.inFreeformWindowingMode()) { continue; } - for (int j = 0; j < stack.getChildCount(); ++j) { - taskBoundsToCheck.add(stack.getChildAt(j).getBounds()); + for (int j = 0; j < task.getChildCount(); ++j) { + taskBoundsToCheck.add(task.getChildAt(j).getBounds()); } } }, false /* traverseTopToBottom */); diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index f1e965ba7a14..d0785ff9a9ac 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -112,16 +112,16 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowContainer" : TAG_WM; - /** Animation layer that happens above all animating {@link ActivityStack}s. */ + /** Animation layer that happens above all animating {@link Task}s. */ static final int ANIMATION_LAYER_STANDARD = 0; - /** Animation layer that happens above all {@link ActivityStack}s. */ + /** Animation layer that happens above all {@link Task}s. */ static final int ANIMATION_LAYER_BOOSTED = 1; /** * Animation layer that is reserved for {@link WindowConfiguration#ACTIVITY_TYPE_HOME} * activities and all activities that are being controlled by the recents animation. This - * layer is generally below all {@link ActivityStack}s. + * layer is generally below all {@link Task}s. */ static final int ANIMATION_LAYER_HOME = 2; @@ -190,7 +190,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< /** * Sources which triggered a surface animation on this container. An animation target can be * promoted to higher level, for example, from a set of {@link ActivityRecord}s to - * {@link ActivityStack}. In this case, {@link ActivityRecord}s are set on this variable while + * {@link Task}. In this case, {@link ActivityRecord}s are set on this variable while * the animation is running, and reset after finishing it. */ private final ArraySet<WindowContainer> mSurfaceAnimationSources = new ArraySet<>(); diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java index 97186b4e9cda..d96b6457f9db 100644 --- a/services/core/java/com/android/server/wm/WindowFrames.java +++ b/services/core/java/com/android/server/wm/WindowFrames.java @@ -57,7 +57,7 @@ public class WindowFrames { public final Rect mParentFrame = new Rect(); /** - * The entire screen area of the {@link ActivityStack} this window is in. Usually equal to the + * The entire screen area of the {@link Task} this window is in. Usually equal to the * screen area of the device. * * TODO(b/111611553): The name is unclear and most likely should be swapped with diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index aa691fc1ae6b..2dd25c969d0d 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1478,9 +1478,14 @@ public class WindowManagerService extends IWindowManager.Stub rootType, attrs.token, attrs.packageName)) { return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } - final IBinder binder = attrs.token != null ? attrs.token : client.asBinder(); - token = new WindowToken(this, binder, type, false, displayContent, - session.mCanAddInternalSystemWindow, isRoundedCornerOverlay); + if (hasParent) { + // Use existing parent window token for child windows. + token = parentWindow.mToken; + } else { + final IBinder binder = attrs.token != null ? attrs.token : client.asBinder(); + token = new WindowToken(this, binder, type, false, displayContent, + session.mCanAddInternalSystemWindow, isRoundedCornerOverlay); + } } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) { activity = token.asActivityRecord(); @@ -1945,7 +1950,7 @@ public class WindowManagerService extends IWindowManager.Stub // re-factor. activity.firstWindowDrawn = false; activity.clearAllDrawn(); - final ActivityStack stack = activity.getStack(); + final Task stack = activity.getStack(); if (stack != null) { stack.mExitingActivities.remove(activity); } @@ -2863,7 +2868,7 @@ public class WindowManagerService extends IWindowManager.Stub } void getStackBounds(int windowingMode, int activityType, Rect bounds) { - final ActivityStack stack = mRoot.getStack(windowingMode, activityType); + final Task stack = mRoot.getStack(windowingMode, activityType); if (stack != null) { stack.getBounds(bounds); return; @@ -4587,7 +4592,7 @@ public class WindowManagerService extends IWindowManager.Stub return mRoot.getTopFocusedDisplayContent().mCurrentFocus; } - ActivityStack getImeFocusStackLocked() { + Task getImeFocusStackLocked() { // Don't use mCurrentFocus.getStack() because it returns home stack for system windows. // Also don't use mInputMethodTarget's stack, because some window with FLAG_NOT_FOCUSABLE // and FLAG_ALT_FOCUSABLE_IM flags both set might be set to IME target so they're moved @@ -4596,7 +4601,7 @@ public class WindowManagerService extends IWindowManager.Stub final DisplayContent topFocusedDisplay = mRoot.getTopFocusedDisplayContent(); final ActivityRecord focusedApp = topFocusedDisplay.mFocusedApp; return (focusedApp != null && focusedApp.getTask() != null) - ? focusedApp.getTask().getStack() : null; + ? focusedApp.getTask().getRootTask() : null; } public boolean detectSafeMode() { diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 24ad85356477..4c5ac937b988 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -317,7 +317,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub Slog.w(TAG, "Container is no longer attached: " + task); return 0; } - final ActivityStack as = (ActivityStack) task; + final Task as = task; if (hop.isReparent()) { final boolean isNonOrganizedRootableTask = @@ -337,12 +337,12 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub + " multi-window mode... newParent=" + newParent + " task=" + task); return 0; } else { - task.reparent((ActivityStack) newParent, + task.reparent((Task) newParent, hop.getToTop() ? POSITION_TOP : POSITION_BOTTOM, false /*moveParents*/, "sanitizeAndApplyHierarchyOp"); } } else { - final ActivityStack rootTask = (ActivityStack) ( + final Task rootTask = (Task) ( (newParent != null && !(newParent instanceof TaskDisplayArea)) ? newParent : task.getRootTask()); if (hop.getToTop()) { @@ -353,7 +353,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } } } else { - throw new RuntimeException("Reparenting leaf Tasks is not supported now."); + throw new RuntimeException("Reparenting leaf Tasks is not supported now. " + task); } } else { // Ugh, of course ActivityStack has its own special reorder logic... @@ -395,10 +395,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub private void resizePinnedStackIfNeeded(ConfigurationContainer container, int configMask, int windowMask, Configuration config) { - if ((container instanceof ActivityStack) + if ((container instanceof Task) && ((configMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0) && ((windowMask & WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)) { - final ActivityStack stack = (ActivityStack) container; + final Task stack = (Task) container; if (stack.inPinnedWindowingMode()) { stack.resize(config.windowConfiguration.getBounds(), PRESERVE_WINDOWS, true /* deferResume */); diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 29cf1776df9c..da9c7f3ea1b5 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -22,13 +22,6 @@ import static android.os.Build.VERSION_CODES.Q; import static android.view.Display.INVALID_DISPLAY; import static com.android.server.am.ActivityManagerService.MY_PID; -import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED; -import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING; -import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; -import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; -import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; -import static com.android.server.wm.ActivityStack.ActivityState.STARTED; -import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RELEASE; @@ -40,6 +33,13 @@ import static com.android.server.wm.ActivityTaskManagerService.ACTIVITY_BG_START import static com.android.server.wm.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS; import static com.android.server.wm.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE; +import static com.android.server.wm.Task.ActivityState.DESTROYED; +import static com.android.server.wm.Task.ActivityState.DESTROYING; +import static com.android.server.wm.Task.ActivityState.PAUSED; +import static com.android.server.wm.Task.ActivityState.PAUSING; +import static com.android.server.wm.Task.ActivityState.RESUMED; +import static com.android.server.wm.Task.ActivityState.STARTED; +import static com.android.server.wm.Task.ActivityState.STOPPING; import android.Manifest; import android.annotation.NonNull; @@ -160,7 +160,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio private volatile boolean mPerceptible; // Set to true when process was launched with a wrapper attached private volatile boolean mUsingWrapper; - // Set to true if this process is currently temporarily whitelisted to start activities even if + // Set to true if this process is currently temporarily allowed to start activities even if // it's not in the foreground private volatile boolean mAllowBackgroundActivityStarts; // Set of UIDs of clients currently bound to this process @@ -454,7 +454,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio } boolean areBackgroundActivityStartsAllowed() { - // allow if the whitelisting flag was explicitly set + // allow if the flag was explicitly set if (mAllowBackgroundActivityStarts) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "[WindowProcessController(" + mPid @@ -690,7 +690,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio if (canUpdate) { // Make sure the previous top activity in the process no longer be resumed. if (mPreQTopResumedActivity != null && mPreQTopResumedActivity.isState(RESUMED)) { - final ActivityStack stack = mPreQTopResumedActivity.getRootTask(); + final Task stack = mPreQTopResumedActivity.getRootTask(); if (stack != null) { stack.startPausingLocked(false /* userLeaving */, false /* uiSleeping */, activity); @@ -924,7 +924,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio // Since there could be more than one activities in a process record, we don't need to // compute the OomAdj with each of them, just need to find out the activity with the // "best" state, the order would be visible, pausing, stopping... - ActivityStack.ActivityState best = DESTROYED; + Task.ActivityState best = DESTROYED; boolean finishing = true; boolean visible = false; synchronized (mAtm.mGlobalLockWithoutBoost) { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index fd4fdfccdea8..9ab157210dbd 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1566,10 +1566,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return mActivityRecord != null ? mActivityRecord.getTask() : null; } - @Nullable ActivityStack getRootTask() { + @Nullable Task getRootTask() { final Task task = getTask(); if (task != null) { - return (ActivityStack) task.getRootTask(); + return task.getRootTask(); } // Some system windows (e.g. "Power off" dialog) don't have a task, but we would still // associate them with some stack to enable dimming. @@ -1611,7 +1611,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP bounds.setEmpty(); mTmpRect.setEmpty(); if (intersectWithStackBounds) { - final ActivityStack stack = task.getStack(); + final Task stack = task.getRootTask(); if (stack != null) { stack.getDimBounds(mTmpRect); } else { @@ -1622,7 +1622,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // the secondary split, it means this is "minimized" and thus must prevent // overlapping with home. // TODO(b/158242495): get rid of this when drag/drop can use surface bounds. - final ActivityStack rootSecondary = + final Task rootSecondary = task.getDisplayArea().getRootSplitScreenSecondaryTask(); if (rootSecondary.isActivityTypeHome() || rootSecondary.isActivityTypeRecents()) { final WindowContainer topTask = rootSecondary.getTopChild(); @@ -2107,7 +2107,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP boolean isObscuringDisplay() { Task task = getTask(); - if (task != null && task.getStack() != null && !task.getStack().fillsParent()) { + if (task != null && task.getRootTask() != null && !task.getRootTask().fillsParent()) { return false; } return isOpaqueDrawn() && fillsDisplay(); @@ -2194,9 +2194,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (dc.mInputMethodInputTarget == this) { dc.setInputMethodInputTarget(null); } - if (dc.mInputMethodControlTarget == this) { - dc.updateImeControlTarget(); - } final int type = mAttrs.type; if (WindowManagerService.excludeWindowTypeFromTapOutTask(type)) { @@ -2418,7 +2415,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return false; } - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); if (stack != null && !stack.isFocusable()) { // Ignore when the stack shouldn't receive input event. // (i.e. the minimized stack in split screen mode.) @@ -2919,7 +2916,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return false; } - return mActivityRecord.getTask().getStack().shouldIgnoreInput() + return mActivityRecord.getTask().getRootTask().shouldIgnoreInput() || !mActivityRecord.mVisibleRequested || isRecentsAnimationConsumingAppInput(); } @@ -3489,7 +3486,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return; } - final ActivityStack stack = task.getStack(); + final Task stack = task.getRootTask(); if (stack == null || inFreeformWindowingMode()) { handle.setTouchableRegionCrop(null); return; @@ -3504,7 +3501,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return; } - final ActivityStack stack = task.getStack(); + final Task stack = task.getRootTask(); if (stack == null || stack.mCreatedByOrganizer) { return; } @@ -3748,7 +3745,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } private int getRootTaskId() { - final ActivityStack stack = getRootTask(); + final Task stack = getRootTask(); if (stack == null) { return INVALID_TASK_ID; } @@ -5451,7 +5448,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP outPoint.offset(-parentBounds.left, -parentBounds.top); } - ActivityStack stack = getRootTask(); + Task stack = getRootTask(); // If we have stack outsets, that means the top-left // will be outset, and we need to inset ourselves diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index da45300ed318..77fee851889e 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -924,15 +924,15 @@ class WindowStateAnimator { int posX = 0; int posY = 0; - task.getStack().getDimBounds(mTmpStackBounds); + task.getRootTask().getDimBounds(mTmpStackBounds); boolean allowStretching = false; - task.getStack().getFinalAnimationSourceHintBounds(mTmpSourceBounds); + task.getRootTask().getFinalAnimationSourceHintBounds(mTmpSourceBounds); // If we don't have source bounds, we can attempt to use the content insets // if we have content insets. if (mTmpSourceBounds.isEmpty() && (mWin.mLastRelayoutContentInsets.width() > 0 || mWin.mLastRelayoutContentInsets.height() > 0)) { - mTmpSourceBounds.set(task.getStack().mPreAnimationBounds); + mTmpSourceBounds.set(task.getRootTask().mPreAnimationBounds); mTmpSourceBounds.inset(mWin.mLastRelayoutContentInsets); allowStretching = true; } @@ -946,7 +946,7 @@ class WindowStateAnimator { if (!mTmpSourceBounds.isEmpty()) { // Get the final target stack bounds, if we are not animating, this is just the // current stack bounds - task.getStack().getFinalAnimationBounds(mTmpAnimatingBounds); + task.getRootTask().getFinalAnimationBounds(mTmpAnimatingBounds); // Calculate the current progress and interpolate the difference between the target // and source bounds @@ -1042,7 +1042,7 @@ class WindowStateAnimator { mSurfaceController.deferTransactionUntil(mWin.getClientViewRootSurface(), mWin.getFrameNumber()); } else { - final ActivityStack stack = mWin.getRootTask(); + final Task stack = mWin.getRootTask(); mTmpPos.x = 0; mTmpPos.y = 0; if (stack != null) { @@ -1576,7 +1576,7 @@ class WindowStateAnimator { */ boolean isForceScaled() { final Task task = mWin.getTask(); - if (task != null && task.getStack().isForceScaled()) { + if (task != null && task.getRootTask().isForceScaled()) { return true; } return mForceScaleUntilResize; diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 7bd455ab82a1..10523a2adbb2 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -200,10 +200,10 @@ public: void setDisplayViewports(JNIEnv* env, jobjectArray viewportObjArray); - status_t registerInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel); - status_t registerInputMonitor(JNIEnv* env, const sp<InputChannel>& inputChannel, - int32_t displayId, bool isGestureMonitor); - status_t unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel); + status_t registerInputChannel(JNIEnv* env, const std::shared_ptr<InputChannel>& inputChannel); + status_t registerInputMonitor(JNIEnv* env, const std::shared_ptr<InputChannel>& inputChannel, + int32_t displayId, bool isGestureMonitor); + status_t unregisterInputChannel(JNIEnv* env, const InputChannel& inputChannel); status_t pilferPointers(const sp<IBinder>& token); void displayRemoved(JNIEnv* env, int32_t displayId); @@ -421,21 +421,22 @@ void NativeInputManager::setDisplayViewports(JNIEnv* env, jobjectArray viewportO InputReaderConfiguration::CHANGE_DISPLAY_INFO); } -status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */, - const sp<InputChannel>& inputChannel) { +status_t NativeInputManager::registerInputChannel( + JNIEnv* /* env */, const std::shared_ptr<InputChannel>& inputChannel) { ATRACE_CALL(); return mInputManager->getDispatcher()->registerInputChannel(inputChannel); } status_t NativeInputManager::registerInputMonitor(JNIEnv* /* env */, - const sp<InputChannel>& inputChannel, int32_t displayId, bool isGestureMonitor) { + const std::shared_ptr<InputChannel>& inputChannel, + int32_t displayId, bool isGestureMonitor) { ATRACE_CALL(); return mInputManager->getDispatcher()->registerInputMonitor( inputChannel, displayId, isGestureMonitor); } status_t NativeInputManager::unregisterInputChannel(JNIEnv* /* env */, - const sp<InputChannel>& inputChannel) { + const InputChannel& inputChannel) { ATRACE_CALL(); return mInputManager->getDispatcher()->unregisterInputChannel(inputChannel); } @@ -1338,21 +1339,22 @@ static void throwInputChannelNotInitialized(JNIEnv* env) { "inputChannel is not initialized"); } -static void handleInputChannelDisposed(JNIEnv* env, - jobject /* inputChannelObj */, const sp<InputChannel>& inputChannel, void* data) { +static void handleInputChannelDisposed(JNIEnv* env, jobject /* inputChannelObj */, + const std::shared_ptr<InputChannel>& inputChannel, + void* data) { NativeInputManager* im = static_cast<NativeInputManager*>(data); ALOGW("Input channel object '%s' was disposed without first being unregistered with " "the input manager!", inputChannel->getName().c_str()); - im->unregisterInputChannel(env, inputChannel); + im->unregisterInputChannel(env, *inputChannel); } static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */, jlong ptr, jobject inputChannelObj) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); - sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, - inputChannelObj); + std::shared_ptr<InputChannel> inputChannel = + android_view_InputChannel_getInputChannel(env, inputChannelObj); if (inputChannel == nullptr) { throwInputChannelNotInitialized(env); return; @@ -1375,8 +1377,8 @@ static void nativeRegisterInputMonitor(JNIEnv* env, jclass /* clazz */, jlong ptr, jobject inputChannelObj, jint displayId, jboolean isGestureMonitor) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); - sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, - inputChannelObj); + std::shared_ptr<InputChannel> inputChannel = + android_view_InputChannel_getInputChannel(env, inputChannelObj); if (inputChannel == nullptr) { throwInputChannelNotInitialized(env); return; @@ -1401,8 +1403,8 @@ static void nativeUnregisterInputChannel(JNIEnv* env, jclass /* clazz */, jlong ptr, jobject inputChannelObj) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); - sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, - inputChannelObj); + std::shared_ptr<InputChannel> inputChannel = + android_view_InputChannel_getInputChannel(env, inputChannelObj); if (inputChannel == nullptr) { throwInputChannelNotInitialized(env); return; @@ -1410,7 +1412,7 @@ static void nativeUnregisterInputChannel(JNIEnv* env, jclass /* clazz */, android_view_InputChannel_setDisposeCallback(env, inputChannelObj, nullptr, nullptr); - status_t status = im->unregisterInputChannel(env, inputChannel); + status_t status = im->unregisterInputChannel(env, *inputChannel); if (status && status != BAD_VALUE) { // ignore already unregistered channel std::string message; message += StringPrintf("Failed to unregister input channel. status=%d", status); @@ -1615,9 +1617,8 @@ static void nativeReloadCalibration(JNIEnv* env, jclass clazz, jlong ptr) { im->reloadCalibration(); } -static void nativeVibrate(JNIEnv* env, - jclass /* clazz */, jlong ptr, jint deviceId, jlongArray patternObj, - jint repeat, jint token) { +static void nativeVibrate(JNIEnv* env, jclass /* clazz */, jlong ptr, jint deviceId, + jlongArray patternObj, jintArray amplitudesObj, jint repeat, jint token) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); size_t patternSize = env->GetArrayLength(patternObj); @@ -1630,14 +1631,19 @@ static void nativeVibrate(JNIEnv* env, jlong* patternMillis = static_cast<jlong*>(env->GetPrimitiveArrayCritical( patternObj, nullptr)); - nsecs_t pattern[patternSize]; + jint* amplitudes = static_cast<jint*>(env->GetPrimitiveArrayCritical(amplitudesObj, nullptr)); + + std::vector<VibrationElement> pattern(patternSize); for (size_t i = 0; i < patternSize; i++) { - pattern[i] = max(jlong(0), min(patternMillis[i], - (jlong)(MAX_VIBRATE_PATTERN_DELAY_NSECS / 1000000LL))) * 1000000LL; + jlong duration = + max(min(patternMillis[i], (jlong)MAX_VIBRATE_PATTERN_DELAY_MSECS), (jlong)0); + pattern[i].duration = std::chrono::milliseconds(duration); + pattern[i].channels = {amplitudes[i]}; } env->ReleasePrimitiveArrayCritical(patternObj, patternMillis, JNI_ABORT); + env->ReleasePrimitiveArrayCritical(amplitudesObj, amplitudes, JNI_ABORT); - im->getInputManager()->getReader()->vibrate(deviceId, pattern, patternSize, repeat, token); + im->getInputManager()->getReader()->vibrate(deviceId, pattern, repeat, token); } static void nativeCancelVibrate(JNIEnv* /* env */, @@ -1789,7 +1795,7 @@ static const JNINativeMethod gInputManagerMethods[] = { {"nativeSetShowTouches", "(JZ)V", (void*)nativeSetShowTouches}, {"nativeSetInteractive", "(JZ)V", (void*)nativeSetInteractive}, {"nativeReloadCalibration", "(J)V", (void*)nativeReloadCalibration}, - {"nativeVibrate", "(JI[JII)V", (void*)nativeVibrate}, + {"nativeVibrate", "(JI[J[III)V", (void*)nativeVibrate}, {"nativeCancelVibrate", "(JII)V", (void*)nativeCancelVibrate}, {"nativeReloadKeyboardLayouts", "(J)V", (void*)nativeReloadKeyboardLayouts}, {"nativeReloadDeviceAliases", "(J)V", (void*)nativeReloadDeviceAliases}, diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp index 6140531538a6..91f70729d5b6 100644 --- a/services/core/jni/com_android_server_power_PowerManagerService.cpp +++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp @@ -29,7 +29,6 @@ #include <nativehelper/ScopedUtfChars.h> #include <powermanager/PowerHalController.h> -#include <powermanager/PowerHalLoader.h> #include <limits.h> @@ -49,12 +48,8 @@ #include "com_android_server_power_PowerManagerService.h" using android::String8; -using android::hardware::Return; -using android::hardware::Void; using android::hardware::power::Boost; using android::hardware::power::Mode; -using android::hardware::power::V1_0::Feature; -using android::hardware::power::V1_0::PowerHint; using android::system::suspend::ISuspendControlService; using android::system::suspend::V1_0::ISystemSuspend; using android::system::suspend::V1_0::IWakeLock; @@ -74,18 +69,7 @@ static struct { // ---------------------------------------------------------------------------- static jobject gPowerManagerServiceObj; -static sp<IPowerV1_0> gPowerHalHidlV1_0_ = nullptr; -static sp<IPowerV1_1> gPowerHalHidlV1_1_ = nullptr; -static sp<IPowerAidl> gPowerHalAidl_ = nullptr; -static std::mutex gPowerHalMutex; - -enum class HalVersion { - NONE, - HIDL_1_0, - HIDL_1_1, - AIDL, -}; - +static power::PowerHalController gPowerHalController; static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1]; // Throttling interval for user activity calls. @@ -103,208 +87,19 @@ static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodNa return false; } -// Check validity of current handle to the power HAL service, and connect to it if necessary. -// The caller must be holding gPowerHalMutex. -static HalVersion connectPowerHalLocked() { - static bool gPowerHalHidlExists = true; - static bool gPowerHalAidlExists = true; - if (!gPowerHalHidlExists && !gPowerHalAidlExists) { - return HalVersion::NONE; - } - if (gPowerHalAidlExists) { - if (!gPowerHalAidl_) { - gPowerHalAidl_ = waitForVintfService<IPowerAidl>(); - } - if (gPowerHalAidl_) { - ALOGV("Successfully connected to Power HAL AIDL service."); - return HalVersion::AIDL; - } else { - gPowerHalAidlExists = false; - } - } - if (gPowerHalHidlExists && gPowerHalHidlV1_0_ == nullptr) { - gPowerHalHidlV1_0_ = IPowerV1_0::getService(); - if (gPowerHalHidlV1_0_) { - ALOGV("Successfully connected to Power HAL HIDL 1.0 service."); - // Try cast to powerHAL HIDL V1_1 - gPowerHalHidlV1_1_ = IPowerV1_1::castFrom(gPowerHalHidlV1_0_); - if (gPowerHalHidlV1_1_) { - ALOGV("Successfully connected to Power HAL HIDL 1.1 service."); - } - } else { - ALOGV("Couldn't load power HAL HIDL service"); - gPowerHalHidlExists = false; - return HalVersion::NONE; - } - } - if (gPowerHalHidlV1_1_) { - return HalVersion::HIDL_1_1; - } else if (gPowerHalHidlV1_0_) { - return HalVersion::HIDL_1_0; - } - return HalVersion::NONE; -} - -// Check if a call to a power HAL function failed; if so, log the failure and invalidate the -// current handle to the power HAL service. -bool processPowerHalReturn(bool isOk, const char* functionName) { - if (!isOk) { - ALOGE("%s() failed: power HAL service not available.", functionName); - gPowerHalMutex.lock(); - gPowerHalHidlV1_0_ = nullptr; - gPowerHalHidlV1_1_ = nullptr; - gPowerHalAidl_ = nullptr; - gPowerHalMutex.unlock(); - } - return isOk; -} - -enum class HalSupport { - UNKNOWN = 0, - ON, - OFF, -}; - -static void setPowerBoostWithHandle(sp<IPowerAidl> handle, Boost boost, int32_t durationMs) { - // Android framework only sends boost upto DISPLAY_UPDATE_IMMINENT. - // Need to increase the array size if more boost supported. - static std::array<std::atomic<HalSupport>, - static_cast<int32_t>(Boost::DISPLAY_UPDATE_IMMINENT) + 1> - boostSupportedArray = {HalSupport::UNKNOWN}; - - // Quick return if boost is not supported by HAL - if (boost > Boost::DISPLAY_UPDATE_IMMINENT || - boostSupportedArray[static_cast<int32_t>(boost)] == HalSupport::OFF) { - ALOGV("Skipped setPowerBoost %s because HAL doesn't support it", toString(boost).c_str()); - return; - } - - if (boostSupportedArray[static_cast<int32_t>(boost)] == HalSupport::UNKNOWN) { - bool isSupported = false; - handle->isBoostSupported(boost, &isSupported); - boostSupportedArray[static_cast<int32_t>(boost)] = - isSupported ? HalSupport::ON : HalSupport::OFF; - if (!isSupported) { - ALOGV("Skipped setPowerBoost %s because HAL doesn't support it", - toString(boost).c_str()); - return; - } - } - - auto ret = handle->setBoost(boost, durationMs); - processPowerHalReturn(ret.isOk(), "setPowerBoost"); -} - static void setPowerBoost(Boost boost, int32_t durationMs) { - std::unique_lock<std::mutex> lock(gPowerHalMutex); - if (connectPowerHalLocked() != HalVersion::AIDL) { - ALOGV("Power HAL AIDL not available"); - return; - } - sp<IPowerAidl> handle = gPowerHalAidl_; - lock.unlock(); - setPowerBoostWithHandle(handle, boost, durationMs); -} - -static bool setPowerModeWithHandle(sp<IPowerAidl> handle, Mode mode, bool enabled) { - // Android framework only sends mode upto DISPLAY_INACTIVE. - // Need to increase the array if more mode supported. - static std::array<std::atomic<HalSupport>, static_cast<int32_t>(Mode::DISPLAY_INACTIVE) + 1> - modeSupportedArray = {HalSupport::UNKNOWN}; - - // Quick return if mode is not supported by HAL - if (mode > Mode::DISPLAY_INACTIVE || - modeSupportedArray[static_cast<int32_t>(mode)] == HalSupport::OFF) { - ALOGV("Skipped setPowerMode %s because HAL doesn't support it", toString(mode).c_str()); - return false; - } - - if (modeSupportedArray[static_cast<int32_t>(mode)] == HalSupport::UNKNOWN) { - bool isSupported = false; - handle->isModeSupported(mode, &isSupported); - modeSupportedArray[static_cast<int32_t>(mode)] = - isSupported ? HalSupport::ON : HalSupport::OFF; - if (!isSupported) { - ALOGV("Skipped setPowerMode %s because HAL doesn't support it", toString(mode).c_str()); - return false; - } - } - - auto ret = handle->setMode(mode, enabled); - processPowerHalReturn(ret.isOk(), "setPowerMode"); - return ret.isOk(); + gPowerHalController.setBoost(boost, durationMs); + SurfaceComposerClient::notifyPowerBoost(static_cast<int32_t>(boost)); } static bool setPowerMode(Mode mode, bool enabled) { - std::unique_lock<std::mutex> lock(gPowerHalMutex); - if (connectPowerHalLocked() != HalVersion::AIDL) { - ALOGV("Power HAL AIDL not available"); - return false; - } - sp<IPowerAidl> handle = gPowerHalAidl_; - lock.unlock(); - return setPowerModeWithHandle(handle, mode, enabled); -} - -static void sendPowerHint(PowerHint hintId, uint32_t data) { - std::unique_lock<std::mutex> lock(gPowerHalMutex); - switch (connectPowerHalLocked()) { - case HalVersion::NONE: - return; - case HalVersion::HIDL_1_0: { - sp<IPowerV1_0> handle = gPowerHalHidlV1_0_; - lock.unlock(); - auto ret = handle->powerHint(hintId, data); - processPowerHalReturn(ret.isOk(), "powerHint"); - break; - } - case HalVersion::HIDL_1_1: { - sp<IPowerV1_1> handle = gPowerHalHidlV1_1_; - lock.unlock(); - auto ret = handle->powerHintAsync(hintId, data); - processPowerHalReturn(ret.isOk(), "powerHintAsync"); - break; - } - case HalVersion::AIDL: { - if (hintId == PowerHint::INTERACTION) { - sp<IPowerAidl> handle = gPowerHalAidl_; - lock.unlock(); - setPowerBoostWithHandle(handle, Boost::INTERACTION, data); - break; - } else if (hintId == PowerHint::LAUNCH) { - sp<IPowerAidl> handle = gPowerHalAidl_; - lock.unlock(); - setPowerModeWithHandle(handle, Mode::LAUNCH, static_cast<bool>(data)); - break; - } else if (hintId == PowerHint::LOW_POWER) { - sp<IPowerAidl> handle = gPowerHalAidl_; - lock.unlock(); - setPowerModeWithHandle(handle, Mode::LOW_POWER, static_cast<bool>(data)); - break; - } else if (hintId == PowerHint::SUSTAINED_PERFORMANCE) { - sp<IPowerAidl> handle = gPowerHalAidl_; - lock.unlock(); - setPowerModeWithHandle(handle, Mode::SUSTAINED_PERFORMANCE, - static_cast<bool>(data)); - break; - } else if (hintId == PowerHint::VR_MODE) { - sp<IPowerAidl> handle = gPowerHalAidl_; - lock.unlock(); - setPowerModeWithHandle(handle, Mode::VR, static_cast<bool>(data)); - break; - } else { - ALOGE("Unsupported power hint: %s.", toString(hintId).c_str()); - return; - } - } - default: { - ALOGE("Unknown power HAL state"); - return; - } - } - if (hintId == PowerHint::INTERACTION) { - SurfaceComposerClient::notifyPowerBoost(static_cast<int32_t>(Boost::INTERACTION)); + android::base::Timer t; + auto result = gPowerHalController.setMode(mode, enabled); + if (mode == Mode::INTERACTIVE && t.duration() > 20ms) { + ALOGD("Excessive delay in setting interactive mode to %s while turning screen %s", + enabled ? "true" : "false", enabled ? "on" : "off"); } + return result == power::HalResult::SUCCESSFUL; } void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) { @@ -324,7 +119,7 @@ void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t gLastEventTime[eventType] = eventTime; // Tell the power HAL when user activity occurs. - sendPowerHint(PowerHint::INTERACTION, 0); + setPowerBoost(Boost::INTERACTION, 0); } JNIEnv* env = AndroidRuntime::getJNIEnv(); @@ -391,10 +186,7 @@ void disableAutoSuspend() { static void nativeInit(JNIEnv* env, jobject obj) { gPowerManagerServiceObj = env->NewGlobalRef(obj); - - gPowerHalMutex.lock(); - connectPowerHalLocked(); - gPowerHalMutex.unlock(); + gPowerHalController.init(); } static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring nameStr) { @@ -407,38 +199,6 @@ static void nativeReleaseSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring release_wake_lock(name.c_str()); } -static void nativeSetInteractive(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) { - std::unique_lock<std::mutex> lock(gPowerHalMutex); - switch (connectPowerHalLocked()) { - case HalVersion::NONE: - return; - case HalVersion::HIDL_1_0: - FALLTHROUGH_INTENDED; - case HalVersion::HIDL_1_1: { - android::base::Timer t; - sp<IPowerV1_0> handle = gPowerHalHidlV1_0_; - lock.unlock(); - auto ret = handle->setInteractive(enable); - processPowerHalReturn(ret.isOk(), "setInteractive"); - if (t.duration() > 20ms) { - ALOGD("Excessive delay in setInteractive(%s) while turning screen %s", - enable ? "true" : "false", enable ? "on" : "off"); - } - return; - } - case HalVersion::AIDL: { - sp<IPowerAidl> handle = gPowerHalAidl_; - lock.unlock(); - setPowerModeWithHandle(handle, Mode::INTERACTIVE, enable); - return; - } - default: { - ALOGE("Unknown power HAL state"); - return; - } - } -} - static void nativeSetAutoSuspend(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) { if (enable) { android::base::Timer t; @@ -455,10 +215,6 @@ static void nativeSetAutoSuspend(JNIEnv* /* env */, jclass /* clazz */, jboolean } } -static void nativeSendPowerHint(JNIEnv* /* env */, jclass /* clazz */, jint hintId, jint data) { - sendPowerHint(static_cast<PowerHint>(hintId), data); -} - static void nativeSetPowerBoost(JNIEnv* /* env */, jclass /* clazz */, jint boost, jint durationMs) { setPowerBoost(static_cast<Boost>(boost), durationMs); @@ -469,33 +225,6 @@ static jboolean nativeSetPowerMode(JNIEnv* /* env */, jclass /* clazz */, jint m return setPowerMode(static_cast<Mode>(mode), enabled); } -static void nativeSetFeature(JNIEnv* /* env */, jclass /* clazz */, jint featureId, jint data) { - std::unique_lock<std::mutex> lock(gPowerHalMutex); - switch (connectPowerHalLocked()) { - case HalVersion::NONE: - return; - case HalVersion::HIDL_1_0: - FALLTHROUGH_INTENDED; - case HalVersion::HIDL_1_1: { - sp<IPowerV1_0> handle = gPowerHalHidlV1_0_; - lock.unlock(); - auto ret = handle->setFeature(static_cast<Feature>(featureId), static_cast<bool>(data)); - processPowerHalReturn(ret.isOk(), "setFeature"); - return; - } - case HalVersion::AIDL: { - sp<IPowerAidl> handle = gPowerHalAidl_; - lock.unlock(); - setPowerModeWithHandle(handle, Mode::DOUBLE_TAP_TO_WAKE, static_cast<bool>(data)); - return; - } - default: { - ALOGE("Unknown power HAL state"); - return; - } - } -} - static bool nativeForceSuspend(JNIEnv* /* env */, jclass /* clazz */) { bool retval = false; getSuspendControl()->forceSuspend(&retval); @@ -512,12 +241,9 @@ static const JNINativeMethod gPowerManagerServiceMethods[] = { {"nativeForceSuspend", "()Z", (void*)nativeForceSuspend}, {"nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V", (void*)nativeReleaseSuspendBlocker}, - {"nativeSetInteractive", "(Z)V", (void*)nativeSetInteractive}, {"nativeSetAutoSuspend", "(Z)V", (void*)nativeSetAutoSuspend}, - {"nativeSendPowerHint", "(II)V", (void*)nativeSendPowerHint}, {"nativeSetPowerBoost", "(II)V", (void*)nativeSetPowerBoost}, {"nativeSetPowerMode", "(IZ)Z", (void*)nativeSetPowerMode}, - {"nativeSetFeature", "(II)V", (void*)nativeSetFeature}, }; #define FIND_CLASS(var, className) \ diff --git a/services/robotests/Android.bp b/services/robotests/Android.bp index 25ab5d36169e..1ae2aec90ba3 100644 --- a/services/robotests/Android.bp +++ b/services/robotests/Android.bp @@ -43,6 +43,7 @@ android_robolectric_test { // Include the testing libraries libs: [ "platform-test-annotations", + "services.backup", "testng", ], static_libs: [ diff --git a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java index dcd7af31af93..8ccaeddc8355 100644 --- a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java @@ -18,7 +18,7 @@ package com.android.server; import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT; import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE; -import static com.android.server.AppStateTracker.TARGET_OP; +import static com.android.server.AppStateTrackerImpl.TARGET_OP; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -68,7 +68,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; -import com.android.server.AppStateTracker.Listener; +import com.android.server.AppStateTrackerImpl.Listener; import com.android.server.usage.AppStandbyInternal; import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener; @@ -91,7 +91,7 @@ import java.util.concurrent.TimeUnit; import java.util.function.Consumer; /** - * Tests for {@link AppStateTracker} + * Tests for {@link AppStateTrackerImpl} * * Run with: atest com.android.server.AppStateTrackerTest */ @@ -100,7 +100,7 @@ import java.util.function.Consumer; @RunWith(AndroidJUnit4.class) public class AppStateTrackerTest { - private class AppStateTrackerTestable extends AppStateTracker { + private class AppStateTrackerTestable extends AppStateTrackerImpl { AppStateTrackerTestable() { super(mMockContext, Looper.getMainLooper()); } @@ -722,7 +722,7 @@ public class AppStateTrackerTest { AppOpsManager.MODE_IGNORED, Collections.emptyMap())); entries.add(new OpEntry( - AppStateTracker.TARGET_OP, + AppStateTrackerImpl.TARGET_OP, AppOpsManager.MODE_IGNORED, Collections.emptyMap())); @@ -731,7 +731,7 @@ public class AppStateTrackerTest { //-------------------------------------------------- entries = new ArrayList<>(); entries.add(new OpEntry( - AppStateTracker.TARGET_OP, + AppStateTrackerImpl.TARGET_OP, AppOpsManager.MODE_IGNORED, Collections.emptyMap())); @@ -740,7 +740,7 @@ public class AppStateTrackerTest { //-------------------------------------------------- entries = new ArrayList<>(); entries.add(new OpEntry( - AppStateTracker.TARGET_OP, + AppStateTrackerImpl.TARGET_OP, AppOpsManager.MODE_ALLOWED, Collections.emptyMap())); @@ -749,7 +749,7 @@ public class AppStateTrackerTest { //-------------------------------------------------- entries = new ArrayList<>(); entries.add(new OpEntry( - AppStateTracker.TARGET_OP, + AppStateTrackerImpl.TARGET_OP, AppOpsManager.MODE_IGNORED, Collections.emptyMap())); entries.add(new OpEntry( @@ -1266,7 +1266,7 @@ public class AppStateTrackerTest { private void checkAnyAppIdUnwhitelisted(int[] prevArray, int[] newArray, boolean expected) { assertEquals("Input: " + Arrays.toString(prevArray) + " " + Arrays.toString(newArray), - expected, AppStateTracker.isAnyAppIdUnwhitelisted(prevArray, newArray)); + expected, AppStateTrackerImpl.isAnyAppIdUnwhitelisted(prevArray, newArray)); // Also test isAnyAppIdUnwhitelistedSlow. assertEquals("Input: " + Arrays.toString(prevArray) + " " + Arrays.toString(newArray), @@ -1298,7 +1298,7 @@ public class AppStateTrackerTest { final int[] array2 = makeRandomArray(); final boolean expected = isAnyAppIdUnwhitelistedSlow(array1, array2); - final boolean actual = AppStateTracker.isAnyAppIdUnwhitelisted(array1, array2); + final boolean actual = AppStateTrackerImpl.isAnyAppIdUnwhitelisted(array1, array2); assertEquals("Input: " + Arrays.toString(array1) + " " + Arrays.toString(array2), expected, actual); diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java index 9251031eb5cd..6cd083e11754 100644 --- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java @@ -164,7 +164,7 @@ public class DeviceIdleControllerTest { } @Override - AppStateTracker getAppStateTracker(Context ctx, Looper loop) { + AppStateTrackerImpl getAppStateTracker(Context ctx, Looper loop) { return mAppStateTracker; } @@ -260,7 +260,7 @@ public class DeviceIdleControllerTest { } } - private class AppStateTrackerForTest extends AppStateTracker { + private class AppStateTrackerForTest extends AppStateTrackerImpl { AppStateTrackerForTest(Context ctx, Looper looper) { super(ctx, looper); } diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java index 6c9b61822c0b..77232dc4644c 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java @@ -89,6 +89,7 @@ import com.android.dx.mockito.inline.extended.MockedVoidMethod; import com.android.internal.annotations.GuardedBy; import com.android.server.AlarmManagerInternal; import com.android.server.AppStateTracker; +import com.android.server.AppStateTrackerImpl; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.usage.AppStandbyInternal; @@ -131,7 +132,7 @@ public class AlarmManagerServiceTest { @Mock private ActivityManagerInternal mActivityManagerInternal; @Mock - private AppStateTracker mAppStateTracker; + private AppStateTrackerImpl mAppStateTracker; @Mock private AlarmManagerService.ClockReceiver mClockReceiver; @Mock @@ -769,8 +770,8 @@ public class AlarmManagerServiceTest { @Test public void testAlarmRestrictedInBatterSaver() throws Exception { - final ArgumentCaptor<AppStateTracker.Listener> listenerArgumentCaptor = - ArgumentCaptor.forClass(AppStateTracker.Listener.class); + final ArgumentCaptor<AppStateTrackerImpl.Listener> listenerArgumentCaptor = + ArgumentCaptor.forClass(AppStateTrackerImpl.Listener.class); verify(mAppStateTracker).addListener(listenerArgumentCaptor.capture()); final PendingIntent alarmPi = getNewMockPendingIntent(); @@ -795,10 +796,10 @@ public class AlarmManagerServiceTest { @Test public void alarmsRemovedOnAppStartModeDisabled() { - final ArgumentCaptor<AppStateTracker.Listener> listenerArgumentCaptor = - ArgumentCaptor.forClass(AppStateTracker.Listener.class); + final ArgumentCaptor<AppStateTrackerImpl.Listener> listenerArgumentCaptor = + ArgumentCaptor.forClass(AppStateTrackerImpl.Listener.class); verify(mAppStateTracker).addListener(listenerArgumentCaptor.capture()); - final AppStateTracker.Listener listener = listenerArgumentCaptor.getValue(); + final AppStateTrackerImpl.Listener listener = listenerArgumentCaptor.getValue(); final PendingIntent alarmPi1 = getNewMockPendingIntent(); final PendingIntent alarmPi2 = getNewMockPendingIntent(); diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java index a462dc309c24..043ca9e02873 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java @@ -55,6 +55,7 @@ import android.os.ServiceManager; import android.os.SystemClock; import com.android.server.AppStateTracker; +import com.android.server.AppStateTrackerImpl; import com.android.server.DeviceIdleInternal; import com.android.server.LocalServices; import com.android.server.SystemServiceManager; @@ -84,7 +85,7 @@ public class JobSchedulerServiceTest { private class TestJobSchedulerService extends JobSchedulerService { TestJobSchedulerService(Context context) { super(context); - mAppStateTracker = mock(AppStateTracker.class); + mAppStateTracker = mock(AppStateTrackerImpl.class); } @Override @@ -112,7 +113,7 @@ public class JobSchedulerServiceTest { .when(() -> LocalServices.getService(UsageStatsManagerInternal.class)); when(mContext.getString(anyInt())).thenReturn("some_test_string"); // Called in BackgroundJobsController constructor. - doReturn(mock(AppStateTracker.class)) + doReturn(mock(AppStateTrackerImpl.class)) .when(() -> LocalServices.getService(AppStateTracker.class)); // Called in BatteryController constructor. doReturn(mock(BatteryManagerInternal.class)) diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java index 5d041b7c5757..3614763fecab 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java @@ -71,7 +71,6 @@ public class TimeControllerTest { private static final String SOURCE_PACKAGE = "com.android.frameworks.mockingservicestests"; private static final int SOURCE_USER_ID = 0; - private TimeController.TcConstants mConstants; private TimeController mTimeController; private MockitoSession mMockingSession; @@ -111,7 +110,6 @@ public class TimeControllerTest { // Initialize real objects. mTimeController = new TimeController(mJobSchedulerService); - mConstants = mTimeController.getTcConstants(); spyOn(mTimeController); } @@ -530,46 +528,6 @@ public class TimeControllerTest { } @Test - public void testJobDelayWakeupAlarmToggling() { - final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); - - JobStatus job = createJobStatus( - "testMaybeStartTrackingJobLocked_DeadlineReverseOrder", - createJob().setMinimumLatency(HOUR_IN_MILLIS)); - - doReturn(true).when(mTimeController) - .wouldBeReadyWithConstraintLocked(eq(job), anyInt()); - - // Starting off with using a wakeup alarm. - mConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY = false; - InOrder inOrder = inOrder(mAlarmManager); - - mTimeController.maybeStartTrackingJobLocked(job, null); - inOrder.verify(mAlarmManager, times(1)) - .set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(now + HOUR_IN_MILLIS), anyLong(), - anyLong(), - eq(TAG_DELAY), any(), any(), any()); - - // Use a non wakeup alarm. - mConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY = true; - - mTimeController.maybeStartTrackingJobLocked(job, null); - inOrder.verify(mAlarmManager, times(1)) - .set(eq(AlarmManager.ELAPSED_REALTIME), eq(now + HOUR_IN_MILLIS), anyLong(), - anyLong(), eq(TAG_DELAY), - any(), any(), any()); - - // Back off, use a wakeup alarm. - mConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY = false; - - mTimeController.maybeStartTrackingJobLocked(job, null); - inOrder.verify(mAlarmManager, times(1)) - .set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(now + HOUR_IN_MILLIS), anyLong(), - anyLong(), - eq(TAG_DELAY), any(), any(), any()); - } - - @Test public void testCheckExpiredDeadlinesAndResetAlarm_AllReady() { doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt()); diff --git a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java index 4fbc587c8a87..6f37ff5ef329 100644 --- a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java @@ -153,6 +153,20 @@ public class GestureLauncherServiceTest { } @Test + public void testIsPanicButtonGestureEnabled_settingDisabled() { + withPanicGestureEnabledSettingValue(false); + assertFalse(mGestureLauncherService.isPanicButtonGestureEnabled( + mContext, FAKE_USER_ID)); + } + + @Test + public void testIsPanicButtonGestureEnabled_settingEnabled() { + withPanicGestureEnabledSettingValue(true); + assertTrue(mGestureLauncherService.isPanicButtonGestureEnabled( + mContext, FAKE_USER_ID)); + } + + @Test public void testHandleCameraLaunchGesture_userSetupComplete() { withUserSetupCompleteValue(true); @@ -882,6 +896,14 @@ public class GestureLauncherServiceTest { UserHandle.USER_CURRENT); } + private void withPanicGestureEnabledSettingValue(boolean enable) { + Settings.Secure.putIntForUser( + mContentResolver, + Settings.Secure.PANIC_GESTURE_ENABLED, + enable ? 1 : 0, + UserHandle.USER_CURRENT); + } + private void withUserSetupCompleteValue(boolean userSetupComplete) { int userSetupCompleteValue = userSetupComplete ? 1 : 0; Settings.Secure.putIntForUser( diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java index 96690100fc03..419fb14df340 100644 --- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java @@ -369,9 +369,11 @@ public class PowerManagerServiceTest { } @Test - public void testCreateService_initializesNativeService() { + public void testCreateService_initializesNativeServiceAndSetsPowerModes() { PowerManagerService service = createService(); verify(mNativeWrapperMock).nativeInit(same(service)); + verify(mNativeWrapperMock).nativeSetPowerMode(eq(Mode.INTERACTIVE), eq(true)); + verify(mNativeWrapperMock).nativeSetPowerMode(eq(Mode.DOUBLE_TAP_TO_WAKE), eq(false)); } @Test diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java index 76239fcd9385..72d6caf1a5be 100644 --- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java +++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java @@ -33,6 +33,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.server.power.batterysaver.BatterySavingStats.BatterySaverState; import com.android.server.power.batterysaver.BatterySavingStats.DozeState; import com.android.server.power.batterysaver.BatterySavingStats.InteractiveState; +import com.android.server.power.batterysaver.BatterySavingStats.PlugState; import org.junit.Test; import org.junit.runner.RunWith; @@ -118,7 +119,8 @@ public class BatterySavingStatsTest { target.transitionState( BatterySaverState.OFF, InteractiveState.INTERACTIVE, - DozeState.NOT_DOZING); + DozeState.NOT_DOZING, + PlugState.UNPLUGGED); target.advanceClock(4); target.drainBattery(100); @@ -126,7 +128,8 @@ public class BatterySavingStatsTest { target.transitionState( BatterySaverState.OFF, InteractiveState.NON_INTERACTIVE, - DozeState.NOT_DOZING); + DozeState.NOT_DOZING, + PlugState.UNPLUGGED); target.advanceClock(2); target.drainBattery(500); @@ -134,7 +137,8 @@ public class BatterySavingStatsTest { target.transitionState( BatterySaverState.OFF, InteractiveState.INTERACTIVE, - DozeState.NOT_DOZING); + DozeState.NOT_DOZING, + PlugState.UNPLUGGED); target.advanceClock(4); target.drainBattery(100); @@ -142,7 +146,8 @@ public class BatterySavingStatsTest { target.transitionState( BatterySaverState.OFF, InteractiveState.NON_INTERACTIVE, - DozeState.NOT_DOZING); + DozeState.NOT_DOZING, + PlugState.UNPLUGGED); target.advanceClock(2); target.drainBattery(500); @@ -150,7 +155,8 @@ public class BatterySavingStatsTest { target.transitionState( BatterySaverState.OFF, InteractiveState.INTERACTIVE, - DozeState.NOT_DOZING); + DozeState.NOT_DOZING, + PlugState.UNPLUGGED); target.advanceClock(3); target.drainBattery(100); @@ -158,7 +164,8 @@ public class BatterySavingStatsTest { target.transitionState( BatterySaverState.OFF, InteractiveState.NON_INTERACTIVE, - DozeState.LIGHT); + DozeState.LIGHT, + PlugState.UNPLUGGED); target.advanceClock(5); target.drainBattery(100); @@ -166,7 +173,8 @@ public class BatterySavingStatsTest { target.transitionState( BatterySaverState.OFF, InteractiveState.NON_INTERACTIVE, - DozeState.DEEP); + DozeState.DEEP, + PlugState.UNPLUGGED); target.advanceClock(1); target.drainBattery(200); @@ -174,7 +182,8 @@ public class BatterySavingStatsTest { target.transitionState( BatterySaverState.ON, InteractiveState.INTERACTIVE, - DozeState.NOT_DOZING); + DozeState.NOT_DOZING, + PlugState.UNPLUGGED); target.advanceClock(1); target.drainBattery(300); @@ -182,7 +191,8 @@ public class BatterySavingStatsTest { target.transitionState( BatterySaverState.OFF, InteractiveState.INTERACTIVE, - DozeState.NOT_DOZING); + DozeState.NOT_DOZING, + PlugState.UNPLUGGED); target.advanceClock(3); target.drainBattery(500); @@ -190,12 +200,17 @@ public class BatterySavingStatsTest { target.transitionState( BatterySaverState.ON, InteractiveState.INTERACTIVE, - DozeState.NOT_DOZING); + DozeState.NOT_DOZING, + PlugState.UNPLUGGED); target.advanceClock(3); target.drainBattery(500); - target.startCharging(); + target.transitionState( + BatterySaverState.ON, + InteractiveState.INTERACTIVE, + DozeState.NOT_DOZING, + PlugState.PLUGGED); target.advanceClock(5); target.drainBattery(1000); @@ -203,28 +218,34 @@ public class BatterySavingStatsTest { target.transitionState( BatterySaverState.ON, InteractiveState.INTERACTIVE, - DozeState.NOT_DOZING); + DozeState.NOT_DOZING, + PlugState.UNPLUGGED); target.advanceClock(5); target.drainBattery(100); - target.startCharging(); + target.transitionState( + BatterySaverState.ON, + InteractiveState.INTERACTIVE, + DozeState.NOT_DOZING, + PlugState.PLUGGED); target.assertDumpable(); assertEquals( - "BS=0,I=0,D=0:{4m,1000,15000.00uA/H,1500.00%}\n" + - "BS=1,I=0,D=0:{0m,0,0.00uA/H,0.00%}\n" + - "BS=0,I=1,D=0:{14m,800,3428.57uA/H,342.86%}\n" + - "BS=1,I=1,D=0:{9m,900,6000.00uA/H,600.00%}\n" + - "BS=0,I=0,D=1:{5m,100,1200.00uA/H,120.00%}\n" + - "BS=1,I=0,D=1:{0m,0,0.00uA/H,0.00%}\n" + - "BS=0,I=1,D=1:{0m,0,0.00uA/H,0.00%}\n" + - "BS=1,I=1,D=1:{0m,0,0.00uA/H,0.00%}\n" + - "BS=0,I=0,D=2:{1m,200,12000.00uA/H,1200.00%}\n" + - "BS=1,I=0,D=2:{0m,0,0.00uA/H,0.00%}\n" + - "BS=0,I=1,D=2:{0m,0,0.00uA/H,0.00%}\n" + - "BS=1,I=1,D=2:{0m,0,0.00uA/H,0.00%}", + "BS=0,I=0,D=0,P=0:{4m,1000,15000.00uA/H,1500.00%}\n" + + "BS=1,I=0,D=0,P=0:{0m,0,0.00uA/H,0.00%}\n" + + "BS=0,I=1,D=0,P=0:{14m,800,3428.57uA/H,342.86%}\n" + + "BS=1,I=1,D=0,P=0:{9m,900,6000.00uA/H,600.00%}\n" + + "BS=0,I=0,D=1,P=0:{5m,100,1200.00uA/H,120.00%}\n" + + "BS=1,I=0,D=1,P=0:{0m,0,0.00uA/H,0.00%}\n" + + "BS=0,I=1,D=1,P=0:{0m,0,0.00uA/H,0.00%}\n" + + "BS=1,I=1,D=1,P=0:{0m,0,0.00uA/H,0.00%}\n" + + "BS=0,I=0,D=2,P=0:{1m,200,12000.00uA/H,1200.00%}\n" + + "BS=1,I=0,D=2,P=0:{0m,0,0.00uA/H,0.00%}\n" + + "BS=0,I=1,D=2,P=0:{0m,0,0.00uA/H,0.00%}\n" + + "BS=1,I=1,D=2,P=0:{0m,0,0.00uA/H,0.00%}\n" + + "BS=1,I=1,D=0,P=1:{5m,1000,12000.00uA/H,1200.00%}", target.toDebugString()); } @@ -242,7 +263,8 @@ public class BatterySavingStatsTest { target.transitionState( BatterySaverState.OFF, InteractiveState.INTERACTIVE, - DozeState.NOT_DOZING); + DozeState.NOT_DOZING, + PlugState.UNPLUGGED); verify(mMetricsLogger, times(0)).count(anyString(), anyInt()); @@ -253,7 +275,8 @@ public class BatterySavingStatsTest { target.transitionState( BatterySaverState.OFF, InteractiveState.NON_INTERACTIVE, - DozeState.NOT_DOZING); + DozeState.NOT_DOZING, + PlugState.UNPLUGGED); assertLog(); @@ -264,7 +287,8 @@ public class BatterySavingStatsTest { target.transitionState( BatterySaverState.OFF, InteractiveState.NON_INTERACTIVE, - DozeState.DEEP); + DozeState.DEEP, + PlugState.UNPLUGGED); target.advanceClock(1); target.drainBattery(2000); @@ -274,7 +298,8 @@ public class BatterySavingStatsTest { target.transitionState( BatterySaverState.OFF, InteractiveState.NON_INTERACTIVE, - DozeState.LIGHT); + DozeState.LIGHT, + PlugState.UNPLUGGED); target.advanceClock(1); target.drainBattery(2000); @@ -284,7 +309,8 @@ public class BatterySavingStatsTest { target.transitionState( BatterySaverState.ON, InteractiveState.INTERACTIVE, - DozeState.NOT_DOZING); + DozeState.NOT_DOZING, + PlugState.UNPLUGGED); assertLog(); @@ -292,7 +318,11 @@ public class BatterySavingStatsTest { target.drainBattery(10000); reset(mMetricsLogger); - target.startCharging(); + target.transitionState( + BatterySaverState.ON, + InteractiveState.INTERACTIVE, + DozeState.NOT_DOZING, + PlugState.PLUGGED); assertLog(); @@ -303,14 +333,19 @@ public class BatterySavingStatsTest { target.transitionState( BatterySaverState.ON, InteractiveState.NON_INTERACTIVE, - DozeState.NOT_DOZING); + DozeState.NOT_DOZING, + PlugState.UNPLUGGED); verify(mMetricsLogger, times(0)).count(anyString(), anyInt()); target.advanceClock(1); target.drainBattery(2000); - target.startCharging(); + target.transitionState( + BatterySaverState.ON, + InteractiveState.NON_INTERACTIVE, + DozeState.NOT_DOZING, + PlugState.PLUGGED); assertLog(); } diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java index 971d2e28b14e..153634548c17 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java @@ -21,12 +21,16 @@ import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSE import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.app.timezonedetector.ITimeZoneConfigurationListener; @@ -158,10 +162,24 @@ public class TimeZoneDetectorServiceTest { } } + @Test(expected = SecurityException.class) + public void testRemoveConfigurationListener_withoutPermission() { + doThrow(new SecurityException("Mock")) + .when(mMockContext).enforceCallingPermission(anyString(), any()); + + ITimeZoneConfigurationListener mockListener = mock(ITimeZoneConfigurationListener.class); + try { + mTimeZoneDetectorService.removeConfigurationListener(mockListener); + fail(); + } finally { + verify(mMockContext).enforceCallingPermission( + eq(android.Manifest.permission.WRITE_SECURE_SETTINGS), + anyString()); + } + } + @Test public void testConfigurationChangeListenerRegistrationAndCallbacks() throws Exception { - doNothing().when(mMockContext).enforceCallingPermission(anyString(), any()); - TimeZoneConfiguration autoDetectDisabledConfiguration = createTimeZoneConfiguration(false /* autoDetectionEnabled */); @@ -169,22 +187,69 @@ public class TimeZoneDetectorServiceTest { IBinder mockListenerBinder = mock(IBinder.class); ITimeZoneConfigurationListener mockListener = mock(ITimeZoneConfigurationListener.class); - when(mockListener.asBinder()).thenReturn(mockListenerBinder); - mTimeZoneDetectorService.addConfigurationListener(mockListener); + { + doNothing().when(mMockContext).enforceCallingPermission(anyString(), any()); + when(mockListener.asBinder()).thenReturn(mockListenerBinder); - verify(mMockContext).enforceCallingPermission( - eq(android.Manifest.permission.WRITE_SECURE_SETTINGS), - anyString()); - verify(mockListenerBinder).linkToDeath(any(), eq(0)); + mTimeZoneDetectorService.addConfigurationListener(mockListener); - // Simulate the configuration being changed and verify the mockListener was notified. - TimeZoneConfiguration autoDetectEnabledConfiguration = - createTimeZoneConfiguration(true /* autoDetectionEnabled */); - mFakeTimeZoneDetectorStrategy.updateConfiguration( - ARBITRARY_USER_ID, autoDetectEnabledConfiguration); + verify(mMockContext).enforceCallingPermission( + eq(android.Manifest.permission.WRITE_SECURE_SETTINGS), + anyString()); + verify(mockListener).asBinder(); + verify(mockListenerBinder).linkToDeath(any(), anyInt()); + verifyNoMoreInteractions(mockListenerBinder, mockListener, mMockContext); + reset(mockListenerBinder, mockListener, mMockContext); + } + + { + doNothing().when(mMockContext).enforceCallingPermission(anyString(), any()); + + // Simulate the configuration being changed and verify the mockListener was notified. + TimeZoneConfiguration autoDetectEnabledConfiguration = + createTimeZoneConfiguration(true /* autoDetectionEnabled */); + + mTimeZoneDetectorService.updateConfiguration(autoDetectEnabledConfiguration); + + verify(mMockContext).enforceCallingPermission( + eq(android.Manifest.permission.WRITE_SECURE_SETTINGS), + anyString()); + verify(mockListener).onChange(autoDetectEnabledConfiguration); + verifyNoMoreInteractions(mockListenerBinder, mockListener, mMockContext); + reset(mockListenerBinder, mockListener, mMockContext); + } + + { + doNothing().when(mMockContext).enforceCallingPermission(anyString(), any()); + when(mockListener.asBinder()).thenReturn(mockListenerBinder); + when(mockListenerBinder.unlinkToDeath(any(), anyInt())).thenReturn(true); + + // Now remove the listener, change the config again, and verify the listener is not + // called. + mTimeZoneDetectorService.removeConfigurationListener(mockListener); - verify(mockListener).onChange(autoDetectEnabledConfiguration); + verify(mMockContext).enforceCallingPermission( + eq(android.Manifest.permission.WRITE_SECURE_SETTINGS), + anyString()); + verify(mockListener).asBinder(); + verify(mockListenerBinder).unlinkToDeath(any(), eq(0)); + verifyNoMoreInteractions(mockListenerBinder, mockListener, mMockContext); + reset(mockListenerBinder, mockListener, mMockContext); + } + + { + doNothing().when(mMockContext).enforceCallingPermission(anyString(), any()); + + mTimeZoneDetectorService.updateConfiguration(autoDetectDisabledConfiguration); + + verify(mMockContext).enforceCallingPermission( + eq(android.Manifest.permission.WRITE_SECURE_SETTINGS), + anyString()); + verify(mockListener, never()).onChange(any()); + verifyNoMoreInteractions(mockListenerBinder, mockListener, mMockContext); + reset(mockListenerBinder, mockListener, mMockContext); + } } @Test(expected = SecurityException.class) diff --git a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java index 62b6a65cc6cb..614949c91b9a 100644 --- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java @@ -43,11 +43,19 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import android.content.ClipData; import android.content.Intent; import android.content.pm.ProviderInfo; import android.net.Uri; +import android.os.UserHandle; import android.util.ArraySet; import androidx.test.InstrumentationRegistry; @@ -62,6 +70,12 @@ public class UriGrantsManagerServiceTest { private UriGrantsMockContext mContext; private UriGrantsManagerInternal mService; + // we expect the following only during grant if a grant is expected + private void verifyNoVisibilityGrant() { + verify(mContext.mPmInternal, never()) + .grantImplicitAccess(anyInt(), any(), anyInt(), anyInt(), anyBoolean()); + } + @Before public void setUp() throws Exception { mContext = new UriGrantsMockContext(InstrumentationRegistry.getContext()); @@ -83,6 +97,7 @@ public class UriGrantsManagerServiceTest { assertEquals(UID_PRIMARY_SOCIAL, needed.targetUid); assertEquals(FLAG_READ, needed.flags); assertEquals(asSet(expectedGrant), needed.uris); + verifyNoVisibilityGrant(); } /** @@ -100,6 +115,7 @@ public class UriGrantsManagerServiceTest { assertEquals(UID_SECONDARY_SOCIAL, needed.targetUid); assertEquals(FLAG_READ, needed.flags); assertEquals(asSet(expectedGrant), needed.uris); + verifyNoVisibilityGrant(); } /** @@ -111,6 +127,8 @@ public class UriGrantsManagerServiceTest { final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent( intent, UID_PRIMARY_PUBLIC, PKG_SOCIAL, USER_PRIMARY); assertNull(needed); + verify(mContext.mPmInternal).grantImplicitAccess(eq(USER_PRIMARY), isNull(), eq( + UserHandle.getAppId(UID_PRIMARY_SOCIAL)), eq(UID_PRIMARY_PUBLIC), eq(false)); } /** @@ -128,6 +146,7 @@ public class UriGrantsManagerServiceTest { assertEquals(UID_SECONDARY_SOCIAL, needed.targetUid); assertEquals(FLAG_READ, needed.flags); assertEquals(asSet(expectedGrant), needed.uris); + verifyNoVisibilityGrant(); } /** diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java index e3bb1b6ca9f3..c60abe8d51d1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java @@ -65,9 +65,9 @@ public class ActivityDisplayTests extends ActivityTestsBase { // Create a stack at bottom. final TaskDisplayArea taskDisplayAreas = mRootWindowContainer.getDefaultDisplay().getDefaultTaskDisplayArea(); - final ActivityStack stack = + final Task stack = new StackBuilder(mRootWindowContainer).setOnTop(!ON_TOP).build(); - final ActivityStack prevFocusedStack = taskDisplayAreas.getFocusedStack(); + final Task prevFocusedStack = taskDisplayAreas.getFocusedStack(); stack.moveToFront("moveStackToFront"); // After moving the stack to front, the previous focused should be the last focused. @@ -86,7 +86,7 @@ public class ActivityDisplayTests extends ActivityTestsBase { @Test public void testFullscreenStackCanBeFocusedWhenFocusablePinnedStackExists() { // Create a pinned stack and move to front. - final ActivityStack pinnedStack = mRootWindowContainer.getDefaultTaskDisplayArea() + final Task pinnedStack = mRootWindowContainer.getDefaultTaskDisplayArea() .createStack(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP); final Task pinnedTask = new TaskBuilder(mService.mStackSupervisor) .setStack(pinnedStack).build(); @@ -98,7 +98,7 @@ public class ActivityDisplayTests extends ActivityTestsBase { assertTrue(pinnedStack.isFocusedStackOnDisplay()); // Create a fullscreen stack and move to front. - final ActivityStack fullscreenStack = createFullscreenStackWithSimpleActivityAt( + final Task fullscreenStack = createFullscreenStackWithSimpleActivityAt( mRootWindowContainer.getDefaultDisplay()); fullscreenStack.moveToFront("moveFullscreenStackToFront"); @@ -114,8 +114,8 @@ public class ActivityDisplayTests extends ActivityTestsBase { public void testStackShouldNotBeFocusedAfterMovingToBackOrRemoving() { // Create a display which only contains 2 stacks. final DisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP); - final ActivityStack stack1 = createFullscreenStackWithSimpleActivityAt(display); - final ActivityStack stack2 = createFullscreenStackWithSimpleActivityAt(display); + final Task stack1 = createFullscreenStackWithSimpleActivityAt(display); + final Task stack2 = createFullscreenStackWithSimpleActivityAt(display); // Put stack1 and stack2 on top. stack1.moveToFront("moveStack1ToFront"); @@ -143,11 +143,11 @@ public class ActivityDisplayTests extends ActivityTestsBase { doReturn(false).when(display).shouldDestroyContentOnRemove(); // Put home stack on the display. - final ActivityStack homeStack = new StackBuilder(mRootWindowContainer) + final Task homeStack = new StackBuilder(mRootWindowContainer) .setDisplay(display).setActivityType(ACTIVITY_TYPE_HOME).build(); // Put a finishing standard activity which will be reparented. - final ActivityStack stack = createFullscreenStackWithSimpleActivityAt(display); + final Task stack = createFullscreenStackWithSimpleActivityAt(display); stack.topRunningActivity().makeFinishingLocked(); clearInvocations(homeStack); @@ -158,8 +158,8 @@ public class ActivityDisplayTests extends ActivityTestsBase { verify(homeStack, never()).resumeTopActivityUncheckedLocked(any(), any()); } - private ActivityStack createFullscreenStackWithSimpleActivityAt(DisplayContent display) { - final ActivityStack fullscreenStack = display.getDefaultTaskDisplayArea().createStack( + private Task createFullscreenStackWithSimpleActivityAt(DisplayContent display) { + final Task fullscreenStack = display.getDefaultTaskDisplayArea().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP); final Task fullscreenTask = new TaskBuilder(mService.mStackSupervisor) .setStack(fullscreenStack).build(); @@ -174,11 +174,11 @@ public class ActivityDisplayTests extends ActivityTestsBase { public void testTopRunningActivity() { final DisplayContent display = mRootWindowContainer.getDefaultDisplay(); final KeyguardController keyguard = mSupervisor.getKeyguardController(); - final ActivityStack stack = new StackBuilder(mRootWindowContainer).build(); + final Task stack = new StackBuilder(mRootWindowContainer).build(); final ActivityRecord activity = stack.getTopNonFinishingActivity(); // Create empty stack on top. - final ActivityStack emptyStack = + final Task emptyStack = new StackBuilder(mRootWindowContainer).setCreateActivity(false).build(); // Make sure the top running activity is not affected when keyguard is not locked. @@ -223,7 +223,7 @@ public class ActivityDisplayTests extends ActivityTestsBase { @Test public void testAlwaysOnTopStackLocation() { final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - final ActivityStack alwaysOnTopStack = taskDisplayArea.createStack(WINDOWING_MODE_FREEFORM, + final Task alwaysOnTopStack = taskDisplayArea.createStack(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */); final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true) .setStack(alwaysOnTopStack).build(); @@ -234,12 +234,12 @@ public class ActivityDisplayTests extends ActivityTestsBase { assertTrue(alwaysOnTopStack.getTopNonFinishingActivity().isAlwaysOnTop()); assertEquals(alwaysOnTopStack, taskDisplayArea.getTopStack()); - final ActivityStack pinnedStack = taskDisplayArea.createStack( + final Task pinnedStack = taskDisplayArea.createStack( WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */); assertEquals(pinnedStack, taskDisplayArea.getRootPinnedTask()); assertEquals(pinnedStack, taskDisplayArea.getTopStack()); - final ActivityStack anotherAlwaysOnTopStack = taskDisplayArea.createStack( + final Task anotherAlwaysOnTopStack = taskDisplayArea.createStack( WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */); anotherAlwaysOnTopStack.setAlwaysOnTop(true); taskDisplayArea.positionStackAtTop(anotherAlwaysOnTopStack, false /* includingParents */); @@ -249,7 +249,7 @@ public class ActivityDisplayTests extends ActivityTestsBase { // existing alwaysOnTop stack. assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getStackAt(topPosition - 1)); - final ActivityStack nonAlwaysOnTopStack = taskDisplayArea.createStack( + final Task nonAlwaysOnTopStack = taskDisplayArea.createStack( WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */); assertEquals(taskDisplayArea, nonAlwaysOnTopStack.getDisplayArea()); topPosition = taskDisplayArea.getStackCount() - 1; @@ -273,7 +273,7 @@ public class ActivityDisplayTests extends ActivityTestsBase { assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop()); assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getStackAt(topPosition - 1)); - final ActivityStack dreamStack = taskDisplayArea.createStack( + final Task dreamStack = taskDisplayArea.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_DREAM, true /* onTop */); assertEquals(taskDisplayArea, dreamStack.getDisplayArea()); assertTrue(dreamStack.isAlwaysOnTop()); @@ -282,7 +282,7 @@ public class ActivityDisplayTests extends ActivityTestsBase { assertEquals(dreamStack, taskDisplayArea.getTopStack()); assertEquals(pinnedStack, taskDisplayArea.getStackAt(topPosition - 1)); - final ActivityStack assistStack = taskDisplayArea.createStack( + final Task assistStack = taskDisplayArea.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */); assertEquals(taskDisplayArea, assistStack.getDisplayArea()); assertFalse(assistStack.isAlwaysOnTop()); @@ -310,13 +310,13 @@ public class ActivityDisplayTests extends ActivityTestsBase { private void removeStackTests(Runnable runnable) { final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - final ActivityStack stack1 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + final Task stack1 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP); - final ActivityStack stack2 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + final Task stack2 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP); - final ActivityStack stack3 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + final Task stack3 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP); - final ActivityStack stack4 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + final Task stack4 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP); final Task task1 = new TaskBuilder(mService.mStackSupervisor).setStack(stack1).build(); final Task task2 = new TaskBuilder(mService.mStackSupervisor).setStack(stack2).build(); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java index e1ce431fc97c..feac6dbe1051 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java @@ -341,7 +341,7 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { public void testConsecutiveLaunchOnDifferentDisplay() { onActivityLaunched(mTopActivity); - final ActivityStack stack = new StackBuilder(mRootWindowContainer) + final Task stack = new StackBuilder(mRootWindowContainer) .setDisplay(addNewDisplayContentAt(DisplayContent.POSITION_BOTTOM)) .setCreateActivity(false) .build(); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 76b1a4d69f05..e45ced64c5b6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -45,19 +45,19 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.ActivityRecord.FINISH_RESULT_CANCELLED; import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED; import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REQUESTED; -import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED; -import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING; -import static com.android.server.wm.ActivityStack.ActivityState.FINISHING; -import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING; -import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; -import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; -import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; -import static com.android.server.wm.ActivityStack.ActivityState.STARTED; -import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; -import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; -import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE; -import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; -import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; +import static com.android.server.wm.Task.ActivityState.DESTROYED; +import static com.android.server.wm.Task.ActivityState.DESTROYING; +import static com.android.server.wm.Task.ActivityState.FINISHING; +import static com.android.server.wm.Task.ActivityState.INITIALIZING; +import static com.android.server.wm.Task.ActivityState.PAUSED; +import static com.android.server.wm.Task.ActivityState.PAUSING; +import static com.android.server.wm.Task.ActivityState.RESUMED; +import static com.android.server.wm.Task.ActivityState.STARTED; +import static com.android.server.wm.Task.ActivityState.STOPPED; +import static com.android.server.wm.Task.ActivityState.STOPPING; +import static com.android.server.wm.Task.STACK_VISIBILITY_INVISIBLE; +import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE; +import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; import static com.google.common.truth.Truth.assertThat; @@ -106,7 +106,7 @@ import android.view.WindowManagerGlobal; import androidx.test.filters.MediumTest; import com.android.internal.R; -import com.android.server.wm.ActivityStack.ActivityState; +import com.android.server.wm.Task.ActivityState; import org.junit.Before; import org.junit.Test; @@ -123,7 +123,7 @@ import org.mockito.invocation.InvocationOnMock; @Presubmit @RunWith(WindowTestRunner.class) public class ActivityRecordTests extends ActivityTestsBase { - private ActivityStack mStack; + private Task mStack; private Task mTask; private ActivityRecord mActivity; @@ -292,7 +292,7 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testSetsRelaunchReason_NotDragResizing() { - mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing"); + mActivity.setState(Task.ActivityState.RESUMED, "Testing"); mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration()); mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), @@ -315,7 +315,7 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testSetsRelaunchReason_DragResizing() { - mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing"); + mActivity.setState(Task.ActivityState.RESUMED, "Testing"); mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration()); mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), @@ -340,7 +340,7 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testSetsRelaunchReason_NonResizeConfigChanges() { - mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing"); + mActivity.setState(Task.ActivityState.RESUMED, "Testing"); mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration()); mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), @@ -366,7 +366,7 @@ public class ActivityRecordTests extends ActivityTestsBase { .setTask(mTask) .setConfigChanges(CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT) .build(); - mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing"); + mActivity.setState(Task.ActivityState.RESUMED, "Testing"); mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), mActivity.getConfiguration())); @@ -489,7 +489,7 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testShouldMakeActive_deferredResume() { - mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing"); + mActivity.setState(Task.ActivityState.STOPPED, "Testing"); mSupervisor.beginDeferResume(); assertEquals(false, mActivity.shouldMakeActive(null /* activeActivity */)); @@ -503,14 +503,14 @@ public class ActivityRecordTests extends ActivityTestsBase { ActivityRecord finishingActivity = new ActivityBuilder(mService).setTask(mTask).build(); finishingActivity.finishing = true; ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); - mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing"); + mActivity.setState(Task.ActivityState.STOPPED, "Testing"); assertEquals(false, mActivity.shouldMakeActive(null /* activeActivity */)); } @Test public void testShouldResume_stackVisibility() { - mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing"); + mActivity.setState(Task.ActivityState.STOPPED, "Testing"); spyOn(mStack); doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null); @@ -525,7 +525,7 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testShouldResumeOrPauseWithResults() { - mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing"); + mActivity.setState(Task.ActivityState.STOPPED, "Testing"); spyOn(mStack); ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); @@ -544,9 +544,9 @@ public class ActivityRecordTests extends ActivityTestsBase { .setLaunchTaskBehind(true) .setConfigChanges(CONFIG_ORIENTATION) .build(); - mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing"); + mActivity.setState(Task.ActivityState.STOPPED, "Testing"); - final ActivityStack stack = new StackBuilder(mRootWindowContainer).build(); + final Task stack = new StackBuilder(mRootWindowContainer).build(); try { doReturn(false).when(stack).isTranslucent(any()); assertFalse(mStack.shouldBeVisible(null /* starting */)); @@ -585,7 +585,7 @@ public class ActivityRecordTests extends ActivityTestsBase { public void testShouldStartWhenMakeClientActive() { ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); topActivity.setOccludesParent(false); - mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing"); + mActivity.setState(Task.ActivityState.STOPPED, "Testing"); mActivity.setVisibility(true); mActivity.makeActiveIfNeeded(null /* activeActivity */); assertEquals(STARTED, mActivity.getState()); @@ -754,14 +754,14 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testFinishActivityIfPossible_adjustStackOrder() { // Prepare the stacks with order (top to bottom): mStack, stack1, stack2. - final ActivityStack stack1 = new StackBuilder(mRootWindowContainer).build(); + final Task stack1 = new StackBuilder(mRootWindowContainer).build(); mStack.moveToFront("test"); // The stack2 is needed here for moving back to simulate the // {@link DisplayContent#mPreferredTopFocusableStack} is cleared, so // {@link DisplayContent#getFocusedStack} will rely on the order of focusable-and-visible // stacks. Then when mActivity is finishing, its stack will be invisible (no running // activities in the stack) that is the key condition to verify. - final ActivityStack stack2 = new StackBuilder(mRootWindowContainer).build(); + final Task stack2 = new StackBuilder(mRootWindowContainer).build(); stack2.moveToBack("test", stack2.getBottomMostTask()); assertTrue(mStack.isTopStackInDisplayArea()); @@ -787,7 +787,7 @@ public class ActivityRecordTests extends ActivityTestsBase { .setCreateTask(true) .setStack(mStack) .build(); - ActivityStack topRootableTask = (ActivityStack) topActivity.getTask(); + Task topRootableTask = topActivity.getTask(); topRootableTask.moveToFront("test"); assertTrue(mStack.isTopStackInDisplayArea()); @@ -807,7 +807,7 @@ public class ActivityRecordTests extends ActivityTestsBase { public void testFinishActivityIfPossible_PreferredTopStackChanged() { final ActivityRecord topActivityOnNonTopDisplay = createActivityOnDisplay(true /* defaultDisplay */, null /* process */); - ActivityStack topRootableTask = topActivityOnNonTopDisplay.getRootTask(); + Task topRootableTask = topActivityOnNonTopDisplay.getRootTask(); topRootableTask.moveToFront("test"); assertTrue(topRootableTask.isTopStackInDisplayArea()); assertEquals(topRootableTask, topActivityOnNonTopDisplay.getDisplayArea() @@ -971,7 +971,7 @@ public class ActivityRecordTests extends ActivityTestsBase { // Simulates that {@code currentTop} starts an existing activity from background (so its // state is stopped) and the starting flow just goes to place it at top. - final ActivityStack nextStack = new StackBuilder(mRootWindowContainer).build(); + final Task nextStack = new StackBuilder(mRootWindowContainer).build(); final ActivityRecord nextTop = nextStack.getTopNonFinishingActivity(); nextTop.setState(STOPPED, "test"); @@ -1093,7 +1093,7 @@ public class ActivityRecordTests extends ActivityTestsBase { // Add another stack to become focused and make the activity there visible. This way it // simulates finishing in non-focused stack in split-screen. - final ActivityStack stack = new StackBuilder(mRootWindowContainer).build(); + final Task stack = new StackBuilder(mRootWindowContainer).build(); final ActivityRecord focusedActivity = stack.getTopMostActivity(); focusedActivity.nowVisible = true; focusedActivity.mVisibleRequested = true; @@ -1199,7 +1199,7 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testDestroyIfPossible_lastActivityAboveEmptyHomeStack() { // Empty the home stack. - final ActivityStack homeStack = mActivity.getDisplayArea().getRootHomeTask(); + final Task homeStack = mActivity.getDisplayArea().getRootHomeTask(); homeStack.forAllLeafTasks((t) -> { homeStack.removeChild(t, "test"); }, true /* traverseTopToBottom */); @@ -1225,7 +1225,7 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testCompleteFinishing_lastActivityAboveEmptyHomeStack() { // Empty the home stack. - final ActivityStack homeStack = mActivity.getDisplayArea().getRootHomeTask(); + final Task homeStack = mActivity.getDisplayArea().getRootHomeTask(); homeStack.forAllLeafTasks((t) -> { homeStack.removeChild(t, "test"); }, true /* traverseTopToBottom */); @@ -1325,7 +1325,7 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testRemoveFromHistory() { - final ActivityStack stack = mActivity.getRootTask(); + final Task stack = mActivity.getRootTask(); final Task task = mActivity.getTask(); mActivity.removeFromHistory("test"); @@ -1334,7 +1334,7 @@ public class ActivityRecordTests extends ActivityTestsBase { assertNull(mActivity.app); assertNull(mActivity.getTask()); assertEquals(0, task.getChildCount()); - assertEquals(task.getStack(), task); + assertEquals(task.getRootTask(), task); assertEquals(0, stack.getChildCount()); } @@ -1576,7 +1576,7 @@ public class ActivityRecordTests extends ActivityTestsBase { // Create a new task with custom config to reparent the activity to. final Task newTask = - new TaskBuilder(mSupervisor).setStack(initialTask.getStack()).build(); + new TaskBuilder(mSupervisor).setStack(initialTask.getRootTask()).build(); final Configuration newConfig = newTask.getConfiguration(); newConfig.densityDpi += 100; newTask.onRequestedOverrideConfigurationChanged(newConfig); @@ -1608,7 +1608,7 @@ public class ActivityRecordTests extends ActivityTestsBase { // Create a new task with custom config to reparent the second activity to. final Task newTask = - new TaskBuilder(mSupervisor).setStack(initialTask.getStack()).build(); + new TaskBuilder(mSupervisor).setStack(initialTask.getRootTask()).build(); final Configuration newConfig = newTask.getConfiguration(); newConfig.densityDpi += 100; newTask.onRequestedOverrideConfigurationChanged(newConfig); @@ -1696,7 +1696,7 @@ public class ActivityRecordTests extends ActivityTestsBase { display = new TestDisplayContent.Builder(mService, 2000, 1000).setDensityDpi(300) .setPosition(DisplayContent.POSITION_TOP).build(); } - final ActivityStack stack = display.getDefaultTaskDisplayArea() + final Task stack = display.getDefaultTaskDisplayArea() .createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */); final Task task = new TaskBuilder(mSupervisor).setStack(stack).build(); return new ActivityBuilder(mService).setTask(task).setUseProcess(process).build(); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java index 5c6906cfa942..197c89a2d479 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java @@ -56,7 +56,7 @@ import org.junit.runner.RunWith; @Presubmit @RunWith(WindowTestRunner.class) public class ActivityStackSupervisorTests extends ActivityTestsBase { - private ActivityStack mFullscreenStack; + private Task mFullscreenStack; @Before public void setUp() throws Exception { @@ -113,7 +113,7 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { public void testHandleNonResizableTaskOnSecondaryDisplay() { // Create an unresizable task on secondary display. final DisplayContent newDisplay = addNewDisplayContentAt(DisplayContent.POSITION_TOP); - final ActivityStack stack = new StackBuilder(mRootWindowContainer) + final Task stack = new StackBuilder(mRootWindowContainer) .setDisplay(newDisplay).build(); final ActivityRecord unresizableActivity = stack.getTopNonFinishingActivity(); final Task task = unresizableActivity.getTask(); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index 373eed921580..5153af2b0d6b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -34,19 +34,19 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; -import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING; -import static com.android.server.wm.ActivityStack.ActivityState.FINISHING; -import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; -import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; -import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; -import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; -import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE; -import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; -import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; +import static com.android.server.wm.Task.ActivityState.DESTROYING; +import static com.android.server.wm.Task.ActivityState.FINISHING; +import static com.android.server.wm.Task.ActivityState.PAUSING; +import static com.android.server.wm.Task.ActivityState.RESUMED; +import static com.android.server.wm.Task.ActivityState.STOPPED; +import static com.android.server.wm.Task.ActivityState.STOPPING; import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG; import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT; +import static com.android.server.wm.Task.STACK_VISIBILITY_INVISIBLE; +import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE; +import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; import static com.android.server.wm.TaskDisplayArea.getStackAbove; import static com.android.server.wm.WindowContainer.POSITION_TOP; @@ -90,7 +90,7 @@ import java.util.function.Consumer; @RunWith(WindowTestRunner.class) public class ActivityStackTests extends ActivityTestsBase { private TaskDisplayArea mDefaultTaskDisplayArea; - private ActivityStack mStack; + private Task mStack; private Task mTask; @Before @@ -119,7 +119,7 @@ public class ActivityStackTests extends ActivityTestsBase { r.setState(RESUMED, "testResumedActivityFromTaskReparenting"); assertEquals(r, mStack.getResumedActivity()); - final ActivityStack destStack = mDefaultTaskDisplayArea.createStack( + final Task destStack = mDefaultTaskDisplayArea.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); mTask.reparent(destStack, true /* toTop */, Task.REPARENT_KEEP_STACK_AT_FRONT, @@ -137,7 +137,7 @@ public class ActivityStackTests extends ActivityTestsBase { r.setState(RESUMED, "testResumedActivityFromActivityReparenting"); assertEquals(r, mStack.getResumedActivity()); - final ActivityStack destStack = mDefaultTaskDisplayArea.createStack( + final Task destStack = mDefaultTaskDisplayArea.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); mTask.reparent(destStack, true /*toTop*/, REPARENT_MOVE_STACK_TO_FRONT, false, false, "testResumedActivityFromActivityReparenting"); @@ -153,7 +153,7 @@ public class ActivityStackTests extends ActivityTestsBase { organizer.setMoveToSecondaryOnEnter(false); // Create primary splitscreen stack. - final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack( + final Task primarySplitScreen = mDefaultTaskDisplayArea.createStack( WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Assert windowing mode. @@ -178,10 +178,10 @@ public class ActivityStackTests extends ActivityTestsBase { public void testMoveToPrimarySplitScreenThenMoveToBack() { TestSplitOrganizer organizer = new TestSplitOrganizer(mService); // This time, start with a fullscreen activitystack - final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack( + final Task primarySplitScreen = mDefaultTaskDisplayArea.createStack( WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */); - primarySplitScreen.reparent((ActivityStack) organizer.mPrimary, POSITION_TOP, + primarySplitScreen.reparent(organizer.mPrimary, POSITION_TOP, false /*moveParents*/, "test"); // Assert windowing mode. @@ -204,13 +204,13 @@ public class ActivityStackTests extends ActivityTestsBase { TestSplitOrganizer organizer = new TestSplitOrganizer(mService); // Set up split-screen with primary on top and secondary containing the home task below // another stack. - final ActivityStack primaryTask = mDefaultTaskDisplayArea.createStack( + final Task primaryTask = mDefaultTaskDisplayArea.createStack( WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityStack homeRoot = mDefaultTaskDisplayArea.getStack( + final Task homeRoot = mDefaultTaskDisplayArea.getStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); - final ActivityStack secondaryTask = mDefaultTaskDisplayArea.createStack( + final Task secondaryTask = mDefaultTaskDisplayArea.createStack( WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); - mDefaultTaskDisplayArea.positionStackAtTop((ActivityStack) organizer.mPrimary, + mDefaultTaskDisplayArea.positionStackAtTop(organizer.mPrimary, false /* includingParents */); // Move primary to back. @@ -228,7 +228,7 @@ public class ActivityStackTests extends ActivityTestsBase { assertEquals(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, primaryTask.getWindowingMode()); // Move secondary to back via parent (should be equivalent) - ((ActivityStack) organizer.mSecondary).moveToBack("test", secondaryTask); + organizer.mSecondary.moveToBack("test", secondaryTask); // Assert that it is now in back but still in secondary split assertEquals(1, homeRoot.compareTo(primaryTask)); @@ -239,12 +239,12 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testRemoveOrganizedTask_UpdateStackReference() { - final ActivityStack rootHomeTask = mDefaultTaskDisplayArea.getRootHomeTask(); + final Task rootHomeTask = mDefaultTaskDisplayArea.getRootHomeTask(); final ActivityRecord homeActivity = new ActivityBuilder(mService) .setStack(rootHomeTask) .setCreateTask(true) .build(); - final ActivityStack secondaryStack = (ActivityStack) WindowContainer.fromBinder( + final Task secondaryStack = (Task) WindowContainer.fromBinder( mService.mTaskOrganizerController.createRootTask(rootHomeTask.getDisplayId(), WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token.asBinder()); @@ -258,7 +258,7 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testStackInheritsDisplayWindowingMode() { - final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack( + final Task primarySplitScreen = mDefaultTaskDisplayArea.createStack( WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */); assertEquals(WINDOWING_MODE_FULLSCREEN, primarySplitScreen.getWindowingMode()); @@ -273,7 +273,7 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testStackOverridesDisplayWindowingMode() { - final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack( + final Task primarySplitScreen = mDefaultTaskDisplayArea.createStack( WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */); assertEquals(WINDOWING_MODE_FULLSCREEN, primarySplitScreen.getWindowingMode()); @@ -354,9 +354,9 @@ public class ActivityStackTests extends ActivityTestsBase { public void testMoveStackToBackIncludingParent() { final TaskDisplayArea taskDisplayArea = addNewDisplayContentAt(DisplayContent.POSITION_TOP) .getDefaultTaskDisplayArea(); - final ActivityStack stack1 = createStackForShouldBeVisibleTest(taskDisplayArea, + final Task stack1 = createStackForShouldBeVisibleTest(taskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityStack stack2 = createStackForShouldBeVisibleTest(taskDisplayArea, + final Task stack2 = createStackForShouldBeVisibleTest(taskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Do not move display to back because there is still another stack. @@ -371,9 +371,9 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testShouldBeVisible_Fullscreen() { - final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, + final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); - final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, + final Task pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Add an activity to the pinned stack so it isn't considered empty for visibility check. final ActivityRecord pinnedActivity = new ActivityBuilder(mService) @@ -384,7 +384,7 @@ public class ActivityStackTests extends ActivityTestsBase { assertTrue(homeStack.shouldBeVisible(null /* starting */)); assertTrue(pinnedStack.shouldBeVisible(null /* starting */)); - final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest( + final Task fullscreenStack = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Home stack shouldn't be visible behind an opaque fullscreen stack, but pinned stack @@ -402,14 +402,14 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testShouldBeVisible_SplitScreen() { - final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, + final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); // Home stack should always be fullscreen for this test. doReturn(false).when(homeStack).supportsSplitScreenWindowingMode(); - final ActivityStack splitScreenPrimary = + final Task splitScreenPrimary = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityStack splitScreenSecondary = + final Task splitScreenSecondary = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); @@ -437,7 +437,7 @@ public class ActivityStackTests extends ActivityTestsBase { assertEquals(STACK_VISIBILITY_VISIBLE, splitScreenSecondary.getVisibility(null /* starting */)); - final ActivityStack splitScreenSecondary2 = + final Task splitScreenSecondary2 = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); // First split-screen secondary shouldn't be visible behind another opaque split-split @@ -460,7 +460,7 @@ public class ActivityStackTests extends ActivityTestsBase { assertEquals(STACK_VISIBILITY_VISIBLE, splitScreenSecondary2.getVisibility(null /* starting */)); - final ActivityStack assistantStack = createStackForShouldBeVisibleTest( + final Task assistantStack = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */); @@ -531,13 +531,13 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testGetVisibility_MultiLevel() { - final ActivityStack homeStack = createStackForShouldBeVisibleTest( + final Task homeStack = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, true /* onTop */); - final ActivityStack splitPrimary = createStackForShouldBeVisibleTest( + final Task splitPrimary = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED, true /* onTop */); - final ActivityStack splitSecondary = createStackForShouldBeVisibleTest( + final Task splitSecondary = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_UNDEFINED, true /* onTop */); @@ -556,7 +556,7 @@ public class ActivityStackTests extends ActivityTestsBase { // Add fullscreen translucent task that partially occludes split tasks - final ActivityStack translucentStack = createStandardStackForVisibilityTest( + final Task translucentStack = createStandardStackForVisibilityTest( WINDOWING_MODE_FULLSCREEN, true /* translucent */); // Fullscreen translucent task should be visible assertEquals(STACK_VISIBILITY_VISIBLE, translucentStack.getVisibility(null /* starting */)); @@ -580,10 +580,10 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testGetVisibility_FullscreenBehindTranslucent() { - final ActivityStack bottomStack = + final Task bottomStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, false /* translucent */); - final ActivityStack translucentStack = + final Task translucentStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, true /* translucent */); @@ -595,13 +595,13 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testGetVisibility_FullscreenBehindTranslucentAndOpaque() { - final ActivityStack bottomStack = + final Task bottomStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, false /* translucent */); - final ActivityStack translucentStack = + final Task translucentStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, true /* translucent */); - final ActivityStack opaqueStack = + final Task opaqueStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, false /* translucent */); @@ -613,13 +613,13 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testGetVisibility_FullscreenBehindOpaqueAndTranslucent() { - final ActivityStack bottomStack = + final Task bottomStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, false /* translucent */); - final ActivityStack opaqueStack = + final Task opaqueStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, false /* translucent */); - final ActivityStack translucentStack = + final Task translucentStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, true /* translucent */); @@ -632,10 +632,10 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testGetVisibility_FullscreenTranslucentBehindTranslucent() { - final ActivityStack bottomTranslucentStack = + final Task bottomTranslucentStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, true /* translucent */); - final ActivityStack translucentStack = + final Task translucentStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, true /* translucent */); @@ -647,10 +647,10 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testGetVisibility_FullscreenTranslucentBehindOpaque() { - final ActivityStack bottomTranslucentStack = + final Task bottomTranslucentStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, true /* translucent */); - final ActivityStack opaqueStack = + final Task opaqueStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, false /* translucent */); @@ -661,13 +661,13 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testGetVisibility_FullscreenBehindTranslucentAndPip() { - final ActivityStack bottomStack = + final Task bottomStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, false /* translucent */); - final ActivityStack translucentStack = + final Task translucentStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, true /* translucent */); - final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, + final Task pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */); assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, @@ -684,7 +684,7 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testShouldBeVisible_Finishing() { - final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, + final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); ActivityRecord topRunningHomeActivity = homeStack.topRunningActivity(); if (topRunningHomeActivity == null) { @@ -694,7 +694,7 @@ public class ActivityStackTests extends ActivityTestsBase { .build(); } - final ActivityStack translucentStack = createStackForShouldBeVisibleTest( + final Task translucentStack = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); doReturn(true).when(translucentStack).isTranslucent(any()); @@ -717,7 +717,7 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testShouldBeVisible_FullscreenBehindTranslucentInHomeStack() { - final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, + final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); final ActivityRecord firstActivity = new ActivityBuilder(mService) @@ -740,9 +740,9 @@ public class ActivityStackTests extends ActivityTestsBase { public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeBehindFullscreen() { mDefaultTaskDisplayArea.removeStack(mStack); - final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, + final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); - final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest( + final Task fullscreenStack = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); @@ -760,9 +760,9 @@ public class ActivityStackTests extends ActivityTestsBase { public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeBehindTranslucent() { mDefaultTaskDisplayArea.removeStack(mStack); - final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, + final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); - final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest( + final Task fullscreenStack = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); @@ -780,10 +780,10 @@ public class ActivityStackTests extends ActivityTestsBase { public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeOnTop() { mDefaultTaskDisplayArea.removeStack(mStack); - final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest( + final Task fullscreenStack = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, + final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); doReturn(false).when(homeStack).isTranslucent(any()); @@ -800,15 +800,15 @@ public class ActivityStackTests extends ActivityTestsBase { public void testMoveHomeStackBehindBottomMostVisibleStack_MoveHomeBehindFullscreen() { mDefaultTaskDisplayArea.removeStack(mStack); - final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, + final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); - final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest( + final Task fullscreenStack1 = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest( + final Task fullscreenStack2 = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, + final Task pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */); doReturn(false).when(homeStack).isTranslucent(any()); @@ -827,12 +827,12 @@ public class ActivityStackTests extends ActivityTestsBase { testMoveHomeStackBehindBottomMostVisibleStack_MoveHomeBehindFullscreenAndTranslucent() { mDefaultTaskDisplayArea.removeStack(mStack); - final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, + final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); - final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest( + final Task fullscreenStack1 = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest( + final Task fullscreenStack2 = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); @@ -851,13 +851,13 @@ public class ActivityStackTests extends ActivityTestsBase { public void testMoveHomeStackBehindStack_BehindHomeStack() { mDefaultTaskDisplayArea.removeStack(mStack); - final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest( + final Task fullscreenStack1 = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest( + final Task fullscreenStack2 = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, + final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); doReturn(false).when(homeStack).isTranslucent(any()); @@ -874,19 +874,19 @@ public class ActivityStackTests extends ActivityTestsBase { public void testMoveHomeStackBehindStack() { mDefaultTaskDisplayArea.removeStack(mStack); - final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest( + final Task fullscreenStack1 = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest( + final Task fullscreenStack2 = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityStack fullscreenStack3 = createStackForShouldBeVisibleTest( + final Task fullscreenStack3 = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityStack fullscreenStack4 = createStackForShouldBeVisibleTest( + final Task fullscreenStack4 = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, + final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); mDefaultTaskDisplayArea.moveStackBehindStack(homeStack, fullscreenStack1); @@ -901,13 +901,13 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testSetAlwaysOnTop() { - final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, + final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); - final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, + final Task pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */); assertEquals(pinnedStack, getStackAbove(homeStack)); - final ActivityStack alwaysOnTopStack = createStackForShouldBeVisibleTest( + final Task alwaysOnTopStack = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */); alwaysOnTopStack.setAlwaysOnTop(true); @@ -915,13 +915,13 @@ public class ActivityStackTests extends ActivityTestsBase { // Ensure (non-pinned) always on top stack is put below pinned stack. assertEquals(pinnedStack, getStackAbove(alwaysOnTopStack)); - final ActivityStack nonAlwaysOnTopStack = createStackForShouldBeVisibleTest( + final Task nonAlwaysOnTopStack = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Ensure non always on top stack is put below always on top stacks. assertEquals(alwaysOnTopStack, getStackAbove(nonAlwaysOnTopStack)); - final ActivityStack alwaysOnTopStack2 = createStackForShouldBeVisibleTest( + final Task alwaysOnTopStack2 = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */); alwaysOnTopStack2.setAlwaysOnTop(true); @@ -946,13 +946,13 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testSplitScreenMoveToFront() { - final ActivityStack splitScreenPrimary = createStackForShouldBeVisibleTest( + final Task splitScreenPrimary = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityStack splitScreenSecondary = createStackForShouldBeVisibleTest( + final Task splitScreenSecondary = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityStack assistantStack = createStackForShouldBeVisibleTest( + final Task assistantStack = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */); @@ -977,18 +977,18 @@ public class ActivityStackTests extends ActivityTestsBase { } } - private ActivityStack createStandardStackForVisibilityTest(int windowingMode, + private Task createStandardStackForVisibilityTest(int windowingMode, boolean translucent) { - final ActivityStack stack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, + final Task stack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, windowingMode, ACTIVITY_TYPE_STANDARD, true /* onTop */); doReturn(translucent).when(stack).isTranslucent(any()); return stack; } @SuppressWarnings("TypeParameterUnusedInFormals") - private ActivityStack createStackForShouldBeVisibleTest( + private Task createStackForShouldBeVisibleTest( TaskDisplayArea taskDisplayArea, int windowingMode, int activityType, boolean onTop) { - final ActivityStack stack; + final Task stack; if (activityType == ACTIVITY_TYPE_HOME) { // Home stack and activity are created in ActivityTestsBase#setupActivityManagerService stack = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); @@ -1021,7 +1021,7 @@ public class ActivityStackTests extends ActivityTestsBase { // Note the activities have non-null ActivityRecord.app, so it won't remove directly. mRootWindowContainer.mFinishDisabledPackageActivitiesHelper.process( firstActivity.packageName, null /* filterByClasses */, true /* doit */, - true /* evenPersistent */, UserHandle.USER_ALL); + true /* evenPersistent */, UserHandle.USER_ALL, false /* onlyRemoveNoProcess */); // If the activity is disabled with {@link android.content.pm.PackageManager#DONT_KILL_APP} // the activity should still follow the normal flow to finish and destroy. @@ -1050,7 +1050,7 @@ public class ActivityStackTests extends ActivityTestsBase { mRootWindowContainer.mFinishDisabledPackageActivitiesHelper.process( activity.packageName, null /* filterByClasses */, true /* doit */, - true /* evenPersistent */, UserHandle.USER_ALL); + true /* evenPersistent */, UserHandle.USER_ALL, false /* onlyRemoveNoProcess */); // Although the overlay activity is in another package, the non-overlay activities are // removed from the task. Since the overlay activity should be removed as well, the task @@ -1152,7 +1152,7 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testWontFinishHomeStackImmediately() { - final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, + final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); ActivityRecord activity = homeStack.topRunningActivity(); @@ -1172,10 +1172,10 @@ public class ActivityStackTests extends ActivityTestsBase { public void testFinishCurrentActivity() { // Create 2 activities on a new display. final DisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP); - final ActivityStack stack1 = createStackForShouldBeVisibleTest( + final Task stack1 = createStackForShouldBeVisibleTest( display.getDefaultTaskDisplayArea(), WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityStack stack2 = createStackForShouldBeVisibleTest( + final Task stack2 = createStackForShouldBeVisibleTest( display.getDefaultTaskDisplayArea(), WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); @@ -1194,7 +1194,7 @@ public class ActivityStackTests extends ActivityTestsBase { eq(display.mDisplayId), anyBoolean(), anyBoolean()); } - private ActivityRecord finishTopActivity(ActivityStack stack) { + private ActivityRecord finishTopActivity(Task stack) { final ActivityRecord activity = stack.topRunningActivity(); assertNotNull(activity); activity.setState(STOPPED, "finishTopActivity"); @@ -1252,7 +1252,7 @@ public class ActivityStackTests extends ActivityTestsBase { public void testStackOrderChangedOnPositionStack() { StackOrderChangedListener listener = new StackOrderChangedListener(); try { - final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest( + final Task fullscreenStack1 = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); mDefaultTaskDisplayArea.registerStackOrderChangedListener(listener); @@ -1382,7 +1382,7 @@ public class ActivityStackTests extends ActivityTestsBase { activities[i] = r; doReturn(null).when(mService).getProcessController( eq(r.processName), eq(r.info.applicationInfo.uid)); - r.setState(ActivityStack.ActivityState.INITIALIZING, "test"); + r.setState(Task.ActivityState.INITIALIZING, "test"); // Ensure precondition that the activity is opaque. assertTrue(r.occludesParent()); mSupervisor.startSpecificActivity(r, false /* andResume */, @@ -1443,7 +1443,7 @@ public class ActivityStackTests extends ActivityTestsBase { public boolean mChanged = false; @Override - public void onStackOrderChanged(ActivityStack stack) { + public void onStackOrderChanged(Task stack) { mChanged = true; } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java index ca4456b7b926..c9a927901a37 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java @@ -77,7 +77,7 @@ public class ActivityStartControllerTests extends ActivityTestsBase { .setCreateTask(true) .build(); final int startFlags = random.nextInt(); - final ActivityStack stack = mService.mRootWindowContainer.getDefaultTaskDisplayArea() + final Task stack = mService.mRootWindowContainer.getDefaultTaskDisplayArea() .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); final WindowProcessController wpc = new WindowProcessController(mService, mService.mContext.getApplicationInfo(), "name", 12345, 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 e3b1d6306a81..3772e2500c1b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -321,7 +321,7 @@ public class ActivityStarterTests extends ActivityTestsBase { if (mockGetLaunchStack) { // Instrument the stack and task used. - final ActivityStack stack = mRootWindowContainer.getDefaultTaskDisplayArea() + final Task stack = mRootWindowContainer.getDefaultTaskDisplayArea() .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); @@ -492,7 +492,7 @@ public class ActivityStarterTests extends ActivityTestsBase { private void assertNoTasks(DisplayContent display) { display.forAllTaskDisplayAreas(taskDisplayArea -> { for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + final Task stack = taskDisplayArea.getStackAt(sNdx); assertFalse(stack.hasChild()); } }); @@ -618,7 +618,7 @@ public class ActivityStarterTests extends ActivityTestsBase { UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, false, true, false, false, false); runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callerIsWhitelisted_notAborted", false, + "disallowed_callerIsAllowed_notAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, false, false, true, false, false); @@ -639,7 +639,7 @@ public class ActivityStarterTests extends ActivityTestsBase { int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState, int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState, boolean hasForegroundActivities, boolean callerIsRecents, - boolean callerIsTempWhitelisted, + boolean callerIsTempAllowed, boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges, boolean isCallingUidDeviceOwner) { // window visibility @@ -664,8 +664,8 @@ public class ActivityStarterTests extends ActivityTestsBase { RecentTasks recentTasks = mock(RecentTasks.class); mService.mStackSupervisor.setRecentTasks(recentTasks); doReturn(callerIsRecents).when(recentTasks).isCallerRecents(callingUid); - // caller is temp whitelisted - callerApp.setAllowBackgroundActivityStarts(callerIsTempWhitelisted); + // caller is temp allowed + callerApp.setAllowBackgroundActivityStarts(callerIsTempAllowed); // caller is instrumenting with background activity starts privileges callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges, callerIsInstrumentingWithBackgroundActivityStartPrivileges); @@ -741,7 +741,7 @@ public class ActivityStarterTests extends ActivityTestsBase { new TestDisplayContent.Builder(mService, 1000, 1500) .setPosition(POSITION_BOTTOM).build(); final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea(); - final ActivityStack stack = secondaryTaskContainer.createStack( + final Task stack = secondaryTaskContainer.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Create an activity record on the top of secondary display. @@ -787,7 +787,7 @@ public class ActivityStarterTests extends ActivityTestsBase { ACTIVITY_TYPE_STANDARD, false /* onTop */)); // Create another activity on top of the secondary display. - final ActivityStack topStack = secondaryTaskContainer.createStack(WINDOWING_MODE_FULLSCREEN, + final Task topStack = secondaryTaskContainer.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); final Task topTask = new TaskBuilder(mSupervisor).setStack(topStack).build(); new ActivityBuilder(mService).setTask(topTask).build(); @@ -826,7 +826,7 @@ public class ActivityStarterTests extends ActivityTestsBase { Task task = topActivity.getTask(); starter.postStartActivityProcessing( - task.getTopNonFinishingActivity(), START_DELIVERED_TO_TOP, task.getStack()); + task.getTopNonFinishingActivity(), START_DELIVERED_TO_TOP, task.getRootTask()); verify(taskChangeNotifier).notifyActivityRestartAttempt( any(), anyBoolean(), anyBoolean(), anyBoolean()); @@ -835,14 +835,14 @@ public class ActivityStarterTests extends ActivityTestsBase { Task task2 = reusableActivity.getTask(); starter.postStartActivityProcessing( - task2.getTopNonFinishingActivity(), START_TASK_TO_FRONT, task.getStack()); + task2.getTopNonFinishingActivity(), START_TASK_TO_FRONT, task.getRootTask()); verify(taskChangeNotifier, times(2)).notifyActivityRestartAttempt( any(), anyBoolean(), anyBoolean(), anyBoolean()); verify(taskChangeNotifier).notifyActivityRestartAttempt( any(), anyBoolean(), anyBoolean(), eq(false)); } - private ActivityRecord createSingleTaskActivityOn(ActivityStack stack) { + private ActivityRecord createSingleTaskActivityOn(Task stack) { final ComponentName componentName = ComponentName.createRelative( DEFAULT_COMPONENT_PACKAGE_NAME, DEFAULT_COMPONENT_PACKAGE_NAME + ".SingleTaskActivity"); @@ -1046,7 +1046,7 @@ public class ActivityStarterTests extends ActivityTestsBase { targetRecord.setVisibility(false); final ActivityRecord sourceRecord = new ActivityBuilder(mService).build(); - final ActivityStack stack = spy( + final Task stack = spy( mRootWindowContainer.getDefaultTaskDisplayArea() .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, /* onTop */true)); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java index f65d6e0c82af..f8faae66c704 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java @@ -73,7 +73,7 @@ public class ActivityTaskManagerServiceTests extends ActivityTestsBase { /** Verify that activity is finished correctly upon request. */ @Test public void testActivityFinish() { - final ActivityStack stack = new StackBuilder(mRootWindowContainer).build(); + final Task stack = new StackBuilder(mRootWindowContainer).build(); final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity(); assertTrue("Activity must be finished", mService.finishActivity(activity.appToken, 0 /* resultCode */, null /* resultData */, @@ -87,7 +87,7 @@ public class ActivityTaskManagerServiceTests extends ActivityTestsBase { @Test public void testOnPictureInPictureRequested() throws RemoteException { - final ActivityStack stack = new StackBuilder(mRootWindowContainer).build(); + final Task stack = new StackBuilder(mRootWindowContainer).build(); final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity(); final ClientLifecycleManager mockLifecycleManager = mock(ClientLifecycleManager.class); doReturn(mockLifecycleManager).when(mService).getLifecycleManager(); @@ -106,7 +106,7 @@ public class ActivityTaskManagerServiceTests extends ActivityTestsBase { @Test(expected = IllegalStateException.class) public void testOnPictureInPictureRequested_cannotEnterPip() throws RemoteException { - final ActivityStack stack = new StackBuilder(mRootWindowContainer).build(); + final Task stack = new StackBuilder(mRootWindowContainer).build(); final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity(); ClientLifecycleManager lifecycleManager = mService.getLifecycleManager(); doReturn(false).when(activity).inPinnedWindowingMode(); @@ -120,7 +120,7 @@ public class ActivityTaskManagerServiceTests extends ActivityTestsBase { @Test(expected = IllegalStateException.class) public void testOnPictureInPictureRequested_alreadyInPIPMode() throws RemoteException { - final ActivityStack stack = new StackBuilder(mRootWindowContainer).build(); + final Task stack = new StackBuilder(mRootWindowContainer).build(); final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity(); ClientLifecycleManager lifecycleManager = mService.getLifecycleManager(); doReturn(true).when(activity).inPinnedWindowingMode(); 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 9d0cd26bc040..5be2f0453bf4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -112,7 +112,7 @@ class ActivityTestsBase extends SystemServiceTestsBase { private String mAffinity; private int mUid = 12345; private boolean mCreateTask; - private ActivityStack mStack; + private Task mStack; private int mActivityFlags; private int mLaunchMode; private int mResizeMode = RESIZE_MODE_RESIZEABLE; @@ -164,7 +164,7 @@ class ActivityTestsBase extends SystemServiceTestsBase { return this; } - ActivityBuilder setStack(ActivityStack stack) { + ActivityBuilder setStack(Task stack) { mStack = stack; return this; } @@ -307,7 +307,7 @@ class ActivityTestsBase extends SystemServiceTestsBase { wpc = mWpc; } else { wpc = new WindowProcessController(mService, - mService.mContext.getApplicationInfo(), mProcessName, mUid, + aInfo.applicationInfo, mProcessName, mUid, UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class)); wpc.setThread(mock(IApplicationThread.class)); @@ -338,7 +338,7 @@ class ActivityTestsBase extends SystemServiceTestsBase { private IVoiceInteractionSession mVoiceSession; private boolean mCreateStack = true; - private ActivityStack mStack; + private Task mStack; private TaskDisplayArea mTaskDisplayArea; TaskBuilder(ActivityStackSupervisor supervisor) { @@ -384,7 +384,7 @@ class ActivityTestsBase extends SystemServiceTestsBase { return this; } - TaskBuilder setStack(ActivityStack stack) { + TaskBuilder setStack(Task stack) { mStack = stack; return this; } @@ -418,7 +418,7 @@ class ActivityTestsBase extends SystemServiceTestsBase { intent.setComponent(mComponent); intent.setFlags(mFlags); - final Task task = new ActivityStack(mSupervisor.mService, mTaskId, aInfo, + final Task task = new Task(mSupervisor.mService, mTaskId, aInfo, intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/, null /*taskDescription*/, mStack); spyOn(task); @@ -503,11 +503,11 @@ class ActivityTestsBase extends SystemServiceTestsBase { return this; } - ActivityStack build() { + Task build() { SystemServicesTestRule.checkHoldsLock(mRootWindowContainer.mWmService.mGlobalLock); final int stackId = mStackId >= 0 ? mStackId : mTaskDisplayArea.getNextStackId(); - final ActivityStack stack = mTaskDisplayArea.createStackUnchecked( + final Task stack = mTaskDisplayArea.createStackUnchecked( mWindowingMode, mActivityType, stackId, mOnTop, mInfo, mIntent, false /* createdByOrganizer */); final ActivityStackSupervisor supervisor = mRootWindowContainer.mStackSupervisor; @@ -593,7 +593,7 @@ class ActivityTestsBase extends SystemServiceTestsBase { DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId); dc.forAllTaskDisplayAreas(taskDisplayArea -> { for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + final Task stack = taskDisplayArea.getStackAt(sNdx); if (!WindowConfiguration.isSplitScreenWindowingMode(stack.getWindowingMode())) { stack.reparent(mSecondary, POSITION_BOTTOM); } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java index e8fab2b0243b..673feb260dd4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java @@ -53,14 +53,14 @@ import org.junit.runner.RunWith; @RunWith(WindowTestRunner.class) public class AppChangeTransitionTests extends WindowTestsBase { - private ActivityStack mStack; + private Task mStack; private Task mTask; private ActivityRecord mActivity; public void setUpOnDisplay(DisplayContent dc) { mActivity = createTestActivityRecord(dc, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD); mTask = mActivity.getTask(); - mStack = mTask.getStack(); + mStack = mTask.getRootTask(); // Set a remote animator with snapshot disabled. Snapshots don't work in wmtests. RemoteAnimationDefinition definition = new RemoteAnimationDefinition(); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java index f2a553906095..d7baf8d05bd6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java @@ -134,12 +134,12 @@ public class AppTransitionControllerTest extends WindowTestsBase { // [DisplayContent] -+- [TaskStack1] - [Task1] - [ActivityRecord1] (opening, invisible) // +- [TaskStack2] - [Task2] - [ActivityRecord2] (closing, visible) - final ActivityStack stack1 = createTaskStackOnDisplay(mDisplayContent); + final Task stack1 = createTaskStackOnDisplay(mDisplayContent); final ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(stack1); activity1.setVisible(false); activity1.mVisibleRequested = true; - final ActivityStack stack2 = createTaskStackOnDisplay(mDisplayContent); + final Task stack2 = createTaskStackOnDisplay(mDisplayContent); final ActivityRecord activity2 = WindowTestUtils.createTestActivityRecord(stack2); final ArraySet<ActivityRecord> opening = new ArraySet<>(); @@ -162,10 +162,10 @@ public class AppTransitionControllerTest extends WindowTestsBase { public void testGetAnimationTargets_visibilityAlreadyUpdated() { // [DisplayContent] -+- [TaskStack1] - [Task1] - [ActivityRecord1] (opening, visible) // +- [TaskStack2] - [Task2] - [ActivityRecord2] (closing, invisible) - final ActivityStack stack1 = createTaskStackOnDisplay(mDisplayContent); + final Task stack1 = createTaskStackOnDisplay(mDisplayContent); final ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(stack1); - final ActivityStack stack2 = createTaskStackOnDisplay(mDisplayContent); + final Task stack2 = createTaskStackOnDisplay(mDisplayContent); final ActivityRecord activity2 = WindowTestUtils.createTestActivityRecord(stack2); activity2.setVisible(false); activity2.mVisibleRequested = false; @@ -202,13 +202,13 @@ public class AppTransitionControllerTest extends WindowTestsBase { public void testGetAnimationTargets_visibilityAlreadyUpdated_butForcedTransitionRequested() { // [DisplayContent] -+- [TaskStack1] - [Task1] - [ActivityRecord1] (closing, invisible) // +- [TaskStack2] - [Task2] - [ActivityRecord2] (opening, visible) - final ActivityStack stack1 = createTaskStackOnDisplay(mDisplayContent); + final Task stack1 = createTaskStackOnDisplay(mDisplayContent); final ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(stack1); activity1.setVisible(true); activity1.mVisibleRequested = true; activity1.mRequestForceTransition = true; - final ActivityStack stack2 = createTaskStackOnDisplay(mDisplayContent); + final Task stack2 = createTaskStackOnDisplay(mDisplayContent); final ActivityRecord activity2 = WindowTestUtils.createTestActivityRecord(stack2); activity2.setVisible(false); activity2.mVisibleRequested = false; @@ -237,7 +237,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { // Create another non-empty task so the animation target won't promote to task display area. WindowTestUtils.createTestActivityRecord( mDisplayContent.getDefaultTaskDisplayArea().getOrCreateRootHomeTask()); - final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); + final Task stack = createTaskStackOnDisplay(mDisplayContent); final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(stack); activity.setVisible(false); activity.mIsExiting = true; @@ -266,7 +266,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { // +- [AppWindow1] (being-replaced) // +- [TaskStack2] - [Task2] - [ActivityRecord2] (closing, invisible) // +- [AppWindow2] (being-replaced) - final ActivityStack stack1 = createTaskStackOnDisplay(mDisplayContent); + final Task stack1 = createTaskStackOnDisplay(mDisplayContent); final ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(stack1); final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( TYPE_BASE_APPLICATION); @@ -275,7 +275,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { appWindow1.mWillReplaceWindow = true; activity1.addWindow(appWindow1); - final ActivityStack stack2 = createTaskStackOnDisplay(mDisplayContent); + final Task stack2 = createTaskStackOnDisplay(mDisplayContent); final ActivityRecord activity2 = WindowTestUtils.createTestActivityRecord(stack2); activity2.setVisible(false); activity2.mVisibleRequested = false; @@ -322,7 +322,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { // | // +- [TaskStack2] - [Task2] -+- [ActivityRecord3] (closing, visible) // +- [ActivityRecord4] (invisible) - final ActivityStack stack1 = createTaskStackOnDisplay(mDisplayContent); + final Task stack1 = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack1, 0 /* userId */); final ActivityRecord activity1 = WindowTestUtils.createActivityRecordInTask( mDisplayContent, task1); @@ -333,7 +333,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { activity2.setVisible(false); activity2.mVisibleRequested = false; - final ActivityStack stack2 = createTaskStackOnDisplay(mDisplayContent); + final Task stack2 = createTaskStackOnDisplay(mDisplayContent); final Task task2 = createTaskInStack(stack2, 0 /* userId */); final ActivityRecord activity3 = WindowTestUtils.createActivityRecordInTask( mDisplayContent, task2); @@ -365,7 +365,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { // [DisplayContent] - [TaskStack] - [Task] -+- [ActivityRecord1] (opening, invisible) // +- [ActivityRecord2] (closing, visible) - final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); + final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stack, 0 /* userId */); final ActivityRecord activity1 = WindowTestUtils.createActivityRecordInTask( mDisplayContent, task); @@ -401,7 +401,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { // +- [TaskStack2] - [Task2] -+- [ActivityRecord3] (closing, visible) // +- [ActivityRecord4] (visible) - final ActivityStack stack1 = createTaskStackOnDisplay(mDisplayContent); + final Task stack1 = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack1, 0 /* userId */); final ActivityRecord activity1 = WindowTestUtils.createActivityRecordInTask( mDisplayContent, task1); @@ -412,7 +412,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { final ActivityRecord activity2 = WindowTestUtils.createActivityRecordInTask( mDisplayContent, task1); - final ActivityStack stack2 = createTaskStackOnDisplay(mDisplayContent); + final Task stack2 = createTaskStackOnDisplay(mDisplayContent); final Task task2 = createTaskInStack(stack2, 0 /* userId */); final ActivityRecord activity3 = WindowTestUtils.createActivityRecordInTask( mDisplayContent, task2); @@ -447,7 +447,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { // +- [TaskStack2] - [Task2] -+- [ActivityRecord3] (closing, visible) // +- [ActivityRecord4] (closing, visible) - final ActivityStack stack1 = createTaskStackOnDisplay(mDisplayContent); + final Task stack1 = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack1, 0 /* userId */); final ActivityRecord activity1 = WindowTestUtils.createActivityRecordInTask( mDisplayContent, task1); @@ -460,7 +460,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { activity2.setVisible(false); activity2.mVisibleRequested = true; - final ActivityStack stack2 = createTaskStackOnDisplay(mDisplayContent); + final Task stack2 = createTaskStackOnDisplay(mDisplayContent); final Task task2 = createTaskInStack(stack2, 0 /* userId */); final ActivityRecord activity3 = WindowTestUtils.createActivityRecordInTask( mDisplayContent, task2); @@ -493,7 +493,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { // [DisplayContent] - [TaskStack] -+- [Task1] - [ActivityRecord1] (opening, invisible) // +- [Task2] - [ActivityRecord2] (closing, visible) - final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); + final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack, 0 /* userId */); final ActivityRecord activity1 = WindowTestUtils.createActivityRecordInTask( mDisplayContent, task1); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java index 8c8fd0516623..17914e7fb68c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java @@ -47,7 +47,6 @@ import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; import android.view.WindowManager; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Before; @@ -150,7 +149,7 @@ public class AppTransitionTests extends WindowTestsBase { final DisplayContent dc1 = createNewDisplay(Display.STATE_ON); final DisplayContent dc2 = createNewDisplay(Display.STATE_ON); - final ActivityStack stack1 = createTaskStackOnDisplay(dc1); + final Task stack1 = createTaskStackOnDisplay(dc1); final Task task1 = createTaskInStack(stack1, 0 /* userId */); final ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(dc1); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java index c8b668bac455..97a2ebe98abb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java @@ -82,7 +82,7 @@ import java.util.ArrayList; @RunWith(WindowTestRunner.class) public class AppWindowTokenTests extends WindowTestsBase { - ActivityStack mStack; + Task mStack; Task mTask; ActivityRecord mActivity; @@ -484,7 +484,7 @@ public class AppWindowTokenTests extends WindowTestsBase { } private ActivityRecord createIsolatedTestActivityRecord() { - final ActivityStack taskStack = createTaskStackOnDisplay(mDisplayContent); + final Task taskStack = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(taskStack, 0 /* userId */); return createTestActivityRecordForGivenTask(task); } diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java index ce0aa79f2d89..4abb6059cc59 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java @@ -531,7 +531,7 @@ public class DisplayAreaPolicyBuilderTest { private Map<DisplayArea<?>, Set<Integer>> calculateZSets( DisplayAreaPolicyBuilder.Result policy, DisplayArea<WindowContainer> ime, - DisplayArea<ActivityStack> tasks) { + DisplayArea<Task> tasks) { Map<DisplayArea<?>, Set<Integer>> zSets = new HashMap<>(); int[] types = {TYPE_STATUS_BAR, TYPE_NAVIGATION_BAR, TYPE_PRESENTATION, TYPE_APPLICATION_OVERLAY}; diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java index d75b35a3db79..39bf8eb857b0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java @@ -94,9 +94,9 @@ public class DisplayAreaPolicyTests { @Test public void testTaskDisplayArea_taskPositionChanged_updatesTaskDisplayAreaPosition() { - final ActivityStack stack1 = mTaskDisplayArea1.createStack( + final Task stack1 = mTaskDisplayArea1.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityStack stack2 = mTaskDisplayArea2.createStack( + final Task stack2 = mTaskDisplayArea2.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Initial order @@ -155,11 +155,11 @@ public class DisplayAreaPolicyTests { .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(group2) .setTaskDisplayAreas(Lists.newArrayList(taskDisplayArea5))) .build(wms); - final ActivityStack stack1 = taskDisplayArea1.createStack( + final Task stack1 = taskDisplayArea1.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityStack stack3 = taskDisplayArea3.createStack( + final Task stack3 = taskDisplayArea3.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityStack stack4 = taskDisplayArea4.createStack( + final Task stack4 = taskDisplayArea4.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Initial order diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index f7b7b584fae5..96ea64667f6e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -144,7 +144,7 @@ public class DisplayContentTests extends WindowTestsBase { waitUntilHandlersIdle(); exitingApp.mIsExiting = true; - exitingApp.getTask().getStack().mExitingActivities.add(exitingApp); + exitingApp.getTask().getRootTask().mExitingActivities.add(exitingApp); assertForAllWindowsOrder(Arrays.asList( mWallpaperWindow, @@ -321,7 +321,7 @@ public class DisplayContentTests extends WindowTestsBase { final DisplayContent dc = createNewDisplay(); // Add stack with activity. - final ActivityStack stack = createTaskStackOnDisplay(dc); + final Task stack = createTaskStackOnDisplay(dc); assertEquals(dc.getDisplayId(), stack.getDisplayContent().getDisplayId()); assertEquals(dc, stack.getDisplayContent()); @@ -395,7 +395,7 @@ public class DisplayContentTests extends WindowTestsBase { final DisplayContent dc1 = createNewDisplay(); // Add stack with activity. - final ActivityStack stack0 = createTaskStackOnDisplay(dc0); + final Task stack0 = createTaskStackOnDisplay(dc0); final Task task0 = createTaskInStack(stack0, 0 /* userId */); final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(dc0); @@ -403,7 +403,7 @@ public class DisplayContentTests extends WindowTestsBase { dc0.configureDisplayPolicy(); assertNotNull(dc0.mTapDetector); - final ActivityStack stack1 = createTaskStackOnDisplay(dc1); + final Task stack1 = createTaskStackOnDisplay(dc1); final Task task1 = createTaskInStack(stack1, 0 /* userId */); final ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(dc0); @@ -849,13 +849,13 @@ public class DisplayContentTests extends WindowTestsBase { dc.getDisplayRotation().setFixedToUserRotation( IWindowManager.FIXED_TO_USER_ROTATION_DISABLED); - final ActivityStack stack = + final Task stack = new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootWindowContainer) .setDisplay(dc) .build(); doReturn(true).when(stack).isVisible(); - final ActivityStack freeformStack = + final Task freeformStack = new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootWindowContainer) .setDisplay(dc) .setWindowingMode(WINDOWING_MODE_FREEFORM) @@ -881,7 +881,7 @@ public class DisplayContentTests extends WindowTestsBase { IWindowManager.FIXED_TO_USER_ROTATION_DISABLED); final int newOrientation = getRotatedOrientation(dc); - final ActivityStack stack = + final Task stack = new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootWindowContainer) .setDisplay(dc).build(); final ActivityRecord activity = stack.getTopMostTask().getTopNonFinishingActivity(); @@ -901,7 +901,7 @@ public class DisplayContentTests extends WindowTestsBase { IWindowManager.FIXED_TO_USER_ROTATION_ENABLED); final int newOrientation = getRotatedOrientation(dc); - final ActivityStack stack = + final Task stack = new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootWindowContainer) .setDisplay(dc).build(); final ActivityRecord activity = stack.getTopMostTask().getTopNonFinishingActivity(); @@ -974,26 +974,6 @@ public class DisplayContentTests extends WindowTestsBase { } @Test - public void testComputeImeControlTarget_exitingApp() throws Exception { - final DisplayContent dc = createNewDisplay(); - - WindowState exitingWin = createWindow(null, TYPE_BASE_APPLICATION, "exiting app"); - makeWindowVisible(exitingWin); - exitingWin.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN; - exitingWin.mAnimatingExit = true; - - dc.mInputMethodControlTarget = exitingWin; - dc.mInputMethodTarget = dc.mInputMethodInputTarget = - createWindow(null, TYPE_BASE_APPLICATION, "starting app"); - - assertEquals(exitingWin, dc.computeImeControlTarget()); - - exitingWin.removeImmediately(); - - assertEquals(dc.mInputMethodInputTarget, dc.computeImeControlTarget()); - } - - @Test public void testComputeImeControlTarget_splitscreen() throws Exception { final DisplayContent dc = createNewDisplay(); dc.mInputMethodInputTarget = createWindow(null, TYPE_BASE_APPLICATION, "app"); @@ -1337,7 +1317,7 @@ public class DisplayContentTests extends WindowTestsBase { // Leave PiP to fullscreen. The orientation can be updated from // ActivityRecord#reportDescendantOrientationChangeIfNeeded. pinnedTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN); - homeActivity.setState(ActivityStack.ActivityState.STOPPED, "test"); + homeActivity.setState(Task.ActivityState.STOPPED, "test"); assertFalse(displayContent.hasTopFixedRotationLaunchingApp()); verify(mWm, atLeastOnce()).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt()); @@ -1445,7 +1425,7 @@ public class DisplayContentTests extends WindowTestsBase { TaskDisplayArea defaultTaskDisplayArea = mWm.mRoot.getDefaultTaskDisplayArea(); // Remove the current home stack if it exists so a new one can be created below. - ActivityStack homeTask = defaultTaskDisplayArea.getRootHomeTask(); + Task homeTask = defaultTaskDisplayArea.getRootHomeTask(); if (homeTask != null) { defaultTaskDisplayArea.removeChild(homeTask); } @@ -1461,7 +1441,7 @@ public class DisplayContentTests extends WindowTestsBase { // Remove the current home stack if it exists so a new one can be created below. TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea(); - ActivityStack homeTask = taskDisplayArea.getRootHomeTask(); + Task homeTask = taskDisplayArea.getRootHomeTask(); if (homeTask != null) { taskDisplayArea.removeChild(homeTask); } @@ -1493,7 +1473,7 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testFindScrollCaptureTargetWindow_behindWindow() { DisplayContent display = createNewDisplay(); - ActivityStack stack = createTaskStackOnDisplay(display); + Task stack = createTaskStackOnDisplay(display); Task task = createTaskInStack(stack, 0 /* userId */); WindowState activityWindow = createAppWindow(task, TYPE_APPLICATION, "App Window"); WindowState behindWindow = createWindow(null, TYPE_SCREENSHOT, display, "Screenshot"); @@ -1506,7 +1486,7 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testFindScrollCaptureTargetWindow_taskId() { DisplayContent display = createNewDisplay(); - ActivityStack stack = createTaskStackOnDisplay(display); + Task stack = createTaskStackOnDisplay(display); Task task = createTaskInStack(stack, 0 /* userId */); WindowState window = createAppWindow(task, TYPE_APPLICATION, "App Window"); WindowState behindWindow = createWindow(null, TYPE_SCREENSHOT, display, "Screenshot"); @@ -1533,7 +1513,7 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testSetWindowingModeAtomicallyUpdatesWindoingModeAndDisplayWindowingMode() { final DisplayContent dc = createNewDisplay(); - final ActivityStack stack = + final Task stack = new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootWindowContainer) .setDisplay(dc) .build(); diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java index 0eee3ca53c7d..e18d93d82686 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java @@ -40,7 +40,6 @@ import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.View; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.server.LocalServices; @@ -98,7 +97,7 @@ public class DragDropControllerTests extends WindowTestsBase { private WindowState createDropTargetWindow(String name, int ownerId) { final ActivityRecord activity = WindowTestUtils.createTestActivityRecord( mDisplayContent); - final ActivityStack stack = createTaskStackOnDisplay( + final Task stack = createTaskStackOnDisplay( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent); final Task task = createTaskInStack(stack, ownerId); task.addChild(activity, 0); diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java index 61de7d83fa1a..a7a8505e336d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java @@ -309,12 +309,12 @@ public class LaunchParamsControllerTests extends ActivityTestsBase { mController.registerModifier(positioner); - final int beforeWindowMode = task.getStack().getWindowingMode(); + final int beforeWindowMode = task.getRootTask().getWindowingMode(); assertNotEquals(windowingMode, beforeWindowMode); mController.layoutTask(task, null /* windowLayout */); - final int afterWindowMode = task.getStack().getWindowingMode(); + final int afterWindowMode = task.getRootTask().getWindowingMode(); assertEquals(windowingMode, afterWindowMode); } diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java index 9bf86d2c4704..e389a538f25d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java @@ -114,7 +114,7 @@ public class LaunchParamsPersisterTests extends ActivityTestsBase { when(mRootWindowContainer.getDisplayContent(eq(mDisplayUniqueId))) .thenReturn(mTestDisplay); - ActivityStack stack = mTestDisplay.getDefaultTaskDisplayArea() + Task stack = mTestDisplay.getDefaultTaskDisplayArea() .createStack(TEST_WINDOWING_MODE, ACTIVITY_TYPE_STANDARD, /* onTop */ true); mTestTask = new TaskBuilder(mSupervisor).setComponent(TEST_COMPONENT).setStack(stack) .build(); @@ -337,7 +337,7 @@ public class LaunchParamsPersisterTests extends ActivityTestsBase { public void testClearsRecordsOfTheUserOnUserCleanUp() { mTarget.saveTask(mTestTask); - ActivityStack stack = mTestDisplay.getDefaultTaskDisplayArea().createStack( + Task stack = mTestDisplay.getDefaultTaskDisplayArea().createStack( TEST_WINDOWING_MODE, ACTIVITY_TYPE_STANDARD, /* onTop */ true); final Task anotherTaskOfTheSameUser = new TaskBuilder(mSupervisor) .setComponent(ALTERNATIVE_COMPONENT) diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index fd169018782b..1724303633d9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -105,7 +105,7 @@ public class RecentTasksTest extends ActivityTestsBase { private static final int INVALID_STACK_ID = 999; private TaskDisplayArea mTaskContainer; - private ActivityStack mStack; + private Task mStack; private TestTaskPersister mTaskPersister; private TestRecentTasks mRecentTasks; private TestRunningTasks mRunningTasks; @@ -829,7 +829,7 @@ public class RecentTasksTest extends ActivityTestsBase { mRecentTasks.add(mTasks.get(2)); mRecentTasks.add(mTasks.get(1)); - ActivityStack stack = mTasks.get(2).getStack(); + Task stack = mTasks.get(2).getRootTask(); stack.moveToFront("", mTasks.get(2)); doReturn(stack).when(mService.mRootWindowContainer).getTopDisplayFocusedStack(); @@ -850,8 +850,8 @@ public class RecentTasksTest extends ActivityTestsBase { public void testBackStackTasks_expectNoTrim() { mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */); - final ActivityStack homeStack = mTaskContainer.getRootHomeTask(); - final ActivityStack aboveHomeStack = mTaskContainer.createStack( + final Task homeStack = mTaskContainer.getRootHomeTask(); + final Task aboveHomeStack = mTaskContainer.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Add a number of tasks (beyond the max) but ensure that nothing is trimmed because all @@ -868,10 +868,10 @@ public class RecentTasksTest extends ActivityTestsBase { public void testBehindHomeStackTasks_expectTaskTrimmed() { mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */); - final ActivityStack behindHomeStack = mTaskContainer.createStack( + final Task behindHomeStack = mTaskContainer.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityStack homeStack = mTaskContainer.getRootHomeTask(); - final ActivityStack aboveHomeStack = mTaskContainer.createStack( + final Task homeStack = mTaskContainer.getRootHomeTask(); + final Task aboveHomeStack = mTaskContainer.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Add a number of tasks (beyond the max) but ensure that only the task in the stack behind @@ -890,9 +890,9 @@ public class RecentTasksTest extends ActivityTestsBase { public void testOtherDisplayTasks_expectNoTrim() { mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */); - final ActivityStack homeStack = mTaskContainer.getRootHomeTask(); + final Task homeStack = mTaskContainer.getRootHomeTask(); final DisplayContent otherDisplay = addNewDisplayContentAt(DisplayContent.POSITION_TOP); - final ActivityStack otherDisplayStack = otherDisplay.getDefaultTaskDisplayArea() + final Task otherDisplayStack = otherDisplay.getDefaultTaskDisplayArea() .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Add a number of tasks (beyond the max) on each display, ensure that the tasks are not diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java index 4fbdd616dc93..695a0e3881ea 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -92,7 +92,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { @Mock RecentsAnimationController.RecentsAnimationCallbacks mAnimationCallbacks; @Mock TaskSnapshot mMockTaskSnapshot; private RecentsAnimationController mController; - private ActivityStack mRootHomeTask; + private Task mRootHomeTask; @Before public void setUp() throws Exception { diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java index 44ca2cdcb142..e3cfe11df99f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java @@ -31,8 +31,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; -import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE; +import static com.android.server.wm.Task.ActivityState.PAUSED; import static com.google.common.truth.Truth.assertThat; @@ -88,7 +88,7 @@ public class RecentsAnimationTest extends ActivityTestsBase { @Test public void testRecentsActivityVisiblility() { TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - ActivityStack recentsStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + Task recentsStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */); ActivityRecord recentActivity = new ActivityBuilder(mService) .setComponent(mRecentsComponent) @@ -116,7 +116,7 @@ public class RecentsAnimationTest extends ActivityTestsBase { @Test public void testPreloadRecentsActivity() { TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - final ActivityStack homeStack = + final Task homeStack = defaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); defaultTaskDisplayArea.positionStackAtTop(homeStack, false /* includingParents */); ActivityRecord topRunningHomeActivity = homeStack.topRunningActivity(); @@ -148,7 +148,7 @@ public class RecentsAnimationTest extends ActivityTestsBase { mService.startRecentsActivity(recentsIntent, null /* assistDataReceiver */, null /* recentsAnimationRunner */); - ActivityStack recentsStack = defaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN, + Task recentsStack = defaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS); assertThat(recentsStack).isNotNull(); @@ -177,7 +177,7 @@ public class RecentsAnimationTest extends ActivityTestsBase { public void testRestartRecentsActivity() throws Exception { // Have a recents activity that is not attached to its process (ActivityRecord.app = null). TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - ActivityStack recentsStack = defaultTaskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + Task recentsStack = defaultTaskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */); ActivityRecord recentActivity = new ActivityBuilder(mService).setComponent( mRecentsComponent).setCreateTask(true).setStack(recentsStack).build(); @@ -206,7 +206,7 @@ public class RecentsAnimationTest extends ActivityTestsBase { @Test public void testSetLaunchTaskBehindOfTargetActivity() { TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - ActivityStack homeStack = taskDisplayArea.getRootHomeTask(); + Task homeStack = taskDisplayArea.getRootHomeTask(); // Assume the home activity support recents. ActivityRecord targetActivity = homeStack.getTopNonFinishingActivity(); if (targetActivity == null) { @@ -248,21 +248,21 @@ public class RecentsAnimationTest extends ActivityTestsBase { @Test public void testCancelAnimationOnVisibleStackOrderChange() { TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - ActivityStack fullscreenStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + Task fullscreenStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); new ActivityBuilder(mService) .setComponent(new ComponentName(mContext.getPackageName(), "App1")) .setCreateTask(true) .setStack(fullscreenStack) .build(); - ActivityStack recentsStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + Task recentsStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */); new ActivityBuilder(mService) .setComponent(mRecentsComponent) .setCreateTask(true) .setStack(recentsStack) .build(); - ActivityStack fullscreenStack2 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + Task fullscreenStack2 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); new ActivityBuilder(mService) .setComponent(new ComponentName(mContext.getPackageName(), "App2")) @@ -289,21 +289,21 @@ public class RecentsAnimationTest extends ActivityTestsBase { @Test public void testKeepAnimationOnHiddenStackOrderChange() { TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - ActivityStack fullscreenStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + Task fullscreenStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); new ActivityBuilder(mService) .setComponent(new ComponentName(mContext.getPackageName(), "App1")) .setCreateTask(true) .setStack(fullscreenStack) .build(); - ActivityStack recentsStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + Task recentsStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */); new ActivityBuilder(mService) .setComponent(mRecentsComponent) .setCreateTask(true) .setStack(recentsStack) .build(); - ActivityStack fullscreenStack2 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + Task fullscreenStack2 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); new ActivityBuilder(mService) .setComponent(new ComponentName(mContext.getPackageName(), "App2")) @@ -326,7 +326,7 @@ public class RecentsAnimationTest extends ActivityTestsBase { public void testMultipleUserHomeActivity_findUserHomeTask() { TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultDisplay() .getDefaultTaskDisplayArea(); - ActivityStack homeStack = taskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED, + Task homeStack = taskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME); ActivityRecord otherUserHomeActivity = new ActivityBuilder(mService) .setStack(homeStack) @@ -335,7 +335,7 @@ public class RecentsAnimationTest extends ActivityTestsBase { .build(); otherUserHomeActivity.getTask().mUserId = TEST_USER_ID; - ActivityStack fullscreenStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + Task fullscreenStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); new ActivityBuilder(mService) .setComponent(new ComponentName(mContext.getPackageName(), "App1")) diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java index d53c89628d93..3a5d33396c3a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -37,9 +37,9 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; -import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE; +import static com.android.server.wm.Task.ActivityState.STOPPED; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -68,7 +68,7 @@ import android.util.Pair; import androidx.test.filters.MediumTest; import com.android.internal.app.ResolverActivity; -import com.android.server.wm.ActivityStack.ActivityState; +import com.android.server.wm.Task.ActivityState; import org.junit.Before; import org.junit.Test; @@ -89,7 +89,7 @@ import java.util.function.Consumer; @Presubmit @RunWith(WindowTestRunner.class) public class RootActivityContainerTests extends ActivityTestsBase { - private ActivityStack mFullscreenStack; + private Task mFullscreenStack; @Before public void setUp() throws Exception { @@ -132,7 +132,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { mRootWindowContainer.moveActivityToPinnedStack(firstActivity, "initialMove"); final TaskDisplayArea taskDisplayArea = mFullscreenStack.getDisplayArea(); - ActivityStack pinnedStack = taskDisplayArea.getRootPinnedTask(); + Task pinnedStack = taskDisplayArea.getRootPinnedTask(); // Ensure a task has moved over. ensureStackPlacement(pinnedStack, firstActivity); ensureStackPlacement(mFullscreenStack, secondActivity); @@ -172,7 +172,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { assertTrue(firstActivity.mRequestForceTransition); } - private static void ensureStackPlacement(ActivityStack stack, ActivityRecord... activities) { + private static void ensureStackPlacement(Task stack, ActivityRecord... activities) { final Task task = stack.getBottomMostTask(); final ArrayList<ActivityRecord> stackActivities = new ArrayList<>(); @@ -194,7 +194,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { public void testApplySleepTokens() { final DisplayContent display = mRootWindowContainer.getDefaultDisplay(); final KeyguardController keyguard = mSupervisor.getKeyguardController(); - final ActivityStack stack = new StackBuilder(mRootWindowContainer) + final Task stack = new StackBuilder(mRootWindowContainer) .setCreateActivity(false) .setDisplay(display) .setOnTop(false) @@ -229,7 +229,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { } private void verifySleepTokenBehavior(DisplayContent display, KeyguardController keyguard, - ActivityStack stack, boolean displaySleeping, boolean displayShouldSleep, + Task stack, boolean displaySleeping, boolean displayShouldSleep, boolean isFocusedStack, boolean keyguardShowing, boolean expectWakeFromSleep, boolean expectResumeTopActivity) { reset(stack); @@ -285,7 +285,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer .getDefaultTaskDisplayArea(); final int originalStackCount = defaultTaskDisplayArea.getStackCount(); - final ActivityStack stack = defaultTaskDisplayArea.createStack( + final Task stack = defaultTaskDisplayArea.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true) .setStack(stack).build(); @@ -309,7 +309,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer .getDefaultTaskDisplayArea(); final int originalStackCount = defaultTaskDisplayArea.getStackCount(); - final ActivityStack stack = defaultTaskDisplayArea.createStack( + final Task stack = defaultTaskDisplayArea.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true) .setStack(stack).build(); @@ -318,7 +318,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { final DisplayContent dc = defaultTaskDisplayArea.getDisplayContent(); final TaskDisplayArea secondTaskDisplayArea = WindowTestsBase.createTaskDisplayArea(dc, mRootWindowContainer.mWmService, "TestTaskDisplayArea", FEATURE_VENDOR_FIRST); - final ActivityStack secondStack = secondTaskDisplayArea.createStack( + final Task secondStack = secondTaskDisplayArea.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); new ActivityBuilder(mService).setCreateTask(true).setStack(secondStack) .setUseProcess(firstActivity.app).build(); @@ -337,7 +337,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { public void testFocusability() { final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer .getDefaultTaskDisplayArea(); - final ActivityStack stack = defaultTaskDisplayArea.createStack( + final Task stack = defaultTaskDisplayArea.createStack( WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true) .setStack(stack).build(); @@ -351,7 +351,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { assertFalse(stack.isTopActivityFocusable()); assertFalse(activity.isFocusable()); - final ActivityStack pinnedStack = defaultTaskDisplayArea.createStack( + final Task pinnedStack = defaultTaskDisplayArea.createStack( WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */); final ActivityRecord pinnedActivity = new ActivityBuilder(mService).setCreateTask(true) .setStack(pinnedStack).build(); @@ -380,7 +380,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { @Test public void testSplitScreenPrimaryChosenWhenTopActivityLaunchedToSecondary() { // Create primary split-screen stack with a task and an activity. - final ActivityStack primaryStack = mRootWindowContainer.getDefaultTaskDisplayArea() + final Task primaryStack = mRootWindowContainer.getDefaultTaskDisplayArea() .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); final Task task = new TaskBuilder(mSupervisor).setStack(primaryStack).build(); @@ -390,7 +390,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { // split-screen secondary. final ActivityOptions options = ActivityOptions.makeBasic(); options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY); - final ActivityStack result = + final Task result = mRootWindowContainer.getLaunchStack(r, options, task, true /* onTop */); // Assert that the primary stack is returned. @@ -403,13 +403,13 @@ public class RootActivityContainerTests extends ActivityTestsBase { @Test public void testFindTaskToMoveToFrontWhenRecentsOnTop() { // Create stack/task on default display. - final ActivityStack targetStack = new StackBuilder(mRootWindowContainer) + final Task targetStack = new StackBuilder(mRootWindowContainer) .setOnTop(false) .build(); final Task targetTask = targetStack.getBottomMostTask(); // Create Recents on top of the display. - final ActivityStack stack = new StackBuilder(mRootWindowContainer).setActivityType( + final Task stack = new StackBuilder(mRootWindowContainer).setActivityType( ACTIVITY_TYPE_RECENTS).build(); final String reason = "findTaskToMoveToFront"; @@ -428,14 +428,14 @@ public class RootActivityContainerTests extends ActivityTestsBase { public void testFindTaskToMoveToFrontWhenRecentsOnOtherDisplay() { // Create stack/task on default display. final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - final ActivityStack targetStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + final Task targetStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); final Task targetTask = new TaskBuilder(mSupervisor).setStack(targetStack).build(); // Create Recents on secondary display. final TestDisplayContent secondDisplay = addNewDisplayContentAt( DisplayContent.POSITION_TOP); - final ActivityStack stack = secondDisplay.getDefaultTaskDisplayArea() + final Task stack = secondDisplay.getDefaultTaskDisplayArea() .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */); final Task task = new TaskBuilder(mSupervisor).setStack(stack).build(); new ActivityBuilder(mService).setTask(task).build(); @@ -455,7 +455,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { public void testResumeActivityWhenNonTopmostStackIsTopFocused() { // Create a stack at bottom. final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - final ActivityStack targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + final Task targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */)); final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build(); final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build(); @@ -511,7 +511,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { // Create an activity on secondary display. final TestDisplayContent secondDisplay = addNewDisplayContentAt( DisplayContent.POSITION_TOP); - final ActivityStack stack = secondDisplay.getDefaultTaskDisplayArea() + final Task stack = secondDisplay.getDefaultTaskDisplayArea() .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); final Task task = new TaskBuilder(mSupervisor).setStack(stack).build(); new ActivityBuilder(mService).setTask(task).build(); @@ -535,7 +535,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { public void testResumeActivityLingeringTransition() { // Create a stack at top. final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - final ActivityStack targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + final Task targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */)); final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build(); final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build(); @@ -555,7 +555,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { public void testResumeActivityLingeringTransition_notExecuted() { // Create a stack at bottom. final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - final ActivityStack targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + final Task targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */)); final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build(); final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build(); @@ -868,7 +868,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN); doReturn(true).when(mSupervisor).canPlaceEntityOnDisplay(secondaryDisplay.mDisplayId, 300 /* test realCallerPid */, 300 /* test realCallerUid */, r.info); - final ActivityStack result = mRootWindowContainer.getLaunchStack(r, options, + final Task result = mRootWindowContainer.getLaunchStack(r, options, null /* task */, true /* onTop */, null, 300 /* test realCallerPid */, 300 /* test realCallerUid */); @@ -889,7 +889,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { .setTask(task).build(); // Make sure the root task is valid and can be reused on default display. - final ActivityStack stack = mRootWindowContainer.getValidLaunchStackInTaskDisplayArea( + final Task stack = mRootWindowContainer.getValidLaunchStackInTaskDisplayArea( mRootWindowContainer.getDefaultTaskDisplayArea(), activity, task, null, null); assertEquals(task, stack); @@ -900,7 +900,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { doReturn(mFullscreenStack).when(mRootWindowContainer).getTopDisplayFocusedStack(); final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - ActivityStack homeStack = taskDisplayArea.getRootHomeTask(); + Task homeStack = taskDisplayArea.getRootHomeTask(); if (homeStack != null) { homeStack.removeImmediately(); } @@ -920,7 +920,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { // Create an activity on secondary display. final TestDisplayContent secondDisplay = addNewDisplayContentAt( DisplayContent.POSITION_TOP); - final ActivityStack stack = secondDisplay.getDefaultTaskDisplayArea() + final Task stack = secondDisplay.getDefaultTaskDisplayArea() .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); final ActivityRecord activity = new ActivityBuilder(mService).setStack(stack).build(); spyOn(activity); diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java index 181de8e2a1a3..2e4c9ea747c5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java @@ -25,11 +25,13 @@ import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; -import static com.android.server.wm.ActivityStack.ActivityState.FINISHING; -import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; -import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; -import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; -import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.server.wm.Task.ActivityState.FINISHING; +import static com.android.server.wm.Task.ActivityState.PAUSED; +import static com.android.server.wm.Task.ActivityState.PAUSING; +import static com.android.server.wm.Task.ActivityState.STOPPED; +import static com.android.server.wm.Task.ActivityState.STOPPING; import static com.google.common.truth.Truth.assertThat; @@ -149,7 +151,7 @@ public class RootWindowContainerTests extends WindowTestsBase { public void testAllPausedActivitiesComplete() { DisplayContent displayContent = mWm.mRoot.getDisplayContent(DEFAULT_DISPLAY); TaskDisplayArea taskDisplayArea = displayContent.getDefaultTaskDisplayArea(); - ActivityStack stack = taskDisplayArea.getStackAt(0); + Task stack = taskDisplayArea.getStackAt(0); ActivityRecord activity = createActivityRecord(displayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); stack.mPausingActivity = activity; @@ -169,5 +171,27 @@ public class RootWindowContainerTests extends WindowTestsBase { activity.setState(FINISHING, "test FINISHING"); assertThat(mWm.mRoot.allPausedActivitiesComplete()).isTrue(); } + + @Test + public void testForceStopPackage() { + final Task task = new ActivityTestsBase.StackBuilder(mWm.mRoot).build(); + final ActivityRecord activity1 = task.getTopMostActivity(); + final ActivityRecord activity2 = + new ActivityTestsBase.ActivityBuilder(mWm.mAtmService).setStack(task).build(); + final WindowProcessController wpc = activity1.app; + spyOn(wpc); + activity1.app = null; + activity2.setProcess(wpc); + doReturn(true).when(wpc).isRemoved(); + + mWm.mAtmService.mInternal.onForceStopPackage(wpc.mInfo.packageName, true /* doit */, + false /* evenPersistent */, wpc.mUserId); + // The activity without process should be removed. + assertEquals(1, task.getChildCount()); + + mWm.mRoot.handleAppDied(wpc); + // The activity with process should be removed because WindowProcessController#isRemoved. + assertFalse(task.hasChild()); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java index 3d3a0f148db5..e51a133d5cce 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java @@ -62,7 +62,7 @@ public class RunningTasksTest extends ActivityTestsBase { final int numStacks = 2; for (int stackIndex = 0; stackIndex < numStacks; stackIndex++) { - final ActivityStack stack = new StackBuilder(mRootWindowContainer) + final Task stack = new StackBuilder(mRootWindowContainer) .setCreateActivity(false) .setDisplay(display) .setOnTop(false) @@ -104,7 +104,7 @@ public class RunningTasksTest extends ActivityTestsBase { final DisplayContent display = new TestDisplayContent.Builder(mService, 1000, 2500).build(); final int numTasks = 10; for (int i = 0; i < numTasks; i++) { - final ActivityStack stack = new StackBuilder(mRootWindowContainer) + final Task stack = new StackBuilder(mRootWindowContainer) .setCreateActivity(false) .setDisplay(display) .setOnTop(true) @@ -130,7 +130,7 @@ public class RunningTasksTest extends ActivityTestsBase { /** * Create a task with a single activity in it, with the given last active time. */ - private Task createTask(ActivityStack stack, String className, int taskId, + private Task createTask(Task stack, String className, int taskId, int lastActiveTime, Bundle extras) { final Task task = new TaskBuilder(mService.mStackSupervisor) .setComponent(new ComponentName(mContext.getPackageName(), className)) diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index a979c862a8e4..250cf09e8547 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -29,7 +29,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; -import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; +import static com.android.server.wm.Task.ActivityState.STOPPED; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -65,7 +65,7 @@ import java.util.ArrayList; @Presubmit @RunWith(WindowTestRunner.class) public class SizeCompatTests extends ActivityTestsBase { - private ActivityStack mStack; + private Task mStack; private Task mTask; private ActivityRecord mActivity; @@ -86,7 +86,7 @@ public class SizeCompatTests extends ActivityTestsBase { doNothing().when(mSupervisor).scheduleRestartTimeout(mActivity); mActivity.mVisibleRequested = true; mActivity.setSavedState(null /* savedState */); - mActivity.setState(ActivityStack.ActivityState.RESUMED, "testRestart"); + mActivity.setState(Task.ActivityState.RESUMED, "testRestart"); prepareUnresizable(1.5f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED); final Rect originalOverrideBounds = new Rect(mActivity.getBounds()); @@ -94,7 +94,7 @@ public class SizeCompatTests extends ActivityTestsBase { // The visible activity should recompute configuration according to the last parent bounds. mService.restartActivityProcessIfVisible(mActivity.appToken); - assertEquals(ActivityStack.ActivityState.RESTARTING_PROCESS, mActivity.getState()); + assertEquals(Task.ActivityState.RESTARTING_PROCESS, mActivity.getState()); assertNotEquals(originalOverrideBounds, mActivity.getBounds()); } @@ -449,7 +449,7 @@ public class SizeCompatTests extends ActivityTestsBase { public void testHandleActivitySizeCompatMode() { setUpDisplaySizeWithApp(1000, 2000); ActivityRecord activity = mActivity; - activity.setState(ActivityStack.ActivityState.RESUMED, "testHandleActivitySizeCompatMode"); + activity.setState(Task.ActivityState.RESUMED, "testHandleActivitySizeCompatMode"); prepareUnresizable(-1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); assertFitted(); @@ -476,7 +476,7 @@ public class SizeCompatTests extends ActivityTestsBase { activity.mVisibleRequested = true; activity.restartProcessIfVisible(); // The full lifecycle isn't hooked up so manually set state to resumed - activity.setState(ActivityStack.ActivityState.RESUMED, "testHandleActivitySizeCompatMode"); + activity.setState(Task.ActivityState.RESUMED, "testHandleActivitySizeCompatMode"); mStack.getDisplay().handleActivitySizeCompatModeIfNeeded(activity); // Expect null token when switching to non-size-compat mode activity. diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java index 2233b2234c68..ff753f21d01b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java @@ -26,7 +26,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.anyInt; import static java.util.concurrent.TimeUnit.SECONDS; @@ -34,6 +33,7 @@ import android.animation.AnimationHandler.AnimationFrameCallbackProvider; import android.animation.ValueAnimator; import android.graphics.Matrix; import android.graphics.Point; +import android.hardware.power.Boost; import android.os.Handler; import android.os.PowerManagerInternal; import android.platform.test.annotations.Presubmit; @@ -202,7 +202,7 @@ public class SurfaceAnimationRunnerTest { mMockTransaction, this::finishedCallback); waitUntilNextFrame(); - verify(mMockPowerManager).powerHint(anyInt(), eq(0)); + verify(mMockPowerManager).setPowerBoost(eq(Boost.INTERACTION), eq(0)); } private void waitUntilNextFrame() throws Exception { 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 50675b03ae1f..eb7d9c2d3c32 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java @@ -319,7 +319,7 @@ public class SystemServicesTestRule implements TestRule { spyOn(display); final TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea(); spyOn(taskDisplayArea); - final ActivityStack homeStack = taskDisplayArea.getStack( + final Task homeStack = taskDisplayArea.getStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); spyOn(homeStack); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java index 8c3661b409f4..27a8fc3c5943 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java @@ -32,7 +32,7 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; -import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; +import static com.android.server.wm.Task.ActivityState.RESUMED; import static com.google.common.truth.Truth.assertThat; @@ -67,7 +67,7 @@ import org.junit.runner.RunWith; @RunWith(WindowTestRunner.class) public class TaskDisplayAreaTests extends WindowTestsBase { - private ActivityStack mPinnedStack; + private Task mPinnedStack; @Before public void setUp() throws Exception { @@ -89,7 +89,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase { @Test public void testActivityWithZBoost_taskDisplayAreaDoesNotMoveUp() { - final ActivityStack stack = createTaskStackOnDisplay( + final Task stack = createTaskStackOnDisplay( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent); final Task task = createTaskInStack(stack, 0 /* userId */); final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(mDisplayContent); @@ -109,8 +109,8 @@ public class TaskDisplayAreaTests extends WindowTestsBase { @Test public void testStackPositionChildAt() { // Test that always-on-top stack can't be moved to position other than top. - final ActivityStack stack1 = createTaskStackOnDisplay(mDisplayContent); - final ActivityStack stack2 = createTaskStackOnDisplay(mDisplayContent); + final Task stack1 = createTaskStackOnDisplay(mDisplayContent); + final Task stack2 = createTaskStackOnDisplay(mDisplayContent); final WindowContainer taskStackContainer = stack1.getParent(); @@ -134,7 +134,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase { @Test public void testStackPositionBelowPinnedStack() { // Test that no stack can be above pinned stack. - final ActivityStack stack1 = createTaskStackOnDisplay(mDisplayContent); + final Task stack1 = createTaskStackOnDisplay(mDisplayContent); final WindowContainer taskStackContainer = stack1.getParent(); @@ -158,7 +158,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase { doReturn(true).when(mDisplayContent).isTrusted(); // The display contains pinned stack that was added in {@link #setUp}. - final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); + final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stack, 0 /* userId */); // Add another display at top. @@ -216,10 +216,10 @@ public class TaskDisplayAreaTests extends WindowTestsBase { final TaskDisplayArea defaultTaskDisplayArea = rootWindowContainer.getDefaultTaskDisplayArea(); - final ActivityStack rootHomeTask = defaultTaskDisplayArea.getRootHomeTask(); + final Task rootHomeTask = defaultTaskDisplayArea.getRootHomeTask(); rootHomeTask.mResizeMode = RESIZE_MODE_UNRESIZEABLE; - final ActivityStack primarySplitTask = + final Task primarySplitTask = new ActivityTestsBase.StackBuilder(rootWindowContainer) .setTaskDisplayArea(defaultTaskDisplayArea) .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) @@ -247,7 +247,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase { private void assertGetOrCreateStack(int windowingMode, int activityType, Task candidateTask, boolean reuseCandidate) { final TaskDisplayArea taskDisplayArea = candidateTask.getDisplayArea(); - final ActivityStack stack = taskDisplayArea.getOrCreateStack(windowingMode, activityType, + final Task stack = taskDisplayArea.getOrCreateStack(windowingMode, activityType, false /* onTop */, null /* intent */, candidateTask /* candidateTask */); assertEquals(reuseCandidate, stack == candidateTask); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java index a69231b9e03a..a048526bb068 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java @@ -30,7 +30,6 @@ import static android.util.DisplayMetrics.DENSITY_DEFAULT; import static android.view.Display.DEFAULT_DISPLAY; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP; @@ -1350,13 +1349,13 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { } private ActivityRecord createSourceActivity(TestDisplayContent display) { - final ActivityStack stack = display.getDefaultTaskDisplayArea() + final Task stack = display.getDefaultTaskDisplayArea() .createStack(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true); return new ActivityBuilder(mService).setStack(stack).setCreateTask(true).build(); } private void addFreeformTaskTo(TestDisplayContent display, Rect bounds) { - final ActivityStack stack = display.getDefaultTaskDisplayArea() + final Task stack = display.getDefaultTaskDisplayArea() .createStack(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true); stack.setWindowingMode(WINDOWING_MODE_FREEFORM); final Task task = new TaskBuilder(mSupervisor).setStack(stack).build(); 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 93dcc9103640..0db3f94d1fc3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java @@ -37,7 +37,6 @@ import android.platform.test.annotations.Presubmit; import android.util.DisplayMetrics; import android.util.Log; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.After; @@ -77,7 +76,7 @@ public class TaskPositionerTests extends WindowTestsBase { mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, dm); removeGlobalMinSizeRestriction(); - final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); + final Task stack = createTaskStackOnDisplay(mDisplayContent); final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(stack.mAtmService) .setStack(stack) // In real case, there is no additional level for freeform mode. 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 abdbd5131fd9..bf76c8ee5f0a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java @@ -173,7 +173,7 @@ public class TaskRecordTests extends ActivityTestsBase { public void testFitWithinBounds() { final Rect parentBounds = new Rect(10, 10, 200, 200); TaskDisplayArea taskDisplayArea = mService.mRootWindowContainer.getDefaultTaskDisplayArea(); - ActivityStack stack = taskDisplayArea.createStack(WINDOWING_MODE_FREEFORM, + Task stack = taskDisplayArea.createStack(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */); Task task = new TaskBuilder(mSupervisor).setStack(stack).build(); final Configuration parentConfig = stack.getConfiguration(); @@ -211,7 +211,7 @@ public class TaskRecordTests extends ActivityTestsBase { @Test public void testBoundsOnModeChangeFreeformToFullscreen() { DisplayContent display = mService.mRootWindowContainer.getDefaultDisplay(); - ActivityStack stack = new StackBuilder(mRootWindowContainer).setDisplay(display) + Task stack = new StackBuilder(mRootWindowContainer).setDisplay(display) .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); Task task = stack.getBottomMostTask(); task.getRootActivity().setOrientation(SCREEN_ORIENTATION_UNSPECIFIED); @@ -252,7 +252,7 @@ public class TaskRecordTests extends ActivityTestsBase { dr.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED); dr.setUserRotation(USER_ROTATION_FREE, ROTATION_0); - ActivityStack stack = new StackBuilder(mRootWindowContainer) + Task stack = new StackBuilder(mRootWindowContainer) .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build(); Task task = stack.getBottomMostTask(); ActivityRecord root = task.getTopNonFinishingActivity(); @@ -313,7 +313,7 @@ public class TaskRecordTests extends ActivityTestsBase { Configuration.ORIENTATION_LANDSCAPE; display.onRequestedOverrideConfigurationChanged( display.getRequestedOverrideConfiguration()); - ActivityStack stack = new StackBuilder(mRootWindowContainer) + Task stack = new StackBuilder(mRootWindowContainer) .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build(); Task task = stack.getBottomMostTask(); ActivityRecord root = task.getTopNonFinishingActivity(); @@ -324,7 +324,7 @@ public class TaskRecordTests extends ActivityTestsBase { parentWindowContainer.setBounds(fullScreenBounds); doReturn(parentWindowContainer).when(task).getParent(); doReturn(display.getDefaultTaskDisplayArea()).when(task).getDisplayArea(); - doReturn(stack).when(task).getStack(); + doReturn(stack).when(task).getRootTask(); doReturn(true).when(parentWindowContainer).handlesOrientationChangeFromDescendant(); // Setting app to fixed portrait fits within parent, but Task shouldn't adjust the @@ -409,15 +409,15 @@ public class TaskRecordTests extends ActivityTestsBase { assertTrue(task.getResolvedOverrideBounds().isEmpty()); int origScreenH = task.getConfiguration().screenHeightDp; Configuration stackConfig = new Configuration(); - stackConfig.setTo(task.getStack().getRequestedOverrideConfiguration()); + stackConfig.setTo(task.getRootTask().getRequestedOverrideConfiguration()); stackConfig.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); // Set bounds on stack (not task) and verify that the task resource configuration changes // despite it's override bounds being empty. - Rect bounds = new Rect(task.getStack().getBounds()); + Rect bounds = new Rect(task.getRootTask().getBounds()); bounds.bottom = (int) (bounds.bottom * 0.6f); stackConfig.windowConfiguration.setBounds(bounds); - task.getStack().onRequestedOverrideConfigurationChanged(stackConfig); + task.getRootTask().onRequestedOverrideConfigurationChanged(stackConfig); assertNotEquals(origScreenH, task.getConfiguration().screenHeightDp); } @@ -439,7 +439,7 @@ public class TaskRecordTests extends ActivityTestsBase { @Test public void testInsetDisregardedWhenFreeformOverlapsNavBar() { TaskDisplayArea taskDisplayArea = mService.mRootWindowContainer.getDefaultTaskDisplayArea(); - ActivityStack stack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + Task stack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); DisplayInfo displayInfo = new DisplayInfo(); mService.mContext.getDisplay().getDisplayInfo(displayInfo); @@ -514,7 +514,7 @@ public class TaskRecordTests extends ActivityTestsBase { info.packageName = DEFAULT_COMPONENT_PACKAGE_NAME; info.targetActivity = targetClassName; - final Task task = new ActivityStack(mService, 1 /* taskId */, info, intent, + final Task task = new Task(mService, 1 /* taskId */, info, intent, null /* voiceSession */, null /* voiceInteractor */, null /* taskDescriptor */, null /*stack*/); assertEquals("The alias activity component should be saved in task intent.", aliasClassName, @@ -880,7 +880,7 @@ public class TaskRecordTests extends ActivityTestsBase { final Task task = getTestTask(); task.setHasBeenVisible(false); task.getDisplayContent().setDisplayWindowingMode(WINDOWING_MODE_FREEFORM); - task.getStack().setWindowingMode(WINDOWING_MODE_FULLSCREEN); + task.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN); task.setHasBeenVisible(true); task.onConfigurationChanged(task.getParent().getConfiguration()); @@ -896,7 +896,7 @@ public class TaskRecordTests extends ActivityTestsBase { final Task task = getTestTask(); task.setHasBeenVisible(false); task.getDisplayContent().setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM); - task.getStack().setWindowingMode(WINDOWING_MODE_FULLSCREEN); + task.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN); final DisplayContent oldDisplay = task.getDisplayContent(); LaunchParamsController.LaunchParams params = new LaunchParamsController.LaunchParams(); @@ -920,7 +920,7 @@ public class TaskRecordTests extends ActivityTestsBase { final Task task = getTestTask(); task.setHasBeenVisible(false); - task.getStack().setWindowingMode(WINDOWING_MODE_FULLSCREEN); + task.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN); task.setHasBeenVisible(true); task.onConfigurationChanged(task.getParent().getConfiguration()); @@ -936,7 +936,7 @@ public class TaskRecordTests extends ActivityTestsBase { final Task task = getTestTask(); task.setHasBeenVisible(false); task.getDisplayContent().setDisplayWindowingMode(WINDOWING_MODE_FREEFORM); - task.getStack().setWindowingMode(WINDOWING_MODE_PINNED); + task.getRootTask().setWindowingMode(WINDOWING_MODE_PINNED); task.setHasBeenVisible(true); task.onConfigurationChanged(task.getParent().getConfiguration()); @@ -976,7 +976,7 @@ public class TaskRecordTests extends ActivityTestsBase { } private Task getTestTask() { - final ActivityStack stack = new StackBuilder(mRootWindowContainer).build(); + final Task stack = new StackBuilder(mRootWindowContainer).build(); return stack.getBottomMostTask(); } @@ -984,7 +984,7 @@ public class TaskRecordTests extends ActivityTestsBase { Rect expectedConfigBounds) { TaskDisplayArea taskDisplayArea = mService.mRootWindowContainer.getDefaultTaskDisplayArea(); - ActivityStack stack = taskDisplayArea.createStack(windowingMode, ACTIVITY_TYPE_STANDARD, + Task stack = taskDisplayArea.createStack(windowingMode, ACTIVITY_TYPE_STANDARD, true /* onTop */); Task task = new TaskBuilder(mSupervisor).setStack(stack).build(); @@ -1024,7 +1024,7 @@ public class TaskRecordTests extends ActivityTestsBase { } private Task createTask(int taskId) { - return new ActivityStack(mService, taskId, new Intent(), null, null, null, + return new Task(mService, taskId, new Intent(), null, null, null, ActivityBuilder.getDefaultComponent(), null, false, false, false, 0, 10050, null, 0, false, null, 0, 0, 0, 0, null, null, 0, false, false, false, 0, 0, null /*ActivityInfo*/, null /*_voiceSession*/, null /*_voiceInteractor*/, diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java index f1dbde066125..205b842253b7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java @@ -59,7 +59,7 @@ public class TaskStackTests extends WindowTestsBase { @Test public void testStackPositionChildAt() { - final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); + final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack, 0 /* userId */); final Task task2 = createTaskInStack(stack, 1 /* userId */); @@ -74,8 +74,8 @@ public class TaskStackTests extends WindowTestsBase { assertEquals(stack.mChildren.get(1), task1); // Non-leaf task should be moved to top regardless of the user id. - createTaskInStack((ActivityStack) task2, 0 /* userId */); - createTaskInStack((ActivityStack) task2, 1 /* userId */); + createTaskInStack(task2, 0 /* userId */); + createTaskInStack(task2, 1 /* userId */); stack.positionChildAt(WindowContainer.POSITION_TOP, task2, false /* includingParents */); assertEquals(stack.mChildren.get(0), task1); assertEquals(stack.mChildren.get(1), task2); @@ -83,7 +83,7 @@ public class TaskStackTests extends WindowTestsBase { @Test public void testClosingAppDifferentStackOrientation() { - final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); + final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack, 0 /* userId */); ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(mDisplayContent); @@ -103,7 +103,7 @@ public class TaskStackTests extends WindowTestsBase { @Test public void testMoveTaskToBackDifferentStackOrientation() { - final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); + final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack, 0 /* userId */); ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(mDisplayContent); @@ -120,9 +120,9 @@ public class TaskStackTests extends WindowTestsBase { @Test public void testStackRemoveImmediately() { - final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); + final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stack, 0 /* userId */); - assertEquals(stack, task.getStack()); + assertEquals(stack, task.getRootTask()); // Remove stack and check if its child is also removed. stack.removeImmediately(); @@ -132,7 +132,7 @@ public class TaskStackTests extends WindowTestsBase { @Test public void testRemoveContainer() { - final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); + final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stack, 0 /* userId */); assertNotNull(stack); @@ -148,7 +148,7 @@ public class TaskStackTests extends WindowTestsBase { @Test public void testRemoveContainer_deferRemoval() { - final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); + final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stack, 0 /* userId */); // Stack removal is deferred if one of its child is animating. @@ -172,12 +172,12 @@ public class TaskStackTests extends WindowTestsBase { @Test public void testReparent() { // Create first stack on primary display. - final ActivityStack stack1 = createTaskStackOnDisplay(mDisplayContent); + final Task stack1 = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack1, 0 /* userId */); // Create second display and put second stack on it. final DisplayContent dc = createNewDisplay(); - final ActivityStack stack2 = createTaskStackOnDisplay(dc); + final Task stack2 = createTaskStackOnDisplay(dc); // Reparent clearInvocations(task1); // reset the number of onDisplayChanged for task. @@ -191,7 +191,7 @@ public class TaskStackTests extends WindowTestsBase { @Test public void testStackOutset() { - final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); + final Task stack = createTaskStackOnDisplay(mDisplayContent); final int stackOutset = 10; spyOn(stack); doReturn(stackOutset).when(stack).getTaskOutset(); @@ -219,7 +219,7 @@ public class TaskStackTests extends WindowTestsBase { @Test public void testActivityAndTaskGetsProperType() { - final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); + final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack, 0 /* userId */); ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(mDisplayContent); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java index 9d88ada5a90c..92b6e6ef8ec9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -54,7 +54,7 @@ public class TaskTests extends WindowTestsBase { @Test public void testRemoveContainer() { - final ActivityStack stackController1 = createTaskStackOnDisplay(mDisplayContent); + final Task stackController1 = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stackController1, 0 /* userId */); final ActivityRecord activity = WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); @@ -68,7 +68,7 @@ public class TaskTests extends WindowTestsBase { @Test public void testRemoveContainer_deferRemoval() { - final ActivityStack stackController1 = createTaskStackOnDisplay(mDisplayContent); + final Task stackController1 = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stackController1, 0 /* userId */); final ActivityRecord activity = WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); @@ -90,9 +90,9 @@ public class TaskTests extends WindowTestsBase { @Test public void testReparent() { - final ActivityStack stackController1 = createTaskStackOnDisplay(mDisplayContent); + final Task stackController1 = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stackController1, 0 /* userId */); - final ActivityStack stackController2 = createTaskStackOnDisplay(mDisplayContent); + final Task stackController2 = createTaskStackOnDisplay(mDisplayContent); final Task task2 = createTaskInStack(stackController2, 0 /* userId */); boolean gotException = false; @@ -120,13 +120,13 @@ public class TaskTests extends WindowTestsBase { @Test public void testReparent_BetweenDisplays() { // Create first stack on primary display. - final ActivityStack stack1 = createTaskStackOnDisplay(mDisplayContent); + final Task stack1 = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stack1, 0 /* userId */); assertEquals(mDisplayContent, stack1.getDisplayContent()); // Create second display and put second stack on it. final DisplayContent dc = createNewDisplay(); - final ActivityStack stack2 = createTaskStackOnDisplay(dc); + final Task stack2 = createTaskStackOnDisplay(dc); final Task task2 = createTaskInStack(stack2, 0 /* userId */); // Reparent and check state clearInvocations(task); // reset the number of onDisplayChanged for task. @@ -139,7 +139,7 @@ public class TaskTests extends WindowTestsBase { @Test public void testBounds() { - final ActivityStack stack1 = createTaskStackOnDisplay(mDisplayContent); + final Task stack1 = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stack1, 0 /* userId */); // Check that setting bounds also updates surface position @@ -186,4 +186,19 @@ public class TaskTests extends WindowTestsBase { assertTrue(r.finishing); }); } + + @Test + public void testSwitchUser() { + final Task rootTask = createTaskStackOnDisplay(mDisplayContent); + final Task childTask = createTaskInStack(rootTask, 0 /* userId */); + final Task leafTask1 = createTaskInStack(childTask, 10 /* userId */); + final Task leafTask2 = createTaskInStack(childTask, 0 /* userId */); + assertEquals(1, rootTask.getChildCount()); + assertEquals(leafTask2, childTask.getTopChild()); + + doReturn(true).when(leafTask1).showToCurrentUser(); + rootTask.switchUser(10); + assertEquals(1, rootTask.getChildCount()); + assertEquals(leafTask1, childTask.getTopChild()); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java index efc03df877b7..3ebc28886377 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java @@ -808,7 +808,7 @@ public class WindowContainerTests extends WindowTestsBase { @Test public void testOnDisplayChanged() { - final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); + final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stack, 0 /* userId */); final ActivityRecord activity = WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); @@ -852,7 +852,7 @@ public class WindowContainerTests extends WindowTestsBase { @Test public void testTaskCanApplyAnimation() { - final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); + final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stack, 0 /* userId */); final ActivityRecord activity2 = WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); @@ -863,7 +863,7 @@ public class WindowContainerTests extends WindowTestsBase { @Test public void testStackCanApplyAnimation() { - final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); + final Task stack = createTaskStackOnDisplay(mDisplayContent); final ActivityRecord activity2 = WindowTestUtils.createActivityRecordInTask(mDisplayContent, createTaskInStack(stack, 0 /* userId */)); final ActivityRecord activity1 = WindowTestUtils.createActivityRecordInTask(mDisplayContent, @@ -879,7 +879,7 @@ public class WindowContainerTests extends WindowTestsBase { assertNull(windowContainer.getDisplayArea()); // ActivityStack > WindowContainer - final ActivityStack activityStack = createTaskStackOnDisplay(mDisplayContent); + final Task activityStack = createTaskStackOnDisplay(mDisplayContent); activityStack.addChild(windowContainer, 0); activityStack.setParent(null); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java index 8fa3a12f027d..f97dff3162c4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java @@ -105,13 +105,13 @@ public class WindowManagerServiceTests extends WindowTestsBase { public void testTaskFocusChange_stackNotHomeType_focusChanges() throws RemoteException { DisplayContent display = createNewDisplay(); // Current focused window - ActivityStack focusedStack = createTaskStackOnDisplay( + Task focusedStack = createTaskStackOnDisplay( WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, display); Task focusedTask = createTaskInStack(focusedStack, 0 /* userId */); WindowState focusedWindow = createAppWindow(focusedTask, TYPE_APPLICATION, "App Window"); mDisplayContent.mCurrentFocus = focusedWindow; // Tapped task - ActivityStack tappedStack = createTaskStackOnDisplay( + Task tappedStack = createTaskStackOnDisplay( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, display); Task tappedTask = createTaskInStack(tappedStack, 0 /* userId */); spyOn(mWm.mActivityTaskManager); @@ -126,13 +126,13 @@ public class WindowManagerServiceTests extends WindowTestsBase { throws RemoteException { DisplayContent display = createNewDisplay(); // Current focused window - ActivityStack focusedStack = createTaskStackOnDisplay( + Task focusedStack = createTaskStackOnDisplay( WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, display); Task focusedTask = createTaskInStack(focusedStack, 0 /* userId */); WindowState focusedWindow = createAppWindow(focusedTask, TYPE_APPLICATION, "App Window"); mDisplayContent.mCurrentFocus = focusedWindow; // Tapped home task - ActivityStack tappedStack = createTaskStackOnDisplay( + Task tappedStack = createTaskStackOnDisplay( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, display); Task tappedTask = createTaskInStack(tappedStack, 0 /* userId */); spyOn(mWm.mActivityTaskManager); @@ -149,13 +149,13 @@ public class WindowManagerServiceTests extends WindowTestsBase { final TaskDisplayArea secondTda = createTaskDisplayArea( display, mWm, "Tapped TDA", FEATURE_VENDOR_FIRST); // Current focused window - ActivityStack focusedStack = createTaskStackOnDisplay( + Task focusedStack = createTaskStackOnDisplay( WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, display); Task focusedTask = createTaskInStack(focusedStack, 0 /* userId */); WindowState focusedWindow = createAppWindow(focusedTask, TYPE_APPLICATION, "App Window"); mDisplayContent.mCurrentFocus = focusedWindow; // Tapped home task on another task display area - ActivityStack tappedStack = createTaskStackOnTaskDisplayArea( + Task tappedStack = createTaskStackOnTaskDisplayArea( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, secondTda); Task tappedTask = createTaskInStack(tappedStack, 0 /* userId */); spyOn(mWm.mActivityTaskManager); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index 7cc19ad0ddd8..bd52e9a294fc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -103,7 +103,7 @@ public class WindowOrganizerTests extends WindowTestsBase { return registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW); } - Task createTask(ActivityStack stack, boolean fakeDraw) { + Task createTask(Task stack, boolean fakeDraw) { final Task task = createTaskInStack(stack, 0); if (fakeDraw) { @@ -112,12 +112,12 @@ public class WindowOrganizerTests extends WindowTestsBase { return task; } - Task createTask(ActivityStack stack) { + Task createTask(Task stack) { // Fake draw notifications for most of our tests. return createTask(stack, true); } - ActivityStack createStack() { + Task createStack() { return createTaskStackOnDisplay(mDisplayContent); } @@ -130,7 +130,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testAppearVanish() throws RemoteException { - final ActivityStack stack = createStack(); + final Task stack = createStack(); final Task task = createTask(stack); final ITaskOrganizer organizer = registerMockOrganizer(); @@ -144,7 +144,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testAppearWaitsForVisibility() throws RemoteException { - final ActivityStack stack = createStack(); + final Task stack = createStack(); final Task task = createTask(stack, false); final ITaskOrganizer organizer = registerMockOrganizer(); @@ -163,7 +163,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testNoVanishedIfNoAppear() throws RemoteException { - final ActivityStack stack = createStack(); + final Task stack = createStack(); final Task task = createTask(stack, false /* hasBeenVisible */); final ITaskOrganizer organizer = registerMockOrganizer(); @@ -179,7 +179,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testSwapOrganizer() throws RemoteException { - final ActivityStack stack = createStack(); + final Task stack = createStack(); final Task task = createTask(stack); final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW); final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_PINNED); @@ -193,7 +193,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testSwapWindowingModes() throws RemoteException { - final ActivityStack stack = createStack(); + final Task stack = createStack(); final Task task = createTask(stack); final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW); final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_PINNED); @@ -207,7 +207,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testTaskNoDraw() throws RemoteException { - final ActivityStack stack = createStack(); + final Task stack = createStack(); final Task task = createTask(stack, false /* fakeDraw */); final ITaskOrganizer organizer = registerMockOrganizer(); @@ -223,7 +223,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testClearOrganizer() throws RemoteException { - final ActivityStack stack = createStack(); + final Task stack = createStack(); final Task task = createTask(stack); final ITaskOrganizer organizer = registerMockOrganizer(); @@ -238,7 +238,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testUnregisterOrganizer() throws RemoteException { - final ActivityStack stack = createStack(); + final Task stack = createStack(); final Task task = createTask(stack); final ITaskOrganizer organizer = registerMockOrganizer(); @@ -253,11 +253,11 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testUnregisterOrganizerReturnsRegistrationToPrevious() throws RemoteException { - final ActivityStack stack = createStack(); + final Task stack = createStack(); final Task task = createTask(stack); - final ActivityStack stack2 = createStack(); + final Task stack2 = createStack(); final Task task2 = createTask(stack2); - final ActivityStack stack3 = createStack(); + final Task stack3 = createStack(); final Task task3 = createTask(stack3); final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW); @@ -297,7 +297,7 @@ public class WindowOrganizerTests extends WindowTestsBase { public void testRegisterTaskOrganizerStackWindowingModeChanges() throws RemoteException { final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_PINNED); - final ActivityStack stack = createStack(); + final Task stack = createStack(); final Task task = createTask(stack); final Task task2 = createTask(stack); stack.setWindowingMode(WINDOWING_MODE_PINNED); @@ -310,7 +310,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testRegisterTaskOrganizerWithExistingTasks() throws RemoteException { - final ActivityStack stack = createStack(); + final Task stack = createStack(); final Task task = createTask(stack); stack.setWindowingMode(WINDOWING_MODE_PINNED); @@ -322,7 +322,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testTaskTransaction() { removeGlobalMinSizeRestriction(); - final ActivityStack stack = new ActivityTestsBase.StackBuilder(mWm.mRoot) + final Task stack = new ActivityTestsBase.StackBuilder(mWm.mRoot) .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); final Task task = stack.getTopMostTask(); testTransaction(task); @@ -331,7 +331,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testStackTransaction() { removeGlobalMinSizeRestriction(); - final ActivityStack stack = new ActivityTestsBase.StackBuilder(mWm.mRoot) + final Task stack = new ActivityTestsBase.StackBuilder(mWm.mRoot) .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); StackInfo info = mWm.mAtmService.getStackInfo(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD); @@ -356,7 +356,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testSetWindowingMode() { - final ActivityStack stack = new ActivityTestsBase.StackBuilder(mWm.mRoot) + final Task stack = new ActivityTestsBase.StackBuilder(mWm.mRoot) .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); testSetWindowingMode(stack); @@ -375,7 +375,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testSetActivityWindowingMode() { final ActivityRecord record = makePipableActivity(); - final ActivityStack stack = record.getStack(); + final Task stack = record.getStack(); final WindowContainerTransaction t = new WindowContainerTransaction(); t.setWindowingMode(stack.mRemoteToken.toWindowContainerToken(), WINDOWING_MODE_PINNED); @@ -390,7 +390,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testContainerFocusableChanges() { removeGlobalMinSizeRestriction(); - final ActivityStack stack = new ActivityTestsBase.StackBuilder(mWm.mRoot) + final Task stack = new ActivityTestsBase.StackBuilder(mWm.mRoot) .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); final Task task = stack.getTopMostTask(); WindowContainerTransaction t = new WindowContainerTransaction(); @@ -406,7 +406,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testContainerHiddenChanges() { removeGlobalMinSizeRestriction(); - final ActivityStack stack = new ActivityTestsBase.StackBuilder(mWm.mRoot) + final Task stack = new ActivityTestsBase.StackBuilder(mWm.mRoot) .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); WindowContainerTransaction t = new WindowContainerTransaction(); assertTrue(stack.shouldBeVisible(null)); @@ -421,7 +421,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testOverrideConfigSize() { removeGlobalMinSizeRestriction(); - final ActivityStack stack = new ActivityTestsBase.StackBuilder(mWm.mRoot) + final Task stack = new ActivityTestsBase.StackBuilder(mWm.mRoot) .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); final Task task = stack.getTopMostTask(); WindowContainerTransaction t = new WindowContainerTransaction(); @@ -489,7 +489,7 @@ public class WindowOrganizerTests extends WindowTestsBase { RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask( mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); - final ActivityStack stack = createTaskStackOnDisplay( + final Task stack = createTaskStackOnDisplay( WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, mDisplayContent); assertEquals(mDisplayContent.getWindowingMode(), stack.getWindowingMode()); WindowContainerTransaction wct = new WindowContainerTransaction(); @@ -550,7 +550,7 @@ public class WindowOrganizerTests extends WindowTestsBase { lastReportedTiles.clear(); called[0] = false; - final ActivityStack stack = createTaskStackOnDisplay( + final Task stack = createTaskStackOnDisplay( WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, mDisplayContent); Task task1 = WindowContainer.fromBinder(info1.token.asBinder()).asTask(); WindowContainerTransaction wct = new WindowContainerTransaction(); @@ -561,7 +561,7 @@ public class WindowOrganizerTests extends WindowTestsBase { lastReportedTiles.clear(); called[0] = false; - final ActivityStack stack2 = createTaskStackOnDisplay( + final Task stack2 = createTaskStackOnDisplay( WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mDisplayContent); wct = new WindowContainerTransaction(); wct.reparent(stack2.mRemoteToken.toWindowContainerToken(), info1.token, true /* onTop */); @@ -617,9 +617,9 @@ public class WindowOrganizerTests extends WindowTestsBase { final int initialRootTaskCount = mWm.mAtmService.mTaskOrganizerController.getRootTasks( mDisplayContent.mDisplayId, null /* activityTypes */).size(); - final ActivityStack stack = createTaskStackOnDisplay( + final Task stack = createTaskStackOnDisplay( WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, mDisplayContent); - final ActivityStack stack2 = createTaskStackOnDisplay( + final Task stack2 = createTaskStackOnDisplay( WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mDisplayContent); // Check getRootTasks works @@ -694,7 +694,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testTrivialBLASTCallback() throws RemoteException { - final ActivityStack stackController1 = createStack(); + final Task stackController1 = createStack(); final Task task = createTask(stackController1); final ITaskOrganizer organizer = registerMockOrganizer(); @@ -716,7 +716,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testOverlappingBLASTCallback() throws RemoteException { - final ActivityStack stackController1 = createStack(); + final Task stackController1 = createStack(); final Task task = createTask(stackController1); final ITaskOrganizer organizer = registerMockOrganizer(); @@ -745,7 +745,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testBLASTCallbackWithWindow() { - final ActivityStack stackController1 = createStack(); + final Task stackController1 = createStack(); final Task task = createTask(stackController1); final ITaskOrganizer organizer = registerMockOrganizer(); final WindowState w = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window"); @@ -769,7 +769,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testBLASTCallbackNoDoubleAdd() { - final ActivityStack stackController1 = createStack(); + final Task stackController1 = createStack(); final Task task = createTask(stackController1); final ITaskOrganizer organizer = registerMockOrganizer(); final WindowState w = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window"); @@ -791,7 +791,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testBLASTCallbackWithInvisibleWindow() { - final ActivityStack stackController1 = createStack(); + final Task stackController1 = createStack(); final Task task = createTask(stackController1); final ITaskOrganizer organizer = registerMockOrganizer(); final WindowState w = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window"); @@ -813,7 +813,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testBLASTCallbackWithChildWindow() { - final ActivityStack stackController1 = createStack(); + final Task stackController1 = createStack(); final Task task = createTask(stackController1); final ITaskOrganizer organizer = registerMockOrganizer(); final WindowState w = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window"); @@ -930,7 +930,7 @@ public class WindowOrganizerTests extends WindowTestsBase { mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o, WINDOWING_MODE_MULTI_WINDOW); - final ActivityStack stack = createStack(); + final Task stack = createStack(); final Task task = createTask(stack); final ActivityRecord record = WindowTestUtils.createActivityRecordInTask( stack.mDisplayContent, task); @@ -943,7 +943,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testPreventDuplicateAppear() throws RemoteException { - final ActivityStack stack = createStack(); + final Task stack = createStack(); final Task task = createTask(stack); final ITaskOrganizer organizer = registerMockOrganizer(); @@ -965,7 +965,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testInterceptBackPressedOnTaskRoot() throws RemoteException { - final ActivityStack stack = createStack(); + final Task stack = createStack(); final Task task = createTask(stack); final ActivityRecord activity = WindowTestUtils.createActivityRecordInTask( stack.mDisplayContent, task); @@ -992,7 +992,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testBLASTCallbackWithMultipleWindows() throws Exception { - final ActivityStack stackController = createStack(); + final Task stackController = createStack(); final Task task = createTask(stackController); final ITaskOrganizer organizer = registerMockOrganizer(); final WindowState w1 = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window 1"); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index ce9dd685293a..3894a2eaa461 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -250,7 +250,7 @@ public class WindowStateTests extends WindowTestsBase { // minimized and home stack is resizable, so that we should ignore input for the stack. final DockedStackDividerController controller = mDisplayContent.getDockedDividerController(); - final ActivityStack stack = createTaskStackOnDisplay(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, + final Task stack = createTaskStackOnDisplay(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, mDisplayContent); spyOn(appWindow); spyOn(controller); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java index 49993610bbed..2502932c5421 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java @@ -32,8 +32,8 @@ import com.android.server.wm.ActivityTestsBase.ActivityBuilder; */ class WindowTestUtils { - /** Creates a {@link Task} and adds it to the specified {@link ActivityStack}. */ - static Task createTaskInStack(WindowManagerService service, ActivityStack stack, int userId) { + /** Creates a {@link Task} and adds it to the specified {@link Task}. */ + static Task createTaskInStack(WindowManagerService service, Task stack, int userId) { final Task task = new ActivityTestsBase.TaskBuilder(stack.mStackSupervisor) .setUserId(userId) .setStack(stack) @@ -48,7 +48,7 @@ class WindowTestUtils { return activity; } - static ActivityRecord createTestActivityRecord(ActivityStack stack) { + static ActivityRecord createTestActivityRecord(Task stack) { final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(stack.mAtmService) .setStack(stack) .setCreateTask(true) diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 0bbe0a04f618..dc388833f338 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -211,7 +211,7 @@ class WindowTestsBase extends SystemServiceTestsBase { ActivityRecord createTestActivityRecord(DisplayContent dc, int windowingMode, int activityType) { - final ActivityStack stack = createTaskStackOnDisplay(windowingMode, activityType, dc); + final Task stack = createTaskStackOnDisplay(windowingMode, activityType, dc); return WindowTestUtils.createTestActivityRecord(stack); } @@ -322,12 +322,12 @@ class WindowTestsBase extends SystemServiceTestsBase { return newTaskDisplayArea; } - /** Creates a {@link ActivityStack} and adds it to the specified {@link DisplayContent}. */ - ActivityStack createTaskStackOnDisplay(DisplayContent dc) { + /** Creates a {@link Task} and adds it to the specified {@link DisplayContent}. */ + Task createTaskStackOnDisplay(DisplayContent dc) { return createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc); } - ActivityStack createTaskStackOnDisplay(int windowingMode, int activityType, DisplayContent dc) { + Task createTaskStackOnDisplay(int windowingMode, int activityType, DisplayContent dc) { return new ActivityTestsBase.StackBuilder(dc.mWmService.mRoot) .setDisplay(dc) .setWindowingMode(windowingMode) @@ -337,7 +337,7 @@ class WindowTestsBase extends SystemServiceTestsBase { .build(); } - ActivityStack createTaskStackOnTaskDisplayArea(int windowingMode, int activityType, + Task createTaskStackOnTaskDisplayArea(int windowingMode, int activityType, TaskDisplayArea tda) { return new ActivityTestsBase.StackBuilder(tda.mWmService.mRoot) .setTaskDisplayArea(tda) @@ -348,8 +348,8 @@ class WindowTestsBase extends SystemServiceTestsBase { .build(); } - /** Creates a {@link Task} and adds it to the specified {@link ActivityStack}. */ - Task createTaskInStack(ActivityStack stack, int userId) { + /** Creates a {@link Task} and adds it to the specified {@link Task}. */ + Task createTaskInStack(Task stack, int userId) { return WindowTestUtils.createTaskInStack(mWm, stack, userId); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java index cef202cdc5d5..f185da395754 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java @@ -84,6 +84,10 @@ public class WindowTokenTests extends WindowTestsBase { assertFalse(token.hasWindow(window12)); assertTrue(token.hasWindow(window2)); assertTrue(token.hasWindow(window3)); + + // The child windows should have the same window token as their parents. + assertEquals(window1.mToken, window11.mToken); + assertEquals(window1.mToken, window12.mToken); } @Test diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp index 070dacbcd91f..5161fba026db 100644 --- a/tests/FlickerTests/Android.bp +++ b/tests/FlickerTests/Android.bp @@ -28,6 +28,7 @@ android_test { "flickerlib", "truth-prebuilt", "app-helpers-core", + "launcher-helper-lib", "launcher-aosp-tapl" ], } diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml index 58df2a806a1e..68c99a35e5d0 100644 --- a/tests/FlickerTests/AndroidTest.xml +++ b/tests/FlickerTests/AndroidTest.xml @@ -27,7 +27,7 @@ </target_preparer> <test class="com.android.tradefed.testtype.AndroidJUnitTest"> <option name="package" value="com.android.server.wm.flicker"/> - <option name="exclude-annotation" value="org.junit.Ignore" /> + <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" /> <option name="shell-timeout" value="6600s" /> <option name="test-timeout" value="6000s" /> <option name="hidden-api-checks" value="false" /> diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.kt index f871ea59ea71..43cfdffb6efb 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.kt @@ -20,22 +20,24 @@ import android.platform.helpers.IAppHelper import android.util.Rational import android.view.Surface import androidx.test.InstrumentationRegistry +import androidx.test.filters.FlakyTest import androidx.test.filters.LargeTest import androidx.test.runner.AndroidJUnit4 import androidx.test.uiautomator.UiDevice import com.android.server.wm.flicker.helpers.ImeAppHelper import com.android.server.wm.flicker.helpers.PipAppHelper import org.junit.FixMethodOrder -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters /** * Tests to help debug individual transitions, capture video recordings and create test cases. + * + * Not actual tests */ @LargeTest -@Ignore("Used for debugging transitions used in FlickerTests.") +@FlakyTest @RunWith(AndroidJUnit4::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class DebugTest { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.kt index 653fecd5219f..1f8150c0977b 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.kt @@ -18,7 +18,6 @@ package com.android.server.wm.flicker import android.view.Surface import androidx.test.filters.FlakyTest -import org.junit.Ignore import org.junit.Test import org.junit.runners.Parameterized @@ -27,7 +26,6 @@ abstract class NonRotationTestBase( protected val beginRotation: Int ) : FlickerTestBase() { @FlakyTest(bugId = 141361128) - @Ignore("Waiting bug feedback") @Test fun checkCoveredRegion_noUncoveredRegions() { val displayBounds = WindowUtils.getDisplayBounds(beginRotation) @@ -38,7 +36,6 @@ abstract class NonRotationTestBase( } @FlakyTest(bugId = 141361128) - @Ignore("Waiting bug feedback") @Test fun checkVisibility_navBarLayerIsAlwaysVisible() { checkResults { @@ -48,7 +45,6 @@ abstract class NonRotationTestBase( } @FlakyTest(bugId = 141361128) - @Ignore("Waiting bug feedback") @Test fun checkVisibility_statusBarLayerIsAlwaysVisible() { checkResults { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/RotationTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/RotationTestBase.kt index 873d60771cb4..dfc3c07d5417 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/RotationTestBase.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/RotationTestBase.kt @@ -18,7 +18,6 @@ package com.android.server.wm.flicker import android.view.Surface import androidx.test.filters.FlakyTest -import org.junit.Ignore import org.junit.Test import org.junit.runners.Parameterized @@ -29,7 +28,6 @@ abstract class RotationTestBase( protected val endRotation: Int ) : FlickerTestBase() { @FlakyTest(bugId = 140855415) - @Ignore("Waiting bug feedback") @Test fun checkVisibility_navBarWindowIsAlwaysVisible() { checkResults { @@ -39,7 +37,6 @@ abstract class RotationTestBase( } @FlakyTest(bugId = 140855415) - @Ignore("Waiting bug feedback") @Test fun checkVisibility_statusBarWindowIsAlwaysVisible() { checkResults { @@ -86,7 +83,6 @@ abstract class RotationTestBase( } @FlakyTest(bugId = 140855415) - @Ignore("Waiting bug feedback") @Test fun checkVisibility_navBarLayerIsAlwaysVisible() { checkResults { @@ -96,7 +92,6 @@ abstract class RotationTestBase( } @FlakyTest(bugId = 140855415) - @Ignore("Waiting bug feedback") @Test fun checkVisibility_statusBarLayerIsAlwaysVisible() { checkResults { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt index 6946618806b8..814cdcf5e114 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt @@ -22,7 +22,6 @@ import com.android.server.wm.flicker.CommonTransitions import com.android.server.wm.flicker.TransitionRunner import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper import org.junit.FixMethodOrder -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -49,21 +48,18 @@ class CloseImeAutoOpenWindowToAppTest( .includeJankyRuns().build() @FlakyTest(bugId = 141458352) - @Ignore("Waiting bug feedback") @Test override fun checkVisibility_imeLayerBecomesInvisible() { super.checkVisibility_imeLayerBecomesInvisible() } @FlakyTest(bugId = 141458352) - @Ignore("Waiting bug feedback") @Test override fun checkVisibility_imeAppLayerIsAlwaysVisible() { super.checkVisibility_imeAppLayerIsAlwaysVisible() } @FlakyTest(bugId = 141458352) - @Ignore("Waiting bug feedback") @Test override fun checkVisibility_imeAppWindowIsAlwaysVisible() { super.checkVisibility_imeAppWindowIsAlwaysVisible() diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt index a1030d8248b7..c2025b6da204 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt @@ -22,7 +22,6 @@ import com.android.server.wm.flicker.CommonTransitions import com.android.server.wm.flicker.TransitionRunner import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper import org.junit.FixMethodOrder -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -49,21 +48,18 @@ class CloseImeAutoOpenWindowToHomeTest( .includeJankyRuns().build() @FlakyTest(bugId = 141458352) - @Ignore("Waiting bug feedback") @Test override fun checkVisibility_imeWindowBecomesInvisible() { super.checkVisibility_imeWindowBecomesInvisible() } @FlakyTest(bugId = 141458352) - @Ignore("Waiting bug feedback") @Test override fun checkVisibility_imeLayerBecomesInvisible() { super.checkVisibility_imeLayerBecomesInvisible() } @FlakyTest(bugId = 157449248) - @Ignore("Waiting bug feedback") @Test override fun checkVisibility_imeAppWindowBecomesInvisible() { super.checkVisibility_imeAppWindowBecomesInvisible() diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt index 6e7c92b97bfb..b38262e9f298 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt @@ -16,6 +16,7 @@ package com.android.server.wm.flicker.ime +import androidx.test.filters.FlakyTest import androidx.test.filters.LargeTest import com.android.server.wm.flicker.CommonTransitions import com.android.server.wm.flicker.LayersTraceSubject @@ -24,7 +25,6 @@ import com.android.server.wm.flicker.TransitionRunner import com.android.server.wm.flicker.WmTraceSubject import com.android.server.wm.flicker.helpers.ImeAppHelper import org.junit.FixMethodOrder -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -50,7 +50,7 @@ open class CloseImeWindowToAppTest( instrumentation, uiDevice, beginRotation) .includeJankyRuns().build() - @Ignore("Flaky. Pending debug") + @FlakyTest @Test open fun checkVisibility_imeLayerBecomesInvisible() { checkResults { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt index ed8bd2a5fe83..ca04babfa0f1 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt @@ -25,7 +25,6 @@ import com.android.server.wm.flicker.TransitionRunner import com.android.server.wm.flicker.WmTraceSubject import com.android.server.wm.flicker.helpers.ImeAppHelper import org.junit.FixMethodOrder -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -63,7 +62,6 @@ open class CloseImeWindowToHomeTest( } @FlakyTest(bugId = 153739621) - @Ignore @Test open fun checkVisibility_imeLayerBecomesInvisible() { checkResults { @@ -77,7 +75,6 @@ open class CloseImeWindowToHomeTest( } @FlakyTest(bugId = 153739621) - @Ignore @Test fun checkVisibility_imeAppLayerBecomesInvisible() { checkResults { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt index 943a52592910..88b885407935 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt @@ -25,7 +25,6 @@ import com.android.server.wm.flicker.StandardAppHelper import com.android.server.wm.flicker.TransitionRunner import com.android.server.wm.flicker.WmTraceSubject import org.junit.FixMethodOrder -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -63,7 +62,6 @@ class OpenAppColdTest( } @FlakyTest(bugId = 140855415) - @Ignore("Waiting bug feedback") @Test fun checkZOrder_appWindowReplacesLauncherAsTopWindow() { checkResults { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt index 7964d949e737..f0bc3f00338a 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt @@ -25,7 +25,6 @@ import com.android.server.wm.flicker.StandardAppHelper import com.android.server.wm.flicker.TransitionRunner import com.android.server.wm.flicker.WmTraceSubject import org.junit.FixMethodOrder -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -63,7 +62,6 @@ class OpenAppWarmTest( } @FlakyTest(bugId = 140855415) - @Ignore("Waiting bug feedback") @Test fun checkZOrder_appWindowReplacesLauncherAsTopWindow() { checkResults { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt index f939a7915e74..89ffb7a57b73 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt @@ -23,7 +23,6 @@ import com.android.server.wm.flicker.TransitionRunner import com.android.server.wm.flicker.WmTraceSubject import com.android.server.wm.flicker.helpers.PipAppHelper import org.junit.FixMethodOrder -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -37,7 +36,6 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @FlakyTest(bugId = 152738416) -@Ignore("Waiting bug feedback") class PipToAppTest( beginRotationName: String, beginRotation: Int diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt index ecfcd8298c3f..8591360cff60 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt @@ -23,7 +23,6 @@ import com.android.server.wm.flicker.TransitionRunner import com.android.server.wm.flicker.WmTraceSubject import com.android.server.wm.flicker.helpers.PipAppHelper import org.junit.FixMethodOrder -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -37,7 +36,6 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @FlakyTest(bugId = 152738416) -@Ignore("Waiting bug feedback") class PipToHomeTest( beginRotationName: String, beginRotation: Int @@ -47,7 +45,6 @@ class PipToHomeTest( uiDevice, beginRotation) .includeJankyRuns().build() - @Ignore @Test fun checkVisibility_backgroundWindowVisibleBehindPipLayer() { checkResults { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt index 7a581d066c2b..fb1cb399e8bc 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt @@ -17,6 +17,7 @@ package com.android.server.wm.flicker.rotation import android.util.Log +import androidx.test.filters.FlakyTest import androidx.test.filters.LargeTest import com.android.server.wm.flicker.CommonTransitions import com.android.server.wm.flicker.LayersTraceSubject @@ -25,7 +26,6 @@ import com.android.server.wm.flicker.StandardAppHelper import com.android.server.wm.flicker.TransitionRunner import com.android.server.wm.flicker.WindowUtils import org.junit.FixMethodOrder -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -67,7 +67,7 @@ class ChangeAppRotationTest( } } - @Ignore("Flaky. Pending debug") + @FlakyTest @Test fun checkVisibility_screenshotLayerBecomesInvisible() { checkResults { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt index d53af6f53bf2..1cd19983f3b1 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt @@ -28,7 +28,6 @@ import com.android.server.wm.flicker.TransitionRunner import com.android.server.wm.flicker.WindowUtils import com.android.server.wm.flicker.testapp.ActivityOptions import org.junit.FixMethodOrder -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -42,7 +41,6 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @FlakyTest(bugId = 147659548) -@Ignore("Waiting bug feedback") class SeamlessAppRotationTest( private val intent: Intent, beginRotationName: String, diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt index b6cce266ab88..6b597e5807ea 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt @@ -38,7 +38,6 @@ import com.android.server.wm.flicker.helpers.ImeAppHelper import com.google.common.truth.Truth import org.junit.AfterClass import org.junit.FixMethodOrder -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -53,7 +52,6 @@ import org.junit.runners.MethodSorters @RunWith(AndroidJUnit4::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @FlakyTest(bugId = 159096424) -@Ignore("Waiting bug feedback") class ResizeSplitScreenTest : FlickerTestBase() { init { testApp = StandardAppHelper(instrumentation, @@ -97,7 +95,7 @@ class ResizeSplitScreenTest : FlickerTestBase() { } @Test - @Ignore("Waiting feedback") + @FlakyTest fun checkPosition_appsStartingBounds() { val displayBounds = WindowUtils.getDisplayBounds() checkResults { result: TransitionResult -> @@ -122,7 +120,7 @@ class ResizeSplitScreenTest : FlickerTestBase() { } @Test - @Ignore("Waiting feedback") + @FlakyTest fun checkPosition_appsEndingBounds() { val displayBounds = WindowUtils.getDisplayBounds() checkResults { result: TransitionResult -> @@ -166,7 +164,6 @@ class ResizeSplitScreenTest : FlickerTestBase() { @Test @FlakyTest(bugId = 156223549) - @Ignore("Waiting bug feedback") fun checkVisibility_topAppWindowIsAlwaysVisible() { checkResults { WmTraceSubject.assertThat(it) @@ -177,7 +174,6 @@ class ResizeSplitScreenTest : FlickerTestBase() { @Test @FlakyTest(bugId = 156223549) - @Ignore("Waiting bug feedback") fun checkVisibility_bottomAppWindowIsAlwaysVisible() { checkResults { WmTraceSubject.assertThat(it) diff --git a/tests/WindowInsetsTests/AndroidManifest.xml b/tests/WindowInsetsTests/AndroidManifest.xml index 597805451b95..61dd9d4cd021 100644 --- a/tests/WindowInsetsTests/AndroidManifest.xml +++ b/tests/WindowInsetsTests/AndroidManifest.xml @@ -16,18 +16,24 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.google.android.test.windowinsetstests"> - - <application android:label="@string/activity_title"> - <activity android:name=".WindowInsetsActivity" - android:theme="@style/appTheme" - android:windowSoftInputMode="adjustResize" - android:exported="true"> + package="com.google.android.test.windowinsetstests"> + <application android:label="@string/application_title"> + <activity android:name=".WindowInsetsTestsMainActivity" + android:exported="true"> <intent-filter> - <action android:name="android.intent.action.MAIN"/> - <category android:name="android.intent.category.LAUNCHER"/> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> + + <activity android:name=".ChatActivity" + android:label="@string/chat_activity_title" + android:theme="@style/chat" + android:windowSoftInputMode="adjustResize" /> + + <activity android:name=".ControllerActivity" + android:label="@string/controller_activity_title" + android:theme="@style/controller" /> </application> </manifest> diff --git a/tests/WindowInsetsTests/res/layout/window_inset_activity.xml b/tests/WindowInsetsTests/res/layout/chat_activity.xml index 1b51c4f83fe0..1b51c4f83fe0 100644 --- a/tests/WindowInsetsTests/res/layout/window_inset_activity.xml +++ b/tests/WindowInsetsTests/res/layout/chat_activity.xml diff --git a/tests/WindowInsetsTests/res/layout/controller_activity.xml b/tests/WindowInsetsTests/res/layout/controller_activity.xml new file mode 100644 index 000000000000..d51a4ddd43e8 --- /dev/null +++ b/tests/WindowInsetsTests/res/layout/controller_activity.xml @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + + +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout + android:id="@+id/content" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <Spinner + android:id="@+id/spinnerBehavior" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:layout_marginBottom="20dp" /> + + <ToggleButton + android:id="@+id/toggleButtonStatus" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:checked="true" + android:text="Status Bars Toggle Button" + android:textOff="Status Bars Invisible" + android:textOn="Status Bars Visible" /> + + <SeekBar + android:id="@+id/seekBarStatus" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:layout_marginBottom="20dp" + android:max="10000" + android:progress="10000" /> + + <ToggleButton + android:id="@+id/toggleButtonNavigation" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:checked="true" + android:text="Navigation Bars Toggle Button" + android:textOff="Navigation Bars Invisible" + android:textOn="Navigation Bars Visible" /> + + <SeekBar + android:id="@+id/seekBarNavigation" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:layout_marginBottom="20dp" + android:max="10000" + android:progress="10000" /> + + <ToggleButton + android:id="@+id/toggleButtonIme" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:checked="true" + android:text="IME Toggle Button" + android:textOff="IME Invisible" + android:textOn="IME Visible" /> + + <SeekBar + android:id="@+id/seekBarIme" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:layout_marginBottom="20dp" + android:max="10000" + android:progress="0" /> + + <TextView + android:id="@+id/textViewControllableInsets" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="5dp" /> + + <EditText + android:id="@+id/editText" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:ems="10" + android:hint="For testing IME..." + android:inputType="text" + android:text="" /> + + </LinearLayout> + +</ScrollView>
\ No newline at end of file diff --git a/tests/WindowInsetsTests/res/layout/main_activity.xml b/tests/WindowInsetsTests/res/layout/main_activity.xml new file mode 100644 index 000000000000..621ed89204d1 --- /dev/null +++ b/tests/WindowInsetsTests/res/layout/main_activity.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2020 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <Button + android:id="@+id/chat_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/chat_activity_title" + android:textAllCaps="false"/> + + <Button + android:id="@+id/controller_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/controller_activity_title" + android:textAllCaps="false"/> + +</LinearLayout> diff --git a/tests/WindowInsetsTests/res/values/strings.xml b/tests/WindowInsetsTests/res/values/strings.xml index 2b8e5f3da362..1a236c6f751d 100644 --- a/tests/WindowInsetsTests/res/values/strings.xml +++ b/tests/WindowInsetsTests/res/values/strings.xml @@ -16,5 +16,14 @@ --> <resources> - <string name="activity_title">New Insets Chat</string> + <string name="application_title">Window Insets Tests</string> + <string name="chat_activity_title">New Insets Chat</string> + <string name="controller_activity_title">Window Insets Controller</string> + + <!-- The item positions should match the flag values respectively. --> + <string-array name="behaviors"> + <item>BEHAVIOR_SHOW_BARS_BY_TOUCH</item> + <item>BEHAVIOR_SHOW_BARS_BY_SWIPE</item> + <item>BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE</item> + </string-array> </resources> diff --git a/tests/WindowInsetsTests/res/values/styles.xml b/tests/WindowInsetsTests/res/values/styles.xml index 220671fb8e71..a84ffbed600d 100644 --- a/tests/WindowInsetsTests/res/values/styles.xml +++ b/tests/WindowInsetsTests/res/values/styles.xml @@ -17,7 +17,7 @@ <resources> - <style name="appTheme" parent="@style/Theme.MaterialComponents.Light"> + <style name="chat" parent="@style/Theme.MaterialComponents.Light"> <item name="windowActionBar">false</item> <item name="windowNoTitle">true</item> @@ -63,5 +63,11 @@ <dimen name="bubble_padding">8dp</dimen> <dimen name="bubble_padding_side">16dp</dimen> + <style name="controller" parent="android:Theme.Material"> + <item name="android:colorPrimaryDark">#111111</item> + <item name="android:navigationBarColor">#111111</item> + <item name="android:colorPrimary">#222222</item> + <item name="android:colorAccent">#33ccff</item> + </style> </resources>
\ No newline at end of file diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ChatActivity.java index 498cb7c1c710..ba12acb2c877 100644 --- a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java +++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ChatActivity.java @@ -30,7 +30,6 @@ import android.content.Context; import android.graphics.Insets; import android.os.Bundle; import android.util.AttributeSet; -import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; @@ -39,8 +38,6 @@ import android.view.WindowInsetsAnimation; import android.view.WindowInsetsAnimation.Callback; import android.view.WindowInsetsAnimationControlListener; import android.view.WindowInsetsAnimationController; -import android.view.WindowInsetsController; -import android.view.WindowInsetsController.OnControllableInsetsChangedListener; import android.view.animation.LinearInterpolator; import android.widget.LinearLayout; @@ -49,7 +46,7 @@ import java.util.List; import androidx.appcompat.app.AppCompatActivity; -public class WindowInsetsActivity extends AppCompatActivity { +public class ChatActivity extends AppCompatActivity { private View mRoot; @@ -58,7 +55,7 @@ public class WindowInsetsActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.window_inset_activity); + setContentView(R.layout.chat_activity); setSupportActionBar(findViewById(R.id.toolbar)); @@ -71,7 +68,7 @@ public class WindowInsetsActivity extends AppCompatActivity { mRoot.setOnTouchListener(new View.OnTouchListener() { private final ViewConfiguration mViewConfiguration = - ViewConfiguration.get(WindowInsetsActivity.this); + ViewConfiguration.get(ChatActivity.this); WindowInsetsAnimationController mAnimationController; WindowInsetsAnimationControlListener mCurrentRequest; boolean mRequestedController = false; diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java new file mode 100644 index 000000000000..beb4049cb230 --- /dev/null +++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.test.windowinsetstests; + +import android.app.Activity; +import android.graphics.Insets; +import android.os.Bundle; +import android.view.View; +import android.view.WindowInsets; +import android.view.WindowInsets.Type; +import android.view.WindowInsetsAnimationControlListener; +import android.view.WindowInsetsAnimationController; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.CompoundButton; +import android.widget.SeekBar; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.ToggleButton; + +public class ControllerActivity extends Activity implements View.OnApplyWindowInsetsListener { + + private ToggleButton mToggleStatus; + private SeekBar mSeekStatus; + private ToggleButton mToggleNavigation; + private SeekBar mSeekNavigation; + private ToggleButton mToggleIme; + private SeekBar mSeekIme; + private TextView mTextControllableInsets; + private boolean[] mNotFromUser = {false}; + private WindowInsets mLastInsets; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.controller_activity); + final Spinner spinnerBehavior = findViewById(R.id.spinnerBehavior); + ArrayAdapter<CharSequence> adapterBehavior = ArrayAdapter.createFromResource(this, + R.array.behaviors, android.R.layout.simple_spinner_item); + adapterBehavior.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + spinnerBehavior.setAdapter(adapterBehavior); + spinnerBehavior.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { + parent.getWindowInsetsController().setSystemBarsBehavior(position); + } + + @Override + public void onNothingSelected(AdapterView<?> parent) { } + }); + mToggleStatus = findViewById(R.id.toggleButtonStatus); + mToggleStatus.setTag(mNotFromUser); + mToggleStatus.setOnCheckedChangeListener(new ToggleListener(Type.statusBars())); + mSeekStatus = findViewById(R.id.seekBarStatus); + mSeekStatus.setOnSeekBarChangeListener(new SeekBarListener(Type.statusBars())); + mToggleNavigation = findViewById(R.id.toggleButtonNavigation); + mToggleNavigation.setTag(mNotFromUser); + mToggleNavigation.setOnCheckedChangeListener(new ToggleListener(Type.navigationBars())); + mSeekNavigation = findViewById(R.id.seekBarNavigation); + mSeekNavigation.setOnSeekBarChangeListener(new SeekBarListener(Type.navigationBars())); + mToggleIme = findViewById(R.id.toggleButtonIme); + mToggleIme.setTag(mNotFromUser); + mToggleIme.setOnCheckedChangeListener(new ToggleListener(Type.ime())); + mSeekIme = findViewById(R.id.seekBarIme); + mSeekIme.setOnSeekBarChangeListener(new SeekBarListener(Type.ime())); + mTextControllableInsets = findViewById(R.id.textViewControllableInsets); + final View contentView = findViewById(R.id.content); + contentView.setOnApplyWindowInsetsListener(this); + contentView.getWindowInsetsController().addOnControllableInsetsChangedListener( + (c, types) -> mTextControllableInsets.setText("ControllableInsetsTypes=" + types)); + } + + @Override + public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { + mNotFromUser[0] = true; + updateWidgets(insets, Type.statusBars(), mToggleStatus, mSeekStatus); + updateWidgets(insets, Type.navigationBars(), mToggleNavigation, mSeekNavigation); + updateWidgets(insets, Type.ime(), mToggleIme, mSeekIme); + mLastInsets = insets; + mNotFromUser[0] = false; + + // Prevent triggering system gestures while controlling seek bars. + final Insets gestureInsets = insets.getInsets(Type.systemGestures()); + v.setPadding(gestureInsets.left, 0, gestureInsets.right, 0); + + return v.onApplyWindowInsets(insets); + } + + private void updateWidgets(WindowInsets insets, int types, ToggleButton toggle, SeekBar seek) { + final boolean isVisible = insets.isVisible(types); + final boolean wasVisible = mLastInsets != null ? mLastInsets.isVisible(types) : !isVisible; + if (isVisible != wasVisible) { + toggle.setChecked(isVisible); + if (!seek.isPressed()) { + seek.setProgress(isVisible ? seek.getMax() : seek.getMin(), true /* animate*/); + } + } + + } + + private static class ToggleListener implements CompoundButton.OnCheckedChangeListener { + + private final @Type.InsetsType int mTypes; + + ToggleListener(int types) { + mTypes = types; + } + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (((boolean[]) buttonView.getTag())[0]) { + // not from user + return; + } + if (isChecked) { + buttonView.getWindowInsetsController().show(mTypes); + } else { + buttonView.getWindowInsetsController().hide(mTypes); + } + } + } + + private static class SeekBarListener implements SeekBar.OnSeekBarChangeListener { + + private final @Type.InsetsType int mTypes; + + private WindowInsetsAnimationController mController; + + SeekBarListener(int types) { + mTypes = types; + } + + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (mController != null && fromUser) { + final int min = seekBar.getMin(); + final float fraction = (progress - min) / (float) (seekBar.getMax() - min); + final Insets shownInsets = mController.getShownStateInsets(); + final Insets hiddenInsets = mController.getHiddenStateInsets(); + final Insets currentInsets = Insets.of( + (int) (0.5f + fraction * (shownInsets.left - hiddenInsets.left)), + (int) (0.5f + fraction * (shownInsets.top - hiddenInsets.top)), + (int) (0.5f + fraction * (shownInsets.right - hiddenInsets.right)), + (int) (0.5f + fraction * (shownInsets.bottom - hiddenInsets.bottom))); + mController.setInsetsAndAlpha(currentInsets, 1f /* alpha */, fraction); + } + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + if (mController != null) { + return; + } + seekBar.getWindowInsetsController().controlWindowInsetsAnimation(mTypes, + -1 /* durationMs */, null /* interpolator */, null /* cancellationSignal */, + new WindowInsetsAnimationControlListener() { + @Override + public void onReady(WindowInsetsAnimationController controller, int types) { + mController = controller; + if (!seekBar.isPressed()) { + onStopTrackingTouch(seekBar); + } + } + + @Override + public void onFinished(WindowInsetsAnimationController controller) { + mController = null; + } + + @Override + public void onCancelled(WindowInsetsAnimationController controller) { + mController = null; + } + }); + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + final int min = seekBar.getMin(); + final int max = seekBar.getMax(); + final boolean shown = (seekBar.getProgress() - min) * 2 > max - min; + seekBar.setProgress(shown ? max : min); + if (mController != null) { + mController.finish(shown); + } + } + } +} diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsTestsMainActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsTestsMainActivity.java new file mode 100644 index 000000000000..8b77a78ff51e --- /dev/null +++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsTestsMainActivity.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.test.windowinsetstests; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; + +public class WindowInsetsTestsMainActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main_activity); + + findViewById(R.id.chat_button).setOnClickListener( + v -> startActivity(new Intent(this, ChatActivity.class))); + + findViewById(R.id.controller_button).setOnClickListener( + v -> startActivity(new Intent(this, ControllerActivity.class))); + } +} diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp index 4a6bfd031284..53d9ffe21949 100644 --- a/tools/aapt2/dump/DumpManifest.cpp +++ b/tools/aapt2/dump/DumpManifest.cpp @@ -1405,6 +1405,29 @@ class UsesStaticLibrary : public ManifestExtractor::Element { } }; +/** Represents <uses-native-library> elements. **/ +class UsesNativeLibrary : public ManifestExtractor::Element { + public: + UsesNativeLibrary() = default; + std::string name; + int required; + + void Extract(xml::Element* element) override { + auto parent_stack = extractor()->parent_stack(); + if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) { + name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), ""); + required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1); + } + } + + void Print(text::Printer* printer) override { + if (!name.empty()) { + printer->Print(StringPrintf("uses-native-library%s:'%s'\n", + (required == 0) ? "-not-required" : "", name.data())); + } + } +}; + /** * Represents <meta-data> elements. These tags are only printed when a flag is passed in to * explicitly enable meta data printing. @@ -2245,6 +2268,7 @@ T* ElementCast(ManifestExtractor::Element* element) { {"uses-static-library", std::is_base_of<UsesStaticLibrary, T>::value}, {"additional-certificate", std::is_base_of<AdditionalCertificate, T>::value}, {"uses-sdk", std::is_base_of<UsesSdkBadging, T>::value}, + {"uses-native-library", std::is_base_of<UsesNativeLibrary, T>::value}, }; auto check = kTagCheck.find(element->tag()); @@ -2295,6 +2319,7 @@ std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Element::Inflate( {"uses-package", &CreateType<UsesPackage>}, {"additional-certificate", &CreateType<AdditionalCertificate>}, {"uses-sdk", &CreateType<UsesSdkBadging>}, + {"uses-native-library", &CreateType<UsesNativeLibrary>}, }; // Attempt to map the xml tag to a element inflater diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp index 3d69093a936a..49f8e1bcd30b 100644 --- a/tools/aapt2/link/ManifestFixer.cpp +++ b/tools/aapt2/link/ManifestFixer.cpp @@ -422,6 +422,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, application_action.Action(OptionalNameIsJavaClassName); application_action["uses-library"].Action(RequiredNameIsNotEmpty); + application_action["uses-native-library"].Action(RequiredNameIsNotEmpty); application_action["library"].Action(RequiredNameIsNotEmpty); application_action["profileable"]; |