diff options
169 files changed, 4693 insertions, 3326 deletions
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java index 93bf541d02b4..e1928615211a 100644 --- a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java +++ b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java @@ -53,7 +53,8 @@ public final class BenchmarkState { private static final int NOT_STARTED = 0; // The benchmark has not started yet. private static final int WARMUP = 1; // The benchmark is warming up. private static final int RUNNING = 2; // The benchmark is running. - private static final int FINISHED = 3; // The benchmark has stopped. + private static final int RUNNING_CUSTOMIZED = 3; // Running for customized measurement. + private static final int FINISHED = 4; // The benchmark has stopped. private int mState = NOT_STARTED; // Current benchmark state. @@ -76,6 +77,14 @@ public final class BenchmarkState { private int mRepeatCount = 0; + /** + * Additional iteration that used to apply customized measurement. The result during these + * iterations won't be counted into {@link #mStats}. + */ + private int mMaxCustomizedIterations; + private int mCustomizedIterations; + private CustomizedIterationListener mCustomizedIterationListener; + // Statistics. These values will be filled when the benchmark has finished. // The computation needs double precision, but long int is fine for final reporting. private Stats mStats; @@ -110,6 +119,15 @@ public final class BenchmarkState { mPaused = false; } + /** + * This is used to run the benchmark with more information by enabling some debug mechanism but + * we don't want to account the special runs (slower) in the stats report. + */ + public void setCustomizedIterations(int iterations, CustomizedIterationListener listener) { + mMaxCustomizedIterations = iterations; + mCustomizedIterationListener = listener; + } + private void beginWarmup() { mStartTimeNs = System.nanoTime(); mIteration = 0; @@ -141,6 +159,11 @@ public final class BenchmarkState { Debug.stopMethodTracing(); } mStats = new Stats(mResults); + if (mMaxCustomizedIterations > 0 && mCustomizedIterationListener != null) { + mState = RUNNING_CUSTOMIZED; + mCustomizedIterationListener.onStart(mCustomizedIterations); + return true; + } mState = FINISHED; return false; } @@ -180,6 +203,15 @@ public final class BenchmarkState { "Resume the benchmark before finishing each step."); } return true; + case RUNNING_CUSTOMIZED: + mCustomizedIterationListener.onFinished(mCustomizedIterations); + mCustomizedIterations++; + if (mCustomizedIterations >= mMaxCustomizedIterations) { + mState = FINISHED; + return false; + } + mCustomizedIterationListener.onStart(mCustomizedIterations); + return true; case FINISHED: throw new IllegalStateException("The benchmark has finished."); default: @@ -240,4 +272,13 @@ public final class BenchmarkState { status.putLong(key + "_standardDeviation", standardDeviation()); instrumentation.sendStatus(Activity.RESULT_OK, status); } + + /** The interface to receive the events of customized iteration. */ + public interface CustomizedIterationListener { + /** The customized iteration starts. */ + void onStart(int iteration); + + /** The customized iteration finished. */ + void onFinished(int iteration); + } } diff --git a/apct-tests/perftests/windowmanager/AndroidManifest.xml b/apct-tests/perftests/windowmanager/AndroidManifest.xml index 85fd7176c33a..95ede345fbee 100644 --- a/apct-tests/perftests/windowmanager/AndroidManifest.xml +++ b/apct-tests/perftests/windowmanager/AndroidManifest.xml @@ -29,5 +29,7 @@ </application> <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" - android:targetPackage="com.android.perftests.wm"/> + android:targetPackage="com.android.perftests.wm"> + <meta-data android:name="listener" android:value="android.wm.WmPerfRunListener" /> + </instrumentation> </manifest> diff --git a/apct-tests/perftests/windowmanager/AndroidTest.xml b/apct-tests/perftests/windowmanager/AndroidTest.xml index aee02c7ab767..6ac9f9373f8c 100644 --- a/apct-tests/perftests/windowmanager/AndroidTest.xml +++ b/apct-tests/perftests/windowmanager/AndroidTest.xml @@ -42,7 +42,7 @@ <option name="hidden-api-checks" value="false"/> <!-- Listener related args for collecting the traces and waiting for the device to stabilize. --> - <option name="device-listeners" value="android.wm.WmPerfRunListener,android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" /> + <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" /> <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. --> <option name="instrumentation-arg" key="newRunListenerMode" value="true" /> @@ -57,8 +57,6 @@ <!-- PerfettoListener related arguments --> <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" /> <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" /> - - <option name="instrumentation-arg" key="newRunListenerMode" value="true" /> </test> <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 index 05fa6279a949..8b5292fd02a5 100644 --- a/apct-tests/perftests/windowmanager/README.md +++ b/apct-tests/perftests/windowmanager/README.md @@ -25,3 +25,11 @@ adb shell am instrument -w -r -e class android.wm.RelayoutPerfTest \ com.android.perftests.wm/androidx.test.runner.AndroidJUnitRunner ``` * `kill-bg` is optional. + +Test arguments + - kill-bg + * boolean: Kill background process before running test. + - profiling-iterations + * int: Run the extra iterations with enabling method profiling. + - profiling-sampling + * int: The interval (0=trace each method, default is 10) of sample profiling in microseconds. diff --git a/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java index 4ed3b4e09d11..5c09ec2e760f 100644 --- a/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java +++ b/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java @@ -41,7 +41,8 @@ import java.util.concurrent.TimeUnit; /** Measure the performance of internal methods in window manager service by trace tag. */ @LargeTest -public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase { +public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase + implements ManualBenchmarkState.CustomizedIterationListener { private static final String TAG = InternalWindowOperationPerfTest.class.getSimpleName(); @Rule @@ -68,6 +69,9 @@ public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase { "finishActivity", "startActivityInner"); + private boolean mIsProfiling; + private boolean mIsTraceStarted; + @Test @ManualBenchmarkTest( targetTestDurationNs = 20 * TIME_1_S_IN_NS, @@ -76,13 +80,13 @@ public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase { | StatsReport.FLAG_MAX | StatsReport.FLAG_COEFFICIENT_VAR)) public void testLaunchAndFinishActivity() throws Throwable { final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + state.setCustomizedIterations(getProfilingIterations(), this); long measuredTimeNs = 0; - boolean isTraceStarted = false; while (state.keepRunning(measuredTimeNs)) { - if (!isTraceStarted && !state.isWarmingUp()) { + if (!mIsTraceStarted && !mIsProfiling && !state.isWarmingUp()) { startAsyncAtrace(); - isTraceStarted = true; + mIsTraceStarted = true; } final long startTime = SystemClock.elapsedRealtimeNanos(); mActivityRule.launchActivity(); @@ -91,7 +95,9 @@ public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase { measuredTimeNs = SystemClock.elapsedRealtimeNanos() - startTime; } - stopAsyncAtrace(); + if (mIsTraceStarted) { + stopAsyncAtrace(); + } mTraceMarkParser.forAllSlices((key, slices) -> { for (TraceMarkSlice slice : slices) { @@ -108,7 +114,7 @@ public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase { SystemClock.sleep(TimeUnit.NANOSECONDS.toMillis(TIME_1_S_IN_NS)); } - private void stopAsyncAtrace() throws IOException { + private void stopAsyncAtrace() { final ParcelFileDescriptor pfd = sUiAutomation.executeShellCommand("atrace --async_stop"); final InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfd); try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { @@ -116,6 +122,28 @@ public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase { while ((line = reader.readLine()) != null) { mTraceMarkParser.visit(line); } + } catch (IOException e) { + Log.w(TAG, "Failed to read the result of stopped atrace", e); + } + } + + @Override + public void onStart(int iteration) { + if (mIsTraceStarted) { + // Do not capture trace when profiling because the result will be much slower. + stopAsyncAtrace(); + mIsTraceStarted = false; + } + mIsProfiling = true; + startProfiling(InternalWindowOperationPerfTest.class.getSimpleName() + + "_MethodTracing_" + iteration + ".trace"); + } + + @Override + public void onFinished(int iteration) { + stopProfiling(); + if (iteration >= getProfilingIterations() - 1) { + mIsProfiling = false; } } } diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java index 6122ef254855..efcabd817109 100644 --- a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java +++ b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java @@ -62,7 +62,8 @@ import java.util.concurrent.TimeUnit; @RunWith(Parameterized.class) @LargeTest -public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase { +public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase + implements ManualBenchmarkState.CustomizedIterationListener { private static Intent sRecentsIntent; @Rule @@ -162,6 +163,7 @@ public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase { | StatsReport.FLAG_COEFFICIENT_VAR)) public void testRecentsAnimation() throws Throwable { final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + state.setCustomizedIterations(getProfilingIterations(), this); final IActivityTaskManager atm = ActivityTaskManager.getService(); final ArrayList<Pair<String, Boolean>> finishCases = new ArrayList<>(); @@ -230,7 +232,21 @@ public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase { state.addExtraResult("start", elapsedTimeNsOfStart); // Ensure the animation callback is done. - Assume.assumeTrue(recentsSemaphore.tryAcquire(TIME_5_S_IN_NS, TimeUnit.NANOSECONDS)); + Assume.assumeTrue(recentsSemaphore.tryAcquire( + sIsProfilingMethod ? 10 * TIME_5_S_IN_NS : TIME_5_S_IN_NS, + TimeUnit.NANOSECONDS)); } } + + @Override + public void onStart(int iteration) { + startProfiling(RecentsAnimationPerfTest.class.getSimpleName() + + "_interval_" + intervalBetweenOperations + + "_MethodTracing_" + iteration + ".trace"); + } + + @Override + public void onFinished(int iteration) { + stopProfiling(); + } } diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java index cff5663e9d9e..269742854cb0 100644 --- a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java +++ b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java @@ -54,7 +54,8 @@ import java.util.function.IntSupplier; @RunWith(Parameterized.class) @LargeTest @Presubmit -public class RelayoutPerfTest extends WindowManagerPerfTestBase { +public class RelayoutPerfTest extends WindowManagerPerfTestBase + implements BenchmarkState.CustomizedIterationListener { private int mIteration; @Rule @@ -93,9 +94,22 @@ public class RelayoutPerfTest extends WindowManagerPerfTestBase { mActivityRule.runOnUiThread(() -> activity.setContentView(contentView)); getInstrumentation().waitForIdleSync(); + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + state.setCustomizedIterations(getProfilingIterations(), this); final RelayoutRunner relayoutRunner = new RelayoutRunner(activity, contentView.getWindow(), () -> visibilities[mIteration++ % visibilities.length]); - relayoutRunner.runBenchmark(mPerfStatusReporter.getBenchmarkState()); + relayoutRunner.runBenchmark(state); + } + + @Override + public void onStart(int iteration) { + startProfiling(RelayoutPerfTest.class.getSimpleName() + "_" + testName + + "_MethodTracing_" + iteration + ".trace"); + } + + @Override + public void onFinished(int iteration) { + stopProfiling(); } /** A dummy view to get IWindow. */ diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java index c72cc9d635e0..c52b1300aedc 100644 --- a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java +++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java @@ -48,8 +48,6 @@ import org.junit.Test; public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase implements ManualBenchmarkState.CustomizedIterationListener { - private static final int PROFILED_ITERATIONS = 2; - @Rule public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter(); @@ -64,7 +62,7 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase sUiAutomation.dropShellPermissionIdentity(); } - /** The last {@link #PROFILED_ITERATIONS} will provide the information of method profiling. */ + /** The last customized iterations will provide the information of method profiling. */ @Override public void onStart(int iteration) { startProfiling(WindowAddRemovePerfTest.class.getSimpleName() @@ -80,7 +78,7 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase @ManualBenchmarkTest(warmupDurationNs = TIME_1_S_IN_NS, targetTestDurationNs = TIME_5_S_IN_NS) public void testAddRemoveWindow() throws Throwable { final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - state.setCustomizedIterations(PROFILED_ITERATIONS, this); + state.setCustomizedIterations(getProfilingIterations(), this); new TestWindow().runBenchmark(state); } diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java index cc0e939a2a80..b51a9a8fb0dd 100644 --- a/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java +++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java @@ -32,6 +32,7 @@ import androidx.test.runner.lifecycle.ActivityLifecycleCallback; import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry; import androidx.test.runner.lifecycle.Stage; +import org.junit.After; import org.junit.BeforeClass; import org.junit.runner.Description; import org.junit.runners.model.Statement; @@ -52,18 +53,17 @@ public class WindowManagerPerfTestBase { /** * The out directory matching the directory-keys of collector in AndroidTest.xml. The directory - * is in /data because while enabling method profling of system server, it cannot write the + * is in /data because while enabling method profiling of system server, it cannot write the * trace to external storage. */ static final File BASE_OUT_PATH = new File("/data/local/tmp/WmPerfTests"); + static boolean sIsProfilingMethod; + @BeforeClass public static void setUpOnce() { final Context context = getInstrumentation().getContext(); - if (!BASE_OUT_PATH.exists()) { - executeShellCommand("mkdir -p " + BASE_OUT_PATH); - } if (!context.getSystemService(PowerManager.class).isInteractive() || context.getSystemService(KeyguardManager.class).isKeyguardLocked()) { executeShellCommand("input keyevent KEYCODE_WAKEUP"); @@ -73,6 +73,14 @@ public class WindowManagerPerfTestBase { .addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); } + @After + public void tearDown() { + // Make sure that profiling is stopped if test fails. + if (sIsProfilingMethod) { + stopProfiling(); + } + } + /** * Executes shell command with reading the output. It may also used to block until the current * command is completed. @@ -93,12 +101,26 @@ public class WindowManagerPerfTestBase { } /** Starts method tracing on system server. */ - void startProfiling(String subPath) { - executeShellCommand("am profile start system " + new File(BASE_OUT_PATH, subPath)); + static void startProfiling(String subPath) { + if (!BASE_OUT_PATH.exists()) { + executeShellCommand("mkdir -p " + BASE_OUT_PATH); + } + final String samplingArg = WmPerfRunListener.sSamplingIntervalUs > 0 + ? ("--sampling " + WmPerfRunListener.sSamplingIntervalUs) + : ""; + executeShellCommand("am profile start " + samplingArg + " system " + + new File(BASE_OUT_PATH, subPath)); + sIsProfilingMethod = true; } - void stopProfiling() { + static void stopProfiling() { executeShellCommand("am profile stop system"); + sIsProfilingMethod = false; + } + + /** Returns how many iterations should run with method tracing. */ + static int getProfilingIterations() { + return WmPerfRunListener.sProfilingIterations; } static void runWithShellPermissionIdentity(Runnable runnable) { diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java b/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java index 6eb85aacb4e8..d955289e5f49 100644 --- a/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java +++ b/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java @@ -31,6 +31,7 @@ import android.os.BatteryManager; import android.os.Bundle; import android.os.SystemClock; import android.provider.Settings; +import android.util.Log; import android.view.WindowManagerPolicyConstants; import android.wm.WindowManagerPerfTestBase.SettingsSession; @@ -46,10 +47,22 @@ 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 String TAG = WmPerfRunListener.class.getSimpleName(); + + private static final String ARGUMENT_LOG_ONLY = "log"; + private static final String ARGUMENT_KILL_BACKGROUND = "kill-bg"; + private static final String ARGUMENT_PROFILING_ITERATIONS = "profiling-iterations"; + private static final String ARGUMENT_PROFILING_SAMPLING = "profiling-sampling"; + private static final String DEFAULT_PROFILING_ITERATIONS = "0"; + private static final String DEFAULT_PROFILING_SAMPLING_US = "10"; private static final long KILL_BACKGROUND_WAIT_MS = 3000; + /** The requested iterations to run with method profiling. */ + static int sProfilingIterations; + + /** The interval of sample profiling in microseconds. */ + static int sSamplingIntervalUs; + private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); private long mWaitPreconditionDoneMs = 500; @@ -83,6 +96,16 @@ public class WmPerfRunListener extends RunListener { @Override public void testRunStarted(Description description) { final Bundle arguments = InstrumentationRegistry.getArguments(); + // If true, it only logs the method names without running. + final boolean skip = Boolean.parseBoolean(arguments.getString(ARGUMENT_LOG_ONLY, "false")); + Log.i(TAG, "arguments=" + arguments); + if (skip) { + return; + } + sProfilingIterations = Integer.parseInt( + arguments.getString(ARGUMENT_PROFILING_ITERATIONS, DEFAULT_PROFILING_ITERATIONS)); + sSamplingIntervalUs = Integer.parseInt( + arguments.getString(ARGUMENT_PROFILING_SAMPLING, DEFAULT_PROFILING_SAMPLING_US)); // Use gesture navigation for consistency. mNavigationModeSetting.set(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL); @@ -97,7 +120,7 @@ public class WmPerfRunListener extends RunListener { }); PhoneWindow.sendCloseSystemWindows(mContext, "WmPerfTests"); - if (Boolean.parseBoolean(arguments.getString(OPTION_KILL_BACKGROUND))) { + if (Boolean.parseBoolean(arguments.getString(ARGUMENT_KILL_BACKGROUND))) { runWithShellPermissionIdentity(this::killBackgroundProcesses); mWaitPreconditionDoneMs = KILL_BACKGROUND_WAIT_MS; } diff --git a/cmds/idmap2/tests/ResultTests.cpp b/cmds/idmap2/tests/ResultTests.cpp index cbced0ae32fb..f2f8854cec3a 100644 --- a/cmds/idmap2/tests/ResultTests.cpp +++ b/cmds/idmap2/tests/ResultTests.cpp @@ -260,7 +260,8 @@ TEST(ResultTests, CascadeError) { struct NoCopyContainer { uint32_t value; // NOLINT(misc-non-private-member-variables-in-classes) - DISALLOW_COPY_AND_ASSIGN(NoCopyContainer); + NoCopyContainer(const NoCopyContainer&) = delete; + NoCopyContainer& operator=(const NoCopyContainer&) = delete; }; Result<std::unique_ptr<NoCopyContainer>> CreateNoCopyContainer(bool succeed) { diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp index 9b684f1248c5..693402a07f05 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp +++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp @@ -652,7 +652,7 @@ void ValueMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const { (unsigned long)mCurrentSlicedBucket.size()); if (verbose) { for (const auto& it : mCurrentSlicedBucket) { - for (const auto& interval : it.second) { + for (const auto& interval : it.second.intervals) { fprintf(out, "\t(what)%s\t(states)%s (value)%s\n", it.first.getDimensionKeyInWhat().toString().c_str(), it.first.getStateValuesKey().toString().c_str(), @@ -804,7 +804,8 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked( // We need to get the intervals stored with the previous state key so we can // close these value intervals. const auto oldStateKey = baseInfos[0].currentState; - vector<Interval>& intervals = mCurrentSlicedBucket[MetricDimensionKey(whatKey, oldStateKey)]; + vector<Interval>& intervals = + mCurrentSlicedBucket[MetricDimensionKey(whatKey, oldStateKey)].intervals; if (intervals.size() < mFieldMatchers.size()) { VLOG("Resizing number of intervals to %d", (int)mFieldMatchers.size()); intervals.resize(mFieldMatchers.size()); @@ -990,7 +991,7 @@ void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs, bool bucketHasData = false; // The current bucket is large enough to keep. for (const auto& slice : mCurrentSlicedBucket) { - ValueBucket bucket = buildPartialBucket(bucketEndTime, slice.second); + PastValueBucket bucket = buildPartialBucket(bucketEndTime, slice.second.intervals); bucket.mConditionTrueNs = conditionTrueDuration; // it will auto create new vector of ValuebucketInfo if the key is not found. if (bucket.valueIndex.size() > 0) { @@ -1030,9 +1031,9 @@ void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs, mCurrentBucketNum += numBucketsForward; } -ValueBucket ValueMetricProducer::buildPartialBucket(int64_t bucketEndTime, - const std::vector<Interval>& intervals) { - ValueBucket bucket; +PastValueBucket ValueMetricProducer::buildPartialBucket(int64_t bucketEndTime, + const std::vector<Interval>& intervals) { + PastValueBucket bucket; bucket.mBucketStartNs = mCurrentBucketStartTimeNs; bucket.mBucketEndNs = bucketEndTime; for (const auto& interval : intervals) { @@ -1059,7 +1060,7 @@ void ValueMetricProducer::initCurrentSlicedBucket(int64_t nextBucketStartTimeNs) // Cleanup data structure to aggregate values. for (auto it = mCurrentSlicedBucket.begin(); it != mCurrentSlicedBucket.end();) { bool obsolete = true; - for (auto& interval : it->second) { + for (auto& interval : it->second.intervals) { interval.hasValue = false; interval.sampleSize = 0; if (interval.seenNewData) { @@ -1107,7 +1108,7 @@ void ValueMetricProducer::appendToFullBucket(const bool isFullBucketReached) { continue; } // TODO: fix this when anomaly can accept double values - auto& interval = slice.second[0]; + auto& interval = slice.second.intervals[0]; if (interval.hasValue) { mCurrentFullBucket[slice.first] += interval.value.long_value; } @@ -1126,7 +1127,7 @@ void ValueMetricProducer::appendToFullBucket(const bool isFullBucketReached) { for (auto& tracker : mAnomalyTrackers) { if (tracker != nullptr) { // TODO: fix this when anomaly can accept double values - auto& interval = slice.second[0]; + auto& interval = slice.second.intervals[0]; if (interval.hasValue) { tracker->addPastBucket(slice.first, interval.value.long_value, mCurrentBucketNum); @@ -1139,7 +1140,7 @@ void ValueMetricProducer::appendToFullBucket(const bool isFullBucketReached) { // Accumulate partial bucket. for (const auto& slice : mCurrentSlicedBucket) { // TODO: fix this when anomaly can accept double values - auto& interval = slice.second[0]; + auto& interval = slice.second.intervals[0]; if (interval.hasValue) { mCurrentFullBucket[slice.first] += interval.value.long_value; } diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h index e72002e88533..fffc866ec61a 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.h +++ b/cmds/statsd/src/metrics/ValueMetricProducer.h @@ -31,7 +31,7 @@ namespace android { namespace os { namespace statsd { -struct ValueBucket { +struct PastValueBucket { int64_t mBucketStartNs; int64_t mBucketEndNs; std::vector<int> valueIndex; @@ -41,7 +41,6 @@ struct ValueBucket { int64_t mConditionTrueNs; }; - // Aggregates values within buckets. // // There are different events that might complete a bucket @@ -173,7 +172,7 @@ private: // if this is pulled metric const bool mIsPulled; - // internal state of an ongoing aggregation bucket. + // Tracks the value information of one value field. typedef struct { // Index in multi value aggregation. int valueIndex; @@ -188,6 +187,12 @@ private: bool seenNewData = false; } Interval; + // Internal state of an ongoing aggregation bucket. + typedef struct CurrentValueBucket { + // Value information for each value field of the metric. + std::vector<Interval> intervals; + } CurrentValueBucket; + typedef struct { // Holds current base value of the dimension. Take diff and update if necessary. Value base; @@ -199,14 +204,16 @@ private: bool hasCurrentState; } BaseInfo; - std::unordered_map<MetricDimensionKey, std::vector<Interval>> mCurrentSlicedBucket; + // Tracks the internal state in the ongoing aggregation bucket for each DimensionsInWhat + // key and StateValuesKey pair. + std::unordered_map<MetricDimensionKey, CurrentValueBucket> mCurrentSlicedBucket; std::unordered_map<HashableDimensionKey, std::vector<BaseInfo>> mCurrentBaseInfo; std::unordered_map<MetricDimensionKey, int64_t> mCurrentFullBucket; // Save the past buckets and we can clear when the StatsLogReport is dumped. - std::unordered_map<MetricDimensionKey, std::vector<ValueBucket>> mPastBuckets; + std::unordered_map<MetricDimensionKey, std::vector<PastValueBucket>> mPastBuckets; const int64_t mMinBucketSizeNs; @@ -224,8 +231,8 @@ private: void accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData, int64_t originalPullTimeNs, int64_t eventElapsedTimeNs); - ValueBucket buildPartialBucket(int64_t bucketEndTime, - const std::vector<Interval>& intervals); + PastValueBucket buildPartialBucket(int64_t bucketEndTime, + const std::vector<Interval>& intervals); void initCurrentSlicedBucket(int64_t nextBucketStartTimeNs); @@ -234,7 +241,7 @@ private: // Reset diff base and mHasGlobalBase void resetBase(); - static const size_t kBucketSize = sizeof(ValueBucket{}); + static const size_t kBucketSize = sizeof(PastValueBucket{}); const size_t mDimensionSoftLimit; diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp index 1000aea14868..ec8adfd8bcf5 100644 --- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp @@ -57,7 +57,7 @@ const int64_t bucket6StartTimeNs = bucketStartTimeNs + 5 * bucketSizeNs; double epsilon = 0.001; static void assertPastBucketValuesSingleKey( - const std::unordered_map<MetricDimensionKey, std::vector<ValueBucket>>& mPastBuckets, + const std::unordered_map<MetricDimensionKey, std::vector<PastValueBucket>>& mPastBuckets, const std::initializer_list<int>& expectedValuesList, const std::initializer_list<int64_t>& expectedDurationNsList, const std::initializer_list<int64_t>& expectedStartTimeNsList, @@ -79,7 +79,7 @@ static void assertPastBucketValuesSingleKey( ASSERT_EQ(1, mPastBuckets.size()); ASSERT_EQ(expectedValues.size(), mPastBuckets.begin()->second.size()); - const vector<ValueBucket>& buckets = mPastBuckets.begin()->second; + const vector<PastValueBucket>& buckets = mPastBuckets.begin()->second; for (int i = 0; i < expectedValues.size(); i++) { EXPECT_EQ(expectedValues[i], buckets[i].values[0].long_value) << "Values differ at index " << i; @@ -288,7 +288,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); @@ -304,7 +304,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) { valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs); // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); @@ -322,7 +322,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) { allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 36)); valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); @@ -426,7 +426,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); @@ -455,7 +455,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) { allData.push_back(CreateTwoValueLogEvent(tagId, bucket4StartTimeNs + 1, 3, 36)); valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; // the base was reset @@ -489,7 +489,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); @@ -502,7 +502,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) { valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs); // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(10, curBaseInfo.base.long_value); @@ -516,7 +516,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) { allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 36)); valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(36, curBaseInfo.base.long_value); @@ -549,7 +549,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); @@ -562,7 +562,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) { valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs); // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(10, curBaseInfo.base.long_value); @@ -573,7 +573,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) { allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 36)); valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(36, curBaseInfo.base.long_value); @@ -624,7 +624,7 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; // startUpdated:false sum:0 start:100 EXPECT_EQ(true, curBaseInfo.hasBase); @@ -641,7 +641,7 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(110, curBaseInfo.base.long_value); @@ -654,7 +654,7 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curInterval.hasValue); EXPECT_EQ(20, curInterval.value.long_value); @@ -879,7 +879,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer.mCurrentSlicedBucket.begin()->second[0]; + valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(10, curInterval.value.long_value); EXPECT_EQ(true, curInterval.hasValue); @@ -888,7 +888,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(30, curInterval.value.long_value); valueProducer.flushIfNeededLocked(bucket2StartTimeNs); @@ -925,8 +925,8 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer.mCurrentSlicedBucket.begin()->second[0]; - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(20, curInterval.value.long_value); LogEvent event3(/*uid=*/0, /*pid=*/0); @@ -935,7 +935,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(50, curInterval.value.long_value); valueProducer.onConditionChangedLocked(false, bucketStartTimeNs + 35); @@ -946,7 +946,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(50, curInterval.value.long_value); valueProducer.flushIfNeededLocked(bucket2StartTimeNs); @@ -1089,7 +1089,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; // startUpdated:true sum:0 start:11 @@ -1104,7 +1104,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) { valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs); // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; // tartUpdated:false sum:12 EXPECT_EQ(true, curBaseInfo.hasBase); @@ -1121,7 +1121,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) { allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket6StartTimeNs + 1, 36)); valueProducer->onDataPulled(allData, /** succeed */ true, bucket6StartTimeNs); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; // startUpdated:false sum:12 EXPECT_EQ(true, curBaseInfo.hasBase); @@ -1180,7 +1180,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(100, curBaseInfo.base.long_value); @@ -1189,7 +1189,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) { // pull on bucket boundary come late, condition change happens before it valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8}, {bucketStartTimeNs}, {bucket2StartTimeNs}); @@ -1203,7 +1203,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) { assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8}, {bucketStartTimeNs}, {bucket2StartTimeNs}); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(false, curBaseInfo.hasBase); EXPECT_EQ(false, curInterval.hasValue); @@ -1252,7 +1252,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; // startUpdated:false sum:0 start:100 EXPECT_EQ(true, curBaseInfo.hasBase); @@ -1265,7 +1265,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) { assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8}, {bucketStartTimeNs}, {bucket2StartTimeNs}); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(false, curBaseInfo.hasBase); EXPECT_EQ(false, curInterval.hasValue); @@ -1274,7 +1274,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) { valueProducer->onConditionChanged(true, bucket2StartTimeNs + 25); assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8}, {bucketStartTimeNs}, {bucket2StartTimeNs}); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(130, curBaseInfo.base.long_value); @@ -1286,7 +1286,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) { allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 50, 140)); valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 50); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(140, curBaseInfo.base.long_value); @@ -1327,7 +1327,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMin) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer.mCurrentSlicedBucket.begin()->second[0]; + valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(10, curInterval.value.long_value); EXPECT_EQ(true, curInterval.hasValue); @@ -1335,7 +1335,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMin) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(10, curInterval.value.long_value); valueProducer.flushIfNeededLocked(bucket2StartTimeNs); @@ -1364,7 +1364,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMax) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer.mCurrentSlicedBucket.begin()->second[0]; + valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(10, curInterval.value.long_value); EXPECT_EQ(true, curInterval.hasValue); @@ -1374,7 +1374,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMax) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(20, curInterval.value.long_value); valueProducer.flushIfNeededLocked(bucket2StartTimeNs); @@ -1405,7 +1405,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateAvg) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval; - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(10, curInterval.value.long_value); EXPECT_EQ(true, curInterval.hasValue); EXPECT_EQ(1, curInterval.sampleSize); @@ -1414,7 +1414,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateAvg) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(25, curInterval.value.long_value); EXPECT_EQ(2, curInterval.sampleSize); @@ -1449,7 +1449,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateSum) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer.mCurrentSlicedBucket.begin()->second[0]; + valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(10, curInterval.value.long_value); EXPECT_EQ(true, curInterval.hasValue); @@ -1457,7 +1457,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateSum) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(25, curInterval.value.long_value); valueProducer.flushIfNeededLocked(bucket2StartTimeNs); @@ -1487,7 +1487,7 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer.mCurrentSlicedBucket.begin()->second[0]; + valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(10, curBaseInfo.base.long_value); @@ -1499,7 +1499,7 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; EXPECT_EQ(true, curInterval.hasValue); EXPECT_EQ(5, curInterval.value.long_value); @@ -1509,7 +1509,7 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) { valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3); ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(15, curBaseInfo.base.long_value); @@ -1520,7 +1520,7 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) { CreateRepeatedValueLogEvent(&event4, tagId, bucket2StartTimeNs + 15, 15); valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4); ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(15, curBaseInfo.base.long_value); @@ -1558,7 +1558,7 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer.mCurrentSlicedBucket.begin()->second[0]; + valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(10, curBaseInfo.base.long_value); @@ -1572,11 +1572,11 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) { // has one slice ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curInterval.hasValue); EXPECT_EQ(5, curInterval.value.long_value); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[1]; curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1]; EXPECT_EQ(true, curInterval.hasValue); EXPECT_EQ(2, curInterval.value.long_value); @@ -1587,13 +1587,13 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) { valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3); ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(15, curBaseInfo.base.long_value); EXPECT_EQ(true, curInterval.hasValue); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[1]; curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(25, curBaseInfo.base.long_value); @@ -1604,12 +1604,12 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) { valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4); ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(15, curBaseInfo.base.long_value); EXPECT_EQ(true, curInterval.hasValue); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1]; + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[1]; curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(29, curBaseInfo.base.long_value); @@ -1656,7 +1656,7 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBase) { ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); auto iter = valueProducer->mCurrentSlicedBucket.begin(); - auto& interval1 = iter->second[0]; + auto& interval1 = iter->second.intervals[0]; auto iterBase = valueProducer->mCurrentBaseInfo.begin(); auto& baseInfo1 = iterBase->second[0]; EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); @@ -1692,7 +1692,7 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBase) { } EXPECT_TRUE(it != iter); EXPECT_TRUE(itBase != iterBase); - auto& interval2 = it->second[0]; + auto& interval2 = it->second.intervals[0]; auto& baseInfo2 = itBase->second[0]; EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); EXPECT_EQ(true, baseInfo2.hasBase); @@ -1732,7 +1732,7 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) { ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); const auto& it = valueProducer->mCurrentSlicedBucket.begin(); - ValueMetricProducer::Interval& interval1 = it->second[0]; + ValueMetricProducer::Interval& interval1 = it->second.intervals[0]; ValueMetricProducer::BaseInfo& baseInfo1 = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat())->second[0]; EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); @@ -1761,7 +1761,7 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) { } } EXPECT_TRUE(it2 != it); - ValueMetricProducer::Interval& interval2 = it2->second[0]; + ValueMetricProducer::Interval& interval2 = it2->second.intervals[0]; ValueMetricProducer::BaseInfo& baseInfo2 = valueProducer->mCurrentBaseInfo.find(it2->first.getDimensionKeyInWhat())->second[0]; EXPECT_EQ(2, it2->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); @@ -1792,10 +1792,10 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) { // Get new references now that entries have been deleted from the map const auto& it3 = valueProducer->mCurrentSlicedBucket.begin(); const auto& it4 = std::next(valueProducer->mCurrentSlicedBucket.begin()); - ASSERT_EQ(it3->second.size(), 1); - ASSERT_EQ(it4->second.size(), 1); - ValueMetricProducer::Interval& interval3 = it3->second[0]; - ValueMetricProducer::Interval& interval4 = it4->second[0]; + ASSERT_EQ(it3->second.intervals.size(), 1); + ASSERT_EQ(it4->second.intervals.size(), 1); + ValueMetricProducer::Interval& interval3 = it3->second.intervals[0]; + ValueMetricProducer::Interval& interval4 = it4->second.intervals[0]; ValueMetricProducer::BaseInfo& baseInfo3 = valueProducer->mCurrentBaseInfo.find(it3->first.getDimensionKeyInWhat())->second[0]; ValueMetricProducer::BaseInfo& baseInfo4 = @@ -1837,7 +1837,7 @@ TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) { ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); auto iter = valueProducer->mCurrentSlicedBucket.begin(); - auto& interval1 = iter->second[0]; + auto& interval1 = iter->second.intervals[0]; auto iterBase = valueProducer->mCurrentBaseInfo.begin(); auto& baseInfo1 = iterBase->second[0]; EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); @@ -1875,7 +1875,7 @@ TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) { } EXPECT_TRUE(it != iter); EXPECT_TRUE(itBase != iterBase); - auto interval2 = it->second[0]; + auto interval2 = it->second.intervals[0]; auto baseInfo2 = itBase->second[0]; EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); EXPECT_EQ(true, baseInfo2.hasBase); @@ -1889,7 +1889,7 @@ TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) { valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs); // Only one interval left. One was trimmed. ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - interval2 = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + interval2 = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); EXPECT_EQ(true, baseInfo2.hasBase); @@ -1903,7 +1903,7 @@ TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) { allData.push_back(CreateTwoValueLogEvent(tagId, bucket5StartTimeNs + 1, 2, 14)); valueProducer->onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs); - interval2 = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + interval2 = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, baseInfo2.hasBase); EXPECT_EQ(14, baseInfo2.base.long_value); @@ -1943,7 +1943,7 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfB // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval& curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo& curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(100, curBaseInfo.base.long_value); @@ -1980,7 +1980,7 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange) { // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval& curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo& curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(100, curBaseInfo.base.long_value); @@ -2030,7 +2030,7 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange) { valueProducer->onConditionChanged(false, bucketStartTimeNs + 1); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval& curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(false, curBaseInfo.hasBase); EXPECT_EQ(false, curInterval.hasValue); @@ -2103,7 +2103,7 @@ TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange) { valueProducer->mHasGlobalBase = true; ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval& curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(100, curBaseInfo.base.long_value); @@ -2156,7 +2156,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenOneConditionFailed // Contains base from last pull which was successful. ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval& curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(140, curBaseInfo.base.long_value); @@ -2294,7 +2294,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenInitialPullFailed) // Contains base from last pull which was successful. ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval& curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(140, curBaseInfo.base.long_value); @@ -2373,7 +2373,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenLastPullFailed) { // Last pull failed so base has been reset. ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval& curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(false, curBaseInfo.hasBase); EXPECT_EQ(false, curInterval.hasValue); @@ -2460,7 +2460,7 @@ TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged) { valueProducer->onConditionChanged(true, bucketStartTimeNs + 10); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval& curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(false, curInterval.hasValue); @@ -2469,7 +2469,7 @@ TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged) { // Empty pull. valueProducer->onConditionChanged(false, bucketStartTimeNs + 10); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(false, curBaseInfo.hasBase); EXPECT_EQ(false, curInterval.hasValue); @@ -2513,7 +2513,7 @@ TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary) { valueProducer->onConditionChanged(true, bucketStartTimeNs + 12); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval& curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(true, curInterval.hasValue); @@ -2524,7 +2524,7 @@ TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary) { allData.clear(); valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; // Data is empty, base should be reset. EXPECT_EQ(false, curBaseInfo.hasBase); @@ -2572,12 +2572,12 @@ TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries) { auto baseInfoIter = valueProducer->mCurrentBaseInfo.begin(); EXPECT_EQ(true, baseInfoIter->second[0].hasBase); EXPECT_EQ(2, baseInfoIter->second[0].base.long_value); - EXPECT_EQ(false, iterator->second[0].hasValue); + EXPECT_EQ(false, iterator->second.intervals[0].hasValue); iterator++; baseInfoIter++; EXPECT_EQ(false, baseInfoIter->second[0].hasBase); EXPECT_EQ(1, baseInfoIter->second[0].base.long_value); - EXPECT_EQ(false, iterator->second[0].hasValue); + EXPECT_EQ(false, iterator->second.intervals[0].hasValue); EXPECT_EQ(true, valueProducer->mHasGlobalBase); } @@ -2676,7 +2676,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundariesOnConditionChange) { valueProducer->onConditionChanged(true, bucket2StartTimeNs + 10); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; auto curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase); EXPECT_EQ(5, curBaseInfo.base.long_value); @@ -2811,7 +2811,7 @@ TEST(ValueMetricProducerTest, TestDataIsNotUpdatedWhenNoConditionChanged) { valueProducer->onConditionChanged(false, bucketStartTimeNs + 12); ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; auto curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curInterval.hasValue); EXPECT_EQ(2, curInterval.value.long_value); @@ -3045,7 +3045,7 @@ TEST(ValueMetricProducerTest, TestPulledData_noDiff_withMultipleConditionChanges // has one slice ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(false, curBaseInfo.hasBase); EXPECT_EQ(true, curInterval.hasValue); @@ -3058,7 +3058,7 @@ TEST(ValueMetricProducerTest, TestPulledData_noDiff_withMultipleConditionChanges assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {50 - 8}, {bucketStartTimeNs}, {bucket2StartTimeNs}); - curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(false, curBaseInfo.hasBase); EXPECT_EQ(false, curInterval.hasValue); @@ -3091,7 +3091,7 @@ TEST(ValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryTrue) { assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {30}, {bucketSizeNs - 8}, {bucketStartTimeNs}, {bucket2StartTimeNs}); ValueMetricProducer::Interval curInterval = - valueProducer->mCurrentSlicedBucket.begin()->second[0]; + valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0]; ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(false, curBaseInfo.hasBase); EXPECT_EQ(false, curInterval.hasValue); @@ -3995,7 +3995,7 @@ TEST(ValueMetricProducerTest, TestSlicedState) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Bucket status after screen state change kStateUnknown->ON. auto screenEvent = CreateScreenStateChangedEvent( @@ -4016,8 +4016,8 @@ TEST(ValueMetricProducerTest, TestSlicedState) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(2, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(2, it->second.intervals[0].value.long_value); // Bucket status after screen state change ON->OFF. screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 10, @@ -4037,16 +4037,16 @@ TEST(ValueMetricProducerTest, TestSlicedState) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(4, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(4, it->second.intervals[0].value.long_value); // Value for dimension, state key {{}, kStateUnknown} it++; EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(2, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(2, it->second.intervals[0].value.long_value); // Bucket status after screen state change OFF->ON. screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15, @@ -4067,24 +4067,24 @@ TEST(ValueMetricProducerTest, TestSlicedState) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(12, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(12, it->second.intervals[0].value.long_value); // Value for dimension, state key {{}, ON} it++; EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(4, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(4, it->second.intervals[0].value.long_value); // Value for dimension, state key {{}, kStateUnknown} it++; EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(2, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(2, it->second.intervals[0].value.long_value); // Start dump report and check output. ProtoOutputStream output; @@ -4206,7 +4206,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Bucket status after screen state change kStateUnknown->ON. auto screenEvent = CreateScreenStateChangedEvent( @@ -4227,8 +4227,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(2, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(2, it->second.intervals[0].value.long_value); // Bucket status after screen state change ON->VR. // Both ON and VR are in the same state group, so the base should not change. @@ -4250,8 +4250,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(2, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(2, it->second.intervals[0].value.long_value); // Bucket status after screen state change VR->ON. // Both ON and VR are in the same state group, so the base should not change. @@ -4273,8 +4273,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(2, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(2, it->second.intervals[0].value.long_value); // Bucket status after screen state change VR->OFF. screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15, @@ -4295,16 +4295,16 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(screenOnGroup.group_id(), it->first.getStateValuesKey().getValues()[0].mValue.long_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(16, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(16, it->second.intervals[0].value.long_value); // Value for dimension, state key {{}, kStateUnknown} it++; EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(2, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(2, it->second.intervals[0].value.long_value); // Start dump report and check output. ProtoOutputStream output; @@ -4459,7 +4459,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Base for dimension key {uid 2} it++; itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); @@ -4475,7 +4475,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Bucket status after uid 1 process state change kStateUnknown -> Foreground. auto uidProcessEvent = CreateUidProcessStateChangedEvent( @@ -4497,8 +4497,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(3, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(3, it->second.intervals[0].value.long_value); // Base for dimension key {uid 2} it++; @@ -4514,7 +4514,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Bucket status after uid 2 process state change kStateUnknown -> Background. uidProcessEvent = CreateUidProcessStateChangedEvent( @@ -4535,8 +4535,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(3, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(3, it->second.intervals[0].value.long_value); // Base for dimension key {uid 2} it++; @@ -4552,8 +4552,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(2, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(2, it->second.intervals[0].value.long_value); // Pull at end of first bucket. vector<shared_ptr<LogEvent>> allData; @@ -4582,7 +4582,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Base for dimension key {uid 1} it++; @@ -4599,7 +4599,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* kStateTracker::kUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Value for key {uid 1, FOREGROUND} it++; @@ -4608,7 +4608,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Value for key {uid 2, kStateUnknown} it++; @@ -4617,7 +4617,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* kStateTracker::kUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Bucket status after uid 1 process state change from Foreground -> Background. uidProcessEvent = CreateUidProcessStateChangedEvent( @@ -4642,7 +4642,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Base for dimension key {uid 1} it++; itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat()); @@ -4658,7 +4658,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Value for key {uid 1, FOREGROUND} it++; ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size()); @@ -4666,8 +4666,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(3, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(3, it->second.intervals[0].value.long_value); // Value for key {uid 2, kStateUnknown} it++; ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size()); @@ -4675,7 +4675,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Bucket status after uid 1 process state change Background->Foreground. uidProcessEvent = CreateUidProcessStateChangedEvent( @@ -4699,7 +4699,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Base for dimension key {uid 1} it++; @@ -4716,7 +4716,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Value for key {uid 1, BACKGROUND} it++; @@ -4725,8 +4725,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(4, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(4, it->second.intervals[0].value.long_value); // Value for key {uid 1, FOREGROUND} it++; @@ -4735,8 +4735,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(3, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(3, it->second.intervals[0].value.long_value); // Value for key {uid 2, kStateUnknown} it++; @@ -4867,13 +4867,13 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) { itBase->second[0].currentState.getValues()[0].mValue.int_value); // Value for key {{}, -1} ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); - std::unordered_map<MetricDimensionKey, std::vector<ValueMetricProducer::Interval>>::iterator - it = valueProducer->mCurrentSlicedBucket.begin(); + std::unordered_map<MetricDimensionKey, ValueMetricProducer::CurrentValueBucket>::iterator it = + valueProducer->mCurrentSlicedBucket.begin(); EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(-1 /*StateTracker::kUnknown*/, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_FALSE(it->second[0].hasValue); + EXPECT_FALSE(it->second.intervals[0].hasValue); // Bucket status after battery saver mode OFF event. unique_ptr<LogEvent> batterySaverOffEvent = @@ -4895,8 +4895,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(BatterySaverModeStateChanged::ON, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(2, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(2, it->second.intervals[0].value.long_value); // Pull at end of first bucket. vector<shared_ptr<LogEvent>> allData; @@ -4933,8 +4933,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) { ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); EXPECT_EQ(BatterySaverModeStateChanged::OFF, it->first.getStateValuesKey().getValues()[0].mValue.int_value); - EXPECT_TRUE(it->second[0].hasValue); - EXPECT_EQ(4, it->second[0].value.long_value); + EXPECT_TRUE(it->second.intervals[0].hasValue); + EXPECT_EQ(4, it->second.intervals[0].value.long_value); // Start dump report and check output. ProtoOutputStream output; diff --git a/config/Android.bp b/config/Android.bp index 0fb56cb3410a..8dd409b51eee 100644 --- a/config/Android.bp +++ b/config/Android.bp @@ -13,6 +13,6 @@ // limitations under the License. filegroup { - name: "preloaded-classes-blacklist", - srcs: ["preloaded-classes-blacklist"], + name: "preloaded-classes-denylist", + srcs: ["preloaded-classes-denylist"], } diff --git a/config/generate-preloaded-classes.sh b/config/generate-preloaded-classes.sh index 0ad3a0263d95..b17a3660e1f1 100755 --- a/config/generate-preloaded-classes.sh +++ b/config/generate-preloaded-classes.sh @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. if [ "$#" -lt 2 ]; then - echo "Usage $0 <input classes file> <blacklist file> [extra classes files]" + echo "Usage $0 <input classes file> <denylist file> [extra classes files]" exit 1 fi @@ -31,9 +31,9 @@ echo "# Preloaded-classes filter file for phones. #" input=$1 -blacklist=$2 +denylist=$2 shift 2 extra_classes_files=("$@") # Disable locale to enable lexicographical sorting -LC_ALL=C sort "$input" "${extra_classes_files[@]}" | uniq | grep -f "$blacklist" -v -F -x | grep -v "\$NoPreloadHolder" +LC_ALL=C sort "$input" "${extra_classes_files[@]}" | uniq | grep -f "$denylist" -v -F -x | grep -v "\$NoPreloadHolder" diff --git a/config/preloaded-classes-blacklist b/config/preloaded-classes-denylist index 8ab5273cd755..8ab5273cd755 100644 --- a/config/preloaded-classes-blacklist +++ b/config/preloaded-classes-denylist diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index f6b045349219..caca05a9e3b3 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -5656,6 +5656,11 @@ public final class ActivityThread extends ClientTransactionHandler { throw new IllegalArgumentException("Activity token not set. Is the activity attached?"); } + // WindowConfiguration differences aren't considered as public, check it separately. + // multi-window / pip mode changes, if any, should be sent before the configuration + // change callback, see also PinnedStackTests#testConfigurationChangeOrderDuringTransition + handleWindowingModeChangeIfNeeded(activity, newConfig); + final boolean movedToDifferentDisplay = isDifferentDisplay(activity, displayId); boolean shouldReportChange = false; if (activity.mCurrentConfig == null) { @@ -5708,11 +5713,6 @@ public final class ActivityThread extends ClientTransactionHandler { } if (shouldReportChange) { - // multi-window / pip mode changes, if any, should be sent before the configuration - // change callback, see also - // PinnedStackTests#testConfigurationChangeOrderDuringTransition - handleWindowingModeChangeIfNeeded(activity, newConfig); - activity.mCalled = false; activity.onConfigurationChanged(configToReport); if (!activity.mCalled) { diff --git a/core/java/android/app/prediction/AppPredictor.java b/core/java/android/app/prediction/AppPredictor.java index 7f436401dbf4..fa135b10ae1f 100644 --- a/core/java/android/app/prediction/AppPredictor.java +++ b/core/java/android/app/prediction/AppPredictor.java @@ -83,6 +83,8 @@ public final class AppPredictor { private final AppPredictionSessionId mSessionId; private final ArrayMap<Callback, CallbackWrapper> mRegisteredCallbacks = new ArrayMap<>(); + private final IBinder mToken = new Binder(); + /** * Creates a new Prediction client. * <p> @@ -98,7 +100,7 @@ public final class AppPredictor { mSessionId = new AppPredictionSessionId( context.getPackageName() + ":" + UUID.randomUUID().toString(), context.getUserId()); try { - mPredictionManager.createPredictionSession(predictionContext, mSessionId); + mPredictionManager.createPredictionSession(predictionContext, mSessionId, mToken); } catch (RemoteException e) { Log.e(TAG, "Failed to create predictor", e); e.rethrowAsRuntimeException(); diff --git a/core/java/android/app/prediction/IPredictionManager.aidl b/core/java/android/app/prediction/IPredictionManager.aidl index 587e3fd52377..863fc6f952dd 100644 --- a/core/java/android/app/prediction/IPredictionManager.aidl +++ b/core/java/android/app/prediction/IPredictionManager.aidl @@ -29,7 +29,7 @@ import android.content.pm.ParceledListSlice; interface IPredictionManager { void createPredictionSession(in AppPredictionContext context, - in AppPredictionSessionId sessionId); + in AppPredictionSessionId sessionId, in IBinder token); void notifyAppTargetEvent(in AppPredictionSessionId sessionId, in AppTargetEvent event); diff --git a/core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl b/core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl index af77fe05b902..6d0fe72b9de1 100644 --- a/core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl +++ b/core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl @@ -20,5 +20,5 @@ import android.app.timezonedetector.TimeZoneConfiguration; /** {@hide} */ oneway interface ITimeZoneConfigurationListener { - void onChange(in TimeZoneConfiguration configuration); + void onChange(); }
\ No newline at end of file diff --git a/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl index 6e93af6a053b..4f7e1f62928a 100644 --- a/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl +++ b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl @@ -32,17 +32,15 @@ import android.app.timezonedetector.TimeZoneConfiguration; * this Binder interface directly. See {@link android.app.timezonedetector.TimeZoneDetectorService} * for more complete documentation. * - * * {@hide} */ interface ITimeZoneDetectorService { TimeZoneCapabilities getCapabilities(); - - TimeZoneConfiguration getConfiguration(); - boolean updateConfiguration(in TimeZoneConfiguration configuration); void addConfigurationListener(ITimeZoneConfigurationListener listener); void removeConfigurationListener(ITimeZoneConfigurationListener listener); + boolean updateConfiguration(in TimeZoneConfiguration configuration); + boolean suggestManualTimeZone(in ManualTimeZoneSuggestion timeZoneSuggestion); void suggestTelephonyTimeZone(in TelephonyTimeZoneSuggestion timeZoneSuggestion); } diff --git a/core/java/android/app/timezonedetector/TimeZoneCapabilities.java b/core/java/android/app/timezonedetector/TimeZoneCapabilities.java index cc0af3f97e49..09fffe9f4f25 100644 --- a/core/java/android/app/timezonedetector/TimeZoneCapabilities.java +++ b/core/java/android/app/timezonedetector/TimeZoneCapabilities.java @@ -16,9 +16,12 @@ package android.app.timezonedetector; +import static android.app.timezonedetector.TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED; +import static android.app.timezonedetector.TimeZoneConfiguration.SETTING_GEO_DETECTION_ENABLED; + import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.UserIdInt; +import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; @@ -38,9 +41,9 @@ import java.util.Objects; * * <p>Actions have associated methods, see the documentation for each action for details. * - * <p>For configuration capabilities, the associated current configuration value can be retrieved - * using {@link TimeZoneDetector#getConfiguration()} and may be changed using - * {@link TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)}. + * <p>For configuration settings capabilities, the associated settings value can be found via + * {@link #getConfiguration()} and may be changed using {@link + * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} (if the user's capabilities allow). * * <p>Note: Capabilities are independent of app permissions required to call the associated APIs. * @@ -60,7 +63,8 @@ public final class TimeZoneCapabilities implements Parcelable { public static final int CAPABILITY_NOT_SUPPORTED = 10; /** - * Indicates that a capability is supported on this device, but not allowed for the user. + * Indicates that a capability is supported on this device, but not allowed for the user, e.g. + * if the capability relates to the ability to modify settings the user is not able to. * This could be because of the user's type (e.g. maybe it applies to the primary user only) or * device policy. Depending on the capability, this could mean the associated UI * should be hidden, or displayed but disabled. @@ -68,9 +72,11 @@ public final class TimeZoneCapabilities implements Parcelable { public static final int CAPABILITY_NOT_ALLOWED = 20; /** - * Indicates that a capability is possessed but not applicable, e.g. if it is configuration, - * the current configuration or device state renders it irrelevant. The associated UI may be - * hidden, disabled, or left visible (but ineffective) depending on requirements. + * Indicates that a capability is possessed but not currently applicable, e.g. if the + * capability relates to the ability to modify settings, the user has the ability to modify + * it, but it is currently rendered irrelevant by other settings or other device state (flags, + * resource config, etc.). The associated UI may be hidden, disabled, or left visible (but + * ineffective) depending on requirements. */ public static final int CAPABILITY_NOT_APPLICABLE = 30; @@ -89,13 +95,13 @@ public final class TimeZoneCapabilities implements Parcelable { }; - private final @UserIdInt int mUserId; + @NonNull private final TimeZoneConfiguration mConfiguration; private final @CapabilityState int mConfigureAutoDetectionEnabled; private final @CapabilityState int mConfigureGeoDetectionEnabled; private final @CapabilityState int mSuggestManualTimeZone; private TimeZoneCapabilities(@NonNull Builder builder) { - this.mUserId = builder.mUserId; + this.mConfiguration = Objects.requireNonNull(builder.mConfiguration); this.mConfigureAutoDetectionEnabled = builder.mConfigureAutoDetectionEnabled; this.mConfigureGeoDetectionEnabled = builder.mConfigureGeoDetectionEnabled; this.mSuggestManualTimeZone = builder.mSuggestManualTimeZone; @@ -103,7 +109,8 @@ public final class TimeZoneCapabilities implements Parcelable { @NonNull private static TimeZoneCapabilities createFromParcel(Parcel in) { - return new TimeZoneCapabilities.Builder(in.readInt()) + return new TimeZoneCapabilities.Builder() + .setConfiguration(in.readParcelable(null)) .setConfigureAutoDetectionEnabled(in.readInt()) .setConfigureGeoDetectionEnabled(in.readInt()) .setSuggestManualTimeZone(in.readInt()) @@ -112,21 +119,24 @@ public final class TimeZoneCapabilities implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(mUserId); + dest.writeParcelable(mConfiguration, flags); dest.writeInt(mConfigureAutoDetectionEnabled); dest.writeInt(mConfigureGeoDetectionEnabled); dest.writeInt(mSuggestManualTimeZone); } - /** Returns the user ID the capabilities are for. */ - public @UserIdInt int getUserId() { - return mUserId; + /** + * Returns the user's time zone behavior configuration. + */ + public @NonNull TimeZoneConfiguration getConfiguration() { + return mConfiguration; } /** - * Returns the user's capability state for controlling whether automatic time zone detection is - * enabled via {@link TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and {@link - * TimeZoneConfiguration#isAutoDetectionEnabled()}. + * Returns the capability state associated with the user's ability to modify the automatic time + * zone detection setting. The setting can be updated via {@link + * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and accessed via {@link + * #getConfiguration()}. */ @CapabilityState public int getConfigureAutoDetectionEnabled() { @@ -134,9 +144,10 @@ public final class TimeZoneCapabilities implements Parcelable { } /** - * Returns the user's capability state for controlling whether geolocation can be used to detect - * time zone via {@link TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and {@link - * TimeZoneConfiguration#isGeoDetectionEnabled()}. + * Returns the capability state associated with the user's ability to modify the geolocation + * detection setting. The setting can be updated via {@link + * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and accessed via {@link + * #getConfiguration()}. */ @CapabilityState public int getConfigureGeoDetectionEnabled() { @@ -144,8 +155,8 @@ public final class TimeZoneCapabilities implements Parcelable { } /** - * Returns the user's capability state for manually setting the time zone on a device via - * {@link TimeZoneDetector#suggestManualTimeZone(ManualTimeZoneSuggestion)}. + * Returns the capability state associated with the user's ability to manually set the time zone + * on a device via {@link TimeZoneDetector#suggestManualTimeZone(ManualTimeZoneSuggestion)}. * * <p>The suggestion will be ignored in all cases unless the value is {@link * #CAPABILITY_POSSESSED}. See also {@link TimeZoneConfiguration#isAutoDetectionEnabled()}. @@ -155,6 +166,38 @@ public final class TimeZoneCapabilities implements Parcelable { return mSuggestManualTimeZone; } + /** + * Constructs a new {@link TimeZoneConfiguration} from an {@code oldConfiguration} and a set of + * {@code requestedChanges}, if the current capabilities allow. The new configuration is + * returned and the capabilities are left unchanged. If the capabilities do not permit one or + * more of the changes then {@code null} is returned. + */ + @Nullable + public TimeZoneConfiguration applyUpdate(TimeZoneConfiguration requestedChanges) { + if (requestedChanges.getUserId() != mConfiguration.getUserId()) { + throw new IllegalArgumentException("User does not match:" + + " this=" + mConfiguration + ", other=" + requestedChanges); + } + + TimeZoneConfiguration.Builder newConfigBuilder = + new TimeZoneConfiguration.Builder(mConfiguration); + if (requestedChanges.hasSetting(SETTING_AUTO_DETECTION_ENABLED)) { + if (getConfigureAutoDetectionEnabled() < CAPABILITY_NOT_APPLICABLE) { + return null; + } + newConfigBuilder.setAutoDetectionEnabled(requestedChanges.isAutoDetectionEnabled()); + } + + if (requestedChanges.hasSetting(SETTING_GEO_DETECTION_ENABLED)) { + if (getConfigureGeoDetectionEnabled() < CAPABILITY_NOT_APPLICABLE) { + return null; + } + newConfigBuilder.setGeoDetectionEnabled(requestedChanges.isGeoDetectionEnabled()); + } + + return newConfigBuilder.build(); + } + @Override public int describeContents() { return 0; @@ -169,7 +212,7 @@ public final class TimeZoneCapabilities implements Parcelable { return false; } TimeZoneCapabilities that = (TimeZoneCapabilities) o; - return mUserId == that.mUserId + return Objects.equals(mConfiguration, that.mConfiguration) && mConfigureAutoDetectionEnabled == that.mConfigureAutoDetectionEnabled && mConfigureGeoDetectionEnabled == that.mConfigureGeoDetectionEnabled && mSuggestManualTimeZone == that.mSuggestManualTimeZone; @@ -177,7 +220,7 @@ public final class TimeZoneCapabilities implements Parcelable { @Override public int hashCode() { - return Objects.hash(mUserId, + return Objects.hash(mConfiguration, mConfigureAutoDetectionEnabled, mConfigureGeoDetectionEnabled, mSuggestManualTimeZone); @@ -186,7 +229,7 @@ public final class TimeZoneCapabilities implements Parcelable { @Override public String toString() { return "TimeZoneDetectorCapabilities{" - + "mUserId=" + mUserId + + "mConfiguration=" + mConfiguration + ", mConfigureAutomaticDetectionEnabled=" + mConfigureAutoDetectionEnabled + ", mConfigureGeoDetectionEnabled=" + mConfigureGeoDetectionEnabled + ", mSuggestManualTimeZone=" + mSuggestManualTimeZone @@ -196,16 +239,18 @@ public final class TimeZoneCapabilities implements Parcelable { /** @hide */ public static class Builder { - private final @UserIdInt int mUserId; + private TimeZoneConfiguration mConfiguration; private @CapabilityState int mConfigureAutoDetectionEnabled; private @CapabilityState int mConfigureGeoDetectionEnabled; private @CapabilityState int mSuggestManualTimeZone; - /** - * Creates a new Builder with no properties set. - */ - public Builder(@UserIdInt int userId) { - mUserId = userId; + /** Sets the user-visible configuration settings. */ + public Builder setConfiguration(@NonNull TimeZoneConfiguration configuration) { + if (!configuration.isComplete()) { + throw new IllegalArgumentException(configuration + " is not complete"); + } + this.mConfiguration = configuration; + return this; } /** Sets the state for the automatic time zone detection enabled config. */ diff --git a/core/java/android/app/timezonedetector/TimeZoneConfiguration.java b/core/java/android/app/timezonedetector/TimeZoneConfiguration.java index 6f84ee22a985..95db0a26cc6e 100644 --- a/core/java/android/app/timezonedetector/TimeZoneConfiguration.java +++ b/core/java/android/app/timezonedetector/TimeZoneConfiguration.java @@ -18,6 +18,7 @@ package android.app.timezonedetector; import android.annotation.NonNull; import android.annotation.StringDef; +import android.annotation.UserIdInt; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -27,21 +28,20 @@ import java.lang.annotation.RetentionPolicy; import java.util.Objects; /** - * Configuration that controls the behavior of the time zone detector associated with a specific - * user. + * User visible settings that control the behavior of the time zone detector / manual time zone + * entry. * - * <p>Configuration consists of a set of known properties. When reading configuration via - * {@link TimeZoneDetector#getConfiguration()} values for all known properties will be provided. In - * some cases, such as when the configuration relies on optional hardware, the values may be - * meaningless / defaulted to safe values. + * <p>When reading the configuration, values for all settings will be provided. In some cases, such + * as when the device behavior relies on optional hardware / OEM configuration, or the value of + * several settings, the device behavior may not be directly affected by the setting value. * - * <p>Configuration properties can be left absent when updating configuration via {@link - * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and those values will not be - * changed. Not all configuration properties can be modified by all users. See {@link - * TimeZoneDetector#getCapabilities()} and {@link TimeZoneCapabilities}. + * <p>Settings can be left absent when updating configuration via {@link + * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and those settings will not be + * changed. Not all configuration settings can be modified by all users: see {@link + * TimeZoneDetector#getCapabilities()} and {@link TimeZoneCapabilities} for details. * - * <p>See {@link #isComplete()} to tell if all known properties are present, and {@link - * #hasProperty(String)} with {@code PROPERTY_} constants for testing individual properties. + * <p>See {@link #hasSetting(String)} with {@code PROPERTY_} constants for testing for the presence + * of individual settings. * * @hide */ @@ -59,80 +59,82 @@ public final class TimeZoneConfiguration implements Parcelable { }; /** All configuration properties */ - @StringDef(PROPERTY_AUTO_DETECTION_ENABLED) + @StringDef({ SETTING_AUTO_DETECTION_ENABLED, SETTING_GEO_DETECTION_ENABLED }) @Retention(RetentionPolicy.SOURCE) - @interface Property {} + @interface Setting {} /** See {@link TimeZoneConfiguration#isAutoDetectionEnabled()} for details. */ - @Property - public static final String PROPERTY_AUTO_DETECTION_ENABLED = "autoDetectionEnabled"; + @Setting + public static final String SETTING_AUTO_DETECTION_ENABLED = "autoDetectionEnabled"; /** See {@link TimeZoneConfiguration#isGeoDetectionEnabled()} for details. */ - @Property - public static final String PROPERTY_GEO_DETECTION_ENABLED = "geoDetectionEnabled"; + @Setting + public static final String SETTING_GEO_DETECTION_ENABLED = "geoDetectionEnabled"; - private final Bundle mBundle; + private final @UserIdInt int mUserId; + @NonNull private final Bundle mBundle; private TimeZoneConfiguration(Builder builder) { - this.mBundle = builder.mBundle; + this.mUserId = builder.mUserId; + this.mBundle = Objects.requireNonNull(builder.mBundle); } private static TimeZoneConfiguration createFromParcel(Parcel in) { - return new TimeZoneConfiguration.Builder() + return new TimeZoneConfiguration.Builder(in.readInt()) .setPropertyBundleInternal(in.readBundle()) .build(); } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mUserId); dest.writeBundle(mBundle); } - /** Returns {@code true} if all known properties are set. */ + /** Returns the ID of the user this configuration is associated with. */ + public @UserIdInt int getUserId() { + return mUserId; + } + + /** Returns {@code true} if all known settings are present. */ public boolean isComplete() { - return hasProperty(PROPERTY_AUTO_DETECTION_ENABLED) - && hasProperty(PROPERTY_GEO_DETECTION_ENABLED); + return hasSetting(SETTING_AUTO_DETECTION_ENABLED) + && hasSetting(SETTING_GEO_DETECTION_ENABLED); } - /** Returns true if the specified property is set. */ - public boolean hasProperty(@Property String property) { - return mBundle.containsKey(property); + /** Returns true if the specified setting is set. */ + public boolean hasSetting(@Setting String setting) { + return mBundle.containsKey(setting); } /** - * Returns the value of the {@link #PROPERTY_AUTO_DETECTION_ENABLED} property. This + * Returns the value of the {@link #SETTING_AUTO_DETECTION_ENABLED} setting. This * controls whether a device will attempt to determine the time zone automatically using - * contextual information. + * contextual information if the device supports auto detection. + * + * <p>This setting is global and can be updated by some users. * - * @throws IllegalStateException if the field has not been set + * @throws IllegalStateException if the setting has not been set */ public boolean isAutoDetectionEnabled() { - if (!mBundle.containsKey(PROPERTY_AUTO_DETECTION_ENABLED)) { - throw new IllegalStateException(PROPERTY_AUTO_DETECTION_ENABLED + " is not set"); - } - return mBundle.getBoolean(PROPERTY_AUTO_DETECTION_ENABLED); + enforceSettingPresent(SETTING_AUTO_DETECTION_ENABLED); + return mBundle.getBoolean(SETTING_AUTO_DETECTION_ENABLED); } /** - * Returns the value of the {@link #PROPERTY_GEO_DETECTION_ENABLED} property. This - * controls whether a device can use location to determine time zone. Only used when - * {@link #isAutoDetectionEnabled()} is true. + * Returns the value of the {@link #SETTING_GEO_DETECTION_ENABLED} setting. This + * controls whether a device can use geolocation to determine time zone. Only used when + * {@link #isAutoDetectionEnabled()} is {@code true} and when the user has allowed their + * location to be used. + * + * <p>This setting is user-scoped and can be updated by some users. + * See {@link TimeZoneCapabilities#getConfigureGeoDetectionEnabled()}. * - * @throws IllegalStateException if the field has not been set + * @throws IllegalStateException if the setting has not been set */ public boolean isGeoDetectionEnabled() { - if (!mBundle.containsKey(PROPERTY_GEO_DETECTION_ENABLED)) { - throw new IllegalStateException(PROPERTY_GEO_DETECTION_ENABLED + " is not set"); - } - return mBundle.getBoolean(PROPERTY_GEO_DETECTION_ENABLED); - } - - /** - * Convenience method to merge this with another. The argument configuration properties have - * precedence. - */ - public TimeZoneConfiguration with(TimeZoneConfiguration other) { - return new Builder(this).mergeProperties(other).build(); + enforceSettingPresent(SETTING_GEO_DETECTION_ENABLED); + return mBundle.getBoolean(SETTING_GEO_DETECTION_ENABLED); } @Override @@ -149,43 +151,61 @@ public final class TimeZoneConfiguration implements Parcelable { return false; } TimeZoneConfiguration that = (TimeZoneConfiguration) o; - return mBundle.kindofEquals(that.mBundle); + return mUserId == that.mUserId + && mBundle.kindofEquals(that.mBundle); } @Override public int hashCode() { - return Objects.hash(mBundle); + return Objects.hash(mUserId, mBundle); } @Override public String toString() { return "TimeZoneDetectorConfiguration{" + + "mUserId=" + mUserId + "mBundle=" + mBundle + '}'; } + private void enforceSettingPresent(@Setting String setting) { + if (!mBundle.containsKey(setting)) { + throw new IllegalStateException(setting + " is not set"); + } + } + /** @hide */ public static class Builder { - private Bundle mBundle = new Bundle(); + private final @UserIdInt int mUserId; + private final Bundle mBundle = new Bundle(); /** - * Creates a new Builder with no properties set. + * Creates a new Builder for a userId with no settings held. */ - public Builder() {} + public Builder(@UserIdInt int userId) { + mUserId = userId; + } /** - * Creates a new Builder by copying properties from an existing instance. + * Creates a new Builder by copying the user ID and settings from an existing instance. */ public Builder(TimeZoneConfiguration toCopy) { + this.mUserId = toCopy.mUserId; mergeProperties(toCopy); } /** - * Merges {@code other} properties into this instances, replacing existing values in this - * where the properties appear in both. + * Merges {@code other} settings into this instances, replacing existing values in this + * where the settings appear in both. */ public Builder mergeProperties(TimeZoneConfiguration other) { + if (mUserId != other.mUserId) { + throw new IllegalArgumentException( + "Cannot merge configurations for different user IDs." + + " this.mUserId=" + this.mUserId + + ", other.mUserId=" + other.mUserId); + } this.mBundle.putAll(other.mBundle); return this; } @@ -195,15 +215,19 @@ public final class TimeZoneConfiguration implements Parcelable { return this; } - /** Sets the desired state of the automatic time zone detection property. */ + /** + * Sets the state of the {@link #SETTING_AUTO_DETECTION_ENABLED} setting. + */ public Builder setAutoDetectionEnabled(boolean enabled) { - this.mBundle.putBoolean(PROPERTY_AUTO_DETECTION_ENABLED, enabled); + this.mBundle.putBoolean(SETTING_AUTO_DETECTION_ENABLED, enabled); return this; } - /** Sets the desired state of the geolocation time zone detection enabled property. */ + /** + * Sets the state of the {@link #SETTING_GEO_DETECTION_ENABLED} setting. + */ public Builder setGeoDetectionEnabled(boolean enabled) { - this.mBundle.putBoolean(PROPERTY_GEO_DETECTION_ENABLED, enabled); + this.mBundle.putBoolean(SETTING_GEO_DETECTION_ENABLED, enabled); return this; } diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java index 7885613bfb59..2b1cbf259c55 100644 --- a/core/java/android/app/timezonedetector/TimeZoneDetector.java +++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java @@ -37,37 +37,29 @@ public interface TimeZoneDetector { TimeZoneCapabilities getCapabilities(); /** - * Returns the current user's complete time zone configuration. See {@link - * TimeZoneConfiguration}. - */ - @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) - @NonNull - TimeZoneConfiguration getConfiguration(); - - /** * Modifies the time zone detection configuration. * - * <p>Configuration properties vary in scope: some may be device-wide, others may be specific to - * the current user. + * <p>Configuration settings vary in scope: some may be global (affect all users), others may be + * specific to the current user. * - * <p>The ability to modify configuration properties can be subject to restrictions. For + * <p>The ability to modify configuration settings can be subject to restrictions. For * example, they may be determined by device hardware, general policy (i.e. only the primary - * user can set them), or by a managed device policy. See {@link #getCapabilities()} to obtain + * user can set them), or by a managed device policy. Use {@link #getCapabilities()} to obtain * information at runtime about the user's capabilities. * - * <p>Attempts to set configuration with capabilities that are {@link + * <p>Attempts to modify configuration settings with capabilities that are {@link * TimeZoneCapabilities#CAPABILITY_NOT_SUPPORTED} or {@link * TimeZoneCapabilities#CAPABILITY_NOT_ALLOWED} will have no effect and a {@code false} - * will be returned. Setting configuration with capabilities that are {@link + * will be returned. Modifying configuration settings with capabilities that are {@link * TimeZoneCapabilities#CAPABILITY_NOT_APPLICABLE} or {@link * TimeZoneCapabilities#CAPABILITY_POSSESSED} will succeed. See {@link * TimeZoneCapabilities} for further details. * - * <p>If the configuration is not "complete", then only the specified properties will be - * updated (where the user's capabilities allow) and other settings will be left unchanged. See - * {@link TimeZoneConfiguration#isComplete()}. + * <p>If the supplied configuration only has some values set, then only the specified settings + * will be updated (where the user's capabilities allow) and other settings will be left + * unchanged. * - * @return {@code true} if all the configuration properties specified have been set to the + * @return {@code true} if all the configuration settings specified have been set to the * new values, {@code false} if none have */ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @@ -76,14 +68,20 @@ public interface TimeZoneDetector { /** * An interface that can be used to listen for changes to the time zone detector configuration. */ + @FunctionalInterface interface TimeZoneConfigurationListener { - /** Called when the configuration changes. There are no guarantees about the thread used. */ - void onChange(@NonNull TimeZoneConfiguration configuration); + /** + * Called when something about the time zone configuration on the device has changed. + * This could be because the current user has changed, one of the device's relevant settings + * has changed, or something that could affect a user's capabilities has changed. + * There are no guarantees about the thread used. + */ + void onChange(); } /** - * 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. + * Registers a listener that will be informed when something about the time zone configuration + * changes. */ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) void addConfigurationListener(@NonNull TimeZoneConfigurationListener listener); diff --git a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java index 0770aff4e9bb..4c69732abec9 100644 --- a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java +++ b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java @@ -57,19 +57,6 @@ public final class TimeZoneDetectorImpl implements TimeZoneDetector { } @Override - @NonNull - public TimeZoneConfiguration getConfiguration() { - if (DEBUG) { - Log.d(TAG, "getConfiguration called"); - } - try { - return mITimeZoneDetectorService.getConfiguration(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - @Override public boolean updateConfiguration(@NonNull TimeZoneConfiguration configuration) { if (DEBUG) { Log.d(TAG, "updateConfiguration called: " + configuration); @@ -94,8 +81,8 @@ public final class TimeZoneDetectorImpl implements TimeZoneDetector { ITimeZoneConfigurationListener iListener = new ITimeZoneConfigurationListener.Stub() { @Override - public void onChange(@NonNull TimeZoneConfiguration configuration) { - notifyConfigurationListeners(configuration); + public void onChange() { + notifyConfigurationListeners(); } }; mConfigurationReceiver = iListener; @@ -116,14 +103,14 @@ public final class TimeZoneDetectorImpl implements TimeZoneDetector { } } - private void notifyConfigurationListeners(@NonNull TimeZoneConfiguration configuration) { + private void notifyConfigurationListeners() { final 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); + configurationListeners.valueAt(i).onChange(); } } diff --git a/core/java/android/preference/OWNERS b/core/java/android/preference/OWNERS index d20511fcfdf2..827134e8fc9d 100644 --- a/core/java/android/preference/OWNERS +++ b/core/java/android/preference/OWNERS @@ -1,2 +1,3 @@ +lpf@google.com pavlis@google.com clarabayarri@google.com diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index c302def19298..03cf0cf2ca78 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6404,6 +6404,17 @@ public final class Settings { public static final int LOCATION_MODE_ON = LOCATION_MODE_HIGH_ACCURACY; /** + * The current location time zone detection enabled state for the user. + * + * See {@link + * android.app.timezonedetector.TimeZoneDetector#getCapabilities} for access. See {@link + * android.app.timezonedetector.TimeZoneDetector#updateConfiguration} to update. + * @hide + */ + public static final String LOCATION_TIME_ZONE_DETECTION_ENABLED = + "location_time_zone_detection_enabled"; + + /** * The accuracy in meters used for coarsening location for clients with only the coarse * location permission. * diff --git a/core/java/android/text/OWNERS b/core/java/android/text/OWNERS index e56137119c28..0b51b2d90b79 100644 --- a/core/java/android/text/OWNERS +++ b/core/java/android/text/OWNERS @@ -1,5 +1,4 @@ set noparent siyamed@google.com -nona@google.com -clarabayarri@google.com +nona@google.com
\ No newline at end of file diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java index 73d148c1f233..0834b2d87c2c 100644 --- a/core/java/com/android/internal/protolog/ProtoLogGroup.java +++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java @@ -36,7 +36,18 @@ public enum ProtoLogGroup implements IProtoLogGroup { Consts.TAG_WM), WM_DEBUG_ADD_REMOVE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM), - WM_DEBUG_FOCUS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM), + WM_DEBUG_CONFIGURATION(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), + WM_DEBUG_SWITCH(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), + WM_DEBUG_CONTAINERS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), + WM_DEBUG_FOCUS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), + WM_DEBUG_IMMERSIVE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), + WM_DEBUG_LOCKTASK(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), WM_DEBUG_STARTING_WINDOW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM), WM_SHOW_TRANSACTIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, diff --git a/core/java/com/android/internal/widget/LocalImageResolver.java b/core/java/com/android/internal/widget/LocalImageResolver.java index 2302de2cd058..b4e108faee2d 100644 --- a/core/java/com/android/internal/widget/LocalImageResolver.java +++ b/core/java/com/android/internal/widget/LocalImageResolver.java @@ -23,6 +23,7 @@ import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.util.Log; import java.io.IOException; import java.io.InputStream; @@ -31,6 +32,7 @@ import java.io.InputStream; * A class to extract Bitmaps from a MessagingStyle message. */ public class LocalImageResolver { + private static final String TAG = LocalImageResolver.class.getSimpleName(); private static final int MAX_SAFE_ICON_SIZE_PX = 480; @@ -60,11 +62,18 @@ public class LocalImageResolver { private static BitmapFactory.Options getBoundsOptionsForImage(Uri uri, Context context) throws IOException { - InputStream input = context.getContentResolver().openInputStream(uri); BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options(); - onlyBoundsOptions.inJustDecodeBounds = true; - BitmapFactory.decodeStream(input, null, onlyBoundsOptions); - input.close(); + try (InputStream input = context.getContentResolver().openInputStream(uri)) { + if (input == null) { + throw new IllegalArgumentException(); + } + onlyBoundsOptions.inJustDecodeBounds = true; + BitmapFactory.decodeStream(input, null, onlyBoundsOptions); + } catch (IllegalArgumentException iae) { + onlyBoundsOptions.outWidth = -1; + onlyBoundsOptions.outHeight = -1; + Log.e(TAG, "error loading image", iae); + } return onlyBoundsOptions; } diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index 23af70a7cc18..cbcbe7f11390 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -613,7 +613,7 @@ void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz, } // Do not change sched policy cgroup after boot complete. - rc = androidSetThreadPriority(pid, pri, !boot_completed); + rc = androidSetThreadPriorityAndPolicy(pid, pri, !boot_completed); if (rc != 0) { if (rc == INVALID_OPERATION) { signalExceptionForPriorityError(env, errno, pid); diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto index 6eb89040998a..6212bcbbc05f 100644 --- a/core/proto/android/app/settings_enums.proto +++ b/core/proto/android/app/settings_enums.proto @@ -2738,4 +2738,14 @@ enum PageId { // CATEGORY: SETTINGS // OS: S SETTINGS_COLUMBUS = 1848; + + // OPEN: Settings > Accessibility > Magnification > Settings > Magnification area > Magnification switch shortcut dialog + // CATEGORY: SETTINGS + // OS: S + DIALOG_MAGNIFICATION_SWITCH_SHORTCUT = 1849; + + // OPEN: Settings > Network & internet > Adaptive connectivity + // CATEGORY: SETTINGS + // OS: R QPR + ADAPTIVE_CONNECTIVITY_CATEGORY = 1850; } diff --git a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java index 72391f4d7dec..db127c6cb9ed 100644 --- a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java +++ b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java @@ -22,6 +22,7 @@ import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSE import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; import org.junit.Test; @@ -31,11 +32,22 @@ public class TimeZoneCapabilitiesTest { @Test public void testEquals() { - TimeZoneCapabilities.Builder builder1 = new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID) + TimeZoneConfiguration configuration1 = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID) + .setAutoDetectionEnabled(true) + .setGeoDetectionEnabled(true) + .build(); + TimeZoneConfiguration configuration2 = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID) + .setAutoDetectionEnabled(false) + .setGeoDetectionEnabled(false) + .build(); + + TimeZoneCapabilities.Builder builder1 = new TimeZoneCapabilities.Builder() + .setConfiguration(configuration1) .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED) .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED) .setSuggestManualTimeZone(CAPABILITY_POSSESSED); - TimeZoneCapabilities.Builder builder2 = new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID) + TimeZoneCapabilities.Builder builder2 = new TimeZoneCapabilities.Builder() + .setConfiguration(configuration1) .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED) .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED) .setSuggestManualTimeZone(CAPABILITY_POSSESSED); @@ -45,6 +57,20 @@ public class TimeZoneCapabilitiesTest { assertEquals(one, two); } + builder2.setConfiguration(configuration2); + { + TimeZoneCapabilities one = builder1.build(); + TimeZoneCapabilities two = builder2.build(); + assertNotEquals(one, two); + } + + builder1.setConfiguration(configuration2); + { + TimeZoneCapabilities one = builder1.build(); + TimeZoneCapabilities two = builder2.build(); + assertEquals(one, two); + } + builder2.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED); { TimeZoneCapabilities one = builder1.build(); @@ -90,7 +116,12 @@ public class TimeZoneCapabilitiesTest { @Test public void testParcelable() { - TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID) + TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID) + .setAutoDetectionEnabled(true) + .setGeoDetectionEnabled(true) + .build(); + TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder() + .setConfiguration(configuration) .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED) .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED) .setSuggestManualTimeZone(CAPABILITY_POSSESSED); @@ -105,4 +136,51 @@ public class TimeZoneCapabilitiesTest { builder.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED); assertRoundTripParcelable(builder.build()); } + + @Test + public void testApplyUpdate_permitted() { + TimeZoneConfiguration oldConfiguration = + new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID) + .setAutoDetectionEnabled(true) + .setGeoDetectionEnabled(true) + .build(); + TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder() + .setConfiguration(oldConfiguration) + .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED) + .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED) + .setSuggestManualTimeZone(CAPABILITY_POSSESSED) + .build(); + assertEquals(oldConfiguration, capabilities.getConfiguration()); + + TimeZoneConfiguration configChange = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID) + .setAutoDetectionEnabled(false) + .build(); + + TimeZoneConfiguration expected = new TimeZoneConfiguration.Builder(oldConfiguration) + .setAutoDetectionEnabled(false) + .build(); + assertEquals(expected, capabilities.applyUpdate(configChange)); + } + + @Test + public void testApplyUpdate_notPermitted() { + TimeZoneConfiguration oldConfiguration = + new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID) + .setAutoDetectionEnabled(true) + .setGeoDetectionEnabled(true) + .build(); + TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder() + .setConfiguration(oldConfiguration) + .setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED) + .setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED) + .setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED) + .build(); + assertEquals(oldConfiguration, capabilities.getConfiguration()); + + TimeZoneConfiguration configChange = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID) + .setAutoDetectionEnabled(false) + .build(); + + assertNull(capabilities.applyUpdate(configChange)); + } } diff --git a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java index 00dc73ed269f..faf908de8d4a 100644 --- a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java +++ b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java @@ -27,11 +27,14 @@ import org.junit.Test; public class TimeZoneConfigurationTest { + private static final int ARBITRARY_USER_ID = 9876; + @Test public void testBuilder_copyConstructor() { - TimeZoneConfiguration.Builder builder1 = new TimeZoneConfiguration.Builder() - .setAutoDetectionEnabled(true) - .setGeoDetectionEnabled(true); + TimeZoneConfiguration.Builder builder1 = + new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID) + .setAutoDetectionEnabled(true) + .setGeoDetectionEnabled(true); TimeZoneConfiguration configuration1 = builder1.build(); TimeZoneConfiguration configuration2 = @@ -41,28 +44,28 @@ public class TimeZoneConfigurationTest { } @Test - public void testIsComplete() { - TimeZoneConfiguration.Builder builder = - new TimeZoneConfiguration.Builder(); - assertFalse(builder.build().isComplete()); - - builder.setAutoDetectionEnabled(true); - assertFalse(builder.build().isComplete()); + public void testIntrospectionMethods() { + TimeZoneConfiguration empty = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID).build(); + assertFalse(empty.isComplete()); + assertFalse(empty.hasSetting(TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED)); - builder.setGeoDetectionEnabled(true); - assertTrue(builder.build().isComplete()); + TimeZoneConfiguration completeConfig = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID) + .setAutoDetectionEnabled(true) + .setGeoDetectionEnabled(true) + .build(); + assertTrue(completeConfig.isComplete()); + assertTrue(completeConfig.hasSetting(TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED)); } @Test public void testBuilder_mergeProperties() { - TimeZoneConfiguration configuration1 = - new TimeZoneConfiguration.Builder() - .setAutoDetectionEnabled(true) - .build(); + TimeZoneConfiguration configuration1 = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID) + .setAutoDetectionEnabled(true) + .build(); { TimeZoneConfiguration mergedEmptyAnd1 = - new TimeZoneConfiguration.Builder() + new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID) .mergeProperties(configuration1) .build(); assertEquals(configuration1, mergedEmptyAnd1); @@ -70,7 +73,7 @@ public class TimeZoneConfigurationTest { { TimeZoneConfiguration configuration2 = - new TimeZoneConfiguration.Builder() + new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID) .setAutoDetectionEnabled(false) .build(); @@ -87,14 +90,22 @@ public class TimeZoneConfigurationTest { @Test public void testEquals() { TimeZoneConfiguration.Builder builder1 = - new TimeZoneConfiguration.Builder(); + new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID); { TimeZoneConfiguration one = builder1.build(); assertEquals(one, one); } + { + TimeZoneConfiguration.Builder differentUserBuilder = + new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID + 1); + TimeZoneConfiguration one = builder1.build(); + TimeZoneConfiguration two = differentUserBuilder.build(); + assertNotEquals(one, two); + } + TimeZoneConfiguration.Builder builder2 = - new TimeZoneConfiguration.Builder(); + new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID); { TimeZoneConfiguration one = builder1.build(); TimeZoneConfiguration two = builder2.build(); @@ -148,7 +159,7 @@ public class TimeZoneConfigurationTest { @Test public void testParcelable() { TimeZoneConfiguration.Builder builder = - new TimeZoneConfiguration.Builder(); + new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID); assertRoundTripParcelable(builder.build()); builder.setAutoDetectionEnabled(true); diff --git a/core/tests/coretests/src/android/text/OWNERS b/core/tests/coretests/src/android/text/OWNERS index a35c6042bf53..0b51b2d90b79 100644 --- a/core/tests/coretests/src/android/text/OWNERS +++ b/core/tests/coretests/src/android/text/OWNERS @@ -1,5 +1,4 @@ set noparent siyamed@google.com -nona@google.com -clarabayarri@google.com
\ No newline at end of file +nona@google.com
\ No newline at end of file diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk index c577eeffd488..fe7c944ebd30 100644 --- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk +++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk @@ -29,6 +29,8 @@ LOCAL_PACKAGE_NAME := MultiDexLegacyTestApp LOCAL_DEX_PREOPT := false +LOCAL_EMMA_INSTRUMENT := false + mainDexList:= \ $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list @@ -60,6 +62,8 @@ LOCAL_PACKAGE_NAME := MultiDexLegacyTestApp2 LOCAL_DEX_PREOPT := false +LOCAL_EMMA_INSTRUMENT := false + mainDexList2:= \ $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk index da40940e92e9..3636c73ffc9c 100644 --- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk +++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk @@ -33,6 +33,8 @@ LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex LOCAL_DEX_PREOPT := false +LOCAL_EMMA_INSTRUMENT := false + include $(BUILD_PACKAGE) $(mainDexList): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS) diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk index 665e22d5a0bc..67f1fa574c07 100644 --- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk +++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk @@ -28,6 +28,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex LOCAL_DEX_PREOPT := false +LOCAL_EMMA_INSTRUMENT := false + mainDexList:= \ $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk index c827fa80ebcd..33871e527820 100644 --- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk +++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk @@ -28,6 +28,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex LOCAL_DEX_PREOPT := false +LOCAL_EMMA_INSTRUMENT := false + mainDexList:= \ $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk index 3d6ad7d1aa57..1b267ee93cce 100644 --- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk +++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk @@ -31,6 +31,8 @@ mainDexList:= \ LOCAL_DEX_PREOPT := false +LOCAL_EMMA_INSTRUMENT := false + LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex include $(BUILD_PACKAGE) diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 73296987adde..03f7be7b41f9 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -13,6 +13,12 @@ "group": "WM_DEBUG_STARTING_WINDOW", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "-2121056984": { + "message": "%s", + "level": "WARN", + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/LockTaskController.java" + }, "-2109936758": { "message": "removeAppToken make exiting: %s", "level": "VERBOSE", @@ -43,6 +49,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-2029985709": { + "message": "setFocusedTask: taskId=%d", + "level": "DEBUG", + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + }, "-2024464438": { "message": "app-onAnimationFinished(): mOuter=%s", "level": "DEBUG", @@ -139,6 +151,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/DisplayRotation.java" }, + "-1868048288": { + "message": "Updating to new configuration after starting activity.", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityStarter.java" + }, "-1862269827": { "message": "applyAnimation: anim=%s transit=%s isEntrance=%b Callers=%s", "level": "VERBOSE", @@ -163,6 +181,18 @@ "group": "WM_DEBUG_RESIZE", "at": "com\/android\/server\/wm\/WindowState.java" }, + "-1810446914": { + "message": "Trying to update display configuration for system\/invalid process.", + "level": "WARN", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + }, + "-1791031393": { + "message": "Ensuring correct configuration: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "-1782453012": { "message": "Checking theme of starting window: 0x%x", "level": "VERBOSE", @@ -211,6 +241,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/DisplayContent.java" }, + "-1699018375": { + "message": "Adding activity %s to task %s callers: %s", + "level": "INFO", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/Task.java" + }, "-1698815688": { "message": "Resetting app token %s of replacing window marks.", "level": "DEBUG", @@ -229,12 +265,30 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-1638958146": { + "message": "Removing activity %s from task=%s adding to task=%s Callers=%s", + "level": "INFO", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java" + }, "-1632122349": { "message": "Changing surface while display frozen: %s", "level": "VERBOSE", "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-1630752478": { + "message": "removeLockedTask: removed %s", + "level": "DEBUG", + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/LockTaskController.java" + }, + "-1598452494": { + "message": "activityDestroyedLocked: r=%s", + "level": "DEBUG", + "group": "WM_DEBUG_CONTAINERS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "-1596995693": { "message": "startAnimation", "level": "DEBUG", @@ -307,6 +361,18 @@ "group": "WM_DEBUG_REMOTE_ANIMATIONS", "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, + "-1495062622": { + "message": "Can't report activity moved to display - client not running, activityRecord=%s, displayId=%d", + "level": "WARN", + "group": "WM_DEBUG_SWITCH", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, + "-1492881555": { + "message": "Starting activity when config will change = %b", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityStarter.java" + }, "-1471946192": { "message": "Marking app token %s with replacing child windows.", "level": "DEBUG", @@ -379,6 +445,12 @@ "group": "WM_DEBUG_IME", "at": "com\/android\/server\/wm\/WindowState.java" }, + "-1305755880": { + "message": "Initial config: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + }, "-1292329638": { "message": "Added starting %s: startingWindow=%s startingView=%s", "level": "VERBOSE", @@ -445,6 +517,12 @@ "group": "WM_DEBUG_RECENTS_ANIMATIONS", "at": "com\/android\/server\/wm\/RecentsAnimation.java" }, + "-1155279885": { + "message": "Frontmost changed immersion: %s", + "level": "DEBUG", + "group": "WM_DEBUG_IMMERSIVE", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + }, "-1144293044": { "message": "SURFACE SET FREEZE LAYER: %s", "level": "INFO", @@ -475,6 +553,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/DisplayRotation.java" }, + "-1115019498": { + "message": "Configuration & display unchanged in %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "-1113134997": { "message": "Attempted to add application window with unknown token %s. Aborting.", "level": "WARN", @@ -559,12 +643,24 @@ "group": "WM_DEBUG_STARTING_WINDOW", "at": "com\/android\/server\/wm\/WindowState.java" }, + "-929676529": { + "message": "Configuration changes for %s, allChanges=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "-928291778": { "message": "applyAnimation: anim=%s nextAppTransition=%d transit=%s Callers=%s", "level": "VERBOSE", "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", "at": "com\/android\/server\/wm\/AppTransition.java" }, + "-927199900": { + "message": "Updating global configuration to: %s", + "level": "INFO", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + }, "-916108501": { "message": "Adding %s to %s", "level": "VERBOSE", @@ -619,12 +715,24 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-846078709": { + "message": "Configuration doesn't matter in finishing %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "-809771899": { "message": "findFocusedWindow: Reached focused app=%s", "level": "VERBOSE", "group": "WM_DEBUG_FOCUS_LIGHT", "at": "com\/android\/server\/wm\/DisplayContent.java" }, + "-804217032": { + "message": "Skipping config check (will change): %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "-793346159": { "message": "New transit into wallpaper: %s", "level": "VERBOSE", @@ -673,6 +781,18 @@ "group": "WM_DEBUG_SCREEN_ON", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-743431900": { + "message": "Configuration no differences in %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, + "-716565534": { + "message": "moveActivityStackToFront: unfocusable activity=%s", + "level": "DEBUG", + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "-714291355": { "message": "Losing delayed focus: %s", "level": "INFO", @@ -739,6 +859,12 @@ "group": "WM_DEBUG_FOCUS_LIGHT", "at": "com\/android\/server\/wm\/DisplayContent.java" }, + "-593535526": { + "message": "Binding proc %s with config %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/am\/ActivityManagerService.java" + }, "-583031528": { "message": "%s", "level": "INFO", @@ -757,6 +883,12 @@ "group": "WM_DEBUG_BOOT", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-548282316": { + "message": "setLockTaskMode: Locking to %s Callers=%s", + "level": "WARN", + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/LockTaskController.java" + }, "-547111355": { "message": "hideIme Control target: %s ", "level": "DEBUG", @@ -781,6 +913,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-503656156": { + "message": "Update process config of %s to new config %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + }, "-496681057": { "message": "Attempted to get remove mode of a display that does not exist: %d", "level": "WARN", @@ -799,6 +937,12 @@ "group": "WM_SHOW_SURFACE_ALLOC", "at": "com\/android\/server\/wm\/WindowStateAnimator.java" }, + "-449118559": { + "message": "Trying to update display configuration for invalid process, pid=%d", + "level": "WARN", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + }, "-445944810": { "message": "finish(%b): mCanceled=%b", "level": "DEBUG", @@ -835,6 +979,12 @@ "group": "WM_DEBUG_STARTING_WINDOW", "at": "com\/android\/server\/wm\/TaskSnapshotSurface.java" }, + "-401282500": { + "message": "destroyIfPossible: r=%s destroy returned removed=%s", + "level": "DEBUG", + "group": "WM_DEBUG_CONTAINERS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "-395922585": { "message": "InsetsSource setWin %s", "level": "DEBUG", @@ -907,18 +1057,42 @@ "group": "WM_DEBUG_ADD_REMOVE", "at": "com\/android\/server\/wm\/WindowState.java" }, + "-317194205": { + "message": "clearLockedTasks: %s", + "level": "INFO", + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/LockTaskController.java" + }, "-303497363": { "message": "reparent: moving activity=%s to task=%d at %d", "level": "INFO", "group": "WM_DEBUG_ADD_REMOVE", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "-272719931": { + "message": "startLockTaskModeLocked: %s", + "level": "WARN", + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + }, + "-260960989": { + "message": "Removing and adding activity %s to stack at top callers=%s", + "level": "INFO", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/Task.java" + }, "-251259736": { "message": "No longer freezing: %s", "level": "VERBOSE", "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "-235225312": { + "message": "Skipping config check for initializing activity: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "-198463978": { "message": "updateRotationUnchecked: alwaysSendConfiguration=%b forceRelayout=%b", "level": "VERBOSE", @@ -943,6 +1117,12 @@ "group": "WM_DEBUG_RECENTS_ANIMATIONS", "at": "com\/android\/server\/wm\/RecentsAnimationController.java" }, + "-168799453": { + "message": "Allowing features %d:0x%s", + "level": "WARN", + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + }, "-167822951": { "message": "Attempted to add starting window to token with already existing starting window", "level": "WARN", @@ -979,6 +1159,12 @@ "group": "WM_DEBUG_FOCUS_LIGHT", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-90559682": { + "message": "Config is skipping already pausing %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "-87705714": { "message": "findFocusedWindow: focusedApp=null using new focus @ %s", "level": "VERBOSE", @@ -1303,6 +1489,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "355940361": { + "message": "Config is destroying non-running %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "371641947": { "message": "Window Manager Crash %s", "level": "WTF", @@ -1315,6 +1507,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "374506950": { + "message": "Reporting activity moved to display, activityRecord=%s, displayId=%d, config=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_SWITCH", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "374972436": { "message": "performEnableScreen: Waiting for anim complete", "level": "INFO", @@ -1411,6 +1609,12 @@ "group": "WM_DEBUG_BOOT", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "556758086": { + "message": "Applying new update lock state '%s' for %s", + "level": "DEBUG", + "group": "WM_DEBUG_IMMERSIVE", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + }, "557227556": { "message": "onAnimationFinished(): Notify animation finished:", "level": "DEBUG", @@ -1531,12 +1735,6 @@ "group": "WM_DEBUG_SCREEN_ON", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "676824470": { - "message": "Test completed successfully: %b %d %o %x %e %g %f %% %s.", - "level": "ERROR", - "group": "TEST_GROUP", - "at": "com\/android\/server\/wm\/ProtoLogGroup.java" - }, "685047360": { "message": "Resizing window %s", "level": "VERBOSE", @@ -1561,6 +1759,18 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "715749922": { + "message": "Allowlisting %d:%s", + "level": "WARN", + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + }, + "736692676": { + "message": "Config is relaunching %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "745391677": { "message": " CREATE SURFACE %s IN SESSION %s: pid=%d format=%d flags=0x%x \/ %s", "level": "INFO", @@ -1615,6 +1825,12 @@ "group": "WM_DEBUG_RECENTS_ANIMATIONS", "at": "com\/android\/server\/wm\/RecentsAnimation.java" }, + "869266572": { + "message": "Removing activity %s from stack, reason= %s callers=%s", + "level": "INFO", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "873914452": { "message": "goodToGo()", "level": "DEBUG", @@ -1645,12 +1861,30 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/WindowStateAnimator.java" }, + "950074526": { + "message": "setLockTaskMode: Can't lock due to auth", + "level": "WARN", + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/LockTaskController.java" + }, "954470154": { "message": "FORCED DISPLAY SCALING DISABLED", "level": "INFO", "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "956374481": { + "message": "removeLockedTask: task=%s last task, reverting locktask mode. Callers=%s", + "level": "DEBUG", + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/LockTaskController.java" + }, + "969323241": { + "message": "Sending new config to %s, config: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "972354148": { "message": "\tcontainer=%s", "level": "DEBUG", @@ -1663,12 +1897,24 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "1040675582": { + "message": "Can't report activity configuration update - client not running, activityRecord=%s", + "level": "WARN", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "1046922686": { "message": "requestScrollCapture: caught exception dispatching callback: %s", "level": "WARN", "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "1049367566": { + "message": "Sending to proc %s new config %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/WindowProcessController.java" + }, "1051545910": { "message": "Exit animation finished in %s: remove=%b", "level": "VERBOSE", @@ -1681,6 +1927,12 @@ "group": "WM_DEBUG_REMOTE_ANIMATIONS", "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java" }, + "1088929964": { + "message": "onLockTaskPackagesUpdated: starting new locktask task=%s", + "level": "DEBUG", + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/LockTaskController.java" + }, "1089714158": { "message": " FREEZE %s: DESTROY", "level": "INFO", @@ -1789,6 +2041,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "1337596507": { + "message": "Sending to proc %s new compat %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/CompatModePackages.java" + }, "1346895820": { "message": "ScreenRotation still animating: type: %d\nmDisplayAnimator: %s\nmEnterBlackFrameAnimator: %s\nmRotateScreenAnimator: %s\nmScreenshotRotationAnimator: %s", "level": "VERBOSE", @@ -1801,6 +2059,12 @@ "group": "WM_DEBUG_FOCUS", "at": "com\/android\/server\/wm\/DisplayContent.java" }, + "1360551978": { + "message": "Trying to update display configuration for non-existing displayId=%d", + "level": "WARN", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + }, "1364498663": { "message": "notifyAppResumed: wasStopped=%b %s", "level": "VERBOSE", @@ -1819,6 +2083,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/TaskDisplayArea.java" }, + "1401295262": { + "message": "Mode default, asking user", + "level": "WARN", + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/LockTaskController.java" + }, "1401700824": { "message": "Window drawn win=%s", "level": "DEBUG", @@ -1927,6 +2197,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "1522489371": { + "message": "moveActivityStackToFront: activity=%s", + "level": "DEBUG", + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "1525976603": { "message": "cancelAnimation(): reason=%s", "level": "DEBUG", @@ -1951,6 +2227,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "1576607724": { + "message": "Report configuration: %s %s %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + }, "1577579529": { "message": "win=%s destroySurfaces: appStopped=%b win.mWindowRemovalAllowed=%b win.mRemoveOnExit=%b", "level": "ERROR", @@ -1981,6 +2263,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "1635062046": { + "message": "Skipping config check invisible: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "1635462459": { "message": "onMovedByResize: Moving %s", "level": "DEBUG", @@ -2023,6 +2311,12 @@ "group": "WM_DEBUG_STARTING_WINDOW", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "1679569477": { + "message": "Configuration doesn't matter not running %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "1720229827": { "message": "Creating animation bounds layer", "level": "INFO", @@ -2077,12 +2371,30 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "1789603530": { + "message": "Removing activity %s hasSavedState=%b stateNotNeeded=%s finishing=%b state=%s callers=%s", + "level": "INFO", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "1822843721": { "message": "Aborted starting %s: startingData=%s", "level": "VERBOSE", "group": "WM_DEBUG_STARTING_WINDOW", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "1824105730": { + "message": "setLockTaskAuth: task=%s mLockTaskAuth=%s", + "level": "DEBUG", + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/Task.java" + }, + "1829094918": { + "message": "onLockTaskPackagesUpdated: removing %s mLockTaskAuth()=%s", + "level": "DEBUG", + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/LockTaskController.java" + }, "1831008694": { "message": "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s surfaceInsets=%s", "level": "DEBUG", @@ -2161,6 +2473,12 @@ "group": "WM_DEBUG_APP_TRANSITIONS", "at": "com\/android\/server\/wm\/AppTransitionController.java" }, + "1975793405": { + "message": "setFocusedStack: stackId=%d", + "level": "DEBUG", + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + }, "1984470582": { "message": "Creating TaskScreenshotAnimatable: task: %s width: %d height: %d", "level": "DEBUG", @@ -2173,6 +2491,12 @@ "group": "WM_SHOW_TRANSACTIONS", "at": "com\/android\/server\/wm\/WindowAnimator.java" }, + "1995093920": { + "message": "Checking to restart %s: changed=0x%s, handles=0x%s, mLastReportedConfiguration=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "2016061474": { "message": "Prepare app transition: transit=%s %s alwaysKeepCurrent=%b displayId=%d Callers=%s", "level": "VERBOSE", @@ -2191,6 +2515,12 @@ "group": "WM_DEBUG_STARTING_WINDOW", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "2022322588": { + "message": "Adding activity %s to stack to task %s callers: %s", + "level": "INFO", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/Task.java" + }, "2022422429": { "message": "createAnimationAdapter(): container=%s", "level": "DEBUG", @@ -2269,6 +2599,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/DisplayRotation.java" }, + "2134999275": { + "message": "moveActivityStackToFront: already on top, activity=%s", + "level": "DEBUG", + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "2137411379": { "message": "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b Callers=%s", "level": "VERBOSE", @@ -2277,9 +2613,6 @@ } }, "groups": { - "TEST_GROUP": { - "tag": "WindowManagetProtoLogTest" - }, "WM_DEBUG_ADD_REMOVE": { "tag": "WindowManager" }, @@ -2292,6 +2625,12 @@ "WM_DEBUG_BOOT": { "tag": "WindowManager" }, + "WM_DEBUG_CONFIGURATION": { + "tag": "WindowManager" + }, + "WM_DEBUG_CONTAINERS": { + "tag": "WindowManager" + }, "WM_DEBUG_DRAW": { "tag": "WindowManager" }, @@ -2304,9 +2643,15 @@ "WM_DEBUG_IME": { "tag": "WindowManager" }, + "WM_DEBUG_IMMERSIVE": { + "tag": "WindowManager" + }, "WM_DEBUG_KEEP_SCREEN_ON": { "tag": "WindowManager" }, + "WM_DEBUG_LOCKTASK": { + "tag": "WindowManager" + }, "WM_DEBUG_ORIENTATION": { "tag": "WindowManager" }, @@ -2325,6 +2670,9 @@ "WM_DEBUG_STARTING_WINDOW": { "tag": "WindowManager" }, + "WM_DEBUG_SWITCH": { + "tag": "WindowManager" + }, "WM_DEBUG_WINDOW_MOVEMENT": { "tag": "WindowManager" }, diff --git a/keystore/TEST_MAPPING b/keystore/TEST_MAPPING new file mode 100644 index 000000000000..0511967a229b --- /dev/null +++ b/keystore/TEST_MAPPING @@ -0,0 +1,74 @@ +{ + "presubmit": [ + { + "name": "CtsKeystoreTestCases", + "options": [ + { + "include-annotation": "android.platform.test.annotations.RequiresDevice" + }, + { + "exclude-filter": "android.keystore.cts.SignatureTest" + }, + { + "exclude-filter": "android.keystore.cts.RsaSignaturePerformanceTest" + }, + { + "exclude-filter": "android.keystore.cts.RsaKeyGenPerformanceTest" + }, + { + "exclude-filter": "android.keystore.cts.RsaCipherPerformanceTest" + }, + { + "exclude-filter": "android.keystore.cts.MacTest#testLargeMsgKat" + }, + { + "exclude-filter": "android.keystore.cts.KeyPairGeneratorTest" + }, + { + "exclude-filter": "android.keystore.cts.KeyGeneratorTest#testHmacKeySupportedSizes" + }, + { + "exclude-filter": "android.keystore.cts.HmacMacPerformanceTest" + }, + { + "exclude-filter": "android.keystore.cts.EcdsaSignaturePerformanceTest" + }, + { + "exclude-filter": "android.keystore.cts.EcKeyGenPerformanceTest" + }, + { + "exclude-filter": "android.keystore.cts.DesCipherPerformanceTest" + }, + { + "exclude-filter": "android.keystore.cts.CipherTest" + }, + { + "exclude-filter": "android.keystore.cts.AttestationPerformanceTest" + }, + { + "exclude-filter": "android.keystore.cts.AndroidKeyStoreTest" + }, + { + "exclude-filter": "android.keystore.cts.AesCipherPerformanceTest" + }, + { + "exclude-filter": "android.keystore.cts.AESCipherNistCavpKatTest" + }, + { + "exclude-filter": "android.keystore.cts.DESedeECBPKCS7PaddingCipherTest" + }, + { + "exclude-filter": "android.keystore.cts.DESedeECBNoPaddingCipherTest" + }, + { + "exclude-filter": "android.keystore.cts.DESedeECBPKCS7PaddingCipherTest" + } + ] + } + ], + "postsubmit": [ + { + "name": "CtsKeystoreTestCases" + } + ] +} diff --git a/libs/input/MouseCursorController.cpp b/libs/input/MouseCursorController.cpp index 80b555be97dd..45da008c3e8e 100644 --- a/libs/input/MouseCursorController.cpp +++ b/libs/input/MouseCursorController.cpp @@ -168,7 +168,7 @@ void MouseCursorController::fade(PointerControllerInterface::Transition transiti updatePointerLocked(); } else { mLocked.pointerFadeDirection = -1; - mContext.startAnimation(); + startAnimationLocked(); } } @@ -185,7 +185,7 @@ void MouseCursorController::unfade(PointerControllerInterface::Transition transi updatePointerLocked(); } else { mLocked.pointerFadeDirection = 1; - mContext.startAnimation(); + startAnimationLocked(); } } @@ -312,10 +312,9 @@ void MouseCursorController::setCustomPointerIcon(const SpriteIcon& icon) { updatePointerLocked(); } -bool MouseCursorController::doFadingAnimation(nsecs_t timestamp, bool keepAnimating) { +bool MouseCursorController::doFadingAnimationLocked(nsecs_t timestamp) REQUIRES(mLock) { nsecs_t frameDelay = timestamp - mContext.getAnimationTime(); - - std::scoped_lock lock(mLock); + bool keepAnimating = false; // Animate pointer fade. if (mLocked.pointerFadeDirection < 0) { @@ -337,13 +336,10 @@ bool MouseCursorController::doFadingAnimation(nsecs_t timestamp, bool keepAnimat } updatePointerLocked(); } - return keepAnimating; } -bool MouseCursorController::doBitmapAnimation(nsecs_t timestamp) { - std::scoped_lock lock(mLock); - +bool MouseCursorController::doBitmapAnimationLocked(nsecs_t timestamp) REQUIRES(mLock) { std::map<int32_t, PointerAnimation>::const_iterator iter = mLocked.animationResources.find(mLocked.requestedPointerType); if (iter == mLocked.animationResources.end()) { @@ -364,7 +360,6 @@ bool MouseCursorController::doBitmapAnimation(nsecs_t timestamp) { spriteController->closeTransaction(); } - // Keep animating. return true; } @@ -399,7 +394,7 @@ void MouseCursorController::updatePointerLocked() REQUIRES(mLock) { if (anim_iter != mLocked.animationResources.end()) { mLocked.animationFrameIndex = 0; mLocked.lastFrameUpdatedTime = systemTime(SYSTEM_TIME_MONOTONIC); - mContext.startAnimation(); + startAnimationLocked(); } mLocked.pointerSprite->setIcon(iter->second); } else { @@ -457,4 +452,38 @@ bool MouseCursorController::resourcesLoaded() { return mLocked.resourcesLoaded; } +bool MouseCursorController::doAnimations(nsecs_t timestamp) { + std::scoped_lock lock(mLock); + bool keepFading = doFadingAnimationLocked(timestamp); + bool keepBitmap = doBitmapAnimationLocked(timestamp); + bool keepAnimating = keepFading || keepBitmap; + if (!keepAnimating) { + /* + * We know that this callback will be removed before another + * is added. mLock in PointerAnimator will not be released + * until after this is removed, and adding another callback + * requires that lock. Thus it's safe to set mLocked.animating + * here. + */ + mLocked.animating = false; + } + return keepAnimating; +} + +void MouseCursorController::startAnimationLocked() REQUIRES(mLock) { + using namespace std::placeholders; + + if (mLocked.animating) { + return; + } + mLocked.animating = true; + + std::function<bool(nsecs_t)> func = std::bind(&MouseCursorController::doAnimations, this, _1); + /* + * Using -1 for displayId here to avoid removing the callback + * if a TouchSpotController with the same display is removed. + */ + mContext.addAnimationCallback(-1, func); +} + } // namespace android diff --git a/libs/input/MouseCursorController.h b/libs/input/MouseCursorController.h index 448165b5ac46..e6dfc4c6f99a 100644 --- a/libs/input/MouseCursorController.h +++ b/libs/input/MouseCursorController.h @@ -25,6 +25,7 @@ #include <utils/Looper.h> #include <utils/RefBase.h> +#include <functional> #include <map> #include <memory> #include <vector> @@ -61,8 +62,7 @@ public: void getAdditionalMouseResources(); bool isViewportValid(); - bool doBitmapAnimation(nsecs_t timestamp); - bool doFadingAnimation(nsecs_t timestamp, bool keepAnimating); + bool doAnimations(nsecs_t timestamp); bool resourcesLoaded(); @@ -96,6 +96,8 @@ private: int32_t buttonState; + bool animating{false}; + } mLocked GUARDED_BY(mLock); bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const; @@ -104,6 +106,11 @@ private: void updatePointerLocked(); void loadResourcesLocked(bool getAdditionalMouseResources); + + bool doBitmapAnimationLocked(nsecs_t timestamp); + bool doFadingAnimationLocked(nsecs_t timestamp); + + void startAnimationLocked(); }; } // namespace android diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp index 14c96cefd462..8f04cfb70469 100644 --- a/libs/input/PointerController.cpp +++ b/libs/input/PointerController.cpp @@ -57,7 +57,6 @@ std::shared_ptr<PointerController> PointerController::create( controller->mContext.setHandlerController(controller); controller->mContext.setCallbackController(controller); - controller->mContext.initializeDisplayEventReceiver(); return controller; } @@ -189,24 +188,6 @@ void PointerController::setCustomPointerIcon(const SpriteIcon& icon) { mCursorController.setCustomPointerIcon(icon); } -void PointerController::doAnimate(nsecs_t timestamp) { - std::scoped_lock lock(mLock); - - mContext.setAnimationPending(false); - - bool keepFading = false; - keepFading = mCursorController.doFadingAnimation(timestamp, keepFading); - - for (auto& [displayID, spotController] : mLocked.spotControllers) { - keepFading = spotController.doFadingAnimation(timestamp, keepFading); - } - - bool keepBitmapFlipping = mCursorController.doBitmapAnimation(timestamp); - if (keepFading || keepBitmapFlipping) { - mContext.startAnimation(); - } -} - void PointerController::doInactivityTimeout() { fade(Transition::GRADUAL); } @@ -221,6 +202,11 @@ void PointerController::onDisplayViewportsUpdated(std::vector<DisplayViewport>& for (auto it = mLocked.spotControllers.begin(); it != mLocked.spotControllers.end();) { int32_t displayID = it->first; if (!displayIdSet.count(displayID)) { + /* + * Ensures that an in-progress animation won't dereference + * a null pointer to TouchSpotController. + */ + mContext.removeAnimationCallback(displayID); it = mLocked.spotControllers.erase(it); } else { ++it; diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h index 1f561da333b1..827fcf1e1bc1 100644 --- a/libs/input/PointerController.h +++ b/libs/input/PointerController.h @@ -70,7 +70,6 @@ public: void setCustomPointerIcon(const SpriteIcon& icon); void setInactivityTimeout(InactivityTimeout inactivityTimeout); void doInactivityTimeout(); - void doAnimate(nsecs_t timestamp); void reloadPointerResources(); void onDisplayViewportsUpdated(std::vector<DisplayViewport>& viewports); diff --git a/libs/input/PointerControllerContext.cpp b/libs/input/PointerControllerContext.cpp index 2d7e22b01112..f30e8d8e33a5 100644 --- a/libs/input/PointerControllerContext.cpp +++ b/libs/input/PointerControllerContext.cpp @@ -38,10 +38,10 @@ PointerControllerContext::PointerControllerContext( mSpriteController(spriteController), mHandler(new MessageHandler()), mCallback(new LooperCallback()), - mController(controller) { + mController(controller), + mAnimator(*this) { std::scoped_lock lock(mLock); mLocked.inactivityTimeout = InactivityTimeout::NORMAL; - mLocked.animationPending = false; } PointerControllerContext::~PointerControllerContext() { @@ -57,15 +57,6 @@ void PointerControllerContext::setInactivityTimeout(InactivityTimeout inactivity } } -void PointerControllerContext::startAnimation() { - std::scoped_lock lock(mLock); - if (!mLocked.animationPending) { - mLocked.animationPending = true; - mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC); - mDisplayEventReceiver.requestNextVsync(); - } -} - void PointerControllerContext::resetInactivityTimeout() { std::scoped_lock lock(mLock); resetInactivityTimeoutLocked(); @@ -85,14 +76,8 @@ void PointerControllerContext::removeInactivityTimeout() { mLooper->removeMessages(mHandler, MessageHandler::MSG_INACTIVITY_TIMEOUT); } -void PointerControllerContext::setAnimationPending(bool animationPending) { - std::scoped_lock lock(mLock); - mLocked.animationPending = animationPending; -} - -nsecs_t PointerControllerContext::getAnimationTime() { - std::scoped_lock lock(mLock); - return mLocked.animationTime; +nsecs_t PointerControllerContext::getAnimationTime() REQUIRES(mAnimator.mLock) { + return mAnimator.getAnimationTimeLocked(); } void PointerControllerContext::setHandlerController(std::shared_ptr<PointerController> controller) { @@ -112,31 +97,8 @@ sp<SpriteController> PointerControllerContext::getSpriteController() { return mSpriteController; } -void PointerControllerContext::initializeDisplayEventReceiver() { - if (mDisplayEventReceiver.initCheck() == NO_ERROR) { - mLooper->addFd(mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK, Looper::EVENT_INPUT, - mCallback, nullptr); - } else { - ALOGE("Failed to initialize DisplayEventReceiver."); - } -} - void PointerControllerContext::handleDisplayEvents() { - bool gotVsync = false; - ssize_t n; - nsecs_t timestamp; - DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE]; - while ((n = mDisplayEventReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) { - for (size_t i = 0; i < static_cast<size_t>(n); ++i) { - if (buf[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { - timestamp = buf[i].header.timestamp; - gotVsync = true; - } - } - } - if (gotVsync) { - mController.doAnimate(timestamp); - } + mAnimator.handleVsyncEvents(); } void PointerControllerContext::MessageHandler::handleMessage(const Message& message) { @@ -176,4 +138,91 @@ int PointerControllerContext::LooperCallback::handleEvent(int /* fd */, int even return 1; // keep the callback } +void PointerControllerContext::addAnimationCallback(int32_t displayId, + std::function<bool(nsecs_t)> callback) { + mAnimator.addCallback(displayId, callback); +} + +void PointerControllerContext::removeAnimationCallback(int32_t displayId) { + mAnimator.removeCallback(displayId); +} + +PointerControllerContext::PointerAnimator::PointerAnimator(PointerControllerContext& context) + : mContext(context) { + initializeDisplayEventReceiver(); +} + +void PointerControllerContext::PointerAnimator::initializeDisplayEventReceiver() { + if (mDisplayEventReceiver.initCheck() == NO_ERROR) { + mContext.mLooper->addFd(mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK, + Looper::EVENT_INPUT, mContext.mCallback, nullptr); + } else { + ALOGE("Failed to initialize DisplayEventReceiver."); + } +} + +void PointerControllerContext::PointerAnimator::addCallback(int32_t displayId, + std::function<bool(nsecs_t)> callback) { + std::scoped_lock lock(mLock); + mLocked.callbacks[displayId] = callback; + startAnimationLocked(); +} + +void PointerControllerContext::PointerAnimator::removeCallback(int32_t displayId) { + std::scoped_lock lock(mLock); + auto it = mLocked.callbacks.find(displayId); + if (it == mLocked.callbacks.end()) { + return; + } + mLocked.callbacks.erase(it); +} + +void PointerControllerContext::PointerAnimator::handleVsyncEvents() { + bool gotVsync = false; + ssize_t n; + nsecs_t timestamp; + DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE]; + while ((n = mDisplayEventReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) { + for (size_t i = 0; i < static_cast<size_t>(n); ++i) { + if (buf[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { + timestamp = buf[i].header.timestamp; + gotVsync = true; + } + } + } + if (gotVsync) { + std::scoped_lock lock(mLock); + mLocked.animationPending = false; + handleCallbacksLocked(timestamp); + } +} + +nsecs_t PointerControllerContext::PointerAnimator::getAnimationTimeLocked() REQUIRES(mLock) { + return mLocked.animationTime; +} + +void PointerControllerContext::PointerAnimator::startAnimationLocked() REQUIRES(mLock) { + if (!mLocked.animationPending) { + mLocked.animationPending = true; + mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC); + mDisplayEventReceiver.requestNextVsync(); + } +} + +void PointerControllerContext::PointerAnimator::handleCallbacksLocked(nsecs_t timestamp) + REQUIRES(mLock) { + for (auto it = mLocked.callbacks.begin(); it != mLocked.callbacks.end();) { + bool keepCallback = it->second(timestamp); + if (!keepCallback) { + it = mLocked.callbacks.erase(it); + } else { + ++it; + } + } + + if (!mLocked.callbacks.empty()) { + startAnimationLocked(); + } +} + } // namespace android diff --git a/libs/input/PointerControllerContext.h b/libs/input/PointerControllerContext.h index 92e1bda25f56..98073fea323e 100644 --- a/libs/input/PointerControllerContext.h +++ b/libs/input/PointerControllerContext.h @@ -26,6 +26,7 @@ #include <utils/Looper.h> #include <utils/RefBase.h> +#include <functional> #include <map> #include <memory> #include <vector> @@ -35,6 +36,8 @@ namespace android { class PointerController; +class MouseCursorController; +class TouchSpotController; /* * Pointer resources. @@ -96,7 +99,6 @@ public: void startAnimation(); void setInactivityTimeout(InactivityTimeout inactivityTimeout); - void setAnimationPending(bool animationPending); nsecs_t getAnimationTime(); void clearSpotsByDisplay(int32_t displayId); @@ -107,9 +109,11 @@ public: sp<PointerControllerPolicyInterface> getPolicy(); sp<SpriteController> getSpriteController(); - void initializeDisplayEventReceiver(); void handleDisplayEvents(); + void addAnimationCallback(int32_t displayId, std::function<bool(nsecs_t)> callback); + void removeAnimationCallback(int32_t displayId); + class MessageHandler : public virtual android::MessageHandler { public: enum { @@ -127,22 +131,47 @@ public: }; private: + class PointerAnimator { + public: + PointerAnimator(PointerControllerContext& context); + + void addCallback(int32_t displayId, std::function<bool(nsecs_t)> callback); + void removeCallback(int32_t displayId); + void handleVsyncEvents(); + nsecs_t getAnimationTimeLocked(); + + mutable std::mutex mLock; + + private: + struct Locked { + bool animationPending{false}; + nsecs_t animationTime{systemTime(SYSTEM_TIME_MONOTONIC)}; + + std::unordered_map<int32_t, std::function<bool(nsecs_t)>> callbacks; + } mLocked GUARDED_BY(mLock); + + DisplayEventReceiver mDisplayEventReceiver; + + PointerControllerContext& mContext; + + void initializeDisplayEventReceiver(); + void startAnimationLocked(); + void handleCallbacksLocked(nsecs_t timestamp); + }; + sp<PointerControllerPolicyInterface> mPolicy; sp<Looper> mLooper; sp<SpriteController> mSpriteController; sp<MessageHandler> mHandler; sp<LooperCallback> mCallback; - DisplayEventReceiver mDisplayEventReceiver; - PointerController& mController; + PointerAnimator mAnimator; + mutable std::mutex mLock; struct Locked { - bool animationPending; - nsecs_t animationTime; - InactivityTimeout inactivityTimeout; } mLocked GUARDED_BY(mLock); diff --git a/libs/input/TouchSpotController.cpp b/libs/input/TouchSpotController.cpp index c7430ceead41..f7c685ff8ba6 100644 --- a/libs/input/TouchSpotController.cpp +++ b/libs/input/TouchSpotController.cpp @@ -142,7 +142,8 @@ TouchSpotController::Spot* TouchSpotController::getSpot(uint32_t id, } TouchSpotController::Spot* TouchSpotController::createAndAddSpotLocked(uint32_t id, - std::vector<Spot*>& spots) { + std::vector<Spot*>& spots) + REQUIRES(mLock) { // Remove spots until we have fewer than MAX_SPOTS remaining. while (spots.size() >= MAX_SPOTS) { Spot* spot = removeFirstFadingSpotLocked(spots); @@ -186,14 +187,13 @@ void TouchSpotController::releaseSpotLocked(Spot* spot) REQUIRES(mLock) { if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) { mLocked.recycledSprites.push_back(spot->sprite); } - delete spot; } void TouchSpotController::fadeOutAndReleaseSpotLocked(Spot* spot) REQUIRES(mLock) { if (spot->id != Spot::INVALID_ID) { spot->id = Spot::INVALID_ID; - mContext.startAnimation(); + startAnimationLocked(); } } @@ -209,8 +209,24 @@ void TouchSpotController::reloadSpotResources() { mContext.getPolicy()->loadPointerResources(&mResources, mDisplayId); } -bool TouchSpotController::doFadingAnimation(nsecs_t timestamp, bool keepAnimating) { +bool TouchSpotController::doAnimations(nsecs_t timestamp) { std::scoped_lock lock(mLock); + bool keepAnimating = doFadingAnimationLocked(timestamp); + if (!keepAnimating) { + /* + * We know that this callback will be removed before another + * is added. mLock in PointerAnimator will not be released + * until after this is removed, and adding another callback + * requires that lock. Thus it's safe to set mLocked.animating + * here. + */ + mLocked.animating = false; + } + return keepAnimating; +} + +bool TouchSpotController::doFadingAnimationLocked(nsecs_t timestamp) REQUIRES(mLock) { + bool keepAnimating = false; nsecs_t animationTime = mContext.getAnimationTime(); nsecs_t frameDelay = timestamp - animationTime; size_t numSpots = mLocked.displaySpots.size(); @@ -233,4 +249,16 @@ bool TouchSpotController::doFadingAnimation(nsecs_t timestamp, bool keepAnimatin return keepAnimating; } +void TouchSpotController::startAnimationLocked() REQUIRES(mLock) { + using namespace std::placeholders; + + if (mLocked.animating) { + return; + } + mLocked.animating = true; + + std::function<bool(nsecs_t)> func = std::bind(&TouchSpotController::doAnimations, this, _1); + mContext.addAnimationCallback(mDisplayId, func); +} + } // namespace android diff --git a/libs/input/TouchSpotController.h b/libs/input/TouchSpotController.h index f3b355010bee..703de3603f48 100644 --- a/libs/input/TouchSpotController.h +++ b/libs/input/TouchSpotController.h @@ -17,6 +17,8 @@ #ifndef _UI_TOUCH_SPOT_CONTROLLER_H #define _UI_TOUCH_SPOT_CONTROLLER_H +#include <functional> + #include "PointerControllerContext.h" namespace android { @@ -34,7 +36,7 @@ public: void clearSpots(); void reloadSpotResources(); - bool doFadingAnimation(nsecs_t timestamp, bool keepAnimating); + bool doAnimations(nsecs_t timestamp); private: struct Spot { @@ -76,6 +78,8 @@ private: std::vector<Spot*> displaySpots; std::vector<sp<Sprite>> recycledSprites; + bool animating{false}; + } mLocked GUARDED_BY(mLock); Spot* getSpot(uint32_t id, const std::vector<Spot*>& spots); @@ -84,6 +88,8 @@ private: void releaseSpotLocked(Spot* spot); void fadeOutAndReleaseSpotLocked(Spot* spot); void fadeOutAndReleaseAllSpotsLocked(); + bool doFadingAnimationLocked(nsecs_t timestamp); + void startAnimationLocked(); }; } // namespace android diff --git a/packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java index 552cadfe967e..b17ad0febb90 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java @@ -16,7 +16,9 @@ package com.android.systemui; +import com.android.systemui.dagger.GlobalModule; import com.android.systemui.dagger.GlobalRootComponent; +import com.android.systemui.dagger.WMModule; import javax.inject.Singleton; @@ -26,7 +28,9 @@ import dagger.Component; @Singleton @Component( modules = { - CarSysUIComponentModule.class + GlobalModule.class, + CarSysUIComponentModule.class, + WMModule.class }) public interface CarGlobalRootComponent extends GlobalRootComponent { /** diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java index 24d9d09d2ca9..90396717de9f 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java @@ -20,7 +20,6 @@ import com.android.systemui.dagger.DependencyBinder; import com.android.systemui.dagger.DependencyProvider; import com.android.systemui.dagger.SysUIComponent; import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.dagger.SystemServicesModule; import com.android.systemui.dagger.SystemUIModule; import com.android.systemui.pip.phone.dagger.PipModule; @@ -35,7 +34,6 @@ import dagger.Subcomponent; DependencyProvider.class, DependencyBinder.class, PipModule.class, - SystemServicesModule.class, SystemUIModule.class, CarSystemUIModule.class, CarSystemUIBinder.class}) diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java index 3b22fdb50765..38e1a48ab3a7 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java @@ -299,10 +299,10 @@ public class NotificationPanelViewController extends OverlayPanelViewController // The glass pane is used to view touch events before passed to the notification list. // This allows us to initialize gesture listeners and detect when to close the notifications glassPane.setOnTouchListener((v, event) -> { - if (event.getActionMasked() == MotionEvent.ACTION_UP) { + if (isClosingAction(event)) { mNotificationListAtEndAtTimeOfTouch = false; } - if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + if (isOpeningAction(event)) { mFirstTouchDownOnGlassPane = event.getRawX(); mNotificationListAtEndAtTimeOfTouch = mNotificationListAtEnd; // Reset the tracker when there is a touch down on the glass pane. @@ -355,8 +355,7 @@ public class NotificationPanelViewController extends OverlayPanelViewController if (rect != null) { clippedHeight = rect.bottom; } - if (!handled && event.getActionMasked() == MotionEvent.ACTION_UP - && mIsSwipingVerticallyToClose) { + if (!handled && isClosingAction(event) && mIsSwipingVerticallyToClose) { if (getSettleClosePercentage() < getPercentageFromEndingEdge() && isTracking) { animatePanel(DEFAULT_FLING_VELOCITY, false); } else if (clippedHeight != getLayout().getHeight() && isTracking) { @@ -369,7 +368,7 @@ public class NotificationPanelViewController extends OverlayPanelViewController // Updating the mNotificationListAtEndAtTimeOfTouch state has to be done after // the event has been passed to the closeGestureDetector above, such that the // closeGestureDetector sees the up event before the state has changed. - if (event.getActionMasked() == MotionEvent.ACTION_UP) { + if (isClosingAction(event)) { mNotificationListAtEndAtTimeOfTouch = false; } return handled || isTracking; diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java index 45808a8a0b3e..bde31f18d8fd 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java @@ -191,6 +191,38 @@ public abstract class OverlayPanelViewController extends OverlayViewController { } } + /** Checks if a {@link MotionEvent} is an action to open the panel. + * @param e {@link MotionEvent} to check. + * @return true only if opening action. + */ + protected boolean isOpeningAction(MotionEvent e) { + if (mAnimateDirection == POSITIVE_DIRECTION) { + return e.getActionMasked() == MotionEvent.ACTION_DOWN; + } + + if (mAnimateDirection == NEGATIVE_DIRECTION) { + return e.getActionMasked() == MotionEvent.ACTION_UP; + } + + return false; + } + + /** Checks if a {@link MotionEvent} is an action to close the panel. + * @param e {@link MotionEvent} to check. + * @return true only if closing action. + */ + protected boolean isClosingAction(MotionEvent e) { + if (mAnimateDirection == POSITIVE_DIRECTION) { + return e.getActionMasked() == MotionEvent.ACTION_UP; + } + + if (mAnimateDirection == NEGATIVE_DIRECTION) { + return e.getActionMasked() == MotionEvent.ACTION_DOWN; + } + + return false; + } + /* ***************************************************************************************** * * Panel Animation * ***************************************************************************************** */ @@ -243,8 +275,7 @@ public abstract class OverlayPanelViewController extends OverlayViewController { * Depending on certain conditions, determines whether to fully expand or collapse the panel. */ protected void maybeCompleteAnimation(MotionEvent event) { - if (event.getActionMasked() == MotionEvent.ACTION_UP - && isPanelVisible()) { + if (isClosingAction(event) && isPanelVisible()) { if (mSettleClosePercentage < mPercentageFromEndingEdge) { animatePanel(DEFAULT_FLING_VELOCITY, false); } else { diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java index 9d52098f37d5..63f8b1f5dbb8 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java @@ -30,7 +30,7 @@ import java.io.PrintWriter; */ @ProvidesInterface(version = FalsingManager.VERSION) public interface FalsingManager { - int VERSION = 4; + int VERSION = 5; void onSuccessfulUnlock(); @@ -42,7 +42,8 @@ public interface FalsingManager { boolean isUnlockingDisabled(); - boolean isFalseTouch(); + /** Returns true if the gesture should be rejected. */ + boolean isFalseTouch(int interactionType); void onNotificatonStopDraggingDown(); diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java index 02c4c5eff26e..4b6efa91a7c8 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java @@ -14,16 +14,16 @@ package com.android.systemui.plugins.statusbar; -import com.android.systemui.plugins.annotations.DependsOn; -import com.android.systemui.plugins.annotations.ProvidesInterface; -import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption; - import android.service.notification.SnoozeCriterion; import android.service.notification.StatusBarNotification; import android.view.MotionEvent; import android.view.View; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; +import com.android.systemui.plugins.annotations.DependsOn; +import com.android.systemui.plugins.annotations.ProvidesInterface; +import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption; + @ProvidesInterface(version = NotificationSwipeActionHelper.VERSION) @DependsOn(target = SnoozeOption.class) public interface NotificationSwipeActionHelper { @@ -52,7 +52,8 @@ public interface NotificationSwipeActionHelper { public boolean isDismissGesture(MotionEvent ev); - public boolean isFalseGesture(MotionEvent ev); + /** Returns true if the gesture should be rejected. */ + boolean isFalseGesture(); public boolean swipedFarEnough(float translation, float viewSize); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java index ecf1c2c91770..5ad8cad8195a 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -22,6 +22,7 @@ import android.widget.RelativeLayout; import android.widget.TextClock; import com.android.internal.colorextraction.ColorExtractor; +import com.android.keyguard.dagger.KeyguardStatusViewScope; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.plugins.ClockPlugin; @@ -36,6 +37,7 @@ import java.util.TimeZone; /** * Switch to show plugin clock when plugin is connected, otherwise it will show default clock. */ +@KeyguardStatusViewScope public class KeyguardClockSwitch extends RelativeLayout { private static final String TAG = "KeyguardClockSwitch"; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java index f17f1ca797e0..fe5fcc6fd632 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java @@ -34,10 +34,11 @@ import javax.inject.Inject; public class KeyguardClockSwitchController { private static final boolean CUSTOM_CLOCKS_ENABLED = true; + private final KeyguardClockSwitch mView; private final StatusBarStateController mStatusBarStateController; private final SysuiColorExtractor mColorExtractor; private final ClockManager mClockManager; - private KeyguardClockSwitch mView; + private final KeyguardSliceViewController mKeyguardSliceViewController; private final StatusBarStateController.StateListener mStateListener = new StatusBarStateController.StateListener() { @@ -52,9 +53,13 @@ public class KeyguardClockSwitchController { * * The color palette changes when the wallpaper is changed. */ - private final ColorExtractor.OnColorsChangedListener mColorsListener = (extractor, which) -> { - if ((which & WallpaperManager.FLAG_LOCK) != 0) { - mView.updateColors(getGradientColors()); + private final ColorExtractor.OnColorsChangedListener mColorsListener = + new ColorExtractor.OnColorsChangedListener() { + @Override + public void onColorsChanged(ColorExtractor extractor, int which) { + if ((which & WallpaperManager.FLAG_LOCK) != 0) { + mView.updateColors(getGradientColors()); + } } }; @@ -84,22 +89,27 @@ public class KeyguardClockSwitchController { }; @Inject - public KeyguardClockSwitchController(StatusBarStateController statusBarStateController, - SysuiColorExtractor colorExtractor, ClockManager clockManager) { + public KeyguardClockSwitchController(KeyguardClockSwitch keyguardClockSwitch, + StatusBarStateController statusBarStateController, + SysuiColorExtractor colorExtractor, ClockManager clockManager, + KeyguardSliceViewController keyguardSliceViewController) { + mView = keyguardClockSwitch; mStatusBarStateController = statusBarStateController; mColorExtractor = colorExtractor; mClockManager = clockManager; + mKeyguardSliceViewController = keyguardSliceViewController; } /** * Attach the controller to the view it relates to. */ - public void attach(KeyguardClockSwitch view) { - mView = view; + public void init() { if (mView.isAttachedToWindow()) { mOnAttachStateChangeListener.onViewAttachedToWindow(mView); } mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener); + + mKeyguardSliceViewController.init(); } /** diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java index 6f19613be28f..be21d203411e 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java @@ -34,12 +34,15 @@ import android.view.View; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; +import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.navigationbar.NavigationBarController; import com.android.systemui.navigationbar.NavigationBarView; import com.android.systemui.util.InjectionInflationController; +import javax.inject.Inject; + public class KeyguardDisplayManager { protected static final String TAG = "KeyguardDisplayManager"; private static boolean DEBUG = KeyguardConstants.DEBUG; @@ -47,6 +50,7 @@ public class KeyguardDisplayManager { private final MediaRouter mMediaRouter; private final DisplayManager mDisplayService; private final InjectionInflationController mInjectableInflater; + private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; private final Context mContext; private boolean mShowing; @@ -86,10 +90,13 @@ public class KeyguardDisplayManager { } }; + @Inject public KeyguardDisplayManager(Context context, - InjectionInflationController injectableInflater) { + InjectionInflationController injectableInflater, + KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory) { mContext = context; mInjectableInflater = injectableInflater; + mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory; mMediaRouter = mContext.getSystemService(MediaRouter.class); mDisplayService = mContext.getSystemService(DisplayManager.class); mDisplayService.registerDisplayListener(mDisplayListener, null /* handler */); @@ -124,6 +131,7 @@ public class KeyguardDisplayManager { Presentation presentation = mPresentations.get(displayId); if (presentation == null) { final Presentation newPresentation = new KeyguardPresentation(mContext, display, + mKeyguardStatusViewComponentFactory, mInjectableInflater.injectable(LayoutInflater.from(mContext))); newPresentation.setOnDismissListener(dialog -> { if (newPresentation.equals(mPresentations.get(displayId))) { @@ -241,7 +249,9 @@ public class KeyguardDisplayManager { static final class KeyguardPresentation extends Presentation { private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height private static final int MOVE_CLOCK_TIMEOUT = 10000; // 10s + private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; private final LayoutInflater mInjectableLayoutInflater; + private KeyguardClockSwitchController mKeyguardClockSwitchController; private View mClock; private int mUsableWidth; private int mUsableHeight; @@ -259,8 +269,10 @@ public class KeyguardDisplayManager { }; KeyguardPresentation(Context context, Display display, + KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory, LayoutInflater injectionLayoutInflater) { super(context, display, R.style.Theme_SystemUI_KeyguardPresentation); + mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory; mInjectableLayoutInflater = injectionLayoutInflater; getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); setCancelable(false); @@ -302,6 +314,12 @@ public class KeyguardDisplayManager { // Avoid screen burn in mClock.post(mMoveTextRunnable); + + mKeyguardClockSwitchController = mKeyguardStatusViewComponentFactory + .build(findViewById(R.id.clock)) + .getKeyguardClockSwitchController(); + + mKeyguardClockSwitchController.init(); } } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java index f639c880c97a..a479bca56c2a 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java @@ -16,12 +16,6 @@ package com.android.keyguard; -import static android.app.slice.Slice.HINT_LIST_ITEM; -import static android.view.Display.DEFAULT_DISPLAY; -import static android.view.Display.INVALID_DISPLAY; - -import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT; - import android.animation.LayoutTransition; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; @@ -35,28 +29,19 @@ import android.graphics.drawable.Drawable; import android.graphics.text.LineBreaker; import android.net.Uri; import android.os.Trace; -import android.provider.Settings; import android.text.TextUtils; import android.text.TextUtils.TruncateAt; import android.util.AttributeSet; -import android.util.Log; import android.util.TypedValue; -import android.view.Display; import android.view.View; import android.view.animation.Animation; import android.widget.LinearLayout; import android.widget.TextView; -import androidx.lifecycle.LiveData; -import androidx.lifecycle.Observer; -import androidx.slice.Slice; import androidx.slice.SliceItem; -import androidx.slice.SliceViewManager; import androidx.slice.core.SliceQuery; -import androidx.slice.widget.ListContent; import androidx.slice.widget.RowContent; import androidx.slice.widget.SliceContent; -import androidx.slice.widget.SliceLiveData; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.ColorUtils; @@ -64,70 +49,49 @@ import com.android.settingslib.Utils; import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.keyguard.KeyguardSliceProvider; -import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.tuner.TunerService; import com.android.systemui.util.wakelock.KeepAwakeAnimationListener; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; - -import javax.inject.Inject; -import javax.inject.Named; +import java.util.Map; /** * View visible under the clock on the lock screen and AoD. */ -public class KeyguardSliceView extends LinearLayout implements View.OnClickListener, - Observer<Slice>, TunerService.Tunable, ConfigurationController.ConfigurationListener { +public class KeyguardSliceView extends LinearLayout { private static final String TAG = "KeyguardSliceView"; public static final int DEFAULT_ANIM_DURATION = 550; - private final HashMap<View, PendingIntent> mClickActions; - private final ActivityStarter mActivityStarter; - private final ConfigurationController mConfigurationController; private final LayoutTransition mLayoutTransition; - private final TunerService mTunerService; - private Uri mKeyguardSliceUri; @VisibleForTesting TextView mTitle; private Row mRow; private int mTextColor; private float mDarkAmount = 0; - private LiveData<Slice> mLiveData; - private int mDisplayId = INVALID_DISPLAY; private int mIconSize; private int mIconSizeWithHeader; /** * Runnable called whenever the view contents change. */ private Runnable mContentChangeListener; - private Slice mSlice; private boolean mHasHeader; private final int mRowWithHeaderPadding; private final int mRowPadding; private float mRowTextSize; private float mRowWithHeaderTextSize; + private View.OnClickListener mOnClickListener; - @Inject - public KeyguardSliceView(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs, - ActivityStarter activityStarter, ConfigurationController configurationController, - TunerService tunerService, @Main Resources resources) { + public KeyguardSliceView(Context context, AttributeSet attrs) { super(context, attrs); - mTunerService = tunerService; - mClickActions = new HashMap<>(); + Resources resources = context.getResources(); mRowPadding = resources.getDimensionPixelSize(R.dimen.subtitle_clock_padding); mRowWithHeaderPadding = resources.getDimensionPixelSize(R.dimen.header_subtitle_padding); - mActivityStarter = activityStarter; - mConfigurationController = configurationController; mLayoutTransition = new LayoutTransition(); mLayoutTransition.setStagger(LayoutTransition.CHANGE_APPEARING, DEFAULT_ANIM_DURATION / 2); @@ -153,39 +117,10 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe R.dimen.widget_label_font_size); mRowWithHeaderTextSize = mContext.getResources().getDimensionPixelSize( R.dimen.header_row_font_size); - mTitle.setOnClickListener(this); mTitle.setBreakStrategy(LineBreaker.BREAK_STRATEGY_BALANCED); } @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - - Display display = getDisplay(); - if (display != null) { - mDisplayId = display.getDisplayId(); - } - mTunerService.addTunable(this, Settings.Secure.KEYGUARD_SLICE_URI); - // Make sure we always have the most current slice - if (mDisplayId == DEFAULT_DISPLAY) { - mLiveData.observeForever(this); - } - mConfigurationController.addCallback(this); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - - // TODO(b/117344873) Remove below work around after this issue be fixed. - if (mDisplayId == DEFAULT_DISPLAY) { - mLiveData.removeObserver(this); - } - mTunerService.removeTunable(this); - mConfigurationController.removeCallback(this); - } - - @Override public void onVisibilityAggregated(boolean isVisible) { super.onVisibilityAggregated(isVisible); setLayoutTransition(isVisible ? mLayoutTransition : null); @@ -198,44 +133,31 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe return mHasHeader; } - private void showSlice() { - Trace.beginSection("KeyguardSliceView#showSlice"); - if (mSlice == null) { - mTitle.setVisibility(GONE); - mRow.setVisibility(GONE); - mHasHeader = false; - if (mContentChangeListener != null) { - mContentChangeListener.run(); - } - Trace.endSection(); - return; - } - mClickActions.clear(); - - ListContent lc = new ListContent(getContext(), mSlice); - SliceContent headerContent = lc.getHeader(); - mHasHeader = headerContent != null && !headerContent.getSliceItem().hasHint(HINT_LIST_ITEM); - List<SliceContent> subItems = new ArrayList<>(); - for (int i = 0; i < lc.getRowItems().size(); i++) { - SliceContent subItem = lc.getRowItems().get(i); - String itemUri = subItem.getSliceItem().getSlice().getUri().toString(); - // Filter out the action row - if (!KeyguardSliceProvider.KEYGUARD_ACTION_URI.equals(itemUri)) { - subItems.add(subItem); - } + void hideSlice() { + mTitle.setVisibility(GONE); + mRow.setVisibility(GONE); + mHasHeader = false; + if (mContentChangeListener != null) { + mContentChangeListener.run(); } + } + + Map<View, PendingIntent> showSlice(RowContent header, List<SliceContent> subItems) { + Trace.beginSection("KeyguardSliceView#showSlice"); + mHasHeader = header != null; + Map<View, PendingIntent> clickActions = new HashMap<>(); + if (!mHasHeader) { mTitle.setVisibility(GONE); } else { mTitle.setVisibility(VISIBLE); - RowContent header = lc.getHeader(); SliceItem mainTitle = header.getTitleItem(); CharSequence title = mainTitle != null ? mainTitle.getText() : null; mTitle.setText(title); if (header.getPrimaryAction() != null && header.getPrimaryAction().getAction() != null) { - mClickActions.put(mTitle, header.getPrimaryAction().getAction()); + clickActions.put(mTitle, header.getPrimaryAction().getAction()); } } @@ -265,7 +187,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe if (rc.getPrimaryAction() != null) { pendingIntent = rc.getPrimaryAction().getAction(); } - mClickActions.put(button, pendingIntent); + clickActions.put(button, pendingIntent); final SliceItem titleItem = rc.getTitleItem(); button.setText(titleItem == null ? null : titleItem.getText()); @@ -286,14 +208,14 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe } } button.setCompoundDrawables(iconDrawable, null, null, null); - button.setOnClickListener(this); + button.setOnClickListener(mOnClickListener); button.setClickable(pendingIntent != null); } // Removing old views for (int i = 0; i < mRow.getChildCount(); i++) { View child = mRow.getChildAt(i); - if (!mClickActions.containsKey(child)) { + if (!clickActions.containsKey(child)) { mRow.removeView(child); i--; } @@ -303,6 +225,8 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe mContentChangeListener.run(); } Trace.endSection(); + + return clickActions; } public void setDarkAmount(float darkAmount) { @@ -323,14 +247,6 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe } } - @Override - public void onClick(View v) { - final PendingIntent action = mClickActions.get(v); - if (action != null) { - mActivityStarter.startPendingIntentDismissingKeyguard(action); - } - } - /** * Runnable that gets invoked every time the title or the row visibility changes. * @param contentChangeListener The listener. @@ -339,43 +255,6 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe mContentChangeListener = contentChangeListener; } - /** - * LiveData observer lifecycle. - * @param slice the new slice content. - */ - @Override - public void onChanged(Slice slice) { - mSlice = slice; - showSlice(); - } - - @Override - public void onTuningChanged(String key, String newValue) { - setupUri(newValue); - } - - /** - * Sets the slice provider Uri. - */ - public void setupUri(String uriString) { - if (uriString == null) { - uriString = KeyguardSliceProvider.KEYGUARD_SLICE_URI; - } - - boolean wasObserving = false; - if (mLiveData != null && mLiveData.hasActiveObservers()) { - wasObserving = true; - mLiveData.removeObserver(this); - } - - mKeyguardSliceUri = Uri.parse(uriString); - mLiveData = SliceLiveData.fromUri(mContext, mKeyguardSliceUri); - - if (wasObserving) { - mLiveData.observeForever(this); - } - } - @VisibleForTesting int getTextColor() { return ColorUtils.blendARGB(mTextColor, Color.WHITE, mDarkAmount); @@ -387,8 +266,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe updateTextColors(); } - @Override - public void onDensityOrFontScaleChanged() { + void onDensityOrFontScaleChanged() { mIconSize = mContext.getResources().getDimensionPixelSize(R.dimen.widget_icon_size); mIconSizeWithHeader = (int) mContext.getResources().getDimension(R.dimen.header_icon_size); mRowTextSize = mContext.getResources().getDimensionPixelSize( @@ -397,37 +275,21 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe R.dimen.header_row_font_size); } - public void refresh() { - Slice slice; - Trace.beginSection("KeyguardSliceView#refresh"); - // We can optimize performance and avoid binder calls when we know that we're bound - // to a Slice on the same process. - if (KeyguardSliceProvider.KEYGUARD_SLICE_URI.equals(mKeyguardSliceUri.toString())) { - KeyguardSliceProvider instance = KeyguardSliceProvider.getAttachedInstance(); - if (instance != null) { - slice = instance.onBindSlice(mKeyguardSliceUri); - } else { - Log.w(TAG, "Keyguard slice not bound yet?"); - slice = null; - } - } else { - slice = SliceViewManager.getInstance(getContext()).bindSlice(mKeyguardSliceUri); - } - onChanged(slice); - Trace.endSection(); - } - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("KeyguardSliceView:"); - pw.println(" mClickActions: " + mClickActions); pw.println(" mTitle: " + (mTitle == null ? "null" : mTitle.getVisibility() == VISIBLE)); pw.println(" mRow: " + (mRow == null ? "null" : mRow.getVisibility() == VISIBLE)); pw.println(" mTextColor: " + Integer.toHexString(mTextColor)); pw.println(" mDarkAmount: " + mDarkAmount); - pw.println(" mSlice: " + mSlice); pw.println(" mHasHeader: " + mHasHeader); } + @Override + public void setOnClickListener(View.OnClickListener onClickListener) { + mOnClickListener = onClickListener; + mTitle.setOnClickListener(onClickListener); + } + public static class Row extends LinearLayout { /** diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java new file mode 100644 index 000000000000..35a2392ba1cf --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.keyguard; + +import static android.app.slice.Slice.HINT_LIST_ITEM; +import static android.view.Display.DEFAULT_DISPLAY; + +import android.app.PendingIntent; +import android.net.Uri; +import android.os.Trace; +import android.provider.Settings; +import android.util.Log; +import android.view.Display; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.Observer; +import androidx.slice.Slice; +import androidx.slice.SliceViewManager; +import androidx.slice.widget.ListContent; +import androidx.slice.widget.RowContent; +import androidx.slice.widget.SliceContent; +import androidx.slice.widget.SliceLiveData; + +import com.android.keyguard.dagger.KeyguardStatusViewScope; +import com.android.systemui.Dumpable; +import com.android.systemui.dump.DumpManager; +import com.android.systemui.keyguard.KeyguardSliceProvider; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.tuner.TunerService; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.inject.Inject; + +/** Controller for a {@link KeyguardSliceView}. */ +@KeyguardStatusViewScope +public class KeyguardSliceViewController implements Dumpable { + private static final String TAG = "KeyguardSliceViewCtrl"; + + private final KeyguardSliceView mView; + private final KeyguardStatusView mKeyguardStatusView; + private final ActivityStarter mActivityStarter; + private final ConfigurationController mConfigurationController; + private final TunerService mTunerService; + private final DumpManager mDumpManager; + private int mDisplayId; + private LiveData<Slice> mLiveData; + private Uri mKeyguardSliceUri; + private Slice mSlice; + private Map<View, PendingIntent> mClickActions; + + private final View.OnAttachStateChangeListener mOnAttachStateChangeListener = + new View.OnAttachStateChangeListener() { + + @Override + public void onViewAttachedToWindow(View v) { + + Display display = mView.getDisplay(); + if (display != null) { + mDisplayId = display.getDisplayId(); + } + mTunerService.addTunable(mTunable, Settings.Secure.KEYGUARD_SLICE_URI); + // Make sure we always have the most current slice + if (mDisplayId == DEFAULT_DISPLAY && mLiveData != null) { + mLiveData.observeForever(mObserver); + } + mConfigurationController.addCallback(mConfigurationListener); + mDumpManager.registerDumpable(TAG, KeyguardSliceViewController.this); + } + + @Override + public void onViewDetachedFromWindow(View v) { + + // TODO(b/117344873) Remove below work around after this issue be fixed. + if (mDisplayId == DEFAULT_DISPLAY) { + mLiveData.removeObserver(mObserver); + } + mTunerService.removeTunable(mTunable); + mConfigurationController.removeCallback(mConfigurationListener); + mDumpManager.unregisterDumpable(TAG); + } + }; + + TunerService.Tunable mTunable = (key, newValue) -> setupUri(newValue); + + ConfigurationController.ConfigurationListener mConfigurationListener = + new ConfigurationController.ConfigurationListener() { + @Override + public void onDensityOrFontScaleChanged() { + mView.onDensityOrFontScaleChanged(); + } + }; + + Observer<Slice> mObserver = new Observer<Slice>() { + @Override + public void onChanged(Slice slice) { + mSlice = slice; + showSlice(slice); + } + }; + + private View.OnClickListener mOnClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + final PendingIntent action = mClickActions.get(v); + if (action != null && mActivityStarter != null) { + mActivityStarter.startPendingIntentDismissingKeyguard(action); + } + } + }; + + @Inject + public KeyguardSliceViewController(KeyguardSliceView keyguardSliceView, + KeyguardStatusView keyguardStatusView, ActivityStarter activityStarter, + ConfigurationController configurationController, TunerService tunerService, + DumpManager dumpManager) { + mView = keyguardSliceView; + mKeyguardStatusView = keyguardStatusView; + mActivityStarter = activityStarter; + mConfigurationController = configurationController; + mTunerService = tunerService; + mDumpManager = dumpManager; + } + + /** Initialize the controller. */ + public void init() { + if (mView.isAttachedToWindow()) { + mOnAttachStateChangeListener.onViewAttachedToWindow(mView); + } + mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener); + mView.setOnClickListener(mOnClickListener); + // TODO: remove the line below. + mKeyguardStatusView.setKeyguardSliceViewController(this); + } + + /** + * Sets the slice provider Uri. + */ + public void setupUri(String uriString) { + if (uriString == null) { + uriString = KeyguardSliceProvider.KEYGUARD_SLICE_URI; + } + + boolean wasObserving = false; + if (mLiveData != null && mLiveData.hasActiveObservers()) { + wasObserving = true; + mLiveData.removeObserver(mObserver); + } + + mKeyguardSliceUri = Uri.parse(uriString); + mLiveData = SliceLiveData.fromUri(mView.getContext(), mKeyguardSliceUri); + + if (wasObserving) { + mLiveData.observeForever(mObserver); + } + } + + /** + * Update contents of the view. + */ + public void refresh() { + Slice slice; + Trace.beginSection("KeyguardSliceViewController#refresh"); + // We can optimize performance and avoid binder calls when we know that we're bound + // to a Slice on the same process. + if (KeyguardSliceProvider.KEYGUARD_SLICE_URI.equals(mKeyguardSliceUri.toString())) { + KeyguardSliceProvider instance = KeyguardSliceProvider.getAttachedInstance(); + if (instance != null) { + slice = instance.onBindSlice(mKeyguardSliceUri); + } else { + Log.w(TAG, "Keyguard slice not bound yet?"); + slice = null; + } + } else { + // TODO: Make SliceViewManager injectable + slice = SliceViewManager.getInstance(mView.getContext()).bindSlice(mKeyguardSliceUri); + } + mObserver.onChanged(slice); + Trace.endSection(); + } + + void showSlice(Slice slice) { + Trace.beginSection("KeyguardSliceViewController#showSlice"); + if (slice == null) { + mView.hideSlice(); + Trace.endSection(); + return; + } + + ListContent lc = new ListContent(slice); + RowContent headerContent = lc.getHeader(); + boolean hasHeader = + headerContent != null && !headerContent.getSliceItem().hasHint(HINT_LIST_ITEM); + + List<SliceContent> subItems = lc.getRowItems().stream().filter(sliceContent -> { + String itemUri = sliceContent.getSliceItem().getSlice().getUri().toString(); + // Filter out the action row + return !KeyguardSliceProvider.KEYGUARD_ACTION_URI.equals(itemUri); + }).collect(Collectors.toList()); + + + mClickActions = mView.showSlice(hasHeader ? headerContent : null, subItems); + + Trace.endSection(); + } + + + @Override + public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { + pw.println(" mSlice: " + mSlice); + pw.println(" mClickActions: " + mClickActions); + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java index 4c6aafb0058a..6e111745627f 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java @@ -32,7 +32,6 @@ import android.util.Slog; import android.util.TypedValue; import android.view.View; import android.widget.GridLayout; -import android.widget.LinearLayout; import android.widget.TextView; import androidx.core.graphics.ColorUtils; @@ -56,7 +55,6 @@ public class KeyguardStatusView extends GridLayout implements private final LockPatternUtils mLockPatternUtils; private final IActivityManager mIActivityManager; - private LinearLayout mStatusViewContainer; private TextView mLogoutView; private KeyguardClockSwitch mClockView; private TextView mOwnerInfo; @@ -64,6 +62,7 @@ public class KeyguardStatusView extends GridLayout implements private View mNotificationIcons; private Runnable mPendingMarqueeStart; private Handler mHandler; + private KeyguardSliceViewController mKeyguardSliceViewController; private boolean mPulsing; private float mDarkAmount = 0; @@ -179,7 +178,6 @@ public class KeyguardStatusView extends GridLayout implements @Override protected void onFinishInflate() { super.onFinishInflate(); - mStatusViewContainer = findViewById(R.id.status_view_container); mLogoutView = findViewById(R.id.logout); mNotificationIcons = findViewById(R.id.clock_notification_icon_container); if (mLogoutView != null) { @@ -250,7 +248,7 @@ public class KeyguardStatusView extends GridLayout implements public void dozeTimeTick() { refreshTime(); - mKeyguardSlice.refresh(); + mKeyguardSliceViewController.refresh(); } private void refreshTime() { @@ -456,4 +454,9 @@ public class KeyguardStatusView extends GridLayout implements Log.e(TAG, "Failed to logout user", re); } } + + // TODO: remove this method when a controller is available. + void setKeyguardSliceViewController(KeyguardSliceViewController keyguardSliceViewController) { + mKeyguardSliceViewController = keyguardSliceViewController; + } } diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java new file mode 100644 index 000000000000..21ccff707d34 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.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.keyguard.dagger; + +import com.android.keyguard.KeyguardClockSwitchController; +import com.android.keyguard.KeyguardStatusView; + +import dagger.BindsInstance; +import dagger.Subcomponent; + +/** + * Subcomponent for helping work with KeyguardStatusView and its children. + */ +@Subcomponent(modules = {KeyguardStatusViewModule.class}) +@KeyguardStatusViewScope +public interface KeyguardStatusViewComponent { + /** Simple factory for {@link KeyguardStatusViewComponent}. */ + @Subcomponent.Factory + interface Factory { + KeyguardStatusViewComponent build(@BindsInstance KeyguardStatusView presentation); + } + + /** Builds a {@link com.android.keyguard.KeyguardClockSwitchController}. */ + KeyguardClockSwitchController getKeyguardClockSwitchController(); +} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewModule.java new file mode 100644 index 000000000000..1d51e5925de8 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewModule.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.keyguard.dagger; + +import com.android.keyguard.KeyguardClockSwitch; +import com.android.keyguard.KeyguardSliceView; +import com.android.keyguard.KeyguardStatusView; +import com.android.systemui.R; + +import dagger.Module; +import dagger.Provides; + +/** Dagger module for {@link KeyguardStatusViewComponent}. */ +@Module +public abstract class KeyguardStatusViewModule { + @Provides + static KeyguardClockSwitch getKeyguardClockSwitch(KeyguardStatusView keyguardPresentation) { + return keyguardPresentation.findViewById(R.id.keyguard_clock_container); + } + + @Provides + static KeyguardSliceView getKeyguardSliceView(KeyguardClockSwitch keyguardClockSwitch) { + return keyguardClockSwitch.findViewById(R.id.keyguard_status_area); + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java new file mode 100644 index 000000000000..880822aa7343 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.keyguard.dagger; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Scope; + +/** + * Scope annotation for singleton items within the StatusBarComponent. + */ +@Documented +@Retention(RUNTIME) +@Scope +public @interface KeyguardStatusViewScope {} diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java index 47066a05b9b8..e91284b546db 100644 --- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java @@ -16,6 +16,8 @@ package com.android.systemui; +import static com.android.systemui.classifier.Classifier.NOTIFICATION_DISMISS; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; @@ -696,14 +698,15 @@ public class SwipeHelper implements Gefingerpoken { float translation = getTranslation(mCurrView); return ev.getActionMasked() == MotionEvent.ACTION_UP && !mFalsingManager.isUnlockingDisabled() - && !isFalseGesture(ev) && (swipedFastEnough() || swipedFarEnough()) + && !isFalseGesture() && (swipedFastEnough() || swipedFarEnough()) && mCallback.canChildBeDismissedInDirection(mCurrView, translation > 0); } - public boolean isFalseGesture(MotionEvent ev) { + /** Returns true if the gesture should be rejected. */ + public boolean isFalseGesture() { boolean falsingDetected = mCallback.isAntiFalsingNeeded(); if (mFalsingManager.isClassifierEnabled()) { - falsingDetected = falsingDetected && mFalsingManager.isFalseTouch(); + falsingDetected = falsingDetected && mFalsingManager.isFalseTouch(NOTIFICATION_DISMISS); } else { falsingDetected = falsingDetected && !mTouchAboveFalsingThreshold; } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java index 646e62062dfb..6961b45c3c37 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java @@ -70,7 +70,7 @@ public class FalsingManagerFake implements FalsingManager { } @Override - public boolean isFalseTouch() { + public boolean isFalseTouch(@Classifier.InteractionType int interactionType) { return mIsFalseTouch; } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java index cc64fb53f15f..decaec10e572 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java @@ -262,7 +262,7 @@ public class FalsingManagerImpl implements FalsingManager { /** * @return true if the classifier determined that this is not a human interacting with the phone */ - public boolean isFalseTouch() { + public boolean isFalseTouch(@Classifier.InteractionType int interactionType) { if (FalsingLog.ENABLED) { // We're getting some false wtfs from touches that happen after the device went // to sleep. Only report missing sessions that happen when the device is interactive. diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java index 83b6df3e701b..2c31862e9b79 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java @@ -187,8 +187,8 @@ public class FalsingManagerProxy implements FalsingManager, Dumpable { } @Override - public boolean isFalseTouch() { - return mInternalFalsingManager.isFalseTouch(); + public boolean isFalseTouch(@Classifier.InteractionType int interactionType) { + return mInternalFalsingManager.isFalseTouch(interactionType); } @Override 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 a50f9ce9713b..9d847ca62465 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java @@ -189,7 +189,8 @@ public class BrightLineFalsingManager implements FalsingManager { } @Override - public boolean isFalseTouch() { + public boolean isFalseTouch(@Classifier.InteractionType int interactionType) { + mDataProvider.setInteractionType(interactionType); if (!mDataProvider.isDirty()) { return mPreviousResult; } 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 ea46441c8fbe..8d067489a8cc 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingDataProvider.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingDataProvider.java @@ -116,7 +116,10 @@ public class FalsingDataProvider { * interactionType is defined by {@link com.android.systemui.classifier.Classifier}. */ final void setInteractionType(@Classifier.InteractionType int interactionType) { - this.mInteractionType = interactionType; + if (mInteractionType != interactionType) { + mInteractionType = interactionType; + mDirty = true; + } } public boolean isDirty() { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java index 8a67e968ae13..0dd9488f1d3e 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java @@ -18,6 +18,8 @@ package com.android.systemui.dagger; import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME; +import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.app.INotificationManager; import android.content.Context; import android.content.SharedPreferences; @@ -26,6 +28,7 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.ServiceManager; +import android.os.UserHandle; import android.util.DisplayMetrics; import android.view.Choreographer; import android.view.IWindowManager; @@ -39,6 +42,7 @@ import com.android.internal.logging.UiEventLoggerImpl; import com.android.internal.util.NotificationMessagingUtil; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.ViewMediatorCallback; +import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.systemui.Prefs; import com.android.systemui.accessibility.ModeSwitchesController; import com.android.systemui.accessibility.SystemActions; @@ -88,7 +92,7 @@ import dagger.Provides; * Provides dependencies for the root component of sysui injection. * * Only SystemUI owned classes and instances should go in here. Other, framework-owned classes - * should go in {@link SystemServicesModule}. + * should go in {@link FrameworkServicesModule}. * * See SystemUI/docs/dagger.md */ @@ -163,6 +167,15 @@ public class DependencyProvider { } + @SuppressLint("MissingPermission") + @SysUISingleton + @Provides + @Nullable + static LocalBluetoothManager provideLocalBluetoothController(Context context, + @Background Handler bgHandler) { + return LocalBluetoothManager.create(context, bgHandler, UserHandle.ALL); + } + /** */ @Provides @SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java index ceb9aeee1d3b..66063a87a70d 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java @@ -17,7 +17,6 @@ package com.android.systemui.dagger; import android.annotation.Nullable; -import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.app.AlarmManager; @@ -49,10 +48,8 @@ import android.net.ConnectivityManager; import android.net.NetworkScoreManager; import android.net.wifi.WifiManager; import android.os.BatteryStats; -import android.os.Handler; import android.os.PowerManager; import android.os.ServiceManager; -import android.os.UserHandle; import android.os.UserManager; import android.os.Vibrator; import android.service.dreams.DreamService; @@ -68,12 +65,12 @@ import android.view.accessibility.AccessibilityManager; import com.android.internal.app.IBatteryStats; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.util.LatencyTracker; -import com.android.settingslib.bluetooth.LocalBluetoothManager; -import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.DisplayId; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.shared.system.PackageManagerWrapper; +import javax.inject.Singleton; + import dagger.Module; import dagger.Provides; @@ -81,51 +78,51 @@ import dagger.Provides; * Provides Non-SystemUI, Framework-Owned instances to the dependency graph. */ @Module -public class SystemServicesModule { +public class FrameworkServicesModule { @Provides - @SysUISingleton + @Singleton static AccessibilityManager provideAccessibilityManager(Context context) { return context.getSystemService(AccessibilityManager.class); } @Provides - @SysUISingleton + @Singleton static ActivityManager provideActivityManager(Context context) { return context.getSystemService(ActivityManager.class); } - @SysUISingleton @Provides + @Singleton static AlarmManager provideAlarmManager(Context context) { return context.getSystemService(AlarmManager.class); } @Provides - @SysUISingleton + @Singleton static AudioManager provideAudioManager(Context context) { return context.getSystemService(AudioManager.class); } @Provides - @SysUISingleton + @Singleton static ColorDisplayManager provideColorDisplayManager(Context context) { return context.getSystemService(ColorDisplayManager.class); } @Provides - @SysUISingleton + @Singleton static ConnectivityManager provideConnectivityManagager(Context context) { return context.getSystemService(ConnectivityManager.class); } @Provides - @SysUISingleton + @Singleton static ContentResolver provideContentResolver(Context context) { return context.getContentResolver(); } @Provides - @SysUISingleton + @Singleton static DevicePolicyManager provideDevicePolicyManager(Context context) { return context.getSystemService(DevicePolicyManager.class); } @@ -137,39 +134,39 @@ public class SystemServicesModule { } @Provides - @SysUISingleton + @Singleton static DisplayManager provideDisplayManager(Context context) { return context.getSystemService(DisplayManager.class); } - @SysUISingleton @Provides + @Singleton static IActivityManager provideIActivityManager() { return ActivityManager.getService(); } - @SysUISingleton @Provides + @Singleton static IActivityTaskManager provideIActivityTaskManager() { return ActivityTaskManager.getService(); } @Provides - @SysUISingleton + @Singleton static IBatteryStats provideIBatteryStats() { return IBatteryStats.Stub.asInterface( ServiceManager.getService(BatteryStats.SERVICE_NAME)); } @Provides - @SysUISingleton + @Singleton static IDreamManager provideIDreamManager() { return IDreamManager.Stub.asInterface( ServiceManager.checkService(DreamService.DREAM_SERVICE)); } @Provides - @SysUISingleton + @Singleton @Nullable static FaceManager provideFaceManager(Context context) { return context.getSystemService(FaceManager.class); @@ -177,13 +174,13 @@ public class SystemServicesModule { } @Provides - @SysUISingleton + @Singleton static IPackageManager provideIPackageManager() { return IPackageManager.Stub.asInterface(ServiceManager.getService("package")); } - @SysUISingleton @Provides + @Singleton static IStatusBarService provideIStatusBarService() { return IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); @@ -196,39 +193,30 @@ public class SystemServicesModule { ServiceManager.getService(Context.WALLPAPER_SERVICE)); } - @SysUISingleton @Provides + @Singleton static IWindowManager provideIWindowManager() { return WindowManagerGlobal.getWindowManagerService(); } - @SysUISingleton @Provides + @Singleton static KeyguardManager provideKeyguardManager(Context context) { return context.getSystemService(KeyguardManager.class); } - @SysUISingleton @Provides + @Singleton static LatencyTracker provideLatencyTracker(Context context) { return LatencyTracker.getInstance(context); } - @SysUISingleton @Provides + @Singleton static LauncherApps provideLauncherApps(Context context) { return context.getSystemService(LauncherApps.class); } - @SuppressLint("MissingPermission") - @SysUISingleton - @Provides - @Nullable - static LocalBluetoothManager provideLocalBluetoothController(Context context, - @Background Handler bgHandler) { - return LocalBluetoothManager.create(context, bgHandler, UserHandle.ALL); - } - @Provides static MediaRouter2Manager provideMediaRouter2Manager(Context context) { return MediaRouter2Manager.getInstance(context); @@ -240,32 +228,32 @@ public class SystemServicesModule { } @Provides - @SysUISingleton + @Singleton static NetworkScoreManager provideNetworkScoreManager(Context context) { return context.getSystemService(NetworkScoreManager.class); } - @SysUISingleton @Provides + @Singleton static NotificationManager provideNotificationManager(Context context) { return context.getSystemService(NotificationManager.class); } - @SysUISingleton @Provides + @Singleton static PackageManager providePackageManager(Context context) { return context.getPackageManager(); } - @SysUISingleton @Provides + @Singleton static PackageManagerWrapper providePackageManagerWrapper() { return PackageManagerWrapper.getInstance(); } /** */ - @SysUISingleton @Provides + @Singleton static PowerManager providePowerManager(Context context) { return context.getSystemService(PowerManager.class); } @@ -277,57 +265,63 @@ public class SystemServicesModule { } @Provides - @SysUISingleton + @Singleton + static RoleManager provideRoleManager(Context context) { + return context.getSystemService(RoleManager.class); + } + + @Provides + @Singleton static SensorManager providesSensorManager(Context context) { return context.getSystemService(SensorManager.class); } - @SysUISingleton @Provides + @Singleton static SensorPrivacyManager provideSensorPrivacyManager(Context context) { return context.getSystemService(SensorPrivacyManager.class); } - @SysUISingleton @Provides + @Singleton static ShortcutManager provideShortcutManager(Context context) { return context.getSystemService(ShortcutManager.class); } @Provides - @SysUISingleton + @Singleton @Nullable static TelecomManager provideTelecomManager(Context context) { return context.getSystemService(TelecomManager.class); } @Provides - @SysUISingleton + @Singleton static TelephonyManager provideTelephonyManager(Context context) { return context.getSystemService(TelephonyManager.class); } @Provides - @SysUISingleton + @Singleton static TrustManager provideTrustManager(Context context) { return context.getSystemService(TrustManager.class); } @Provides - @SysUISingleton + @Singleton @Nullable static Vibrator provideVibrator(Context context) { return context.getSystemService(Vibrator.class); } @Provides - @SysUISingleton + @Singleton static ViewConfiguration provideViewConfiguration(Context context) { return ViewConfiguration.get(context); } @Provides - @SysUISingleton + @Singleton static UserManager provideUserManager(Context context) { return context.getSystemService(UserManager.class); } @@ -338,21 +332,15 @@ public class SystemServicesModule { } @Provides - @SysUISingleton + @Singleton @Nullable static WifiManager provideWifiManager(Context context) { return context.getSystemService(WifiManager.class); } - @SysUISingleton @Provides + @Singleton static WindowManager provideWindowManager(Context context) { return context.getSystemService(WindowManager.class); } - - @Provides - @SysUISingleton - static RoleManager provideRoleManager(Context context) { - return context.getSystemService(RoleManager.class); - } } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java index 553655bf672c..fd4a4093110f 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java @@ -16,63 +16,23 @@ package com.android.systemui.dagger; -import android.content.Context; -import android.content.SharedPreferences; -import android.hardware.display.AmbientDisplayConfiguration; -import android.util.DisplayMetrics; -import android.view.Choreographer; - -import com.android.systemui.Prefs; -import com.android.systemui.dagger.qualifiers.Main; - -import javax.inject.Singleton; - import dagger.Module; -import dagger.Provides; /** - * Supplies globally scoped instances. + * Supplies globally scoped instances that should be available in all versions of SystemUI * * Providers in this module will be accessible to both WMComponent and SysUIComponent scoped * classes. They are in here because they are either needed globally or are inherently universal * to the application. * * Note that just because a class might be used by both WM and SysUI does not necessarily mean that - * it should got into this module. If WM and SysUI might need the class for different purposes + * it should go into this module. If WM and SysUI might need the class for different purposes * or different semantics, it may make sense to ask them to supply their own. Something like * threading and concurrency provide a good example. Both components need * Threads/Handlers/Executors, but they need separate instances of them in many cases. * * Please use discretion when adding things to the global scope. */ -@Module +@Module(includes = {FrameworkServicesModule.class}) public class GlobalModule { - /** */ - @Provides - @Main - public SharedPreferences provideSharePreferences(Context context) { - return Prefs.get(context); - } - - /** */ - @Provides - public AmbientDisplayConfiguration provideAmbientDisplayConfiguration(Context context) { - return new AmbientDisplayConfiguration(context); - } - - /** */ - @Provides - @Singleton - public Choreographer providesChoreographer() { - return Choreographer.getInstance(); - } - - /** */ - @Provides - @Singleton - public DisplayMetrics provideDisplayMetrics(Context context) { - DisplayMetrics displayMetrics = new DisplayMetrics(); - context.getDisplay().getMetrics(displayMetrics); - return displayMetrics; - } } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java index 3d7c8ad4c43e..36fd3373290d 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java @@ -28,6 +28,7 @@ import dagger.Component; */ @Singleton @Component(modules = { + GlobalModule.class, SysUISubcomponentModule.class, WMModule.class}) public interface GlobalRootComponent { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java index b606201cc803..e4e3d7aacdf0 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java @@ -37,7 +37,6 @@ import dagger.Subcomponent; DependencyProvider.class, DependencyBinder.class, PipModule.class, - SystemServicesModule.class, SystemUIBinder.class, SystemUIModule.class, SystemUIDefaultModule.class}) diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index e38dce05a32e..8364b486c8d7 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -262,11 +262,11 @@ public class DozeTriggers implements DozeMachine.Part { onWakeScreen(wakeEvent, mMachine.isExecutingTransition() ? null : mMachine.getState()); } else if (isLongPress) { requestPulse(pulseReason, true /* alreadyPerformedProxCheck */, - null /* onPulseSupressedListener */); + null /* onPulseSuppressedListener */); } else if (isWakeLockScreen) { if (wakeEvent) { requestPulse(pulseReason, true /* alreadyPerformedProxCheck */, - null /* onPulseSupressedListener */); + null /* onPulseSuppressedListener */); } } else { proximityCheckThenCall((result) -> { @@ -536,7 +536,7 @@ public class DozeTriggers implements DozeMachine.Part { if (PULSE_ACTION.equals(intent.getAction())) { if (DozeMachine.DEBUG) Log.d(TAG, "Received pulse intent"); requestPulse(DozeLog.PULSE_REASON_INTENT, false, /* performedProxCheck */ - null /* onPulseSupressedListener */); + null /* onPulseSuppressedListener */); } if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) { mMachine.requestState(DozeMachine.State.FINISH); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 6214a6448287..33407918f938 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -89,15 +89,14 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.dagger.KeyguardModule; +import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.phone.BiometricUnlockController; import com.android.systemui.statusbar.phone.KeyguardBypassController; -import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.statusbar.phone.NotificationPanelViewController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.util.DeviceConfigProxy; -import com.android.systemui.util.InjectionInflationController; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -228,7 +227,6 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { /** TrustManager for letting it know when we change visibility */ private final TrustManager mTrustManager; - private final InjectionInflationController mInjectionInflationController; /** * Used to keep the device awake while to ensure the keyguard finishes opening before @@ -345,7 +343,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { /** * For managing external displays */ - private KeyguardDisplayManager mKeyguardDisplayManager; + private final KeyguardDisplayManager mKeyguardDisplayManager; private final ArrayList<IKeyguardStateCallback> mKeyguardStateCallbacks = new ArrayList<>(); @@ -724,7 +722,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { TrustManager trustManager, DeviceConfigProxy deviceConfig, NavigationModeController navigationModeController, - InjectionInflationController injectionInflationController) { + KeyguardDisplayManager keyguardDisplayManager) { super(context); mFalsingManager = falsingManager; mLockPatternUtils = lockPatternUtils; @@ -735,7 +733,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { mUpdateMonitor = keyguardUpdateMonitor; mPM = powerManager; mTrustManager = trustManager; - mInjectionInflationController = injectionInflationController; + mKeyguardDisplayManager = keyguardDisplayManager; dumpManager.registerDumpable(getClass().getName(), this); mDeviceConfig = deviceConfig; mShowHomeOverLockscreen = mDeviceConfig.getBoolean( @@ -775,9 +773,6 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { mContext.registerReceiver(mDelayedLockBroadcastReceiver, delayedActionFilter, SYSTEMUI_PERMISSION, null /* scheduler */); - mKeyguardDisplayManager = new KeyguardDisplayManager(mContext, - mInjectionInflationController); - mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); KeyguardUpdateMonitor.setCurrentUser(ActivityManager.getCurrentUser()); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index c9164f0c4459..9d8e73a0ff47 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -26,8 +26,10 @@ import android.os.Handler; import android.os.PowerManager; import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardDisplayManager; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardViewController; +import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; @@ -43,7 +45,6 @@ import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.KeyguardLiftController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.util.DeviceConfigProxy; -import com.android.systemui.util.InjectionInflationController; import com.android.systemui.util.sensors.AsyncSensorManager; import com.android.systemui.util.settings.GlobalSettings; import com.android.systemui.util.settings.SystemSettings; @@ -58,7 +59,7 @@ import dagger.Provides; /** * Dagger Module providing {@link StatusBar}. */ -@Module +@Module(subcomponents = {KeyguardStatusViewComponent.class}) public class KeyguardModule { /** * Provides our instance of KeyguardViewMediator which is considered optional. @@ -79,7 +80,7 @@ public class KeyguardModule { @UiBackground Executor uiBgExecutor, DeviceConfigProxy deviceConfig, NavigationModeController navigationModeController, - InjectionInflationController injectionInflationController) { + KeyguardDisplayManager keyguardDisplayManager) { return new KeyguardViewMediator( context, falsingManager, @@ -94,7 +95,8 @@ public class KeyguardModule { trustManager, deviceConfig, navigationModeController, - injectionInflationController); + keyguardDisplayManager + ); } @SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt index 77cac5023db3..486399979db7 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt @@ -30,6 +30,7 @@ import com.android.settingslib.Utils import com.android.systemui.Gefingerpoken import com.android.systemui.qs.PageIndicator import com.android.systemui.R +import com.android.systemui.classifier.Classifier.NOTIFICATION_DISMISS import com.android.systemui.plugins.FalsingManager import com.android.systemui.util.animation.PhysicsAnimator import com.android.systemui.util.concurrency.DelayableExecutor @@ -315,7 +316,8 @@ class MediaCarouselScrollHandler( return false } - private fun isFalseTouch() = falsingProtectionNeeded && falsingManager.isFalseTouch + private fun isFalseTouch() = falsingProtectionNeeded && + falsingManager.isFalseTouch(NOTIFICATION_DISMISS) private fun getMaxTranslation() = if (showsSettingsButton) { settingsButton.width diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java index 214088c99eeb..70374036ef14 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java @@ -36,8 +36,8 @@ import javax.inject.Inject; * Activity to show the PIP menu to control PIP. */ public class PipMenuActivity extends Activity implements PipManager.Listener { - private static final boolean DEBUG = false; private static final String TAG = "PipMenuActivity"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); static final String EXTRA_CUSTOM_ACTIONS = "custom_actions"; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java index 4fa782269c2d..e61e05a7dc2f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar; +import static com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; @@ -163,7 +165,7 @@ public class DragDownHelper implements Gefingerpoken { if (!mDragDownCallback.isFalsingCheckNeeded()) { return false; } - return mFalsingManager.isFalseTouch() || !mDraggedFarEnough; + return mFalsingManager.isFalseTouch(NOTIFICATION_DRAG_DOWN) || !mDraggedFarEnough; } private void captureStartingChild(float x, float y) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt index ba54d1bff6e8..6fa3633acc43 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt @@ -30,6 +30,7 @@ import android.view.ViewConfiguration import com.android.systemui.Gefingerpoken import com.android.systemui.Interpolators import com.android.systemui.R +import com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN import com.android.systemui.dagger.SysUISingleton import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.statusbar.StatusBarStateController @@ -106,7 +107,7 @@ constructor( private var velocityTracker: VelocityTracker? = null private val isFalseTouch: Boolean - get() = falsingManager.isFalseTouch + get() = falsingManager.isFalseTouch(NOTIFICATION_DRAG_DOWN) var qsExpanded: Boolean = false var pulseExpandAbortListener: Runnable? = null var bouncerShowing: Boolean = false 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 1e80e88df1a1..ba01c8420ef2 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 @@ -227,7 +227,7 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc || (isFastNonDismissGesture && isAbleToShowMenu); int menuSnapTarget = menuRow.getMenuSnapTarget(); boolean isNonFalseMenuRevealingGesture = - !isFalseGesture(ev) && isMenuRevealingGestureAwayFromMenu; + !isFalseGesture() && isMenuRevealingGestureAwayFromMenu; if ((isNonDismissGestureTowardsMenu || isNonFalseMenuRevealingGesture) && menuSnapTarget != 0) { // Menu has not been snapped to previously and this is menu revealing gesture diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java index 858023dc6c62..ba9420265849 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java @@ -27,6 +27,7 @@ import android.view.ViewConfiguration; import com.android.systemui.Interpolators; import com.android.systemui.R; +import com.android.systemui.classifier.Classifier; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.KeyguardAffordanceView; @@ -317,7 +318,9 @@ public class KeyguardAffordanceHelper { // We snap back if the current translation is not far enough boolean snapBack = false; if (mCallback.needsAntiFalsing()) { - snapBack = snapBack || mFalsingManager.isFalseTouch(); + snapBack = snapBack || mFalsingManager.isFalseTouch( + mTargetedView == mRightIcon + ? Classifier.RIGHT_AFFORDANCE : Classifier.LEFT_AFFORDANCE); } snapBack = snapBack || isBelowFalsingThreshold(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index d83758a57401..e0576b7d5904 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone; import static android.view.View.GONE; +import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS; import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL; @@ -68,9 +69,11 @@ import com.android.keyguard.KeyguardClockSwitchController; import com.android.keyguard.KeyguardStatusView; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; +import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.systemui.DejankUtils; import com.android.systemui.Interpolators; import com.android.systemui.R; +import com.android.systemui.classifier.Classifier; import com.android.systemui.dagger.qualifiers.DisplayId; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.doze.DozeLog; @@ -129,7 +132,6 @@ import java.util.function.Consumer; import java.util.function.Function; import javax.inject.Inject; -import javax.inject.Provider; @StatusBarComponent.StatusBarScope public class NotificationPanelViewController extends PanelViewController { @@ -260,7 +262,7 @@ public class NotificationPanelViewController extends PanelViewController { private final ConversationNotificationManager mConversationNotificationManager; private final MediaHierarchyManager mMediaHierarchyManager; private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; - private final Provider<KeyguardClockSwitchController> mKeyguardClockSwitchControllerProvider; + private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; // Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card. // If there are exactly 1 + mMaxKeyguardNotifications, then still shows all notifications private final int mMaxKeyguardNotifications; @@ -511,9 +513,9 @@ public class NotificationPanelViewController extends PanelViewController { MediaHierarchyManager mediaHierarchyManager, BiometricUnlockController biometricUnlockController, StatusBarKeyguardViewManager statusBarKeyguardViewManager, - Provider<KeyguardClockSwitchController> keyguardClockSwitchControllerProvider, NotificationStackScrollLayoutController notificationStackScrollLayoutController, - NotificationIconAreaController notificationIconAreaController) { + NotificationIconAreaController notificationIconAreaController, + KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory) { super(view, falsingManager, dozeLog, keyguardStateController, (SysuiStatusBarStateController) statusBarStateController, vibratorHelper, latencyTracker, flingAnimationUtilsBuilder, statusBarTouchableRegionManager); @@ -525,9 +527,9 @@ public class NotificationPanelViewController extends PanelViewController { mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder; mMediaHierarchyManager = mediaHierarchyManager; mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; - mKeyguardClockSwitchControllerProvider = keyguardClockSwitchControllerProvider; mNotificationStackScrollLayoutController = notificationStackScrollLayoutController; mNotificationIconAreaController = notificationIconAreaController; + mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory; mView.setWillNotDraw(!DEBUG); mInjectionInflationController = injectionInflationController; mFalsingManager = falsingManager; @@ -602,8 +604,10 @@ public class NotificationPanelViewController extends PanelViewController { mKeyguardStatusView = mView.findViewById(R.id.keyguard_status_view); KeyguardClockSwitchController keyguardClockSwitchController = - mKeyguardClockSwitchControllerProvider.get(); - keyguardClockSwitchController.attach(mView.findViewById(R.id.keyguard_clock_container)); + mKeyguardStatusViewComponentFactory + .build(mKeyguardStatusView) + .getKeyguardClockSwitchController(); + keyguardClockSwitchController.init(); mBigClockContainer = mView.findViewById(R.id.big_clock_container); keyguardClockSwitchController.setBigClockContainer(mBigClockContainer); @@ -733,8 +737,10 @@ public class NotificationPanelViewController extends PanelViewController { // Re-associate the clock container with the keyguard clock switch. mBigClockContainer.removeAllViews(); KeyguardClockSwitchController keyguardClockSwitchController = - mKeyguardClockSwitchControllerProvider.get(); - keyguardClockSwitchController.attach(mView.findViewById(R.id.keyguard_clock_container)); + mKeyguardStatusViewComponentFactory + .build(mKeyguardStatusView) + .getKeyguardClockSwitchController(); + keyguardClockSwitchController.init(); keyguardClockSwitchController.setBigClockContainer(mBigClockContainer); // Update keyguard bottom area @@ -1264,7 +1270,7 @@ public class NotificationPanelViewController extends PanelViewController { } private boolean flingExpandsQs(float vel) { - if (mFalsingManager.isUnlockingDisabled() || isFalseTouch()) { + if (mFalsingManager.isUnlockingDisabled() || isFalseTouch(QUICK_SETTINGS)) { return false; } if (Math.abs(vel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) { @@ -1274,12 +1280,12 @@ public class NotificationPanelViewController extends PanelViewController { } } - private boolean isFalseTouch() { + private boolean isFalseTouch(@Classifier.InteractionType int interactionType) { if (!mKeyguardAffordanceHelperCallback.needsAntiFalsing()) { return false; } if (mFalsingManager.isClassifierEnabled()) { - return mFalsingManager.isFalseTouch(); + return mFalsingManager.isFalseTouch(interactionType); } return !mQsTouchAboveFalsingThreshold; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java index 965368e78e69..0e72506c6d94 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -16,6 +16,10 @@ package com.android.systemui.statusbar.phone; +import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK; +import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS; +import static com.android.systemui.classifier.Classifier.UNLOCK; + import static java.lang.Float.isNaN; import android.animation.Animator; @@ -41,6 +45,7 @@ import com.android.internal.util.LatencyTracker; import com.android.systemui.DejankUtils; import com.android.systemui.Interpolators; import com.android.systemui.R; +import com.android.systemui.classifier.Classifier; import com.android.systemui.doze.DozeLog; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.statusbar.FlingAnimationUtils; @@ -397,7 +402,12 @@ public abstract class PanelViewController { mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_UNLOCK, heightDp, velocityDp); mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_UNLOCK); } - fling(vel, expand, isFalseTouch(x, y)); + @Classifier.InteractionType int interactionType = vel > 0 + ? QUICK_SETTINGS : ( + mKeyguardStateController.canDismissLockScreen() + ? UNLOCK : BOUNCER_UNLOCK); + + fling(vel, expand, isFalseTouch(x, y, interactionType)); onTrackingStopped(expand); mUpdateFlingOnLayout = expand && mPanelClosedOnDown && !mHasLayoutedSinceDown; if (mUpdateFlingOnLayout) { @@ -492,7 +502,11 @@ public abstract class PanelViewController { return true; } - if (isFalseTouch(x, y)) { + @Classifier.InteractionType int interactionType = vel > 0 + ? QUICK_SETTINGS : ( + mKeyguardStateController.canDismissLockScreen() ? UNLOCK : BOUNCER_UNLOCK); + + if (isFalseTouch(x, y, interactionType)) { return true; } if (Math.abs(vectorVel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) { @@ -511,12 +525,13 @@ public abstract class PanelViewController { * @param y the final y-coordinate when the finger was lifted * @return whether this motion should be regarded as a false touch */ - private boolean isFalseTouch(float x, float y) { + private boolean isFalseTouch(float x, float y, + @Classifier.InteractionType int interactionType) { if (!mStatusBar.isFalsingThresholdNeeded()) { return false; } if (mFalsingManager.isClassifierEnabled()) { - return mFalsingManager.isFalseTouch(); + return mFalsingManager.isFalseTouch(interactionType); } if (!mTouchAboveFalsingThreshold) { return true; diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java index 37aac1124048..df741a0e98ff 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java +++ b/packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java @@ -16,7 +16,9 @@ package com.android.systemui.tv; +import com.android.systemui.dagger.GlobalModule; import com.android.systemui.dagger.GlobalRootComponent; +import com.android.systemui.dagger.WMModule; import javax.inject.Singleton; @@ -26,7 +28,11 @@ import dagger.Component; * Root component for Dagger injection. */ @Singleton -@Component(modules = {TvSysUIComponentModule.class}) +@Component(modules = { + GlobalModule.class, + TvSysUIComponentModule.class, + WMModule.class +}) public interface TvGlobalRootComponent extends GlobalRootComponent { /** * Component Builder interface. This allows to bind Context instance in the component diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java index 302301d79c3a..3577bc05d1c4 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java @@ -21,7 +21,6 @@ import com.android.systemui.dagger.DependencyBinder; import com.android.systemui.dagger.DependencyProvider; import com.android.systemui.dagger.SysUIComponent; import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.dagger.SystemServicesModule; import com.android.systemui.dagger.SystemUIBinder; import com.android.systemui.dagger.SystemUIModule; @@ -35,7 +34,6 @@ import dagger.Subcomponent; DefaultComponentBinder.class, DependencyProvider.class, DependencyBinder.class, - SystemServicesModule.class, SystemUIBinder.class, SystemUIModule.class, TvSystemUIModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java index d278905abacb..eb8f065149c8 100644 --- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java +++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java @@ -24,7 +24,6 @@ import android.view.LayoutInflater; import android.view.View; import com.android.keyguard.KeyguardMessageArea; -import com.android.keyguard.KeyguardSliceView; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.qs.QSFooterImpl; import com.android.systemui.qs.QSPanel; @@ -109,11 +108,6 @@ public class InjectionInflationController { NotificationStackScrollLayout createNotificationStackScrollLayout(); /** - * Creates the KeyguardSliceView. - */ - KeyguardSliceView createKeyguardSliceView(); - - /** * Creates the KeyguardMessageArea. */ KeyguardMessageArea createKeyguardMessageArea(); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java index 657e4fbb4633..3aa6ec08683f 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java @@ -62,6 +62,8 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase { private ClockPlugin mClockPlugin; @Mock ColorExtractor.GradientColors mGradientColors; + @Mock + KeyguardSliceViewController mKeyguardSliceViewController; private KeyguardClockSwitchController mController; @@ -69,28 +71,30 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase { public void setup() { MockitoAnnotations.initMocks(this); + when(mView.isAttachedToWindow()).thenReturn(true); + mController = new KeyguardClockSwitchController( - mStatusBarStateController, mColorExtractor, mClockManager); + mView, mStatusBarStateController, mColorExtractor, mClockManager, + mKeyguardSliceViewController); - when(mView.isAttachedToWindow()).thenReturn(true); when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE); when(mColorExtractor.getColors(anyInt())).thenReturn(mGradientColors); } @Test - public void testAttach_viewAlreadyAttached() { - mController.attach(mView); + public void testInit_viewAlreadyAttached() { + mController.init(); verifyAttachment(times(1)); } @Test - public void testAttach_viewNotYetAttached() { + public void testInit_viewNotYetAttached() { ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor = ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class); when(mView.isAttachedToWindow()).thenReturn(false); - mController.attach(mView); + mController.init(); verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture()); verifyAttachment(never()); @@ -100,12 +104,17 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase { verifyAttachment(times(1)); } + @Test + public void testInitSubControllers() { + mController.init(); + verify(mKeyguardSliceViewController).init(); + } @Test - public void testAttach_viewDetached() { + public void testInit_viewDetached() { ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor = ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class); - mController.attach(mView); + mController.init(); verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture()); verifyAttachment(times(1)); @@ -122,7 +131,7 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase { public void testBigClockPassesStatusBarState() { ViewGroup testView = new FrameLayout(mContext); - mController.attach(mView); + mController.init(); when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE); mController.setBigClockContainer(testView); verify(mView).setBigClockContainer(testView, StatusBarState.SHADE); @@ -143,7 +152,7 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase { ArgumentCaptor<ClockManager.ClockChangedListener> listenerArgumentCaptor = ArgumentCaptor.forClass(ClockManager.ClockChangedListener.class); - mController.attach(mView); + mController.init(); verify(mClockManager).addOnClockChangedListener(listenerArgumentCaptor.capture()); listenerArgumentCaptor.getValue().onClockChanged(mClockPlugin); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java index 446b1228f1bb..559284ac0672 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java @@ -16,6 +16,7 @@ package com.android.keyguard; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import android.content.Context; @@ -28,6 +29,7 @@ import android.view.View; import androidx.test.filters.SmallTest; import com.android.keyguard.KeyguardDisplayManager.KeyguardPresentation; +import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.systemui.R; import com.android.systemui.SystemUIFactory; import com.android.systemui.SysuiTestCase; @@ -51,6 +53,12 @@ public class KeyguardPresentationTest extends SysuiTestCase { KeyguardSliceView mMockKeyguardSliceView; @Mock KeyguardStatusView mMockKeyguardStatusView; + @Mock + private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; + @Mock + private KeyguardStatusViewComponent mKeyguardStatusViewComponent; + @Mock + private KeyguardClockSwitchController mKeyguardClockSwitchController; LayoutInflater mLayoutInflater; @@ -62,6 +70,11 @@ public class KeyguardPresentationTest extends SysuiTestCase { when(mMockKeyguardSliceView.getContext()).thenReturn(mContext); when(mMockKeyguardStatusView.getContext()).thenReturn(mContext); when(mMockKeyguardStatusView.findViewById(R.id.clock)).thenReturn(mMockKeyguardStatusView); + when(mKeyguardStatusViewComponentFactory.build(any(KeyguardStatusView.class))) + .thenReturn(mKeyguardStatusViewComponent); + when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController()) + .thenReturn(mKeyguardClockSwitchController); + allowTestableLooperAsMainThread(); InjectionInflationController inflationController = new InjectionInflationController( @@ -99,7 +112,8 @@ public class KeyguardPresentationTest extends SysuiTestCase { @Test public void testInflation_doesntCrash() { KeyguardPresentation keyguardPresentation = new KeyguardPresentation(mContext, - mContext.getDisplayNoVerify(), mLayoutInflater); + mContext.getDisplayNoVerify(), mKeyguardStatusViewComponentFactory, + mLayoutInflater); keyguardPresentation.onCreate(null /*savedInstanceState */); } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java new file mode 100644 index 000000000000..b7bcaa3c3566 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.keyguard; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper.RunWithLooper; +import android.view.View; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.dump.DumpManager; +import com.android.systemui.keyguard.KeyguardSliceProvider; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.tuner.TunerService; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@RunWithLooper(setAsMainLooper = true) +public class KeyguardSliceViewControllerTest extends SysuiTestCase { + @Mock + private KeyguardSliceView mView;; + @Mock + private KeyguardStatusView mKeyguardStatusView; + @Mock + private TunerService mTunerService; + @Mock + private ConfigurationController mConfigurationController; + @Mock + private ActivityStarter mActivityStarter; + private DumpManager mDumpManager = new DumpManager(); + + private KeyguardSliceViewController mController; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(mView.isAttachedToWindow()).thenReturn(true); + when(mView.getContext()).thenReturn(mContext); + mController = new KeyguardSliceViewController( + mView, mKeyguardStatusView, mActivityStarter, mConfigurationController, + mTunerService, mDumpManager); + mController.setupUri(KeyguardSliceProvider.KEYGUARD_SLICE_URI); + } + + @Test + public void refresh_replacesSliceContentAndNotifiesListener() { + mController.refresh(); + verify(mView).hideSlice(); + } + + @Test + public void onAttachedToWindow_registersListeners() { + mController.init(); + verify(mTunerService).addTunable(any(TunerService.Tunable.class), anyString()); + verify(mConfigurationController).addCallback( + any(ConfigurationController.ConfigurationListener.class)); + } + + @Test + public void onDetachedFromWindow_unregistersListeners() { + ArgumentCaptor<View.OnAttachStateChangeListener> attachListenerArgumentCaptor = + ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class); + + mController.init(); + verify(mView).addOnAttachStateChangeListener(attachListenerArgumentCaptor.capture()); + + attachListenerArgumentCaptor.getValue().onViewDetachedFromWindow(mView); + + verify(mTunerService).removeTunable(any(TunerService.Tunable.class)); + verify(mConfigurationController).removeCallback( + any(ConfigurationController.ConfigurationListener.class)); + } +} diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java index 06552b9bdbb4..1ab08c27088a 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java @@ -15,37 +15,27 @@ */ package com.android.keyguard; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.verify; - -import android.content.Context; -import android.content.res.Resources; import android.graphics.Color; import android.net.Uri; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; -import android.util.AttributeSet; import android.view.LayoutInflater; -import android.view.View; +import androidx.slice.Slice; import androidx.slice.SliceProvider; import androidx.slice.SliceSpecs; import androidx.slice.builders.ListBuilder; +import androidx.slice.widget.RowContent; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.keyguard.KeyguardSliceProvider; -import com.android.systemui.plugins.ActivityStarter; -import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.tuner.TunerService; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.Collections; @@ -53,46 +43,18 @@ import java.util.HashSet; import java.util.concurrent.atomic.AtomicBoolean; @SmallTest -@RunWithLooper +@RunWithLooper(setAsMainLooper = true) @RunWith(AndroidTestingRunner.class) public class KeyguardSliceViewTest extends SysuiTestCase { private KeyguardSliceView mKeyguardSliceView; private Uri mSliceUri; - @Mock - private TunerService mTunerService; - @Mock - private ConfigurationController mConfigurationController; - @Mock - private ActivityStarter mActivityStarter; - @Mock - private Resources mResources; - @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - allowTestableLooperAsMainThread(); LayoutInflater layoutInflater = LayoutInflater.from(getContext()); - layoutInflater.setPrivateFactory(new LayoutInflater.Factory2() { - - @Override - public View onCreateView(View parent, String name, Context context, - AttributeSet attrs) { - return onCreateView(name, context, attrs); - } - - @Override - public View onCreateView(String name, Context context, AttributeSet attrs) { - if ("com.android.keyguard.KeyguardSliceView".equals(name)) { - return new KeyguardSliceView(getContext(), attrs, mActivityStarter, - mConfigurationController, mTunerService, mResources); - } - return null; - } - }); mKeyguardSliceView = (KeyguardSliceView) layoutInflater .inflate(R.layout.keyguard_status_area, null); - mKeyguardSliceView.setupUri(KeyguardSliceProvider.KEYGUARD_SLICE_URI); mSliceUri = Uri.parse(KeyguardSliceProvider.KEYGUARD_SLICE_URI); SliceProvider.setSpecs(new HashSet<>(Collections.singletonList(SliceSpecs.LIST))); } @@ -100,9 +62,13 @@ public class KeyguardSliceViewTest extends SysuiTestCase { @Test public void showSlice_notifiesListener() { ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY); + builder.setHeader(new ListBuilder.HeaderBuilder().setTitle("header title!")); + Slice slice = builder.build(); + RowContent rowContent = new RowContent(slice.getItemArray()[0], 0); + AtomicBoolean notified = new AtomicBoolean(); mKeyguardSliceView.setContentChangeListener(()-> notified.set(true)); - mKeyguardSliceView.onChanged(builder.build()); + mKeyguardSliceView.showSlice(rowContent, Collections.EMPTY_LIST); Assert.assertTrue("Listener should be notified about slice changes.", notified.get()); } @@ -111,7 +77,7 @@ public class KeyguardSliceViewTest extends SysuiTestCase { public void showSlice_emptySliceNotifiesListener() { AtomicBoolean notified = new AtomicBoolean(); mKeyguardSliceView.setContentChangeListener(()-> notified.set(true)); - mKeyguardSliceView.onChanged(null); + mKeyguardSliceView.showSlice(null, Collections.EMPTY_LIST); Assert.assertTrue("Listener should be notified about slice changes.", notified.get()); } @@ -119,24 +85,17 @@ public class KeyguardSliceViewTest extends SysuiTestCase { @Test public void hasHeader_readsSliceData() { ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY); - mKeyguardSliceView.onChanged(builder.build()); + mKeyguardSliceView.showSlice(null, Collections.EMPTY_LIST); Assert.assertFalse("View should not have a header", mKeyguardSliceView.hasHeader()); builder.setHeader(new ListBuilder.HeaderBuilder().setTitle("header title!")); - mKeyguardSliceView.onChanged(builder.build()); + Slice slice = builder.build(); + RowContent rowContent = new RowContent(slice.getItemArray()[0], 0); + mKeyguardSliceView.showSlice(rowContent, Collections.EMPTY_LIST); Assert.assertTrue("View should have a header", mKeyguardSliceView.hasHeader()); } @Test - public void refresh_replacesSliceContentAndNotifiesListener() { - AtomicBoolean notified = new AtomicBoolean(); - mKeyguardSliceView.setContentChangeListener(()-> notified.set(true)); - mKeyguardSliceView.refresh(); - Assert.assertTrue("Listener should be notified about slice changes.", - notified.get()); - } - - @Test public void getTextColor_whiteTextWhenAOD() { // Set text color to red since the default is white and test would always pass mKeyguardSliceView.setTextColor(Color.RED); @@ -147,18 +106,4 @@ public class KeyguardSliceViewTest extends SysuiTestCase { Assert.assertEquals("Should be using AOD text color", Color.WHITE, mKeyguardSliceView.getTextColor()); } - - @Test - public void onAttachedToWindow_registersListeners() { - mKeyguardSliceView.onAttachedToWindow(); - verify(mTunerService).addTunable(eq(mKeyguardSliceView), anyString()); - verify(mConfigurationController).addCallback(eq(mKeyguardSliceView)); - } - - @Test - public void onDetachedFromWindow_unregistersListeners() { - mKeyguardSliceView.onDetachedFromWindow(); - verify(mTunerService).removeTunable(eq(mKeyguardSliceView)); - verify(mConfigurationController).removeCallback(eq(mKeyguardSliceView)); - } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java index 0bf137689aa1..0431704778c3 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java @@ -40,7 +40,8 @@ import org.mockito.Mock; public class KeyguardStatusViewTest extends SysuiTestCase { @Mock - KeyguardSliceView mKeyguardSlice; + KeyguardSliceViewController mKeyguardSliceViewController; + @Mock KeyguardClockSwitch mClockView; @InjectMocks @@ -64,7 +65,7 @@ public class KeyguardStatusViewTest extends SysuiTestCase { @Test public void dozeTimeTick_updatesSlice() { mKeyguardStatusView.dozeTimeTick(); - verify(mKeyguardSlice).refresh(); + verify(mKeyguardSliceViewController).refresh(); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index c874b1fb72ad..f6d6f562e3fa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -37,6 +37,7 @@ import android.testing.TestableLooper.RunWithLooper; import androidx.test.filters.SmallTest; import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardDisplayManager; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; @@ -46,7 +47,6 @@ import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.DeviceConfigProxyFake; -import com.android.systemui.util.InjectionInflationController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; @@ -72,7 +72,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { private @Mock PowerManager mPowerManager; private @Mock TrustManager mTrustManager; private @Mock NavigationModeController mNavigationModeController; - private @Mock InjectionInflationController mInjectionInflationController; + private @Mock KeyguardDisplayManager mKeyguardDisplayManager; private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake(); private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); @@ -91,7 +91,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { () -> mStatusBarKeyguardViewManager, mDismissCallbackRegistry, mUpdateMonitor, mDumpManager, mUiBgExecutor, mPowerManager, mTrustManager, mDeviceConfig, mNavigationModeController, - mInjectionInflationController); + mKeyguardDisplayManager); mViewMediator.start(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index 04e870d4b35c..a9484af66c12 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -54,6 +54,7 @@ import com.android.keyguard.KeyguardClockSwitch; import com.android.keyguard.KeyguardClockSwitchController; import com.android.keyguard.KeyguardStatusView; import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingManagerFake; @@ -187,10 +188,16 @@ public class NotificationPanelViewTest extends SysuiTestCase { @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @Mock + private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; + @Mock + private KeyguardStatusViewComponent mKeyguardStatusViewComponent; + @Mock private KeyguardClockSwitchController mKeyguardClockSwitchController; @Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController; + private FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder; + private NotificationPanelViewController mNotificationPanelViewController; private View.AccessibilityDelegate mAccessibiltyDelegate; @@ -241,6 +248,10 @@ public class NotificationPanelViewTest extends SysuiTestCase { mock(NotificationRoundnessManager.class), mStatusBarStateController, new FalsingManagerFake()); + when(mKeyguardStatusViewComponentFactory.build(any())) + .thenReturn(mKeyguardStatusViewComponent); + when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController()) + .thenReturn(mKeyguardClockSwitchController); mNotificationPanelViewController = new NotificationPanelViewController(mView, mResources, mInjectionInflationController, @@ -254,9 +265,9 @@ public class NotificationPanelViewTest extends SysuiTestCase { flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager, mConversationNotificationManager, mMediaHiearchyManager, mBiometricUnlockController, mStatusBarKeyguardViewManager, - () -> mKeyguardClockSwitchController, mNotificationStackScrollLayoutController, - mNotificationAreaController); + mNotificationAreaController, + mKeyguardStatusViewComponentFactory); mNotificationPanelViewController.initDependencies( mStatusBar, mGroupManager, 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 b587dd33c4e5..d127172c3aa6 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -594,15 +594,23 @@ public class TouchExplorer extends BaseEventStreamTransformation if (pointerIndex < 0) { return; } - final float deltaX = - mReceivedPointerTracker.getReceivedPointerDownX(pointerId) - - rawEvent.getX(pointerIndex); - final float deltaY = - mReceivedPointerTracker.getReceivedPointerDownY(pointerId) - - rawEvent.getY(pointerIndex); - final double moveDelta = Math.hypot(deltaX, deltaY); - if (moveDelta < mTouchSlop) { - return; + // Require both fingers to have moved a certain amount before starting a drag. + for (int index = 0; index < event.getPointerCount(); ++index) { + int id = event.getPointerId(index); + if (!mReceivedPointerTracker.isReceivedPointerDown(id)) { + // Something is wrong with the event stream. + Slog.e(LOG_TAG, "Invalid pointer id: " + id); + } + final float deltaX = + mReceivedPointerTracker.getReceivedPointerDownX(id) + - rawEvent.getX(index); + final float deltaY = + mReceivedPointerTracker.getReceivedPointerDownY(id) + - rawEvent.getY(index); + final double moveDelta = Math.hypot(deltaX, deltaY); + if (moveDelta < mTouchSlop) { + return; + } } } // More than one pointer so the user is not touch exploring @@ -612,12 +620,20 @@ public class TouchExplorer extends BaseEventStreamTransformation if (isDraggingGesture(event)) { // Two pointers moving in the same direction within // a given distance perform a drag. - mState.startDragging(); computeDraggingPointerIdIfNeeded(event); pointerIdBits = 1 << mDraggingPointerId; event.setEdgeFlags(mReceivedPointerTracker.getLastReceivedDownEdgeFlags()); - mDispatcher.sendMotionEvent( - event, ACTION_DOWN, rawEvent, pointerIdBits, policyFlags); + MotionEvent downEvent = computeDownEventForDrag(event); + if (downEvent != null) { + mDispatcher.sendMotionEvent( + downEvent, ACTION_DOWN, rawEvent, pointerIdBits, policyFlags); + mDispatcher.sendMotionEvent( + event, ACTION_MOVE, rawEvent, pointerIdBits, policyFlags); + } else { + mDispatcher.sendMotionEvent( + event, ACTION_DOWN, rawEvent, pointerIdBits, policyFlags); + } + mState.startDragging(); } else { // Two pointers moving arbitrary are delegated to the view hierarchy. mState.startDelegating(); @@ -1004,6 +1020,49 @@ public class TouchExplorer extends BaseEventStreamTransformation return distance; } + /** + * Creates a down event using the down coordinates of the dragging pointer and other information + * from the supplied event. The supplied event's down time is adjusted to reflect the time when + * the dragging pointer initially went down. + */ + private MotionEvent computeDownEventForDrag(MotionEvent event) { + // Creating a down event only makes sense if we haven't started touch exploring yet. + if (mState.isTouchExploring() + || mDraggingPointerId == INVALID_POINTER_ID + || event == null) { + return null; + } + final float x = mReceivedPointerTracker.getReceivedPointerDownX(mDraggingPointerId); + final float y = mReceivedPointerTracker.getReceivedPointerDownY(mDraggingPointerId); + final long time = mReceivedPointerTracker.getReceivedPointerDownTime(mDraggingPointerId); + MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[1]; + coords[0] = new MotionEvent.PointerCoords(); + coords[0].x = x; + coords[0].y = y; + MotionEvent.PointerProperties[] properties = new MotionEvent.PointerProperties[1]; + properties[0] = new MotionEvent.PointerProperties(); + properties[0].id = mDraggingPointerId; + properties[0].toolType = MotionEvent.TOOL_TYPE_FINGER; + MotionEvent downEvent = + MotionEvent.obtain( + time, + time, + ACTION_DOWN, + 1, + properties, + coords, + event.getMetaState(), + event.getButtonState(), + event.getXPrecision(), + event.getYPrecision(), + event.getDeviceId(), + event.getEdgeFlags(), + event.getSource(), + event.getFlags()); + event.setDownTime(time); + return downEvent; + } + public TouchState getState() { return mState; } diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java index 1c4db1214d3b..59ba82e4616a 100644 --- a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java +++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java @@ -34,6 +34,7 @@ import android.app.prediction.IPredictionManager; import android.content.Context; import android.content.pm.ParceledListSlice; import android.os.Binder; +import android.os.IBinder; import android.os.ResultReceiver; import android.os.ShellCallback; import android.util.Slog; @@ -108,9 +109,9 @@ public class AppPredictionManagerService extends @Override public void createPredictionSession(@NonNull AppPredictionContext context, - @NonNull AppPredictionSessionId sessionId) { - runForUserLocked("createPredictionSession", sessionId, - (service) -> service.onCreatePredictionSessionLocked(context, sessionId)); + @NonNull AppPredictionSessionId sessionId, @NonNull IBinder token) { + runForUserLocked("createPredictionSession", sessionId, (service) -> + service.onCreatePredictionSessionLocked(context, sessionId, token)); } @Override diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java index 7ee607c3eab4..735f420ca03e 100644 --- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java +++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java @@ -30,6 +30,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ParceledListSlice; import android.content.pm.ServiceInfo; +import android.os.IBinder; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.provider.DeviceConfig; @@ -44,8 +45,6 @@ import com.android.server.LocalServices; import com.android.server.infra.AbstractPerUserSystemService; import com.android.server.people.PeopleServiceInternal; -import java.util.function.Consumer; - /** * Per-user instance of {@link AppPredictionManagerService}. */ @@ -112,17 +111,24 @@ public class AppPredictionPerUserService extends */ @GuardedBy("mLock") public void onCreatePredictionSessionLocked(@NonNull AppPredictionContext context, - @NonNull AppPredictionSessionId sessionId) { - if (!mSessionInfos.containsKey(sessionId)) { - mSessionInfos.put(sessionId, new AppPredictionSessionInfo(sessionId, context, - DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, - PREDICT_USING_PEOPLE_SERVICE_PREFIX + context.getUiSurface(), false), - this::removeAppPredictionSessionInfo)); - } - final boolean serviceExists = resolveService(sessionId, s -> - s.onCreatePredictionSession(context, sessionId), true); - if (!serviceExists) { - mSessionInfos.remove(sessionId); + @NonNull AppPredictionSessionId sessionId, @NonNull IBinder token) { + final boolean usesPeopleService = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, + PREDICT_USING_PEOPLE_SERVICE_PREFIX + context.getUiSurface(), false); + final boolean serviceExists = resolveService(sessionId, false, + usesPeopleService, s -> s.onCreatePredictionSession(context, sessionId)); + if (serviceExists && !mSessionInfos.containsKey(sessionId)) { + final AppPredictionSessionInfo sessionInfo = new AppPredictionSessionInfo( + sessionId, context, usesPeopleService, token, () -> { + synchronized (mLock) { + onDestroyPredictionSessionLocked(sessionId); + } + }); + if (sessionInfo.linkToDeath()) { + mSessionInfos.put(sessionId, sessionInfo); + } else { + // destroy the session if calling process is already dead + onDestroyPredictionSessionLocked(sessionId); + } } } @@ -132,7 +138,10 @@ public class AppPredictionPerUserService extends @GuardedBy("mLock") public void notifyAppTargetEventLocked(@NonNull AppPredictionSessionId sessionId, @NonNull AppTargetEvent event) { - resolveService(sessionId, s -> s.notifyAppTargetEvent(sessionId, event), false); + final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId); + if (sessionInfo == null) return; + resolveService(sessionId, false, sessionInfo.mUsesPeopleService, + s -> s.notifyAppTargetEvent(sessionId, event)); } /** @@ -141,8 +150,10 @@ public class AppPredictionPerUserService extends @GuardedBy("mLock") public void notifyLaunchLocationShownLocked(@NonNull AppPredictionSessionId sessionId, @NonNull String launchLocation, @NonNull ParceledListSlice targetIds) { - resolveService(sessionId, s -> - s.notifyLaunchLocationShown(sessionId, launchLocation, targetIds), false); + final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId); + if (sessionInfo == null) return; + resolveService(sessionId, false, sessionInfo.mUsesPeopleService, + s -> s.notifyLaunchLocationShown(sessionId, launchLocation, targetIds)); } /** @@ -151,7 +162,10 @@ public class AppPredictionPerUserService extends @GuardedBy("mLock") public void sortAppTargetsLocked(@NonNull AppPredictionSessionId sessionId, @NonNull ParceledListSlice targets, @NonNull IPredictionCallback callback) { - resolveService(sessionId, s -> s.sortAppTargets(sessionId, targets, callback), true); + final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId); + if (sessionInfo == null) return; + resolveService(sessionId, true, sessionInfo.mUsesPeopleService, + s -> s.sortAppTargets(sessionId, targets, callback)); } /** @@ -160,10 +174,12 @@ public class AppPredictionPerUserService extends @GuardedBy("mLock") public void registerPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId, @NonNull IPredictionCallback callback) { - final boolean serviceExists = resolveService(sessionId, s -> - s.registerPredictionUpdates(sessionId, callback), false); final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId); - if (serviceExists && sessionInfo != null) { + if (sessionInfo == null) return; + final boolean serviceExists = resolveService(sessionId, false, + sessionInfo.mUsesPeopleService, + s -> s.registerPredictionUpdates(sessionId, callback)); + if (serviceExists) { sessionInfo.addCallbackLocked(callback); } } @@ -174,10 +190,12 @@ public class AppPredictionPerUserService extends @GuardedBy("mLock") public void unregisterPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId, @NonNull IPredictionCallback callback) { - final boolean serviceExists = resolveService(sessionId, s -> - s.unregisterPredictionUpdates(sessionId, callback), false); final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId); - if (serviceExists && sessionInfo != null) { + if (sessionInfo == null) return; + final boolean serviceExists = resolveService(sessionId, false, + sessionInfo.mUsesPeopleService, + s -> s.unregisterPredictionUpdates(sessionId, callback)); + if (serviceExists) { sessionInfo.removeCallbackLocked(callback); } } @@ -187,7 +205,10 @@ public class AppPredictionPerUserService extends */ @GuardedBy("mLock") public void requestPredictionUpdateLocked(@NonNull AppPredictionSessionId sessionId) { - resolveService(sessionId, s -> s.requestPredictionUpdate(sessionId), true); + final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId); + if (sessionInfo == null) return; + resolveService(sessionId, true, sessionInfo.mUsesPeopleService, + s -> s.requestPredictionUpdate(sessionId)); } /** @@ -195,12 +216,14 @@ public class AppPredictionPerUserService extends */ @GuardedBy("mLock") public void onDestroyPredictionSessionLocked(@NonNull AppPredictionSessionId sessionId) { - final boolean serviceExists = resolveService(sessionId, s -> - s.onDestroyPredictionSession(sessionId), false); - final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId); - if (serviceExists && sessionInfo != null) { - sessionInfo.destroy(); + if (isDebug()) { + Slog.d(TAG, "onDestroyPredictionSessionLocked(): sessionId=" + sessionId); } + final AppPredictionSessionInfo sessionInfo = mSessionInfos.remove(sessionId); + if (sessionInfo == null) return; + resolveService(sessionId, false, sessionInfo.mUsesPeopleService, + s -> s.onDestroyPredictionSession(sessionId)); + sessionInfo.destroy(); } @Override @@ -291,27 +314,18 @@ public class AppPredictionPerUserService extends } for (AppPredictionSessionInfo sessionInfo : mSessionInfos.values()) { - sessionInfo.resurrectSessionLocked(this); - } - } - - private void removeAppPredictionSessionInfo(AppPredictionSessionId sessionId) { - if (isDebug()) { - Slog.d(TAG, "removeAppPredictionSessionInfo(): sessionId=" + sessionId); - } - synchronized (mLock) { - mSessionInfos.remove(sessionId); + sessionInfo.resurrectSessionLocked(this, sessionInfo.mToken); } } @GuardedBy("mLock") @Nullable - protected boolean resolveService(@NonNull final AppPredictionSessionId sessionId, - @NonNull final AbstractRemoteService.AsyncRequest<IPredictionService> cb, - boolean sendImmediately) { - final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId); - if (sessionInfo == null) return false; - if (sessionInfo.mUsesPeopleService) { + protected boolean resolveService( + @NonNull final AppPredictionSessionId sessionId, + boolean sendImmediately, + boolean usesPeopleService, + @NonNull final AbstractRemoteService.AsyncRequest<IPredictionService> cb) { + if (usesPeopleService) { final IPredictionService service = LocalServices.getService(PeopleServiceInternal.class); if (service != null) { @@ -368,7 +382,9 @@ public class AppPredictionPerUserService extends private final AppPredictionContext mPredictionContext; private final boolean mUsesPeopleService; @NonNull - private final Consumer<AppPredictionSessionId> mRemoveSessionInfoAction; + final IBinder mToken; + @NonNull + final IBinder.DeathRecipient mDeathRecipient; private final RemoteCallbackList<IPredictionCallback> mCallbacks = new RemoteCallbackList<IPredictionCallback>() { @@ -388,14 +404,16 @@ public class AppPredictionPerUserService extends @NonNull final AppPredictionSessionId id, @NonNull final AppPredictionContext predictionContext, final boolean usesPeopleService, - @NonNull final Consumer<AppPredictionSessionId> removeSessionInfoAction) { + @NonNull final IBinder token, + @NonNull final IBinder.DeathRecipient deathRecipient) { if (DEBUG) { Slog.d(TAG, "Creating AppPredictionSessionInfo for session Id=" + id); } mSessionId = id; mPredictionContext = predictionContext; mUsesPeopleService = usesPeopleService; - mRemoveSessionInfoAction = removeSessionInfoAction; + mToken = token; + mDeathRecipient = deathRecipient; } void addCallbackLocked(IPredictionCallback callback) { @@ -414,23 +432,38 @@ public class AppPredictionPerUserService extends mCallbacks.unregister(callback); } + boolean linkToDeath() { + try { + mToken.linkToDeath(mDeathRecipient, 0); + } catch (RemoteException e) { + if (DEBUG) { + Slog.w(TAG, "Caller is dead before session can be started, sessionId: " + + mSessionId); + } + return false; + } + return true; + } + void destroy() { if (DEBUG) { Slog.d(TAG, "Removing all callbacks for session Id=" + mSessionId + " and " + mCallbacks.getRegisteredCallbackCount() + " callbacks."); } + if (mToken != null) { + mToken.unlinkToDeath(mDeathRecipient, 0); + } mCallbacks.kill(); - mRemoveSessionInfoAction.accept(mSessionId); } - void resurrectSessionLocked(AppPredictionPerUserService service) { + void resurrectSessionLocked(AppPredictionPerUserService service, IBinder token) { int callbackCount = mCallbacks.getRegisteredCallbackCount(); if (DEBUG) { Slog.d(TAG, "Resurrecting remote service (" + service.getRemoteServiceLocked() + ") for session Id=" + mSessionId + " and " + callbackCount + " callbacks."); } - service.onCreatePredictionSessionLocked(mPredictionContext, mSessionId); + service.onCreatePredictionSessionLocked(mPredictionContext, mSessionId, token); mCallbacks.broadcast( callback -> service.registerPredictionUpdatesLocked(mSessionId, callback)); } diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index 96d973ec5272..687af107590a 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -85,6 +85,7 @@ import java.util.Arrays; import java.util.Date; import java.util.LinkedList; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; public class VibratorService extends IVibratorService.Stub implements InputManager.InputDeviceListener { @@ -114,6 +115,9 @@ public class VibratorService extends IVibratorService.Stub private static final VibrationAttributes DEFAULT_ATTRIBUTES = new VibrationAttributes.Builder().build(); + // Used to generate globally unique vibration ids. + private final AtomicInteger mNextVibrationId = new AtomicInteger(1); // 0 = no callback + // A mapping from the intensity adjustment to the scaling to apply, where the intensity // adjustment is defined as the delta between the default intensity level and the user selected // intensity level. It's important that we apply the scaling on the delta between the two so @@ -171,34 +175,34 @@ public class VibratorService extends IVibratorService.Stub private int mRingIntensity; private SparseArray<Vibration> mAlwaysOnEffects = new SparseArray<>(); - static native long vibratorInit(); + static native long vibratorInit(OnCompleteListener listener); static native long vibratorGetFinalizer(); - static native boolean vibratorExists(long controllerPtr); + static native boolean vibratorExists(long nativeServicePtr); - static native void vibratorOn(long controllerPtr, long milliseconds, Vibration vibration); + static native void vibratorOn(long nativeServicePtr, long milliseconds, long vibrationId); - static native void vibratorOff(long controllerPtr); + static native void vibratorOff(long nativeServicePtr); - static native void vibratorSetAmplitude(long controllerPtr, int amplitude); + static native void vibratorSetAmplitude(long nativeServicePtr, int amplitude); - static native int[] vibratorGetSupportedEffects(long controllerPtr); + static native int[] vibratorGetSupportedEffects(long nativeServicePtr); - static native int[] vibratorGetSupportedPrimitives(long controllerPtr); + static native int[] vibratorGetSupportedPrimitives(long nativeServicePtr); static native long vibratorPerformEffect( - long controllerPtr, long effect, long strength, Vibration vibration); + long nativeServicePtr, long effect, long strength, long vibrationId); - static native void vibratorPerformComposedEffect(long controllerPtr, - VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration); + static native void vibratorPerformComposedEffect(long nativeServicePtr, + VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId); - static native void vibratorSetExternalControl(long controllerPtr, boolean enabled); + static native void vibratorSetExternalControl(long nativeServicePtr, boolean enabled); - static native long vibratorGetCapabilities(long controllerPtr); - static native void vibratorAlwaysOnEnable(long controllerPtr, long id, long effect, + static native long vibratorGetCapabilities(long nativeServicePtr); + static native void vibratorAlwaysOnEnable(long nativeServicePtr, long id, long effect, long strength); - static native void vibratorAlwaysOnDisable(long controllerPtr, long id); + static native void vibratorAlwaysOnDisable(long nativeServicePtr, long id); private final IUidObserver mUidObserver = new IUidObserver.Stub() { @Override public void onUidStateChanged(int uid, int procState, long procStateSeq, @@ -220,12 +224,19 @@ public class VibratorService extends IVibratorService.Stub } }; + /** Listener for vibration completion callbacks from native. */ + public interface OnCompleteListener { + + /** Callback triggered when vibration is complete, identified by {@link Vibration#id}. */ + void onComplete(long vibrationId); + } + /** * Holder for a vibration to be played. This class can be shared with native methods for * hardware callback support. */ - @VisibleForTesting - public final class Vibration implements IBinder.DeathRecipient { + private final class Vibration implements IBinder.DeathRecipient { + public final IBinder token; // Start time in CLOCK_BOOTTIME base. public final long startTime; @@ -234,6 +245,7 @@ public class VibratorService extends IVibratorService.Stub // not to be affected by discontinuities created by RTC adjustments. public final long startTimeDebug; public final VibrationAttributes attrs; + public final long id; public final int uid; public final String opPkg; public final String reason; @@ -248,6 +260,7 @@ public class VibratorService extends IVibratorService.Stub VibrationAttributes attrs, int uid, String opPkg, String reason) { this.token = token; this.effect = effect; + this.id = mNextVibrationId.getAndIncrement(); this.startTime = SystemClock.elapsedRealtime(); this.startTimeDebug = System.currentTimeMillis(); this.attrs = attrs; @@ -268,19 +281,6 @@ public class VibratorService extends IVibratorService.Stub } } - /** Callback for when vibration is complete, to be called by native. */ - @VisibleForTesting - public void onComplete() { - synchronized (mLock) { - if (this == mCurrentVibration) { - if (DEBUG) { - Slog.d(TAG, "Vibration finished by callback, cleaning up"); - } - doCancelVibrateLocked(); - } - } - } - public boolean hasTimeoutLongerThan(long millis) { final long duration = effect.getDuration(); return duration >= 0 && duration > millis; @@ -385,14 +385,14 @@ public class VibratorService extends IVibratorService.Stub mNativeWrapper = injector.getNativeWrapper(); mH = injector.createHandler(Looper.myLooper()); - long controllerPtr = mNativeWrapper.vibratorInit(); + long nativeServicePtr = mNativeWrapper.vibratorInit(this::onVibrationComplete); long finalizerPtr = mNativeWrapper.vibratorGetFinalizer(); if (finalizerPtr != 0) { NativeAllocationRegistry registry = NativeAllocationRegistry.createMalloced( VibratorService.class.getClassLoader(), finalizerPtr); - registry.registerNativeAllocation(this, controllerPtr); + registry.registerNativeAllocation(this, nativeServicePtr); } // Reset the hardware to a default state, in case this is a runtime @@ -549,6 +549,19 @@ public class VibratorService extends IVibratorService.Stub } } + /** Callback for when vibration is complete, to be called by native. */ + @VisibleForTesting + public void onVibrationComplete(long vibrationId) { + synchronized (mLock) { + if (mCurrentVibration != null && mCurrentVibration.id == vibrationId) { + if (DEBUG) { + Slog.d(TAG, "Vibration finished by callback, cleaning up"); + } + doCancelVibrateLocked(); + } + } + } + @Override // Binder call public boolean hasVibrator() { return doVibratorExists(); @@ -1266,18 +1279,18 @@ public class VibratorService extends IVibratorService.Stub return mNativeWrapper.vibratorExists(); } - /** Vibrates with native callback trigger for {@link Vibration#onComplete()}. */ + /** Vibrates with native callback trigger for {@link #onVibrationComplete(long)}. */ private void doVibratorOn(long millis, int amplitude, Vibration vib) { - doVibratorOn(millis, amplitude, vib.uid, vib.attrs, vib); + doVibratorOn(millis, amplitude, vib.uid, vib.attrs, vib.id); } /** Vibrates without native callback. */ private void doVibratorOn(long millis, int amplitude, int uid, VibrationAttributes attrs) { - doVibratorOn(millis, amplitude, uid, attrs, /* vib= */ null); + doVibratorOn(millis, amplitude, uid, attrs, /* vibrationId= */ 0); } private void doVibratorOn(long millis, int amplitude, int uid, VibrationAttributes attrs, - @Nullable Vibration vib) { + long vibrationId) { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn"); try { synchronized (mInputDeviceVibrators) { @@ -1299,7 +1312,7 @@ public class VibratorService extends IVibratorService.Stub // Note: ordering is important here! Many haptic drivers will reset their // amplitude when enabled, so we always have to enable first, then set the // amplitude. - mNativeWrapper.vibratorOn(millis, vib); + mNativeWrapper.vibratorOn(millis, vibrationId); doVibratorSetAmplitude(amplitude); } } @@ -1348,7 +1361,7 @@ public class VibratorService extends IVibratorService.Stub // Input devices don't support prebaked effect, so skip trying it with them. if (!usingInputDeviceVibrators) { long duration = mNativeWrapper.vibratorPerformEffect( - prebaked.getId(), prebaked.getEffectStrength(), vib); + prebaked.getId(), prebaked.getEffectStrength(), vib.id); if (duration > 0) { noteVibratorOnLocked(vib.uid, duration); return; @@ -1395,7 +1408,7 @@ public class VibratorService extends IVibratorService.Stub PrimitiveEffect[] primitiveEffects = composed.getPrimitiveEffects().toArray(new PrimitiveEffect[0]); - mNativeWrapper.vibratorPerformComposedEffect(primitiveEffects, vib); + mNativeWrapper.vibratorPerformComposedEffect(primitiveEffects, vib.id); // Composed effects don't actually give us an estimated duration, so we just guess here. noteVibratorOnLocked(vib.uid, 10 * primitiveEffects.length); @@ -1726,20 +1739,20 @@ public class VibratorService extends IVibratorService.Stub @VisibleForTesting public static class NativeWrapper { - private long mNativeControllerPtr = 0; + private long mNativeServicePtr = 0; /** Checks if vibrator exists on device. */ public boolean vibratorExists() { - return VibratorService.vibratorExists(mNativeControllerPtr); + return VibratorService.vibratorExists(mNativeServicePtr); } /** * Returns native pointer to newly created controller and initializes connection to vibrator * HAL service. */ - public long vibratorInit() { - mNativeControllerPtr = VibratorService.vibratorInit(); - return mNativeControllerPtr; + public long vibratorInit(OnCompleteListener listener) { + mNativeServicePtr = VibratorService.vibratorInit(listener); + return mNativeServicePtr; } /** Returns pointer to native finalizer function to be called by GC. */ @@ -1748,60 +1761,61 @@ public class VibratorService extends IVibratorService.Stub } /** Turns vibrator on for given time. */ - public void vibratorOn(long milliseconds, @Nullable Vibration vibration) { - VibratorService.vibratorOn(mNativeControllerPtr, milliseconds, vibration); + public void vibratorOn(long milliseconds, long vibrationId) { + VibratorService.vibratorOn(mNativeServicePtr, milliseconds, vibrationId); } /** Turns vibrator off. */ public void vibratorOff() { - VibratorService.vibratorOff(mNativeControllerPtr); + VibratorService.vibratorOff(mNativeServicePtr); } /** Sets the amplitude for the vibrator to run. */ public void vibratorSetAmplitude(int amplitude) { - VibratorService.vibratorSetAmplitude(mNativeControllerPtr, amplitude); + VibratorService.vibratorSetAmplitude(mNativeServicePtr, amplitude); } /** Returns all predefined effects supported by the device vibrator. */ public int[] vibratorGetSupportedEffects() { - return VibratorService.vibratorGetSupportedEffects(mNativeControllerPtr); + return VibratorService.vibratorGetSupportedEffects(mNativeServicePtr); } /** Returns all compose primitives supported by the device vibrator. */ public int[] vibratorGetSupportedPrimitives() { - return VibratorService.vibratorGetSupportedPrimitives(mNativeControllerPtr); + return VibratorService.vibratorGetSupportedPrimitives(mNativeServicePtr); } /** Turns vibrator on to perform one of the supported effects. */ - public long vibratorPerformEffect(long effect, long strength, Vibration vibration) { + public long vibratorPerformEffect(long effect, long strength, long vibrationId) { return VibratorService.vibratorPerformEffect( - mNativeControllerPtr, effect, strength, vibration); + mNativeServicePtr, effect, strength, vibrationId); } /** Turns vibrator on to perform one of the supported composed effects. */ public void vibratorPerformComposedEffect( - VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration) { - VibratorService.vibratorPerformComposedEffect(mNativeControllerPtr, effect, vibration); + VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId) { + VibratorService.vibratorPerformComposedEffect(mNativeServicePtr, effect, + vibrationId); } /** Enabled the device vibrator to be controlled by another service. */ public void vibratorSetExternalControl(boolean enabled) { - VibratorService.vibratorSetExternalControl(mNativeControllerPtr, enabled); + VibratorService.vibratorSetExternalControl(mNativeServicePtr, enabled); } /** Returns all capabilities of the device vibrator. */ public long vibratorGetCapabilities() { - return VibratorService.vibratorGetCapabilities(mNativeControllerPtr); + return VibratorService.vibratorGetCapabilities(mNativeServicePtr); } /** Enable always-on vibration with given id and effect. */ public void vibratorAlwaysOnEnable(long id, long effect, long strength) { - VibratorService.vibratorAlwaysOnEnable(mNativeControllerPtr, id, effect, strength); + VibratorService.vibratorAlwaysOnEnable(mNativeServicePtr, id, effect, strength); } /** Disable always-on vibration for given id. */ public void vibratorAlwaysOnDisable(long id) { - VibratorService.vibratorAlwaysOnDisable(mNativeControllerPtr, id); + VibratorService.vibratorAlwaysOnDisable(mNativeServicePtr, id); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 6e1e3d0a9a9a..2d803437beb9 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -83,6 +83,7 @@ import static android.provider.Settings.Global.NETWORK_ACCESS_TIMEOUT_MS; import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER; import static android.text.format.DateUtils.DAY_IN_MILLIS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKGROUND_CHECK; @@ -117,7 +118,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NA import static com.android.server.am.MemoryStatUtil.hasMemcg; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK; @@ -319,6 +319,7 @@ import com.android.internal.os.IResultReceiver; import com.android.internal.os.ProcessCpuTracker; import com.android.internal.os.TransferPipe; import com.android.internal.os.Zygote; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastPrintWriter; @@ -4946,9 +4947,8 @@ public class ActivityManagerService extends IActivityManager.Stub notifyPackageUse(instr.mClass.getPackageName(), PackageManager.NOTIFY_PACKAGE_USE_INSTRUMENTATION); } - if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Binding proc " - + processName + " with config " - + app.getWindowProcessController().getConfiguration()); + ProtoLog.v(WM_DEBUG_CONFIGURATION, "Binding proc %s with config %s", + processName, app.getWindowProcessController().getConfiguration()); ApplicationInfo appInfo = instr != null ? instr.mTargetInfo : app.info; app.compat = compatibilityInfoForPackage(appInfo); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java index 3f949bab8a2e..653323de8d60 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java @@ -25,7 +25,7 @@ import java.util.Arrays; * A helper class to build {@link HdmiCecMessage} from various cec commands. */ public class HdmiCecMessageBuilder { - private static final int OSD_NAME_MAX_LENGTH = 13; + private static final int OSD_NAME_MAX_LENGTH = 14; private HdmiCecMessageBuilder() {} diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java index 05aa3150cfef..06105bfcc0f3 100644 --- a/services/core/java/com/android/server/location/LocationProviderManager.java +++ b/services/core/java/com/android/server/location/LocationProviderManager.java @@ -314,6 +314,14 @@ class LocationProviderManager extends } @Override + public final <Listener> void onOperationFailure(ListenerOperation<Listener> operation, + Exception e) { + synchronized (mLock) { + super.onOperationFailure(operation, e); + } + } + + @Override public final LocationRequest getRequest() { return mProviderLocationRequest; } diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 4f3d3600ae37..ed62362b04fb 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -134,6 +134,7 @@ import com.android.internal.os.SomeArgs; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.Preconditions; import com.android.server.LocalServices; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.dex.DexManager; @@ -1554,12 +1555,28 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } private void onSessionValidationFailure(int error, String detailMessage) { - // Session is sealed but could not be verified, we need to destroy it. + // Session is sealed but could not be validated, we need to destroy it. destroyInternal(); // Dispatch message to remove session from PackageInstallerService. dispatchSessionFinished(error, detailMessage, null); } + private void onSessionVerificationFailure(int error, String detailMessage) { + Slog.e(TAG, "Failed to verify session " + sessionId + " [" + detailMessage + "]"); + // Session is sealed and committed but could not be verified, we need to destroy it. + destroyInternal(); + if (isStaged()) { + setStagedSessionFailed( + SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, detailMessage); + // TODO(b/136257624): Remove this once all verification logic has been transferred out + // of StagingManager. + mStagingManager.notifyVerificationComplete(sessionId); + } else { + // Dispatch message to remove session from PackageInstallerService. + dispatchSessionFinished(error, detailMessage, null); + } + } + private void onStorageUnhealthy() { final String packageName = getPackageName(); if (TextUtils.isEmpty(packageName)) { @@ -1680,7 +1697,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } if (params.isStaged) { mStagingManager.commitSession(this); - destroyInternal(); + // TODO(b/136257624): CTS test fails if we don't send session finished broadcast, even + // though ideally, we just need to send session committed broadcast. dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null); return; } @@ -1691,14 +1709,30 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { "APEX packages can only be installed using staged sessions.", null); return; } + verify(); + } + /** + * Resumes verification process for non-final committed staged session. + * + * Useful if a device gets rebooted before verification is complete and we need to restart the + * verification. + */ + void verifyStagedSession() { + assertCallerIsOwnerOrRootOrSystemLocked(); + Preconditions.checkArgument(isCommitted()); + Preconditions.checkArgument(isStaged()); + Preconditions.checkArgument(!mStagedSessionApplied && !mStagedSessionFailed); + + verify(); + } + + private void verify() { try { verifyNonStaged(); } catch (PackageManagerException e) { final String completeMsg = ExceptionUtils.getCompleteMessage(e); - Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg); - destroyInternal(); - dispatchSessionFinished(e.error, completeMsg, null); + onSessionVerificationFailure(e.error, completeMsg); } } @@ -1846,7 +1880,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private PackageManagerService.VerificationParams makeVerificationParamsLocked() throws PackageManagerException { - if (!params.isMultiPackage) { + // TODO(b/136257624): Some logic in this if block probably belongs in + // makeInstallParams(). + if (!params.isMultiPackage && !isApexInstallation()) { Objects.requireNonNull(mPackageName); Objects.requireNonNull(mSigningDetails); Objects.requireNonNull(mResolvedBaseFile); @@ -1923,8 +1959,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (returnCode == PackageManager.INSTALL_SUCCEEDED) { onVerificationComplete(); } else { - destroyInternal(); - dispatchSessionFinished(returnCode, msg, extras); + onSessionVerificationFailure(returnCode, msg); } } }; @@ -1946,9 +1981,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } private void onVerificationComplete() { - if ((params.installFlags & PackageManager.INSTALL_DRY_RUN) != 0) { - destroyInternal(); - dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Dry run", new Bundle()); + // Staged sessions will be installed later during boot + if (isStaged()) { + // TODO(b/136257624): Remove this once all verification logic has been transferred out + // of StagingManager. + mStagingManager.notifyPreRebootVerification_Apk_Complete(sessionId); + // TODO(b/136257624): We also need to destroy internals for verified staged session, + // otherwise file descriptors are never closed for verified staged session until reboot return; } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 5fd73743c3ac..c05bc455887d 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -15201,6 +15201,13 @@ public class PackageManagerService extends IPackageManager.Stub } public void handleStartCopy() { + if ((installFlags & PackageManager.INSTALL_APEX) != 0) { + // Apex packages get verified in StagingManager currently. + // TODO(b/136257624): Move apex verification logic out of StagingManager + mRet = INSTALL_SUCCEEDED; + return; + } + PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext, origin.resolvedPath, installFlags, packageAbiOverride); diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 7e2ef41943d6..4d2e22a2640e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -103,6 +103,7 @@ import android.util.SparseArray; import com.android.internal.content.PackageHelper; import com.android.internal.util.ArrayUtils; import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.Preconditions; import com.android.server.LocalServices; import com.android.server.SystemConfig; import com.android.server.pm.PackageManagerShellCommandDataLoader.Metadata; @@ -138,7 +139,7 @@ class PackageManagerShellCommand extends ShellCommand { private static final String STDIN_PATH = "-"; /** Path where ART profiles snapshots are dumped for the shell user */ private final static String ART_PROFILE_SNAPSHOT_DEBUG_LOCATION = "/data/misc/profman/"; - private static final int DEFAULT_WAIT_MS = 60 * 1000; + private static final int DEFAULT_STAGED_READY_TIMEOUT_MS = 60 * 1000; private static final String TAG = "PackageManagerShellCommand"; final IPackageManager mInterface; @@ -463,9 +464,20 @@ class PackageManagerShellCommand extends ShellCommand { return 1; } - private int runRollbackApp() { + private int runRollbackApp() throws RemoteException { final PrintWriter pw = getOutPrintWriter(); + String opt; + long stagedReadyTimeoutMs = DEFAULT_STAGED_READY_TIMEOUT_MS; + while ((opt = getNextOption()) != null) { + switch (opt) { + case "--staged-ready-timeout": + stagedReadyTimeoutMs = Long.parseLong(getNextArgRequired()); + break; + default: + throw new IllegalArgumentException("Unknown option: " + opt); + } + } final String packageName = getNextArgRequired(); if (packageName == null) { pw.println("Error: package name not specified"); @@ -495,14 +507,21 @@ class PackageManagerShellCommand extends ShellCommand { final Intent result = receiver.getResult(); final int status = result.getIntExtra(RollbackManager.EXTRA_STATUS, RollbackManager.STATUS_FAILURE); - if (status == RollbackManager.STATUS_SUCCESS) { - pw.println("Success"); - return 0; - } else { + + if (status != RollbackManager.STATUS_SUCCESS) { pw.println("Failure [" + result.getStringExtra(RollbackManager.EXTRA_STATUS_MESSAGE) + "]"); return 1; } + + if (rollback.isStaged() && stagedReadyTimeoutMs > 0) { + final int committedSessionId = rollback.getCommittedSessionId(); + return doWaitForStagedSessionReady(committedSessionId, stagedReadyTimeoutMs, pw); + } + + pw.println("Success"); + return 0; + } private void setParamsSize(InstallParams params, List<String> inPaths) { @@ -1307,11 +1326,12 @@ class PackageManagerShellCommand extends ShellCommand { } abandonSession = false; - if (!params.sessionParams.isStaged || !params.mWaitForStagedSessionReady) { - pw.println("Success"); - return 0; + if (params.sessionParams.isStaged && params.stagedReadyTimeoutMs > 0) { + return doWaitForStagedSessionReady(sessionId, params.stagedReadyTimeoutMs, pw); } - return doWaitForStagedSessionRead(sessionId, params.timeoutMs, pw); + + pw.println("Success"); + return 0; } finally { if (abandonSession) { try { @@ -1322,11 +1342,9 @@ class PackageManagerShellCommand extends ShellCommand { } } - private int doWaitForStagedSessionRead(int sessionId, long timeoutMs, PrintWriter pw) + private int doWaitForStagedSessionReady(int sessionId, long timeoutMs, PrintWriter pw) throws RemoteException { - if (timeoutMs <= 0) { - timeoutMs = DEFAULT_WAIT_MS; - } + Preconditions.checkArgument(timeoutMs > 0); PackageInstaller.SessionInfo si = mInterface.getPackageInstaller() .getSessionInfo(sessionId); if (si == null) { @@ -1376,25 +1394,14 @@ class PackageManagerShellCommand extends ShellCommand { private int runInstallCommit() throws RemoteException { final PrintWriter pw = getOutPrintWriter(); String opt; - boolean waitForStagedSessionReady = true; - long timeoutMs = -1; + long stagedReadyTimeoutMs = DEFAULT_STAGED_READY_TIMEOUT_MS; while ((opt = getNextOption()) != null) { switch (opt) { - case "--wait-for-staged-ready": - waitForStagedSessionReady = true; - // If there is only one remaining argument, then it represents the sessionId, we - // shouldn't try to parse it as timeoutMs. - if (getRemainingArgsCount() > 1) { - try { - timeoutMs = Long.parseLong(peekNextArg()); - getNextArg(); - } catch (NumberFormatException ignore) { - } - } - break; - case "--no-wait": - waitForStagedSessionReady = false; + case "--staged-ready-timeout": + stagedReadyTimeoutMs = Long.parseLong(getNextArgRequired()); break; + default: + throw new IllegalArgumentException("Unknown option: " + opt); } } final int sessionId = Integer.parseInt(getNextArg()); @@ -1403,11 +1410,11 @@ class PackageManagerShellCommand extends ShellCommand { } final PackageInstaller.SessionInfo si = mInterface.getPackageInstaller() .getSessionInfo(sessionId); - if (si == null || !si.isStaged() || !waitForStagedSessionReady) { - pw.println("Success"); - return 0; + if (si != null && si.isStaged() && stagedReadyTimeoutMs > 0) { + return doWaitForStagedSessionReady(sessionId, stagedReadyTimeoutMs, pw); } - return doWaitForStagedSessionRead(sessionId, timeoutMs, pw); + pw.println("Success"); + return 0; } private int runInstallCreate() throws RemoteException { @@ -2738,8 +2745,7 @@ class PackageManagerShellCommand extends ShellCommand { SessionParams sessionParams; String installerPackageName; int userId = UserHandle.USER_ALL; - boolean mWaitForStagedSessionReady = true; - long timeoutMs = DEFAULT_WAIT_MS; + long stagedReadyTimeoutMs = DEFAULT_STAGED_READY_TIMEOUT_MS; } private InstallParams makeInstallParams() { @@ -2868,16 +2874,8 @@ class PackageManagerShellCommand extends ShellCommand { } sessionParams.installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK; break; - case "--wait-for-staged-ready": - params.mWaitForStagedSessionReady = true; - try { - params.timeoutMs = Long.parseLong(peekNextArg()); - getNextArg(); - } catch (NumberFormatException ignore) { - } - break; - case "--no-wait": - params.mWaitForStagedSessionReady = false; + case "--staged-ready-timeout": + params.stagedReadyTimeoutMs = Long.parseLong(getNextArgRequired()); break; case "--skip-verification": sessionParams.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION; @@ -3613,7 +3611,7 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" [--preload] [--instant] [--full] [--dont-kill]"); pw.println(" [--enable-rollback]"); pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]"); - pw.println(" [--apex] [--wait-for-staged-ready TIMEOUT]"); + pw.println(" [--apex] [--staged-ready-timeout TIMEOUT]"); pw.println(" [PATH [SPLIT...]|-]"); pw.println(" Install an application. Must provide the apk data to install, either as"); pw.println(" file path(s) or '-' to read from stdin. Options are:"); @@ -3641,9 +3639,11 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" 3=device setup, 4=user request"); pw.println(" --force-uuid: force install on to disk volume with given UUID"); pw.println(" --apex: install an .apex file, not an .apk"); - pw.println(" --wait-for-staged-ready: when performing staged install, wait TIMEOUT"); - pw.println(" ms for pre-reboot verification to complete. If TIMEOUT is not"); - pw.println(" specified it will wait for " + DEFAULT_WAIT_MS + " milliseconds."); + pw.println(" --staged-ready-timeout: By default, staged sessions wait " + + DEFAULT_STAGED_READY_TIMEOUT_MS); + pw.println(" milliseconds for pre-reboot verification to complete when"); + pw.println(" performing staged install. This flag is used to alter the waiting"); + pw.println(" time. You can skip the waiting time by specifying a TIMEOUT of '0'"); pw.println(""); pw.println(" install-existing [--user USER_ID|all|current]"); pw.println(" [--instant] [--full] [--wait] [--restrict-permissions] PACKAGE"); diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 105a9b06cf42..0c4eaec32ba5 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -88,7 +88,6 @@ import java.util.List; import java.util.Set; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.Supplier; @@ -189,7 +188,6 @@ public class StagingManager { * Validates the signature used to sign the container of the new apex package * * @param newApexPkg The new apex package that is being installed - * @throws PackageManagerException */ private void validateApexSignature(PackageInfo newApexPkg) throws PackageManagerException { @@ -725,12 +723,9 @@ public class StagingManager { return ret; } - @NonNull private PackageInstallerSession createAndWriteApkSession( - @NonNull PackageInstallerSession originalSession, boolean preReboot) - throws PackageManagerException { - final int errorCode = preReboot ? SessionInfo.STAGED_SESSION_VERIFICATION_FAILED - : SessionInfo.STAGED_SESSION_ACTIVATION_FAILED; + PackageInstallerSession originalSession) throws PackageManagerException { + final int errorCode = SessionInfo.STAGED_SESSION_ACTIVATION_FAILED; if (originalSession.stageDir == null) { Slog.wtf(TAG, "Attempting to install a staged APK session with no staging dir"); throw new PackageManagerException(errorCode, @@ -746,12 +741,7 @@ public class StagingManager { PackageInstaller.SessionParams params = originalSession.params.copy(); params.isStaged = false; params.installFlags |= PackageManager.INSTALL_STAGED; - if (preReboot) { - params.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK; - params.installFlags |= PackageManager.INSTALL_DRY_RUN; - } else { - params.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION; - } + params.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION; try { int apkSessionId = mPi.createSession( params, originalSession.getInstallerPackageName(), @@ -783,12 +773,10 @@ public class StagingManager { * apks in the given session. Only parent session is returned for multi-package session. */ @Nullable - private PackageInstallerSession extractApksInSession(PackageInstallerSession session, - boolean preReboot) throws PackageManagerException { - final int errorCode = preReboot ? SessionInfo.STAGED_SESSION_VERIFICATION_FAILED - : SessionInfo.STAGED_SESSION_ACTIVATION_FAILED; + private PackageInstallerSession extractApksInSession(PackageInstallerSession session) + throws PackageManagerException { if (!session.isMultiPackage() && !isApexSession(session)) { - return createAndWriteApkSession(session, preReboot); + return createAndWriteApkSession(session); } else if (session.isMultiPackage()) { // For multi-package staged sessions containing APKs, we identify which child sessions // contain an APK, and with those then create a new multi-package group of sessions, @@ -810,10 +798,6 @@ public class StagingManager { } final PackageInstaller.SessionParams params = session.params.copy(); params.isStaged = false; - if (preReboot) { - params.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK; - params.installFlags |= PackageManager.INSTALL_DRY_RUN; - } final int apkParentSessionId = mPi.createSession( params, session.getInstallerPackageName(), session.getInstallerAttributionTag(), session.userId); @@ -823,18 +807,18 @@ public class StagingManager { } catch (IOException e) { Slog.e(TAG, "Unable to prepare multi-package session for staged session " + session.sessionId); - throw new PackageManagerException(errorCode, + throw new PackageManagerException(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, "Unable to prepare multi-package session for staged session"); } for (int i = 0, size = childSessions.size(); i < size; i++) { final PackageInstallerSession apkChildSession = createAndWriteApkSession( - childSessions.get(i), preReboot); + childSessions.get(i)); try { apkParentSession.addChildSessionId(apkChildSession.sessionId); } catch (IllegalStateException e) { Slog.e(TAG, "Failed to add a child session for installing the APK files", e); - throw new PackageManagerException(errorCode, + throw new PackageManagerException(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, "Failed to add a child session " + apkChildSession.sessionId); } } @@ -877,11 +861,9 @@ public class StagingManager { } } - private void installApksInSession(@NonNull PackageInstallerSession session) + private void installApksInSession(PackageInstallerSession session) throws PackageManagerException { - - final PackageInstallerSession apksToInstall = extractApksInSession( - session, /* preReboot */ false); + final PackageInstallerSession apksToInstall = extractApksInSession(session); if (apksToInstall == null) { return; } @@ -1047,7 +1029,7 @@ public class StagingManager { /** * <p>Abort committed staged session * - * <p>This method must be called while holding {@link PackageInstallerSession.mLock}. + * <p>This method must be called while holding {@link PackageInstallerSession#mLock}. * * <p>The method returns {@code false} to indicate it is not safe to clean up the session from * system yet. When it is safe, the method returns {@code true}. @@ -1218,7 +1200,7 @@ public class StagingManager { } } - void markStagedSessionsAsSuccessful() { + private void markStagedSessionsAsSuccessful() { synchronized (mSuccessfulStagedSessionIds) { for (int i = 0; i < mSuccessfulStagedSessionIds.size(); i++) { mApexManager.markStagedSessionSuccessful(mSuccessfulStagedSessionIds.get(i)); @@ -1242,30 +1224,10 @@ public class StagingManager { mFailureReasonFile.delete(); } - private static class LocalIntentReceiverAsync { - final Consumer<Intent> mConsumer; - - LocalIntentReceiverAsync(Consumer<Intent> consumer) { - mConsumer = consumer; - } - - private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() { - @Override - public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken, - IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { - mConsumer.accept(intent); - } - }; - - public IntentSender getIntentSender() { - return new IntentSender((IIntentSender) mLocalSender); - } - } - private static class LocalIntentReceiverSync { private final LinkedBlockingQueue<Intent> mResult = new LinkedBlockingQueue<>(); - private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() { + private final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() { @Override public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken, IIntentReceiver finishedReceiver, String requiredPermission, @@ -1299,6 +1261,20 @@ public class StagingManager { return session; } + // TODO(b/136257624): Temporary API to let PMS communicate with StagingManager. When all + // verification logic is extracted out of StagingManager into PMS, we can remove + // this. + void notifyVerificationComplete(int sessionId) { + mPreRebootVerificationHandler.onPreRebootVerificationComplete(sessionId); + } + + // TODO(b/136257624): Temporary API to let PMS communicate with StagingManager. When all + // verification logic is extracted out of StagingManager into PMS, we can remove + // this. + void notifyPreRebootVerification_Apk_Complete(int sessionId) { + mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete(sessionId); + } + private final class PreRebootVerificationHandler extends Handler { // Hold session ids before handler gets ready to do the verification. private IntArray mPendingSessionIds; @@ -1500,54 +1476,16 @@ public class StagingManager { } /** - * Pre-reboot verification state for apk files: - * <p><ul> - * <li>performs a dry-run install of apk</li> - * </ul></p> + * Pre-reboot verification state for apk files. Session is sent to + * {@link PackageManagerService} for verification and it notifies back the result via + * {@link #notifyPreRebootVerification_Apk_Complete(int)} */ private void handlePreRebootVerification_Apk(@NonNull PackageInstallerSession session) { if (!sessionContainsApk(session)) { notifyPreRebootVerification_Apk_Complete(session.sessionId); return; } - - try { - Slog.d(TAG, "Running a pre-reboot verification for APKs in session " - + session.sessionId + " by performing a dry-run install"); - // verifyApksInSession will notify the handler when APK verification is complete - verifyApksInSession(session); - } catch (PackageManagerException e) { - onPreRebootVerificationFailure(session, e.error, e.getMessage()); - } - } - - private void verifyApksInSession(PackageInstallerSession session) - throws PackageManagerException { - - final PackageInstallerSession apksToVerify = extractApksInSession( - session, /* preReboot */ true); - if (apksToVerify == null) { - return; - } - - final LocalIntentReceiverAsync receiver = new LocalIntentReceiverAsync( - (Intent result) -> { - final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, - PackageInstaller.STATUS_FAILURE); - if (status != PackageInstaller.STATUS_SUCCESS) { - final String errorMessage = result.getStringExtra( - PackageInstaller.EXTRA_STATUS_MESSAGE); - Slog.e(TAG, "Failure to verify APK staged session " - + session.sessionId + " [" + errorMessage + "]"); - onPreRebootVerificationFailure(session, - SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMessage); - return; - } - mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete( - session.sessionId); - }); - - apksToVerify.commit(receiver.getIntentSender(), false); + session.verifyStagedSession(); } /** diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index c1aebd33889c..d137fd05f793 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -84,7 +84,6 @@ import android.os.storage.StorageManager; import android.security.GateKeeper; import android.service.gatekeeper.IGateKeeperService; import android.stats.devicepolicy.DevicePolicyEnums; -import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; @@ -142,6 +141,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicInteger; /** * Service for {@link UserManager}. @@ -159,10 +159,6 @@ public class UserManagerService extends IUserManager.Stub { private static final String LOG_TAG = "UserManagerService"; static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE private static final boolean DBG_WITH_STACKTRACE = false; // DO NOT SUBMIT WITH TRUE - - // TODO(b/164159026): remove once owner_name issue on automotive is fixed - // Can be used to track getUsers() / userWithNameLU() behavior - public static final boolean DBG_CACHED_USERINFOS = false; // DO NOT SUBMIT WITH TRUE // Can be used for manual testing of id recycling private static final boolean RELEASE_DELETED_USER_ID = false; // DO NOT SUBMIT WITH TRUE @@ -276,25 +272,6 @@ public class UserManagerService extends IUserManager.Stub { private DevicePolicyManagerInternal mDevicePolicyManagerInternal; /** - * Reference to the {@link UserHandle#SYSTEM} user's UserInfo; it's {@code name} was either - * manually set, or it's {@code null}. - * - * <p>The reference is set just once, but it's {@code name} is updated when it's manually set. - */ - @GuardedBy("mUsersLock") - private UserInfo mSystemUserInfo; - - /** - * Reference to the {@link UserHandle#SYSTEM} user's UserInfo, with its {@code name} set to - * the localized value of {@code owner_name}. - * - * <p>The reference is set just once, but it's {@code name} is updated everytime the reference - * is used and the locale changed. - */ - @GuardedBy("mUsersLock") - private UserInfo mSystemUserInfoWithName; - - /** * Internal non-parcelable wrapper for UserInfo that is not exposed to other system apps. */ @VisibleForTesting @@ -467,6 +444,11 @@ public class UserManagerService extends IUserManager.Stub { } }; + // TODO(b/161915546): remove once userWithName() is fixed / removed + // Use to debug / dump when user 0 is allocated at userWithName() + public static final boolean DBG_ALLOCATION = false; // DO NOT SUBMIT WITH TRUE + public final AtomicInteger mUser0Allocations; + /** * Start an {@link IntentSender} when user is unlocked after disabling quiet mode. * @@ -656,6 +638,7 @@ public class UserManagerService extends IUserManager.Stub { LocalServices.addService(UserManagerInternal.class, mLocalService); mLockPatternUtils = new LockPatternUtils(mContext); mUserStates.put(UserHandle.USER_SYSTEM, UserState.STATE_BOOTING); + mUser0Allocations = DBG_ALLOCATION ? new AtomicInteger() : null; } void systemReady() { @@ -801,7 +784,7 @@ public class UserManagerService extends IUserManager.Stub { || (excludePreCreated && ui.preCreated)) { continue; } - users.add(userWithNameLU(ui)); + users.add(userWithName(ui)); } return users; } @@ -870,7 +853,7 @@ public class UserManagerService extends IUserManager.Stub { userInfo.name = null; userInfo.iconPath = null; } else { - userInfo = userWithNameLU(userInfo); + userInfo = userWithName(userInfo); } users.add(userInfo); } @@ -1327,57 +1310,26 @@ public class UserManagerService extends IUserManager.Stub { public UserInfo getUserInfo(@UserIdInt int userId) { checkManageOrCreateUsersPermission("query user"); synchronized (mUsersLock) { - return userWithNameLU(getUserInfoLU(userId)); + return userWithName(getUserInfoLU(userId)); } } /** * Returns a UserInfo object with the name filled in, for Owner, or the original * if the name is already set. - * - * <p>Note:</p> the Owner name is localized, so the current value must be checked every time - * this method is called. */ - private UserInfo userWithNameLU(UserInfo orig) { - // Only the system user uses the owner_name string. - if (orig == null || orig.id != UserHandle.USER_SYSTEM) return orig; - - if (mSystemUserInfo == null) { - mSystemUserInfo = orig; - if (DBG_CACHED_USERINFOS) { - Slog.d(LOG_TAG, "Set mSystemUserInfo:" + mSystemUserInfo.toFullString()); - } - } - - if (mSystemUserInfo.name != null) { - if (DBG_CACHED_USERINFOS) { - Slog.v(LOG_TAG, "Returning mSystemUserInfo: " + mSystemUserInfo.toFullString()); - } - return mSystemUserInfo; - } - - final String ownerName = getOwnerName(); - - if (mSystemUserInfoWithName == null) { - mSystemUserInfoWithName = new UserInfo(orig); - mSystemUserInfoWithName.name = ownerName; - if (DBG_CACHED_USERINFOS) { - Slog.d(LOG_TAG, "Set mSystemUserInfoWithName: " - + mSystemUserInfoWithName.toFullString()); - } - } else if (!TextUtils.equals(ownerName, mSystemUserInfoWithName.name)) { - if (DBG_CACHED_USERINFOS) { - Slog.d(LOG_TAG, "Updating mSystemUserInfoWithName.name from " - + mSystemUserInfoWithName.name + " to " + ownerName); - } - mSystemUserInfoWithName.name = ownerName; - } - - if (DBG_CACHED_USERINFOS) { - Slog.v(LOG_TAG, "Returning mSystemUserInfoWithName:" - + mSystemUserInfoWithName.toFullString()); + private UserInfo userWithName(UserInfo orig) { + if (orig != null && orig.name == null && orig.id == UserHandle.USER_SYSTEM) { + if (DBG_ALLOCATION) { + final int number = mUser0Allocations.incrementAndGet(); + Slog.w(LOG_TAG, "System user instantiated at least " + number + " times"); + } + UserInfo withName = new UserInfo(orig); + withName.name = getOwnerName(); + return withName; + } else { + return orig; } - return mSystemUserInfoWithName; } /** Returns whether the given user type is one of the FULL user types. */ @@ -1530,7 +1482,7 @@ public class UserManagerService extends IUserManager.Stub { } final int userId = UserHandle.getUserId(Binder.getCallingUid()); synchronized (mUsersLock) { - UserInfo userInfo = userWithNameLU(getUserInfoLU(userId)); + UserInfo userInfo = userWithName(getUserInfoLU(userId)); return userInfo == null ? "" : userInfo.name; } } @@ -1645,13 +1597,6 @@ public class UserManagerService extends IUserManager.Stub { Slog.w(LOG_TAG, "getUserInfo: unknown user #" + userId); return null; } - - if (DBG_CACHED_USERINFOS && userId == UserHandle.USER_SYSTEM && userData != null - && userData.info != mSystemUserInfo) { - Slog.wtf(LOG_TAG, "getUserInfoLU(): system user on userData (" + userData.info - + ") is not the same as mSystemUserInfo (" + mSystemUserInfo + ")"); - } - return userData != null ? userData.info : null; } @@ -4910,15 +4855,8 @@ public class UserManagerService extends IUserManager.Stub { pw.println(" Is headless-system mode: " + UserManager.isHeadlessSystemUserMode()); pw.println(" User version: " + mUserVersion); pw.println(" Owner name: " + getOwnerName()); - if (mSystemUserInfo == null) { - pw.println(" (mSystemUserInfo not set)"); - } else { - pw.println(" System user: " + mSystemUserInfo.toFullString()); - } - if (mSystemUserInfoWithName == null) { - pw.println(" (mSystemUserInfoWithName not set)"); - } else { - pw.println(" System user (with name): " + mSystemUserInfoWithName.toFullString()); + if (DBG_ALLOCATION) { + pw.println(" System user allocations: " + mUser0Allocations.get()); } // Dump UserTypes diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 548cd70de4d1..137c587b1d79 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -2219,11 +2219,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override - public int getMaxWallpaperLayer() { - return getWindowLayerFromTypeLw(TYPE_NOTIFICATION_SHADE); - } - - @Override public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs) { return attrs.type == TYPE_NOTIFICATION_SHADE; } @@ -5324,15 +5319,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override - public boolean isTopLevelWindow(int windowType) { - if (windowType >= WindowManager.LayoutParams.FIRST_SUB_WINDOW - && windowType <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { - return (windowType == WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG); - } - return true; - } - - @Override public void dumpDebug(ProtoOutputStream proto, long fieldId) { final long token = proto.start(fieldId); proto.write(ROTATION_MODE, mDefaultDisplayRotation.getUserRotationMode()); diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 651eafd77fe7..b96d65cb7433 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -67,7 +67,6 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.WindowConfiguration; import android.content.Context; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; @@ -90,7 +89,6 @@ import android.view.animation.Animation; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.policy.IShortcutService; import com.android.server.wm.DisplayRotation; -import com.android.server.wm.WindowFrames; import java.io.PrintWriter; import java.lang.annotation.Retention; @@ -181,92 +179,11 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { */ public interface WindowState { /** - * Return the uid of the app that owns this window. - */ - int getOwningUid(); - - /** * Return the package name of the app that owns this window. */ String getOwningPackage(); /** - * Perform standard frame computation. The result can be obtained with - * getFrame() if so desired. Must be called with the window manager - * lock held. - * - */ - public void computeFrameLw(); - - /** - * Retrieve the current frame of the window that has been assigned by - * the window manager. Must be called with the window manager lock held. - * - * @return Rect The rectangle holding the window frame. - */ - public Rect getFrameLw(); - - /** - * Retrieve the frame of the display that this window was last - * laid out in. Must be called with the - * window manager lock held. - * - * @return Rect The rectangle holding the display frame. - */ - public Rect getDisplayFrameLw(); - - /** - * Retrieve the frame of the content area that this window was last - * laid out in. This is the area in which the content of the window - * should be placed. It will be smaller than the display frame to - * account for screen decorations such as a status bar or soft - * keyboard. Must be called with the - * window manager lock held. - * - * @return Rect The rectangle holding the content frame. - */ - public Rect getContentFrameLw(); - - /** - * Retrieve the frame of the visible area that this window was last - * laid out in. This is the area of the screen in which the window - * will actually be fully visible. It will be smaller than the - * content frame to account for transient UI elements blocking it - * such as an input method's candidates UI. Must be called with the - * window manager lock held. - * - * @return Rect The rectangle holding the visible frame. - */ - public Rect getVisibleFrameLw(); - - /** - * Returns true if this window is waiting to receive its given - * internal insets from the client app, and so should not impact the - * layout of other windows. - */ - public boolean getGivenInsetsPendingLw(); - - /** - * Retrieve the insets given by this window's client for the content - * area of windows behind it. Must be called with the - * window manager lock held. - * - * @return Rect The left, top, right, and bottom insets, relative - * to the window's frame, of the actual contents. - */ - public Rect getGivenContentInsetsLw(); - - /** - * Retrieve the insets given by this window's client for the visible - * area of windows behind it. Must be called with the - * window manager lock held. - * - * @return Rect The left, top, right, and bottom insets, relative - * to the window's frame, of the actual visible area. - */ - public Rect getGivenVisibleInsetsLw(); - - /** * Retrieve the current LayoutParams of the window. * * @return WindowManager.LayoutParams The window's internal LayoutParams @@ -275,17 +192,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { public WindowManager.LayoutParams getAttrs(); /** - * Retrieve the current system UI visibility flags associated with - * this window. - */ - public int getSystemUiVisibility(); - - /** - * Get the layer at which this window's surface will be Z-ordered. - */ - public int getSurfaceLayer(); - - /** * Retrieve the type of the top-level window. * * @return the base type of the parent window if attached or its own type otherwise @@ -301,22 +207,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { public IApplicationToken getAppToken(); /** - * Return true if this window is participating in voice interaction. - */ - public boolean isVoiceInteraction(); - - /** - * Return true if, at any point, the application token associated with - * this window has actually displayed any windows. This is most useful - * with the "starting up" window to determine if any windows were - * displayed when it is closed. - * - * @return Returns true if one or more windows have been displayed, - * else false. - */ - public boolean hasAppShownWindows(); - - /** * Is this window visible? It is not visible if there is no * surface, or we are in the process of running an exit animation * that will remove the surface. @@ -324,42 +214,12 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { boolean isVisibleLw(); /** - * Is this window currently visible to the user on-screen? It is - * displayed either if it is visible or it is currently running an - * animation before no longer being visible. Must be called with the - * window manager lock held. - */ - boolean isDisplayedLw(); - - /** * Return true if this window (or a window it is attached to, but not * considering its app token) is currently animating. */ boolean isAnimatingLw(); /** - * Is this window considered to be gone for purposes of layout? - */ - boolean isGoneForLayoutLw(); - - /** - * Returns true if the window has a surface that it has drawn a - * complete UI in to. Note that this is different from {@link #hasDrawnLw()} - * in that it also returns true if the window is READY_TO_SHOW, but was not yet - * promoted to HAS_DRAWN. - */ - boolean isDrawnLw(); - - /** - * Returns true if this window has been shown on screen at some time in - * the past. Must be called with the window manager lock held. - * - * @deprecated Use {@link #isDrawnLw} or any of the other drawn/visibility methods. - */ - @Deprecated - public boolean hasDrawnLw(); - - /** * Can be called by the policy to force a window to be hidden, * regardless of whether the client or window manager would like * it shown. Must be called with the window manager lock held. @@ -377,51 +237,12 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { public boolean showLw(boolean doAnimation); /** - * Check whether the process hosting this window is currently alive. - */ - public boolean isAlive(); - - /** - * Check if window is on {@link Display#DEFAULT_DISPLAY}. - * @return true if window is on default display. - */ - public boolean isDefaultDisplay(); - - /** * Check whether the window is currently dimming. */ public boolean isDimming(); - /** - * Returns true if the window is letterboxed for the display cutout. - */ - default boolean isLetterboxedForDisplayCutoutLw() { - return false; - } - - /** @return the current windowing mode of this window. */ - int getWindowingMode(); - - /** - * Returns the {@link WindowConfiguration.ActivityType} associated with the configuration - * of this window. - */ - default int getActivityType() { - return WindowConfiguration.WINDOWING_MODE_UNDEFINED; - } - - /** - * Returns true if the window is current in multi-windowing mode. i.e. it shares the - * screen with other application windows. - */ - boolean inMultiWindowMode(); - - public int getRotationAnimationHint(); - public boolean isInputMethodWindow(); - public boolean isInputMethodTarget(); - public int getDisplayId(); /** @@ -432,42 +253,8 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { return false; } - /** - * Returns true if the window owner has the permission to acquire a sleep token when it's - * visible. That is, they have the permission {@link Manifest.permission#DEVICE_POWER}. - */ - boolean canAcquireSleepToken(); - - /** @return true if this window desires key events. */ - boolean canReceiveKeys(); - /** @return true if the window can show over keyguard. */ boolean canShowWhenLocked(); - - /** - * Writes {@link com.android.server.wm.IdentifierProto} to stream. - */ - void writeIdentifierToProto(ProtoOutputStream proto, long fieldId); - - /** - * @return The {@link WindowFrames} associated with this {@link WindowState} - */ - WindowFrames getWindowFrames(); - } - - /** - * Representation of a input consumer that the policy has added to the - * window manager to consume input events going to windows below it. - */ - public interface InputConsumer { - /** - * Remove the input consumer from the window manager. - */ - void dismiss(); - /** - * Dispose the input consumer and input receiver from UI thread. - */ - void dispose(); } /** @@ -538,11 +325,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { void unregisterPointerEventListener(PointerEventListener listener, int displayId); /** - * @return The currently active input method window. - */ - WindowState getInputMethodWindowLw(); - - /** * Notifies window manager that {@link #isKeyguardTrustedLw} has changed. */ void notifyKeyguardTrustedChanged(); @@ -615,17 +397,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { } /** - * Provides the rotation of a device. - * - * @see com.android.server.policy.WindowOrientationListener - */ - public interface RotationSource { - int getProposedRotation(); - - void setCurrentRotation(int rotation); - } - - /** * Interface to get public information of a display content. */ public interface DisplayContentInfo { @@ -889,12 +660,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { } /** - * Get the highest layer (actually one more than) that the wallpaper is - * allowed to be in. - */ - public int getMaxWallpaperLayer(); - - /** * Return whether the given window can become the Keyguard window. Typically returns true for * the StatusBar. */ @@ -1384,17 +1149,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { void dumpDebug(ProtoOutputStream proto, long fieldId); /** - * Returns whether a given window type is considered a top level one. - * A top level window does not have a container, i.e. attached window, - * or if it has a container it is laid out as a top-level window, not - * as a child of its container. - * - * @param windowType The window type. - * @return True if the window is a top level one. - */ - public boolean isTopLevelWindow(int windowType); - - /** * Notifies the keyguard to start fading out. * * @param startTime the start time of the animation in uptime milliseconds diff --git a/services/core/java/com/android/server/timezonedetector/CallerIdentityInjector.java b/services/core/java/com/android/server/timezonedetector/CallerIdentityInjector.java new file mode 100644 index 000000000000..1500cfaeb3a2 --- /dev/null +++ b/services/core/java/com/android/server/timezonedetector/CallerIdentityInjector.java @@ -0,0 +1,62 @@ +/* + * 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.timezonedetector; + +import android.annotation.UserIdInt; +import android.os.Binder; +import android.os.UserHandle; + +/** + * An interface to wrap various difficult-to-intercept calls that services make to access / manage + * caller identity, e.g. {@link Binder#clearCallingIdentity()}. + */ +public interface CallerIdentityInjector { + + /** A singleton for the real implementation of {@link CallerIdentityInjector}. */ + CallerIdentityInjector REAL = new Real(); + + /** A {@link UserHandle#getCallingUserId()} call. */ + @UserIdInt int getCallingUserId(); + + /** A {@link Binder#clearCallingIdentity()} call. */ + long clearCallingIdentity(); + + /** A {@link Binder#restoreCallingIdentity(long)} ()} call. */ + void restoreCallingIdentity(long token); + + /** The real implementation of {@link CallerIdentityInjector}. */ + class Real implements CallerIdentityInjector { + + protected Real() { + } + + @Override + public int getCallingUserId() { + return UserHandle.getCallingUserId(); + } + + @Override + public long clearCallingIdentity() { + return Binder.clearCallingIdentity(); + } + + @Override + public void restoreCallingIdentity(long token) { + Binder.restoreCallingIdentity(token); + } + } +} diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java b/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java new file mode 100644 index 000000000000..4c7b1f38dd5a --- /dev/null +++ b/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java @@ -0,0 +1,26 @@ +/* + * Copyright 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.server.timezonedetector; + +/** + * A listener used to receive notification that time zone configuration has changed. + */ +@FunctionalInterface +public interface ConfigurationChangeListener { + /** Called when the current user or a configuration value has changed. */ + void onChange(); +} diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java new file mode 100644 index 000000000000..aee3d8d3499b --- /dev/null +++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java @@ -0,0 +1,288 @@ +/* + * 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.timezonedetector; + +import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED; +import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE; +import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED; +import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED; + +import android.annotation.NonNull; +import android.annotation.UserIdInt; +import android.app.timezonedetector.TimeZoneCapabilities; +import android.app.timezonedetector.TimeZoneConfiguration; + +import java.util.Objects; + +/** + * Holds all configuration values that affect time zone behavior and some associated logic, e.g. + * {@link #getAutoDetectionEnabledBehavior()}, {@link #getGeoDetectionEnabledBehavior()} and {@link + * #createCapabilities()}. + */ +public final class ConfigurationInternal { + + private final @UserIdInt int mUserId; + private final boolean mUserConfigAllowed; + private final boolean mAutoDetectionSupported; + private final boolean mAutoDetectionEnabled; + private final boolean mLocationEnabled; + private final boolean mGeoDetectionEnabled; + + private ConfigurationInternal(Builder builder) { + mUserId = builder.mUserId; + mUserConfigAllowed = builder.mUserConfigAllowed; + mAutoDetectionSupported = builder.mAutoDetectionSupported; + mAutoDetectionEnabled = builder.mAutoDetectionEnabled; + mLocationEnabled = builder.mLocationEnabled; + mGeoDetectionEnabled = builder.mGeoDetectionEnabled; + } + + /** Returns the ID of the user this configuration is associated with. */ + public @UserIdInt int getUserId() { + return mUserId; + } + + /** Returns true if the user allowed to modify time zone configuration. */ + public boolean isUserConfigAllowed() { + return mUserConfigAllowed; + } + + /** Returns true if the device supports some form of auto time zone detection. */ + public boolean isAutoDetectionSupported() { + return mAutoDetectionSupported; + } + + /** Returns the value of the auto time zone detection enabled setting. */ + public boolean getAutoDetectionEnabledSetting() { + return mAutoDetectionEnabled; + } + + /** + * Returns true if auto time zone detection behavior is actually enabled, which can be distinct + * from the raw setting value. */ + public boolean getAutoDetectionEnabledBehavior() { + return mAutoDetectionSupported && mAutoDetectionEnabled; + } + + /** Returns true if user's location can be used generally. */ + public boolean isLocationEnabled() { + return mLocationEnabled; + } + + /** Returns the value of the geolocation time zone detection enabled setting. */ + public boolean getGeoDetectionEnabledSetting() { + return mGeoDetectionEnabled; + } + + /** + * Returns true if geolocation time zone detection behavior is actually enabled, which can be + * distinct from the raw setting value. + */ + public boolean getGeoDetectionEnabledBehavior() { + if (getAutoDetectionEnabledBehavior()) { + return mLocationEnabled && mGeoDetectionEnabled; + } + return false; + } + + /** Creates a {@link TimeZoneCapabilities} object using the configuration values. */ + public TimeZoneCapabilities createCapabilities() { + TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder() + .setConfiguration(asConfiguration()); + + boolean allowConfigDateTime = isUserConfigAllowed(); + + // Automatic time zone detection is only supported on devices if there is a telephony + // network available or geolocation time zone detection is possible. + boolean deviceHasTimeZoneDetection = isAutoDetectionSupported(); + + final int configureAutoDetectionEnabledCapability; + if (!deviceHasTimeZoneDetection) { + configureAutoDetectionEnabledCapability = CAPABILITY_NOT_SUPPORTED; + } else if (!allowConfigDateTime) { + configureAutoDetectionEnabledCapability = CAPABILITY_NOT_ALLOWED; + } else { + configureAutoDetectionEnabledCapability = CAPABILITY_POSSESSED; + } + builder.setConfigureAutoDetectionEnabled(configureAutoDetectionEnabledCapability); + + final int configureGeolocationDetectionEnabledCapability; + if (!deviceHasTimeZoneDetection) { + configureGeolocationDetectionEnabledCapability = CAPABILITY_NOT_SUPPORTED; + } else if (!allowConfigDateTime) { + configureGeolocationDetectionEnabledCapability = CAPABILITY_NOT_ALLOWED; + } else if (!isLocationEnabled()) { + configureGeolocationDetectionEnabledCapability = CAPABILITY_NOT_APPLICABLE; + } else { + configureGeolocationDetectionEnabledCapability = CAPABILITY_POSSESSED; + } + builder.setConfigureGeoDetectionEnabled(configureGeolocationDetectionEnabledCapability); + + // The ability to make manual time zone suggestions can also be restricted by policy. With + // the current logic above, this could lead to a situation where a device hardware does not + // support auto detection, the device has been forced into "auto" mode by an admin and the + // user is unable to disable auto detection. + final int suggestManualTimeZoneCapability; + if (!allowConfigDateTime) { + suggestManualTimeZoneCapability = CAPABILITY_NOT_ALLOWED; + } else if (getAutoDetectionEnabledBehavior()) { + suggestManualTimeZoneCapability = CAPABILITY_NOT_APPLICABLE; + } else { + suggestManualTimeZoneCapability = CAPABILITY_POSSESSED; + } + builder.setSuggestManualTimeZone(suggestManualTimeZoneCapability); + + return builder.build(); + } + + /** Returns a {@link TimeZoneConfiguration} from the configuration values. */ + public TimeZoneConfiguration asConfiguration() { + return new TimeZoneConfiguration.Builder(mUserId) + .setAutoDetectionEnabled(getAutoDetectionEnabledSetting()) + .setGeoDetectionEnabled(getGeoDetectionEnabledSetting()) + .build(); + } + + /** + * Merges the configuration values from this with any properties set in {@code + * newConfiguration}. The new configuration has precedence. Used to apply user updates to + * internal configuration. + */ + public ConfigurationInternal merge(TimeZoneConfiguration newConfiguration) { + Builder builder = new Builder(this); + if (newConfiguration.hasSetting(TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED)) { + builder.setAutoDetectionEnabled(newConfiguration.isAutoDetectionEnabled()); + } + if (newConfiguration.hasSetting(TimeZoneConfiguration.SETTING_GEO_DETECTION_ENABLED)) { + builder.setGeoDetectionEnabled(newConfiguration.isGeoDetectionEnabled()); + } + return builder.build(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ConfigurationInternal that = (ConfigurationInternal) o; + return mUserId == that.mUserId + && mUserConfigAllowed == that.mUserConfigAllowed + && mAutoDetectionSupported == that.mAutoDetectionSupported + && mAutoDetectionEnabled == that.mAutoDetectionEnabled + && mLocationEnabled == that.mLocationEnabled + && mGeoDetectionEnabled == that.mGeoDetectionEnabled; + } + + @Override + public int hashCode() { + return Objects.hash(mUserId, mUserConfigAllowed, mAutoDetectionSupported, + mAutoDetectionEnabled, mLocationEnabled, mGeoDetectionEnabled); + } + + @Override + public String toString() { + return "TimeZoneDetectorConfiguration{" + + "mUserId=" + mUserId + + "mUserConfigAllowed=" + mUserConfigAllowed + + "mAutoDetectionSupported=" + mAutoDetectionSupported + + "mAutoDetectionEnabled=" + mAutoDetectionEnabled + + "mLocationEnabled=" + mLocationEnabled + + "mGeoDetectionEnabled=" + mGeoDetectionEnabled + + '}'; + } + + /** + * A Builder for {@link ConfigurationInternal}. + */ + public static class Builder { + + private final @UserIdInt int mUserId; + private boolean mUserConfigAllowed; + private boolean mAutoDetectionSupported; + private boolean mAutoDetectionEnabled; + private boolean mLocationEnabled; + private boolean mGeoDetectionEnabled; + + /** + * Creates a new Builder with only the userId set. + */ + public Builder(@UserIdInt int userId) { + mUserId = userId; + } + + /** + * Creates a new Builder by copying values from an existing instance. + */ + public Builder(ConfigurationInternal toCopy) { + this.mUserId = toCopy.mUserId; + this.mUserConfigAllowed = toCopy.mUserConfigAllowed; + this.mAutoDetectionSupported = toCopy.mAutoDetectionSupported; + this.mAutoDetectionEnabled = toCopy.mAutoDetectionEnabled; + this.mLocationEnabled = toCopy.mLocationEnabled; + this.mGeoDetectionEnabled = toCopy.mGeoDetectionEnabled; + } + + /** + * Sets whether the user is allowed to configure time zone settings on this device. + */ + public Builder setUserConfigAllowed(boolean configAllowed) { + mUserConfigAllowed = configAllowed; + return this; + } + + /** + * Sets whether automatic time zone detection is supported on this device. + */ + public Builder setAutoDetectionSupported(boolean supported) { + mAutoDetectionSupported = supported; + return this; + } + + /** + * Sets the value of the automatic time zone detection enabled setting for this device. + */ + public Builder setAutoDetectionEnabled(boolean enabled) { + mAutoDetectionEnabled = enabled; + return this; + } + + /** + * Sets the value of the location mode setting for this user. + */ + public Builder setLocationEnabled(boolean enabled) { + mLocationEnabled = enabled; + return this; + } + + /** + * Sets the value of the geolocation time zone detection setting for this user. + */ + public Builder setGeoDetectionEnabled(boolean enabled) { + mGeoDetectionEnabled = enabled; + return this; + } + + /** Returns a new {@link ConfigurationInternal}. */ + @NonNull + public ConfigurationInternal build() { + return new ConfigurationInternal(this); + } + } +} diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java index 0ca36e0fc258..d64032325539 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java @@ -16,24 +16,30 @@ package com.android.server.timezonedetector; -import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED; -import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE; -import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED; -import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED; +import static android.content.Intent.ACTION_USER_SWITCHED; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; +import android.app.ActivityManagerInternal; import android.app.AlarmManager; -import android.app.timezonedetector.TimeZoneCapabilities; import android.app.timezonedetector.TimeZoneConfiguration; +import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.database.ContentObserver; +import android.location.LocationManager; import android.net.ConnectivityManager; +import android.os.Handler; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.util.Slog; + +import com.android.server.LocalServices; import java.util.Objects; @@ -42,103 +48,87 @@ import java.util.Objects; */ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrategyImpl.Callback { + private static final String LOG_TAG = "TimeZoneDetectorCallbackImpl"; private static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; - private final Context mContext; - private final ContentResolver mCr; - private final UserManager mUserManager; - - TimeZoneDetectorCallbackImpl(Context context) { - mContext = context; + @NonNull private final Context mContext; + @NonNull private final Handler mHandler; + @NonNull private final ContentResolver mCr; + @NonNull private final UserManager mUserManager; + @NonNull private final boolean mGeoDetectionFeatureEnabled; + @NonNull private final LocationManager mLocationManager; + // @NonNull after setConfigChangeListener() is called. + private ConfigurationChangeListener mConfigChangeListener; + + TimeZoneDetectorCallbackImpl(@NonNull Context context, @NonNull Handler handler, + boolean geoDetectionFeatureEnabled) { + mContext = Objects.requireNonNull(context); + mHandler = Objects.requireNonNull(handler); mCr = context.getContentResolver(); mUserManager = context.getSystemService(UserManager.class); + mLocationManager = context.getSystemService(LocationManager.class); + mGeoDetectionFeatureEnabled = geoDetectionFeatureEnabled; + + // Wire up the change listener. All invocations are performed on the mHandler thread. + + // Listen for the user changing / the user's location mode changing. + IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_USER_SWITCHED); + filter.addAction(LocationManager.MODE_CHANGED_ACTION); + mContext.registerReceiverForAllUsers(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + handleConfigChangeOnHandlerThread(); + } + }, filter, null, mHandler); + + // Add async callbacks for global settings being changed. + ContentResolver contentResolver = mContext.getContentResolver(); + contentResolver.registerContentObserver( + Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true, + new ContentObserver(mHandler) { + public void onChange(boolean selfChange) { + handleConfigChangeOnHandlerThread(); + } + }); + + // Add async callbacks for user scoped location settings being changed. + contentResolver.registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED), + true, + new ContentObserver(mHandler) { + public void onChange(boolean selfChange) { + handleConfigChangeOnHandlerThread(); + } + }, UserHandle.USER_ALL); } - @Override - public TimeZoneCapabilities getCapabilities(@UserIdInt int userId) { - UserHandle userHandle = UserHandle.of(userId); - boolean disallowConfigDateTime = - mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME, userHandle); - - TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder(userId); - - // Automatic time zone detection is only supported (currently) on devices if there is a - // telephony network available. - if (!deviceHasTelephonyNetwork()) { - builder.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_SUPPORTED); - } else if (disallowConfigDateTime) { - builder.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED); - } else { - builder.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED); - } - - // TODO(b/149014708) Replace this with real logic when the settings storage is fully - // implemented. - builder.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_SUPPORTED); - - // The ability to make manual time zone suggestions can also be restricted by policy. With - // the current logic above, this could lead to a situation where a device hardware does not - // support auto detection, the device has been forced into "auto" mode by an admin and the - // user is unable to disable auto detection. - if (disallowConfigDateTime) { - builder.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED); - } else if (isAutoDetectionEnabled()) { - builder.setSuggestManualTimeZone(CAPABILITY_NOT_APPLICABLE); - } else { - builder.setSuggestManualTimeZone(CAPABILITY_POSSESSED); + private void handleConfigChangeOnHandlerThread() { + if (mConfigChangeListener == null) { + Slog.wtf(LOG_TAG, "mConfigChangeListener is unexpectedly null"); } - return builder.build(); + mConfigChangeListener.onChange(); } @Override - public TimeZoneConfiguration getConfiguration(@UserIdInt int userId) { - return new TimeZoneConfiguration.Builder() - .setAutoDetectionEnabled(isAutoDetectionEnabled()) - .setGeoDetectionEnabled(isGeoDetectionEnabled()) - .build(); + public void setConfigChangeListener(@NonNull ConfigurationChangeListener listener) { + mConfigChangeListener = Objects.requireNonNull(listener); } @Override - public void setConfiguration( - @UserIdInt int userId, @NonNull TimeZoneConfiguration configuration) { - Objects.requireNonNull(configuration); - if (!configuration.isComplete()) { - throw new IllegalArgumentException("configuration=" + configuration + " not complete"); - } - - // Avoid writing auto detection config for devices that do not support auto time zone - // detection: if we wrote it down then we'd set the default explicitly. That might influence - // what happens on later releases that do support auto detection on the same hardware. - if (isAutoDetectionSupported()) { - final int autoEnabledValue = configuration.isAutoDetectionEnabled() ? 1 : 0; - Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE, autoEnabledValue); - - final boolean geoTzDetectionEnabledValue = configuration.isGeoDetectionEnabled(); - // TODO(b/149014708) Write this down to user-scoped settings once implemented. - } - } - - @Override - public boolean isAutoDetectionEnabled() { - // To ensure that TimeZoneConfiguration is "complete" for simplicity, devices that do not - // support auto detection have safe, hard coded configuration values that make it look like - // auto detection is turned off. It is therefore important that false is returned from this - // method for devices that do not support auto time zone detection. Such devices will not - // have a UI to turn the auto detection on/off. Returning true could prevent the user - // entering information manually. On devices that do support auto time detection the default - // is to turn auto detection on. - if (isAutoDetectionSupported()) { - return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0; - } - return false; + public ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) { + return new ConfigurationInternal.Builder(userId) + .setUserConfigAllowed(isUserConfigAllowed(userId)) + .setAutoDetectionSupported(isAutoDetectionSupported()) + .setAutoDetectionEnabled(isAutoDetectionEnabled()) + .setLocationEnabled(isLocationEnabled(userId)) + .setGeoDetectionEnabled(isGeoDetectionEnabled(userId)) + .build(); } @Override - public boolean isGeoDetectionEnabled() { - // TODO(b/149014708) Read this from user-scoped settings once implemented. The user's - // location toggle will act as an override for this setting, i.e. so that the setting will - // return false if the location toggle is disabled. - return false; + public @UserIdInt int getCurrentUserId() { + return LocalServices.getService(ActivityManagerInternal.class).getCurrentUserId(); } @Override @@ -165,8 +155,55 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat alarmManager.setTimeZone(zoneId); } + @Override + public void storeConfiguration(TimeZoneConfiguration configuration) { + Objects.requireNonNull(configuration); + + // Avoid writing the auto detection enabled setting for devices that do not support auto + // time zone detection: if we wrote it down then we'd set the value explicitly, which would + // prevent detecting "default" later. That might influence what happens on later releases + // that support new types of auto detection on the same hardware. + if (isAutoDetectionSupported()) { + final boolean autoDetectionEnabled = configuration.isAutoDetectionEnabled(); + setAutoDetectionEnabled(autoDetectionEnabled); + + final int userId = configuration.getUserId(); + final boolean geoTzDetectionEnabled = configuration.isGeoDetectionEnabled(); + setGeoDetectionEnabled(userId, geoTzDetectionEnabled); + } + } + + private boolean isUserConfigAllowed(@UserIdInt int userId) { + UserHandle userHandle = UserHandle.of(userId); + return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME, userHandle); + } + private boolean isAutoDetectionSupported() { - return deviceHasTelephonyNetwork(); + return deviceHasTelephonyNetwork() || mGeoDetectionFeatureEnabled; + } + + private boolean isAutoDetectionEnabled() { + return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0; + } + + private void setAutoDetectionEnabled(boolean enabled) { + Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE, enabled ? 1 : 0); + } + + private boolean isLocationEnabled(@UserIdInt int userId) { + return mLocationManager.isLocationEnabledForUser(UserHandle.of(userId)); + } + + private boolean isGeoDetectionEnabled(@UserIdInt int userId) { + final boolean locationEnabled = isLocationEnabled(userId); + return Settings.Secure.getIntForUser(mCr, + Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED, + locationEnabled ? 1 : 0 /* defaultValue */, userId) != 0; + } + + private void setGeoDetectionEnabled(@UserIdInt int userId, boolean enabled) { + Settings.Secure.putIntForUser(mCr, Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED, + enabled ? 1 : 0, userId); } private boolean deviceHasTelephonyNetwork() { @@ -174,4 +211,4 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat return mContext.getSystemService(ConnectivityManager.class) .isNetworkSupported(ConnectivityManager.TYPE_MOBILE); } -} +}
\ No newline at end of file diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java index fb7a73d12632..2d50390c27a9 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java @@ -27,6 +27,12 @@ import android.annotation.NonNull; */ public interface TimeZoneDetectorInternal extends Dumpable.Container { + /** Adds a listener that will be invoked when time zone detection configuration is changed. */ + void addConfigurationListener(ConfigurationChangeListener listener); + + /** Returns the {@link ConfigurationInternal} for the current user. */ + ConfigurationInternal getCurrentUserConfigurationInternal(); + /** * Suggests the current time zone, determined using geolocation, to the detector. The * detector may ignore the signal based on system settings, whether better information is diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java index 15412a0d14a1..f0ce827cec5e 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java @@ -20,8 +20,8 @@ import android.annotation.NonNull; import android.content.Context; import android.os.Handler; -import com.android.internal.annotations.VisibleForTesting; - +import java.util.ArrayList; +import java.util.List; import java.util.Objects; /** @@ -34,18 +34,26 @@ public final class TimeZoneDetectorInternalImpl implements TimeZoneDetectorInter @NonNull private final Context mContext; @NonNull private final Handler mHandler; @NonNull private final TimeZoneDetectorStrategy mTimeZoneDetectorStrategy; + @NonNull private final List<ConfigurationChangeListener> mConfigurationListeners = + new ArrayList<>(); - static TimeZoneDetectorInternalImpl create(@NonNull Context context, @NonNull Handler handler, - @NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) { - return new TimeZoneDetectorInternalImpl(context, handler, timeZoneDetectorStrategy); - } - - @VisibleForTesting public TimeZoneDetectorInternalImpl(@NonNull Context context, @NonNull Handler handler, @NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) { mContext = Objects.requireNonNull(context); mHandler = Objects.requireNonNull(handler); mTimeZoneDetectorStrategy = Objects.requireNonNull(timeZoneDetectorStrategy); + + // Wire up a change listener so that any downstream listeners can be notified when + // the configuration changes for any reason. + mTimeZoneDetectorStrategy.addConfigChangeListener(this::handleConfigurationChanged); + } + + private void handleConfigurationChanged() { + synchronized (mConfigurationListeners) { + for (ConfigurationChangeListener listener : mConfigurationListeners) { + listener.onChange(); + } + } } @Override @@ -54,6 +62,19 @@ public final class TimeZoneDetectorInternalImpl implements TimeZoneDetectorInter } @Override + public void addConfigurationListener(ConfigurationChangeListener listener) { + synchronized (mConfigurationListeners) { + mConfigurationListeners.add(Objects.requireNonNull(listener)); + } + } + + @Override + @NonNull + public ConfigurationInternal getCurrentUserConfigurationInternal() { + return mTimeZoneDetectorStrategy.getCurrentUserConfigurationInternal(); + } + + @Override public void suggestGeolocationTimeZone( @NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion) { Objects.requireNonNull(timeZoneSuggestion); diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java index d81f949742bd..7501d9fe6a7c 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java @@ -24,32 +24,24 @@ import android.app.timezonedetector.ManualTimeZoneSuggestion; import android.app.timezonedetector.TelephonyTimeZoneSuggestion; import android.app.timezonedetector.TimeZoneCapabilities; import android.app.timezonedetector.TimeZoneConfiguration; -import android.content.ContentResolver; import android.content.Context; -import android.database.ContentObserver; -import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; -import android.os.UserHandle; -import android.provider.Settings; import android.util.IndentingPrintWriter; import android.util.Slog; -import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DumpUtils; import com.android.server.FgThread; import com.android.server.SystemService; -import com.android.server.timezonedetector.TimeZoneDetectorStrategy.StrategyListener; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Iterator; import java.util.Objects; /** @@ -65,6 +57,9 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub private static final String TAG = "TimeZoneDetectorService"; + /** A compile time switch for enabling / disabling geolocation-based time zone detection. */ + private static final boolean GEOLOCATION_TIME_ZONE_DETECTION_ENABLED = false; + /** * Handles the service lifecycle for {@link TimeZoneDetectorService} and * {@link TimeZoneDetectorInternalImpl}. @@ -80,18 +75,20 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub // Obtain / create the shared dependencies. Context context = getContext(); Handler handler = FgThread.getHandler(); + TimeZoneDetectorStrategy timeZoneDetectorStrategy = - TimeZoneDetectorStrategyImpl.create(context); + TimeZoneDetectorStrategyImpl.create( + context, handler, GEOLOCATION_TIME_ZONE_DETECTION_ENABLED); // Create and publish the local service for use by internal callers. TimeZoneDetectorInternal internal = - TimeZoneDetectorInternalImpl.create(context, handler, timeZoneDetectorStrategy); + new TimeZoneDetectorInternalImpl(context, handler, timeZoneDetectorStrategy); publishLocalService(TimeZoneDetectorInternal.class, internal); // Publish the binder service so it can be accessed from other (appropriately // permissioned) processes. - TimeZoneDetectorService service = - TimeZoneDetectorService.create(context, handler, timeZoneDetectorStrategy); + TimeZoneDetectorService service = TimeZoneDetectorService.create( + context, handler, timeZoneDetectorStrategy); publishBinderService(Context.TIME_ZONE_DETECTOR_SERVICE, service); } } @@ -103,79 +100,51 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub private final Handler mHandler; @NonNull + private final CallerIdentityInjector mCallerIdentityInjector; + + @NonNull private final TimeZoneDetectorStrategy mTimeZoneDetectorStrategy; - /** - * This sparse array acts as a map from userId to listeners running as that userId. User scoped - * as time zone detection configuration is partially user-specific, so different users can - * get different configuration. - */ @GuardedBy("mConfigurationListeners") @NonNull - private final SparseArray<ArrayList<ITimeZoneConfigurationListener>> mConfigurationListeners = - new SparseArray<>(); + private final ArrayList<ITimeZoneConfigurationListener> mConfigurationListeners = + new ArrayList<>(); private static TimeZoneDetectorService create( @NonNull Context context, @NonNull Handler handler, @NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) { - TimeZoneDetectorService service = - new TimeZoneDetectorService(context, handler, timeZoneDetectorStrategy); - - ContentResolver contentResolver = context.getContentResolver(); - contentResolver.registerContentObserver( - Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true, - new ContentObserver(handler) { - public void onChange(boolean selfChange) { - service.handleAutoTimeZoneConfigChanged(); - } - }); - // TODO(b/149014708) Listen for changes to geolocation time zone detection enabled config. - // This should also include listening to the current user and the current user's location - // toggle since the config is user-scoped and the location toggle overrides the geolocation - // time zone enabled setting. + CallerIdentityInjector callerIdentityInjector = CallerIdentityInjector.REAL; + TimeZoneDetectorService service = new TimeZoneDetectorService( + context, handler, callerIdentityInjector, timeZoneDetectorStrategy); return service; } @VisibleForTesting public TimeZoneDetectorService(@NonNull Context context, @NonNull Handler handler, + @NonNull CallerIdentityInjector callerIdentityInjector, @NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) { mContext = Objects.requireNonNull(context); mHandler = Objects.requireNonNull(handler); + mCallerIdentityInjector = Objects.requireNonNull(callerIdentityInjector); mTimeZoneDetectorStrategy = Objects.requireNonNull(timeZoneDetectorStrategy); - mTimeZoneDetectorStrategy.setStrategyListener(new StrategyListener() { - @Override - public void onConfigurationChanged() { - handleConfigurationChanged(); - } - }); - } - - @Override - @NonNull - public TimeZoneCapabilities getCapabilities() { - enforceManageTimeZoneDetectorConfigurationPermission(); - int userId = UserHandle.getCallingUserId(); - long token = Binder.clearCallingIdentity(); - try { - return mTimeZoneDetectorStrategy.getCapabilities(userId); - } finally { - Binder.restoreCallingIdentity(token); - } + // Wire up a change listener so that ITimeZoneConfigurationListeners can be notified when + // the configuration changes for any reason. + mTimeZoneDetectorStrategy.addConfigChangeListener(this::handleConfigurationChanged); } @Override @NonNull - public TimeZoneConfiguration getConfiguration() { + public TimeZoneCapabilities getCapabilities() { enforceManageTimeZoneDetectorConfigurationPermission(); - int userId = UserHandle.getCallingUserId(); - long token = Binder.clearCallingIdentity(); + int userId = mCallerIdentityInjector.getCallingUserId(); + long token = mCallerIdentityInjector.clearCallingIdentity(); try { - return mTimeZoneDetectorStrategy.getConfiguration(userId); + return mTimeZoneDetectorStrategy.getConfigurationInternal(userId).createCapabilities(); } finally { - Binder.restoreCallingIdentity(token); + mCallerIdentityInjector.restoreCallingIdentity(token); } } @@ -184,12 +153,16 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub enforceManageTimeZoneDetectorConfigurationPermission(); Objects.requireNonNull(configuration); - int userId = UserHandle.getCallingUserId(); - long token = Binder.clearCallingIdentity(); + int callingUserId = mCallerIdentityInjector.getCallingUserId(); + if (callingUserId != configuration.getUserId()) { + return false; + } + + long token = mCallerIdentityInjector.clearCallingIdentity(); try { - return mTimeZoneDetectorStrategy.updateConfiguration(userId, configuration); + return mTimeZoneDetectorStrategy.updateConfiguration(configuration); } finally { - Binder.restoreCallingIdentity(token); + mCallerIdentityInjector.restoreCallingIdentity(token); } } @@ -197,25 +170,17 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub public void addConfigurationListener(@NonNull ITimeZoneConfigurationListener listener) { enforceManageTimeZoneDetectorConfigurationPermission(); Objects.requireNonNull(listener); - int userId = UserHandle.getCallingUserId(); synchronized (mConfigurationListeners) { - ArrayList<ITimeZoneConfigurationListener> listeners = - mConfigurationListeners.get(userId); - if (listeners != null && listeners.contains(listener)) { + if (mConfigurationListeners.contains(listener)) { return; } try { - if (listeners == null) { - listeners = new ArrayList<>(1); - mConfigurationListeners.put(userId, listeners); - } - // Ensure the reference to the listener will be removed if the client process dies. listener.asBinder().linkToDeath(this, 0 /* flags */); // Only add the listener if we can linkToDeath(). - listeners.add(listener); + mConfigurationListeners.add(listener); } catch (RemoteException e) { Slog.e(TAG, "Unable to linkToDeath() for listener=" + listener, e); } @@ -226,19 +191,16 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub public void removeConfigurationListener(@NonNull ITimeZoneConfigurationListener listener) { enforceManageTimeZoneDetectorConfigurationPermission(); Objects.requireNonNull(listener); - int userId = UserHandle.getCallingUserId(); synchronized (mConfigurationListeners) { boolean removedListener = false; - ArrayList<ITimeZoneConfigurationListener> userListeners = - mConfigurationListeners.get(userId); - if (userListeners.remove(listener)) { + if (mConfigurationListeners.remove(listener)) { // Stop listening for the client process to die. listener.asBinder().unlinkToDeath(this, 0 /* flags */); removedListener = true; } if (!removedListener) { - Slog.w(TAG, "Client asked to remove listenener=" + listener + Slog.w(TAG, "Client asked to remove listener=" + listener + ", but no listeners were removed." + " mConfigurationListeners=" + mConfigurationListeners); } @@ -259,19 +221,14 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub public void binderDied(IBinder who) { synchronized (mConfigurationListeners) { boolean removedListener = false; - final int userCount = mConfigurationListeners.size(); - for (int i = 0; i < userCount; i++) { - ArrayList<ITimeZoneConfigurationListener> userListeners = - mConfigurationListeners.valueAt(i); - Iterator<ITimeZoneConfigurationListener> userListenerIterator = - userListeners.iterator(); - while (userListenerIterator.hasNext()) { - ITimeZoneConfigurationListener userListener = userListenerIterator.next(); - if (userListener.asBinder().equals(who)) { - userListenerIterator.remove(); - removedListener = true; - break; - } + final int listenerCount = mConfigurationListeners.size(); + for (int listenerIndex = listenerCount - 1; listenerIndex >= 0; listenerIndex--) { + ITimeZoneConfigurationListener listener = + mConfigurationListeners.get(listenerIndex); + if (listener.asBinder().equals(who)) { + mConfigurationListeners.remove(listenerIndex); + removedListener = true; + break; } } if (!removedListener) { @@ -283,42 +240,25 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub } void handleConfigurationChanged() { - // Note: we could trigger an async time zone detection operation here via a call to - // handleAutoTimeZoneConfigChanged(), but that is triggered in response to the underlying - // setting value changing so it is currently unnecessary. If we get to a point where all - // configuration changes are guaranteed to happen in response to an updateConfiguration() - // call, then we can remove that path and call it here instead. - // Configuration has changed, but each user may have a different view of the configuration. // It's possible that this will cause unnecessary notifications but that shouldn't be a // problem. synchronized (mConfigurationListeners) { - final int userCount = mConfigurationListeners.size(); - for (int userIndex = 0; userIndex < userCount; userIndex++) { - int userId = mConfigurationListeners.keyAt(userIndex); - TimeZoneConfiguration configuration = - mTimeZoneDetectorStrategy.getConfiguration(userId); - - ArrayList<ITimeZoneConfigurationListener> listeners = - mConfigurationListeners.valueAt(userIndex); - final int listenerCount = listeners.size(); - for (int listenerIndex = 0; listenerIndex < listenerCount; listenerIndex++) { - ITimeZoneConfigurationListener listener = listeners.get(listenerIndex); - try { - listener.onChange(configuration); - } catch (RemoteException e) { - Slog.w(TAG, "Unable to notify listener=" + listener - + " for userId=" + userId - + " of updated configuration=" + configuration, e); - } + final int listenerCount = mConfigurationListeners.size(); + for (int listenerIndex = 0; listenerIndex < listenerCount; listenerIndex++) { + ITimeZoneConfigurationListener listener = + mConfigurationListeners.get(listenerIndex); + try { + listener.onChange(); + } catch (RemoteException e) { + Slog.w(TAG, "Unable to notify listener=" + listener, e); } } } } /** Provided for command-line access. This is not exposed as a binder API. */ - void suggestGeolocationTimeZone( - @NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion) { + void suggestGeolocationTimeZone(@NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion) { enforceSuggestGeolocationTimeZonePermission(); Objects.requireNonNull(timeZoneSuggestion); @@ -331,12 +271,12 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub enforceSuggestManualTimeZonePermission(); Objects.requireNonNull(timeZoneSuggestion); - int userId = UserHandle.getCallingUserId(); - long token = Binder.clearCallingIdentity(); + int userId = mCallerIdentityInjector.getCallingUserId(); + long token = mCallerIdentityInjector.clearCallingIdentity(); try { return mTimeZoneDetectorStrategy.suggestManualTimeZone(userId, timeZoneSuggestion); } finally { - Binder.restoreCallingIdentity(token); + mCallerIdentityInjector.restoreCallingIdentity(token); } } @@ -358,12 +298,6 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub ipw.flush(); } - /** Internal method for handling the auto time zone configuration being changed. */ - @VisibleForTesting - public void handleAutoTimeZoneConfigChanged() { - mHandler.post(mTimeZoneDetectorStrategy::handleAutoTimeZoneConfigChanged); - } - private void enforceManageTimeZoneDetectorConfigurationPermission() { // TODO Switch to a dedicated MANAGE_TIME_AND_ZONE_CONFIGURATION permission. mContext.enforceCallingPermission( diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java index c5b7e39f4fef..f944c5638fa9 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java @@ -19,51 +19,84 @@ import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.timezonedetector.ManualTimeZoneSuggestion; import android.app.timezonedetector.TelephonyTimeZoneSuggestion; -import android.app.timezonedetector.TimeZoneCapabilities; import android.app.timezonedetector.TimeZoneConfiguration; import android.util.IndentingPrintWriter; /** - * The interface for the class that implements the time detection algorithm used by the - * {@link TimeZoneDetectorService}. + * The interface for the class that is responsible for setting the time zone on a device, used by + * {@link TimeZoneDetectorService} and {@link TimeZoneDetectorInternal}. * - * <p>The strategy uses suggestions to decide whether to modify the device's time zone setting - * and what to set it to. + * <p>The strategy receives suggestions, which it may use to modify the device's time zone setting. + * Suggestions are acted on or ignored as needed, depending on previously received suggestions and + * the current user's configuration (see {@link ConfigurationInternal}). * - * <p>Most calls will be handled by a single thread, but that is not true for all calls. For example - * {@link #dump(IndentingPrintWriter, String[])}) may be called on a different thread concurrently - * with other operations so implementations must still handle thread safety. + * <p>Devices can have zero, one or two automatic time zone detection algorithm available at any + * point in time. + * + * <p>The two automatic detection algorithms supported are "telephony" and "geolocation". Algorithm + * availability and use depends on several factors: + * <ul> + * <li>Telephony is only available on devices with a telephony stack. + * <li>Geolocation is also optional and configured at image creation time. When enabled on a + * device, its availability depends on the current user's settings, so switching between users can + * change the automatic algorithm used by the device.</li> + * </ul> + * + * <p>If there are no automatic time zone detections algorithms available then the user can usually + * change the device time zone manually. Under most circumstances the current user can turn + * automatic time zone detection on or off, or choose the algorithm via settings. + * + * <p>Telephony detection is independent of the current user. The device keeps track of the most + * recent telephony suggestion from each slotIndex. When telephony detection is in use, the highest + * scoring suggestion is used to set the device time zone based on a scoring algorithm. If several + * slotIndexes provide the same score then the slotIndex with the lowest numeric value "wins". If + * the situation changes and it is no longer possible to be confident about the time zone, + * slotIndexes must have an empty suggestion submitted in order to "withdraw" their previous + * suggestion otherwise it will remain in use. + * + * <p>Geolocation detection is dependent on the current user and their settings. The device retains + * at most one geolocation suggestion. Generally, use of a device's location is dependent on the + * user's "location toggle", but even when that is enabled the user may choose to enable / disable + * the use of geolocation for device time zone detection. If the current user changes to one that + * does not have geolocation detection enabled, or the user turns off geolocation detection, then + * the strategy discards the latest geolocation suggestion. Devices that lose a location fix must + * have an empty suggestion submitted in order to "withdraw" their previous suggestion otherwise it + * will remain in use. + * + * <p>Threading: + * + * <p>Suggestion calls with a void return type may be handed off to a separate thread and handled + * asynchronously. Synchronous calls like {@link #getCurrentUserConfigurationInternal()}, and debug + * calls like {@link #dump(IndentingPrintWriter, String[])}, may be called on a different thread + * concurrently with other operations. * * @hide */ public interface TimeZoneDetectorStrategy extends Dumpable, Dumpable.Container { - /** A listener for strategy events. */ - interface StrategyListener { - /** - * Invoked when configuration has been changed. - */ - void onConfigurationChanged(); - } - - /** Sets the listener that enables the strategy to communicate with the surrounding service. */ - void setStrategyListener(@NonNull StrategyListener listener); + /** + * Sets a listener that will be triggered whenever time zone detection configuration is + * changed. + */ + void addConfigChangeListener(@NonNull ConfigurationChangeListener listener); - /** Returns the user's time zone capabilities. */ + /** Returns the user's time zone configuration. */ @NonNull - TimeZoneCapabilities getCapabilities(@UserIdInt int userId); + ConfigurationInternal getConfigurationInternal(@UserIdInt int userId); /** - * Returns the configuration that controls time zone detector behavior. + * Returns the configuration that controls time zone detector behavior for the current user. */ @NonNull - TimeZoneConfiguration getConfiguration(@UserIdInt int userId); + ConfigurationInternal getCurrentUserConfigurationInternal(); /** - * Updates the configuration settings that control time zone detector behavior. + * Updates the configuration properties that control a device's time zone behavior. + * + * <p>This method returns {@code true} if the configuration was changed, + * {@code false} otherwise. */ - boolean updateConfiguration( - @UserIdInt int userId, @NonNull TimeZoneConfiguration configuration); + boolean updateConfiguration(@NonNull TimeZoneConfiguration configuration); /** * Suggests zero, one or more time zones for the device, or withdraws a previous suggestion if @@ -85,9 +118,4 @@ public interface TimeZoneDetectorStrategy extends Dumpable, Dumpable.Container { * suggestion. */ void suggestTelephonyTimeZone(@NonNull TelephonyTimeZoneSuggestion suggestion); - - /** - * Called when there has been a change to the automatic time zone detection configuration. - */ - void handleAutoTimeZoneConfigChanged(); } diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java index d1369a289428..8a42b18b514f 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java @@ -20,10 +20,7 @@ import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYP import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS; import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET; import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE; -import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE; import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED; -import static android.app.timezonedetector.TimeZoneConfiguration.PROPERTY_AUTO_DETECTION_ENABLED; -import static android.app.timezonedetector.TimeZoneConfiguration.PROPERTY_GEO_DETECTION_ENABLED; import android.annotation.NonNull; import android.annotation.Nullable; @@ -33,6 +30,7 @@ import android.app.timezonedetector.TelephonyTimeZoneSuggestion; import android.app.timezonedetector.TimeZoneCapabilities; import android.app.timezonedetector.TimeZoneConfiguration; import android.content.Context; +import android.os.Handler; import android.util.IndentingPrintWriter; import android.util.LocalLog; import android.util.Slog; @@ -45,15 +43,7 @@ import java.util.List; import java.util.Objects; /** - * An implementation of {@link TimeZoneDetectorStrategy} that handle telephony and manual - * suggestions. Suggestions are acted on or ignored as needed, dependent on the current "auto time - * zone detection" setting. - * - * <p>For automatic detection, it keeps track of the most recent telephony suggestion from each - * slotIndex and it uses the best suggestion based on a scoring algorithm. If several slotIndexes - * provide the same score then the slotIndex with the lowest numeric value "wins". If the situation - * changes and it is no longer possible to be confident about the time zone, slotIndexes must have - * an empty suggestion submitted in order to "withdraw" their previous suggestion. + * The real implementation of {@link TimeZoneDetectorStrategy}. * * <p>Most public methods are marked synchronized to ensure thread safety around internal state. */ @@ -61,48 +51,27 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat /** * Used by {@link TimeZoneDetectorStrategyImpl} to interact with device configuration / settings - * / system properties. It can be faked for testing different scenarios. + * / system properties. It can be faked for testing. * * <p>Note: Because the settings / system properties-derived values can currently be modified - * independently and from different threads (and processes!), their use are prone to race - * conditions. That will be true until the responsibility for setting their values is moved to - * {@link TimeZoneDetectorStrategyImpl} (which is thread safe). + * independently and from different threads (and processes!), their use is prone to race + * conditions. */ @VisibleForTesting public interface Callback { /** - * Returns the capabilities for the user. - */ - @NonNull - TimeZoneCapabilities getCapabilities(@UserIdInt int userId); - - /** - * Returns the configuration for the user. - * @param userId + * Sets a {@link ConfigurationChangeListener} that will be invoked when there are any + * changes that could affect time zone detection. This is invoked during system server + * setup. */ - @NonNull - TimeZoneConfiguration getConfiguration(int userId); + void setConfigChangeListener(@NonNull ConfigurationChangeListener listener); - /** - * Sets the configuration for the user. This method handles storage only, the configuration - * must have been validated by the caller and be complete. - * - * @throws IllegalArgumentException if {@link TimeZoneConfiguration#isComplete()} - * returns {@code false} - */ - void setConfiguration(@UserIdInt int userId, @NonNull TimeZoneConfiguration configuration); - - /** - * Returns true if automatic time zone detection is currently enabled. - */ - boolean isAutoDetectionEnabled(); + /** Returns the current user at the instant it is called. */ + @UserIdInt int getCurrentUserId(); - /** - * Returns whether geolocation can be used for time zone detection when {@link - * #isAutoDetectionEnabled()} returns {@code true}. - */ - boolean isGeoDetectionEnabled(); + /** Returns the {@link ConfigurationInternal} for the specified user. */ + ConfigurationInternal getConfigurationInternal(@UserIdInt int userId); /** * Returns true if the device has had an explicit time zone set. @@ -118,6 +87,13 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat * Sets the device's time zone. */ void setDeviceTimeZone(@NonNull String zoneId); + + /** + * Stores the configuration properties contained in {@code newConfiguration}. + * All checks about user capabilities must be done by the caller and + * {@link TimeZoneConfiguration#isComplete()} must be {@code true}. + */ + void storeConfiguration(TimeZoneConfiguration newConfiguration); } private static final String LOG_TAG = "TimeZoneDetectorStrategy"; @@ -189,9 +165,9 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat @NonNull private final Callback mCallback; - /** Non-null after {@link #setStrategyListener(StrategyListener)} is called. */ - @Nullable - private StrategyListener mListener; + @GuardedBy("this") + @NonNull + private List<ConfigurationChangeListener> mConfigChangeListeners = new ArrayList<>(); /** * A log that records the decisions / decision metadata that affected the device's time zone. @@ -211,7 +187,8 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat new ArrayMapWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE); /** - * The latest geolocation suggestion received. + * The latest geolocation suggestion received. If the user disabled geolocation time zone + * detection then the latest suggestion is cleared. */ @GuardedBy("this") private ReferenceWithHistory<GeolocationTimeZoneSuggestion> mLatestGeoLocationSuggestion = @@ -223,113 +200,120 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat /** * Creates a new instance of {@link TimeZoneDetectorStrategyImpl}. */ - public static TimeZoneDetectorStrategyImpl create(Context context) { - Callback timeZoneDetectionServiceHelper = new TimeZoneDetectorCallbackImpl(context); - return new TimeZoneDetectorStrategyImpl(timeZoneDetectionServiceHelper); + public static TimeZoneDetectorStrategyImpl create( + @NonNull Context context, @NonNull Handler handler, + boolean geolocationTimeZoneDetectionEnabled) { + + TimeZoneDetectorCallbackImpl callback = new TimeZoneDetectorCallbackImpl( + context, handler, geolocationTimeZoneDetectionEnabled); + return new TimeZoneDetectorStrategyImpl(callback); } @VisibleForTesting - public TimeZoneDetectorStrategyImpl(Callback callback) { + public TimeZoneDetectorStrategyImpl(@NonNull Callback callback) { mCallback = Objects.requireNonNull(callback); + mCallback.setConfigChangeListener(this::handleConfigChanged); } /** - * Sets a listener that allows the strategy to communicate with the surrounding service. This - * must be called before the instance is used and must only be called once. + * Adds a listener that allows the strategy to communicate with the surrounding service / + * internal. This must be called before the instance is used. */ @Override - public synchronized void setStrategyListener(@NonNull StrategyListener listener) { - if (mListener != null) { - throw new IllegalStateException("Strategy already has a listener"); - } - mListener = Objects.requireNonNull(listener); + public synchronized void addConfigChangeListener( + @NonNull ConfigurationChangeListener listener) { + Objects.requireNonNull(listener); + mConfigChangeListeners.add(listener); } @Override @NonNull - public synchronized TimeZoneCapabilities getCapabilities(@UserIdInt int userId) { - return mCallback.getCapabilities(userId); + public ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) { + return mCallback.getConfigurationInternal(userId); } @Override @NonNull - public synchronized TimeZoneConfiguration getConfiguration(@UserIdInt int userId) { - return mCallback.getConfiguration(userId); + public synchronized ConfigurationInternal getCurrentUserConfigurationInternal() { + int currentUserId = mCallback.getCurrentUserId(); + return getConfigurationInternal(currentUserId); } @Override public synchronized boolean updateConfiguration( - @UserIdInt int userId, @NonNull TimeZoneConfiguration configurationChanges) { - Objects.requireNonNull(configurationChanges); - - // Validate the requested configuration changes before applying any of them. - TimeZoneCapabilities capabilities = mCallback.getCapabilities(userId); - boolean canManageTimeZoneDetection = - capabilities.getConfigureAutoDetectionEnabled() >= CAPABILITY_NOT_APPLICABLE; - if (!canManageTimeZoneDetection - && containsAutoTimeDetectionProperties(configurationChanges)) { + @NonNull TimeZoneConfiguration requestedConfiguration) { + Objects.requireNonNull(requestedConfiguration); + + int userId = requestedConfiguration.getUserId(); + TimeZoneCapabilities capabilities = getConfigurationInternal(userId).createCapabilities(); + + // Create a new configuration builder, and copy across the mutable properties users are + // able to modify. Other properties are therefore ignored. + final TimeZoneConfiguration newConfiguration = + capabilities.applyUpdate(requestedConfiguration); + if (newConfiguration == null) { + // The changes could not be made due to return false; } - // Create a complete configuration by merging the existing and new (possibly partial) - // configuration. - final TimeZoneConfiguration oldConfiguration = mCallback.getConfiguration(userId); - final TimeZoneConfiguration newConfiguration = - new TimeZoneConfiguration.Builder(oldConfiguration) - .mergeProperties(configurationChanges) - .build(); - - // Set the configuration / notify as needed. - boolean configurationChanged = !oldConfiguration.equals(newConfiguration); - if (configurationChanged) { - mCallback.setConfiguration(userId, newConfiguration); - - String logMsg = "Configuration changed:" - + "oldConfiguration=" + oldConfiguration - + ", configuration=" + configurationChanges - + ", newConfiguration=" + newConfiguration; - mTimeZoneChangesLog.log(logMsg); - if (DBG) { - Slog.d(LOG_TAG, logMsg); - } - mListener.onConfigurationChanged(); + // Store the configuration / notify as needed. This will cause the mCallback to invoke + // handleConfigChanged() asynchronously. + mCallback.storeConfiguration(newConfiguration); + + TimeZoneConfiguration oldConfiguration = capabilities.getConfiguration(); + String logMsg = "Configuration changed:" + + " oldConfiguration=" + oldConfiguration + + ", newConfiguration=" + newConfiguration; + mTimeZoneChangesLog.log(logMsg); + if (DBG) { + Slog.d(LOG_TAG, logMsg); } return true; } - private static boolean containsAutoTimeDetectionProperties( - @NonNull TimeZoneConfiguration configuration) { - return configuration.hasProperty(PROPERTY_AUTO_DETECTION_ENABLED) - || configuration.hasProperty(PROPERTY_GEO_DETECTION_ENABLED); - } - @Override public synchronized void suggestGeolocationTimeZone( @NonNull GeolocationTimeZoneSuggestion suggestion) { + + int currentUserId = mCallback.getCurrentUserId(); + ConfigurationInternal currentUserConfig = mCallback.getConfigurationInternal(currentUserId); if (DBG) { - Slog.d(LOG_TAG, "Geolocation suggestion received. newSuggestion=" + suggestion); + Slog.d(LOG_TAG, "Geolocation suggestion received." + + " currentUserConfig=" + currentUserConfig + + " newSuggestion=" + suggestion); } - Objects.requireNonNull(suggestion); - mLatestGeoLocationSuggestion.set(suggestion); - // Now perform auto time zone detection. The new suggestion may be used to modify the time - // zone setting. - if (mCallback.isGeoDetectionEnabled()) { + if (currentUserConfig.getGeoDetectionEnabledBehavior()) { + // Only store a geolocation suggestion if geolocation detection is currently enabled. + mLatestGeoLocationSuggestion.set(suggestion); + + // Now perform auto time zone detection. The new suggestion may be used to modify the + // time zone setting. String reason = "New geolocation time zone suggested. suggestion=" + suggestion; - doAutoTimeZoneDetection(reason); + doAutoTimeZoneDetection(currentUserConfig, reason); } } @Override public synchronized boolean suggestManualTimeZone( @UserIdInt int userId, @NonNull ManualTimeZoneSuggestion suggestion) { + + int currentUserId = mCallback.getCurrentUserId(); + if (userId != currentUserId) { + Slog.w(LOG_TAG, "Manual suggestion received but user != current user, userId=" + userId + + " suggestion=" + suggestion); + + // Only listen to changes from the current user. + return false; + } + Objects.requireNonNull(suggestion); String timeZoneId = suggestion.getZoneId(); String cause = "Manual time suggestion received: suggestion=" + suggestion; - TimeZoneCapabilities capabilities = mCallback.getCapabilities(userId); + TimeZoneCapabilities capabilities = getConfigurationInternal(userId).createCapabilities(); if (capabilities.getSuggestManualTimeZone() != CAPABILITY_POSSESSED) { Slog.i(LOG_TAG, "User does not have the capability needed to set the time zone manually" + ", capabilities=" + capabilities @@ -345,8 +329,12 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat @Override public synchronized void suggestTelephonyTimeZone( @NonNull TelephonyTimeZoneSuggestion suggestion) { + + int currentUserId = mCallback.getCurrentUserId(); + ConfigurationInternal currentUserConfig = mCallback.getConfigurationInternal(currentUserId); if (DBG) { - Slog.d(LOG_TAG, "Telephony suggestion received. newSuggestion=" + suggestion); + Slog.d(LOG_TAG, "Telephony suggestion received. currentUserConfig=" + currentUserConfig + + " newSuggestion=" + suggestion); } Objects.requireNonNull(suggestion); @@ -360,9 +348,9 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat // Now perform auto time zone detection. The new suggestion may be used to modify the time // zone setting. - if (!mCallback.isGeoDetectionEnabled()) { + if (!currentUserConfig.getGeoDetectionEnabledBehavior()) { String reason = "New telephony time zone suggested. suggestion=" + suggestion; - doAutoTimeZoneDetection(reason); + doAutoTimeZoneDetection(currentUserConfig, reason); } } @@ -392,15 +380,15 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat * Performs automatic time zone detection. */ @GuardedBy("this") - private void doAutoTimeZoneDetection(@NonNull String detectionReason) { - if (!mCallback.isAutoDetectionEnabled()) { - // Avoid doing unnecessary work with this (race-prone) check. + private void doAutoTimeZoneDetection( + @NonNull ConfigurationInternal currentUserConfig, @NonNull String detectionReason) { + if (!currentUserConfig.getAutoDetectionEnabledBehavior()) { + // Avoid doing unnecessary work. return; } - // Use the right suggestions based on the current configuration. This check is potentially - // race-prone until this value is set via a call to TimeZoneDetectorStrategy. - if (mCallback.isGeoDetectionEnabled()) { + // Use the right suggestions based on the current configuration. + if (currentUserConfig.getGeoDetectionEnabledBehavior()) { doGeolocationTimeZoneDetection(detectionReason); } else { doTelephonyTimeZoneDetection(detectionReason); @@ -480,35 +468,18 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat // Paranoia: Every suggestion above the SCORE_USAGE_THRESHOLD should have a non-null time // zone ID. - String newZoneId = bestTelephonySuggestion.suggestion.getZoneId(); - if (newZoneId == null) { + String zoneId = bestTelephonySuggestion.suggestion.getZoneId(); + if (zoneId == null) { Slog.w(LOG_TAG, "Empty zone suggestion scored higher than expected. This is an error:" + " bestTelephonySuggestion=" + bestTelephonySuggestion + " detectionReason=" + detectionReason); return; } - String zoneId = bestTelephonySuggestion.suggestion.getZoneId(); String cause = "Found good suggestion." + ", bestTelephonySuggestion=" + bestTelephonySuggestion + ", detectionReason=" + detectionReason; - setAutoDeviceTimeZoneIfRequired(zoneId, cause); - } - - @GuardedBy("this") - private void setAutoDeviceTimeZoneIfRequired(@NonNull String newZoneId, @NonNull String cause) { - Objects.requireNonNull(newZoneId); - Objects.requireNonNull(cause); - - if (!mCallback.isAutoDetectionEnabled()) { - if (DBG) { - Slog.d(LOG_TAG, "Auto time zone detection is not enabled." - + ", newZoneId=" + newZoneId - + ", cause=" + cause); - } - return; - } - setDeviceTimeZoneIfRequired(newZoneId, cause); + setDeviceTimeZoneIfRequired(zoneId, cause); } @GuardedBy("this") @@ -582,13 +553,39 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat return findBestTelephonySuggestion(); } - @Override - public synchronized void handleAutoTimeZoneConfigChanged() { + private synchronized void handleConfigChanged() { if (DBG) { - Slog.d(LOG_TAG, "handleAutoTimeZoneConfigChanged()"); + Slog.d(LOG_TAG, "handleConfigChanged()"); + } + + clearGeolocationSuggestionIfNeeded(); + + for (ConfigurationChangeListener listener : mConfigChangeListeners) { + listener.onChange(); + } + } + + @GuardedBy("this") + private void clearGeolocationSuggestionIfNeeded() { + // This method is called whenever the user changes or the config for any user changes. We + // don't know what happened, so we capture the current user's config, check to see if we + // need to clear state associated with a previous user, and rerun detection. + int currentUserId = mCallback.getCurrentUserId(); + ConfigurationInternal currentUserConfig = mCallback.getConfigurationInternal(currentUserId); + + GeolocationTimeZoneSuggestion latestGeoLocationSuggestion = + mLatestGeoLocationSuggestion.get(); + if (latestGeoLocationSuggestion != null + && !currentUserConfig.getGeoDetectionEnabledBehavior()) { + // The current user's config has geodetection disabled, so clear the latest suggestion. + // This is done to ensure we only ever keep a geolocation suggestion if the user has + // said it is ok to do so. + mLatestGeoLocationSuggestion.set(null); + mTimeZoneChangesLog.log( + "clearGeolocationSuggestionIfNeeded: Cleared latest Geolocation suggestion."); } - doAutoTimeZoneDetection("handleAutoTimeZoneConfigChanged()"); + doAutoTimeZoneDetection(currentUserConfig, "clearGeolocationSuggestionIfNeeded()"); } @Override @@ -604,11 +601,14 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat ipw.println("TimeZoneDetectorStrategy:"); ipw.increaseIndent(); // level 1 - ipw.println("mCallback.isAutoDetectionEnabled()=" + mCallback.isAutoDetectionEnabled()); + int currentUserId = mCallback.getCurrentUserId(); + ipw.println("mCallback.getCurrentUserId()=" + currentUserId); + ConfigurationInternal configuration = mCallback.getConfigurationInternal(currentUserId); + ipw.println("mCallback.getConfiguration(currentUserId)=" + configuration); + ipw.println("[Capabilities=" + configuration.createCapabilities() + "]"); ipw.println("mCallback.isDeviceTimeZoneInitialized()=" + mCallback.isDeviceTimeZoneInitialized()); ipw.println("mCallback.getDeviceTimeZone()=" + mCallback.getDeviceTimeZone()); - ipw.println("mCallback.isGeoDetectionEnabled()=" + mCallback.isGeoDetectionEnabled()); ipw.println("Time zone change log:"); ipw.increaseIndent(); // level 2 diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index 1536473ff0a1..4c2d0d08cd4e 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -700,8 +700,8 @@ final class AccessibilityController { touchableRegion.getBounds(touchableFrame); RectF windowFrame = mTempRectF; windowFrame.set(touchableFrame); - windowFrame.offset(-windowState.getFrameLw().left, - -windowState.getFrameLw().top); + windowFrame.offset(-windowState.getFrame().left, + -windowState.getFrame().top); matrix.mapRect(windowFrame); Region windowBounds = mTempRegion2; windowBounds.set((int) windowFrame.left, (int) windowFrame.top, @@ -730,7 +730,7 @@ final class AccessibilityController { } // Count letterbox into nonMagnifiedBounds - if (windowState.isLetterboxedForDisplayCutoutLw()) { + if (windowState.isLetterboxedForDisplayCutout()) { Region letterboxBounds = getLetterboxBounds(windowState); nonMagnifiedBounds.op(letterboxBounds, Region.Op.UNION); availableBounds.op(letterboxBounds, Region.Op.DIFFERENCE); @@ -1429,11 +1429,11 @@ final class AccessibilityController { // Account for all space in the task, whether the windows in it are // touchable or not. The modal window blocks all touches from the task's // area. - unaccountedSpace.op(windowState.getDisplayFrameLw(), unaccountedSpace, + unaccountedSpace.op(windowState.getDisplayFrame(), unaccountedSpace, Region.Op.REVERSE_DIFFERENCE); } else { // If a window has tap exclude region, we need to account it. - final Region displayRegion = new Region(windowState.getDisplayFrameLw()); + final Region displayRegion = new Region(windowState.getDisplayFrame()); final Region tapExcludeRegion = new Region(); windowState.getTapExcludeRegion(tapExcludeRegion); displayRegion.op(tapExcludeRegion, displayRegion, @@ -1470,7 +1470,7 @@ final class AccessibilityController { // Move to origin as all transforms are captured by the matrix. RectF windowFrame = mTempRectF; windowFrame.set(rect); - windowFrame.offset(-windowState.getFrameLw().left, -windowState.getFrameLw().top); + windowFrame.offset(-windowState.getFrame().left, -windowState.getFrame().top); matrix.mapRect(windowFrame); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index b8b20a3e80af..56261c4fce97 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -110,9 +110,13 @@ import static android.view.WindowManager.TRANSIT_UNSET; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONTAINERS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SWITCH; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static com.android.server.wm.ActivityRecordProto.ALL_DRAWN; @@ -145,9 +149,6 @@ import static com.android.server.wm.ActivityRecordProto.WINDOW_TOKEN; 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; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONTAINERS; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_FOCUS; 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_SAVED_STATE; @@ -1096,15 +1097,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A private void scheduleActivityMovedToDisplay(int displayId, Configuration config) { if (!attachedToProcess()) { - if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.w(TAG, - "Can't report activity moved to display - client not running, activityRecord=" - + this + ", displayId=" + displayId); + ProtoLog.w(WM_DEBUG_SWITCH, "Can't report activity moved " + + "to display - client not running, activityRecord=%s, displayId=%d", + this, displayId); return; } try { - if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG, - "Reporting activity moved to display" + ", activityRecord=" + this - + ", displayId=" + displayId + ", config=" + config); + ProtoLog.v(WM_DEBUG_SWITCH, "Reporting activity moved to " + + "display, activityRecord=%s, displayId=%d, config=%s", this, displayId, + config); mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, MoveToDisplayItem.obtain(displayId, config)); @@ -1115,14 +1116,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A private void scheduleConfigurationChanged(Configuration config) { if (!attachedToProcess()) { - if (DEBUG_CONFIGURATION) Slog.w(TAG, - "Can't report activity configuration update - client not running" - + ", activityRecord=" + this); + ProtoLog.w(WM_DEBUG_CONFIGURATION, "Can't report activity configuration " + + "update - client not running, activityRecord=%s", this); return; } try { - if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + this + ", config: " - + config); + ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending new config to %s, " + + "config: %s", this, config); mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, ActivityConfigurationChangeItem.obtain(config)); @@ -1334,7 +1334,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (w == null || winHint != null && w != winHint) { return; } - final boolean surfaceReady = w.isDrawnLw() // Regular case + final boolean surfaceReady = w.isDrawn() // Regular case || w.mWinAnimator.mSurfaceDestroyDeferred // The preserved surface is still ready. || w.isDragResizeChanged(); // Waiting for relayoutWindow to call preserveSurface. final boolean needsLetterbox = surfaceReady && w.isLetterboxedAppWindow() && fillsParent(); @@ -1355,7 +1355,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A : inMultiWindowMode() ? task.getBounds() : getRootTask().getParent().getBounds(); - mLetterbox.layout(spaceToFill, w.getFrameLw(), mTmpPoint); + mLetterbox.layout(spaceToFill, w.getFrame(), mTmpPoint); } else if (mLetterbox != null) { mLetterbox.hide(); } @@ -1949,10 +1949,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A startingWindow = null; startingDisplayed = false; if (surface == null) { - ProtoLog.v(WM_DEBUG_STARTING_WINDOW, - "startingWindow was set but startingSurface==null, couldn't " - + "remove"); - + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "startingWindow was set but " + + "startingSurface==null, couldn't remove"); return; } } else { @@ -1962,9 +1960,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return; } + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Schedule remove starting %s startingWindow=%s" - + " startingView=%s Callers=%s", - this, startingWindow, startingSurface, Debug.getCallers(5)); + + " startingView=%s Callers=%s", this, startingWindow, startingSurface, + Debug.getCallers(5)); // Use the same thread to remove the window as we used to add it, as otherwise we end up @@ -2399,9 +2398,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A */ boolean moveFocusableActivityToTop(String reason) { if (!isFocusable()) { - if (DEBUG_FOCUS) { - Slog.d(TAG_FOCUS, "moveActivityStackToFront: unfocusable activity=" + this); - } + ProtoLog.d(WM_DEBUG_FOCUS, "moveActivityStackToFront: unfocusable " + + "activity=%s", this); return false; } @@ -2414,15 +2412,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (mRootWindowContainer.getTopResumedActivity() == this && getDisplayContent().mFocusedApp == this) { - if (DEBUG_FOCUS) { - Slog.d(TAG_FOCUS, "moveActivityStackToFront: already on top, activity=" + this); - } + ProtoLog.d(WM_DEBUG_FOCUS, "moveActivityStackToFront: already on top, " + + "activity=%s", this); return !isState(RESUMED); } - - if (DEBUG_FOCUS) { - Slog.d(TAG_FOCUS, "moveActivityStackToFront: activity=" + this); - } + ProtoLog.d(WM_DEBUG_FOCUS, "moveActivityStackToFront: activity=%s", this); stack.moveToFront(reason, task); // Report top activity change to tracking services and WM @@ -2798,10 +2792,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mRootWindowContainer.resumeFocusedStacksTopActivities(); } - if (DEBUG_CONTAINERS) { - Slog.d(TAG_CONTAINERS, "destroyIfPossible: r=" + this + " destroy returned removed=" - + activityRemoved); - } + ProtoLog.d(WM_DEBUG_CONTAINERS, "destroyIfPossible: r=%s destroy returned " + + "removed=%s", this, activityRemoved); return activityRemoved; } @@ -2859,12 +2851,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A app.removeActivity(this, true /* keepAssociation */); if (!app.hasActivities()) { mAtmService.clearHeavyWeightProcessIfEquals(app); - // Update any services we are bound to that might care about whether - // their client may have activities. - // No longer have activities, so update LRU list and oom adj. - app.updateProcessInfo(true /* updateServiceConnectionActivities */, - false /* activityChange */, true /* updateOomAdj */, - false /* addPendingTopUid */); } boolean skipDestroy = false; @@ -2941,10 +2927,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A finishActivityResults(Activity.RESULT_CANCELED, null /* resultData */, null /* resultGrants */); makeFinishingLocked(); - if (ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE) { - Slog.i(TAG_ADD_REMOVE, "Removing activity " + this + " from stack, reason=" - + reason + ", callers=" + Debug.getCallers(5)); - } + + ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing activity %s from stack, reason= %s " + + "callers=%s", this, reason, Debug.getCallers(5)); takeFromHistory(); removeTimeouts(); @@ -2984,7 +2969,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A void destroyed(String reason) { removeDestroyTimeout(); - if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS, "activityDestroyedLocked: r=" + this); + ProtoLog.d(WM_DEBUG_CONTAINERS, "activityDestroyedLocked: r=%s", this); if (!isState(DESTROYING, DESTROYED)) { throw new IllegalStateException( @@ -3185,12 +3170,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A remove = false; } if (remove) { - if (ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE || DEBUG_CLEANUP) { - Slog.i(TAG_ADD_REMOVE, "Removing activity " + this - + " hasSavedState=" + mHaveState + " stateNotNeeded=" + stateNotNeeded - + " finishing=" + finishing + " state=" + mState - + " callers=" + Debug.getCallers(5)); - } + ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing activity %s hasSavedState=%b " + + "stateNotNeeded=%s finishing=%b state=%s callers=%s", this, + mHaveState, stateNotNeeded, finishing, mState, Debug.getCallers(5)); if (!finishing || (app != null && app.isRemoved())) { Slog.w(TAG, "Force removing " + this + ": app died, no saved state"); EventLogTags.writeWmFinishActivity(mUserId, System.identityHashCode(this), @@ -4302,7 +4284,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } else { // If we are being set visible, and the starting window is not yet displayed, // then make sure it doesn't get displayed. - if (startingWindow != null && !startingWindow.isDrawnLw()) { + if (startingWindow != null && !startingWindow.isDrawn()) { startingWindow.clearPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY); startingWindow.mLegacyPolicyVisibilityAfterAnim = false; } @@ -4484,16 +4466,40 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A detachChildren(); } - if (state == RESUMED) { - mAtmService.updateBatteryStats(this, true); - mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_RESUMED); - } else if (state == PAUSED) { - mAtmService.updateBatteryStats(this, false); - mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_PAUSED); - } else if (state == STOPPED) { - mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_STOPPED); - } else if (state == DESTROYED) { - mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_DESTROYED); + switch (state) { + case RESUMED: + mAtmService.updateBatteryStats(this, true); + mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_RESUMED); + // Fall through. + case STARTED: + // Update process info while making an activity from invisible to visible, to make + // sure the process state is updated to foreground. + if (app != null) { + app.updateProcessInfo(false /* updateServiceConnectionActivities */, + true /* activityChange */, true /* updateOomAdj */, + true /* addPendingTopUid */); + } + break; + case PAUSED: + mAtmService.updateBatteryStats(this, false); + mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_PAUSED); + break; + case STOPPED: + mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_STOPPED); + break; + case DESTROYED: + mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_DESTROYED); + // Fall through. + case DESTROYING: + if (app != null && !app.hasActivities()) { + // Update any services we are bound to that might care about whether + // their client may have activities. + // No longer have activities, so update LRU list and oom adj. + app.updateProcessInfo(true /* updateServiceConnectionActivities */, + false /* activityChange */, true /* updateOomAdj */, + false /* addPendingTopUid */); + } + break; } } @@ -4804,14 +4810,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } setState(STARTED, "makeActiveIfNeeded"); - // Update process info while making an activity from invisible to visible, to make - // sure the process state is updated to foreground. - if (app != null) { - app.updateProcessInfo(false /* updateServiceConnectionActivities */, - true /* activityChange */, true /* updateOomAdj */, - true /* addPendingTopUid */); - } - try { mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, StartActivityItem.obtain()); @@ -5586,9 +5584,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) { final boolean isAnimationSet = isAnimating(TRANSITION | PARENTS, ANIMATION_TYPE_APP_TRANSITION); - Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw() + Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawn() + ", isAnimationSet=" + isAnimationSet); - if (!w.isDrawnLw()) { + if (!w.isDrawn()) { Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController + " pv=" + w.isVisibleByPolicy() + " mDrawState=" + winAnimator.drawStateToString() @@ -5603,7 +5601,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (findMainWindow(false /* includeStartingApp */) != w) { mNumInterestingWindows++; } - if (w.isDrawnLw()) { + if (w.isDrawn()) { mNumDrawnWindows++; if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) { @@ -5616,7 +5614,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A isInterestingAndDrawn = true; } } - } else if (w.isDrawnLw()) { + } else if (w.isDrawn()) { // The starting window for this container is drawn. mStackSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(this); startingDisplayed = true; @@ -6145,7 +6143,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (win == null) { return; } - final Rect frame = win.getRelativeFrameLw(); + final Rect frame = win.getRelativeFrame(); final int thumbnailDrawableRes = task.mUserId == mWmService.mCurrentUserId ? R.drawable.ic_account_circle : R.drawable.ic_corp_badge; @@ -6171,7 +6169,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // destination of the thumbnail header animation. If this is a full screen // window scenario, we use the whole display as the target. WindowState win = findMainWindow(); - Rect appRect = win != null ? win.getContentFrameLw() : + final Rect appRect = win != null ? win.getContentFrame() : new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight); final Rect insets = win != null ? win.getContentInsets() : null; final Configuration displayConfig = mDisplayContent.getConfiguration(); @@ -6997,27 +6995,27 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A boolean ignoreVisibility) { final Task stack = getRootTask(); if (stack.mConfigWillChange) { - if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, - "Skipping config check (will change): " + this); + ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check " + + "(will change): %s", this); return true; } // We don't worry about activities that are finishing. if (finishing) { - if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, - "Configuration doesn't matter in finishing " + this); + ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration doesn't matter " + + "in finishing %s", this); stopFreezingScreenLocked(false); return true; } if (!ignoreVisibility && (mState == STOPPING || mState == STOPPED || !shouldBeVisible())) { - if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, - "Skipping config check invisible: " + this); + ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check " + + "invisible: %s", this); return true; } - if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, - "Ensuring correct configuration: " + this); + ProtoLog.v(WM_DEBUG_CONFIGURATION, "Ensuring correct " + + "configuration: %s", this); final int newDisplayId = getDisplayId(); final boolean displayChanged = mLastReportedDisplayId != newDisplayId; @@ -7033,8 +7031,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // the combine configurations are equal, but would otherwise differ in the override config mTmpConfig.setTo(mLastReportedConfiguration.getMergedConfiguration()); if (getConfiguration().equals(mTmpConfig) && !forceNewConfig && !displayChanged) { - if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, - "Configuration & display unchanged in " + this); + ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration & display " + + "unchanged in %s", this); return true; } @@ -7054,14 +7052,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // No need to relaunch or schedule new config for activity that hasn't been launched // yet. We do, however, return after applying the config to activity record, so that // it will use it for launch transaction. - if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, - "Skipping config check for initializing activity: " + this); + ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check for " + + "initializing activity: %s", this); return true; } if (changes == 0 && !forceNewConfig) { - if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, - "Configuration no differences in " + this); + ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration no differences in %s", + this); // There are no significant differences, so we won't relaunch but should still deliver // the new configuration to the client process. if (displayChanged) { @@ -7072,26 +7070,23 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return true; } - if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, - "Configuration changes for " + this + ", allChanges=" - + Configuration.configurationDiffToString(changes)); + ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration changes for %s, " + + "allChanges=%s", this, Configuration.configurationDiffToString(changes)); // If the activity isn't currently running, just leave the new configuration and it will // pick that up next time it starts. if (!attachedToProcess()) { - if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, - "Configuration doesn't matter not running " + this); + ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration doesn't matter not running %s", this); stopFreezingScreenLocked(false); forceNewConfig = false; return true; } // Figure out how to handle the changes between the configurations. - if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, - "Checking to restart " + info.name + ": changed=0x" - + Integer.toHexString(changes) + ", handles=0x" - + Integer.toHexString(info.getRealConfigChanged()) - + ", mLastReportedConfiguration=" + mLastReportedConfiguration); + ProtoLog.v(WM_DEBUG_CONFIGURATION, "Checking to restart %s: changed=0x%s, " + + "handles=0x%s, mLastReportedConfiguration=%s", info.name, + Integer.toHexString(changes), Integer.toHexString(info.getRealConfigChanged()), + mLastReportedConfiguration); if (shouldRelaunchLocked(changes, mTmpConfig) || forceNewConfig) { // Aha, the activity isn't handling the change, so DIE DIE DIE. @@ -7108,20 +7103,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mRelaunchReason = RELAUNCH_REASON_NONE; } if (!attachedToProcess()) { - if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, - "Config is destroying non-running " + this); + ProtoLog.v(WM_DEBUG_CONFIGURATION, + "Config is destroying non-running %s", this); destroyImmediately("config"); } else if (mState == PAUSING) { // A little annoying: we are waiting for this activity to finish pausing. Let's not // do anything now, but just flag that it needs to be restarted when done pausing. - if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, - "Config is skipping already pausing " + this); + ProtoLog.v(WM_DEBUG_CONFIGURATION, + "Config is skipping already pausing %s", this); deferRelaunchUntilPaused = true; preserveWindowOnDeferredRelaunch = preserveWindow; return true; } else { - if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, - "Config is relaunching " + this); + ProtoLog.v(WM_DEBUG_CONFIGURATION, "Config is relaunching %s", + this); if (DEBUG_STATES && !mVisibleRequested) { Slog.v(TAG_STATES, "Config is relaunching invisible activity " + this + " called by " + Debug.getCallers(4)); diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 4c93b9ef64de..be7a6aed7489 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -56,12 +56,12 @@ 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.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; 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.TAG_TASKS; 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_PERMISSIONS_REVIEW; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; @@ -116,6 +116,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.HeavyWeightSwitcherActivity; import com.android.internal.app.IVoiceInteractor; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.am.PendingIntentRecord; import com.android.server.pm.InstantAppResolver; import com.android.server.power.ShutdownCheckPoints; @@ -669,10 +670,8 @@ class ActivityStarter { if (stack != null) { stack.mConfigWillChange = globalConfigWillChange; } - if (DEBUG_CONFIGURATION) { - Slog.v(TAG_CONFIGURATION, "Starting activity when config will change = " - + globalConfigWillChange); - } + ProtoLog.v(WM_DEBUG_CONFIGURATION, "Starting activity when config " + + "will change = %b", globalConfigWillChange); final long origId = Binder.clearCallingIdentity(); @@ -695,10 +694,9 @@ class ActivityStarter { if (stack != null) { stack.mConfigWillChange = false; } - if (DEBUG_CONFIGURATION) { - Slog.v(TAG_CONFIGURATION, + ProtoLog.v(WM_DEBUG_CONFIGURATION, "Updating to new configuration after starting activity."); - } + mService.updateConfigurationLocked(mRequest.globalConfig, null, false); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java b/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java index da0bfd67e353..3c562a6472b2 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java @@ -43,12 +43,6 @@ public class ActivityTaskManagerDebugConfig { // Enable all debug log categories for activities. private static final boolean DEBUG_ALL_ACTIVITIES = DEBUG_ALL || false; - static final boolean DEBUG_ADD_REMOVE = DEBUG_ALL_ACTIVITIES || false; - public static final boolean DEBUG_CONFIGURATION = DEBUG_ALL || false; - static final boolean DEBUG_CONTAINERS = DEBUG_ALL_ACTIVITIES || false; - static final boolean DEBUG_FOCUS = false; - static final boolean DEBUG_IMMERSIVE = DEBUG_ALL || false; - static final boolean DEBUG_LOCKTASK = DEBUG_ALL || false; static final boolean DEBUG_PAUSE = DEBUG_ALL || false; static final boolean DEBUG_RECENTS = DEBUG_ALL || false; static final boolean DEBUG_RECENTS_TRIM_TASKS = DEBUG_RECENTS || false; diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 2adaa52dfb30..6a8cbfbb5840 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -66,6 +66,10 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.TRANSIT_NONE; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IMMERSIVE; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK; import static com.android.server.am.ActivityManagerService.ANR_TRACE_DIR; import static com.android.server.am.ActivityManagerService.MY_PID; import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS; @@ -92,10 +96,6 @@ 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.ActivityTaskManagerDebugConfig.DEBUG_ALL; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_FOCUS; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IMMERSIVE; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; @@ -242,6 +242,7 @@ import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.os.TransferPipe; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.policy.KeyguardDismissCallback; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastPrintWriter; import com.android.internal.util.FrameworkStatsLog; @@ -813,7 +814,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // in-place. updateConfigurationLocked(configuration, null, true); final Configuration globalConfig = getGlobalConfiguration(); - if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Initial config: " + globalConfig); + ProtoLog.v(WM_DEBUG_CONFIGURATION, "Initial config: %s", globalConfig); // Load resources only after the current configuration has been set. final Resources res = mContext.getResources(); @@ -1960,7 +1961,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // update associated state if we're frontmost if (r.isFocusedActivityOnDisplay()) { - if (DEBUG_IMMERSIVE) Slog.d(TAG_IMMERSIVE, "Frontmost changed immersion: "+ r); + ProtoLog.d(WM_DEBUG_IMMERSIVE, "Frontmost changed immersion: %s", r); applyUpdateLockStateLocked(r); } } @@ -1974,8 +1975,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final boolean nextState = r != null && r.immersive; mH.post(() -> { if (mUpdateLock.isHeld() != nextState) { - if (DEBUG_IMMERSIVE) Slog.d(TAG_IMMERSIVE, - "Applying new update lock state '" + nextState + "' for " + r); + ProtoLog.d(WM_DEBUG_IMMERSIVE, "Applying new update lock state '%s' for %s", + nextState, r); if (nextState) { mUpdateLock.acquire(); } else { @@ -2176,7 +2177,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void setFocusedStack(int stackId) { mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedStack()"); - if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedStack: stackId=" + stackId); + ProtoLog.d(WM_DEBUG_FOCUS, "setFocusedStack: stackId=%d", stackId); final long callingId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -2198,7 +2199,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void setFocusedTask(int taskId) { mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedTask()"); - if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedTask: taskId=" + taskId); + ProtoLog.d(WM_DEBUG_FOCUS, "setFocusedTask: taskId=%d", taskId); final long callingId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -3013,7 +3014,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } private void startLockTaskModeLocked(@Nullable Task task, boolean isSystemCaller) { - if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "startLockTaskModeLocked: " + task); + ProtoLog.w(WM_DEBUG_LOCKTASK, "startLockTaskModeLocked: %s", task); if (task == null || task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) { return; } @@ -3075,8 +3076,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { "updateLockTaskPackages()"); } synchronized (mGlobalLock) { - if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Allowlisting " + userId + ":" - + Arrays.toString(packages)); + ProtoLog.w(WM_DEBUG_LOCKTASK, "Allowlisting %d:%s", userId, Arrays.toString(packages)); getLockTaskController().updateLockTaskPackages(userId, packages); } } @@ -4001,9 +4001,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void reportSizeConfigurations(IBinder token, int[] horizontalSizeConfiguration, int[] verticalSizeConfigurations, int[] smallestSizeConfigurations) { - if (DEBUG_CONFIGURATION) Slog.v(TAG, "Report configuration: " + token + " " - + Arrays.toString(horizontalSizeConfiguration) + " " - + Arrays.toString(verticalSizeConfigurations)); + ProtoLog.v(WM_DEBUG_CONFIGURATION, "Report configuration: %s %s %s", + token, Arrays.toString(horizontalSizeConfiguration), + Arrays.toString(verticalSizeConfigurations)); synchronized (mGlobalLock) { ActivityRecord record = ActivityRecord.isInStackLocked(token); if (record == null) { @@ -4497,8 +4497,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { "updateLockTaskFeatures()"); } synchronized (mGlobalLock) { - if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Allowing features " + userId + ":0x" + - Integer.toHexString(flags)); + ProtoLog.w(WM_DEBUG_LOCKTASK, "Allowing features %d:0x%s", + userId, Integer.toHexString(flags)); getLockTaskController().updateLockTaskFeatures(userId, flags); } } @@ -5183,8 +5183,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return 0; } - if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.i(TAG_CONFIGURATION, - "Updating global configuration to: " + values); + ProtoLog.i(WM_DEBUG_CONFIGURATION, "Updating global configuration " + + "to: %s", values); writeConfigurationChanged(changes); FrameworkStatsLog.write(FrameworkStatsLog.RESOURCE_CONFIGURATION_CHANGED, values.colorMode, @@ -5262,10 +5262,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { for (int i = pidMap.size() - 1; i >= 0; i--) { final int pid = pidMap.keyAt(i); final WindowProcessController app = pidMap.get(pid); - if (DEBUG_CONFIGURATION) { - Slog.v(TAG_CONFIGURATION, "Update process config of " - + app.mName + " to new config " + configCopy); - } + ProtoLog.v(WM_DEBUG_CONFIGURATION, "Update process config of %s to new " + + "config %s", app.mName, configCopy); app.onConfigurationChanged(configCopy); } @@ -6563,10 +6561,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (InputMethodSystemProperty.MULTI_CLIENT_IME_ENABLED) return; if (pid == MY_PID || pid < 0) { - if (DEBUG_CONFIGURATION) { - Slog.w(TAG, + ProtoLog.w(WM_DEBUG_CONFIGURATION, "Trying to update display configuration for system/invalid process."); - } return; } synchronized (mGlobalLock) { @@ -6574,18 +6570,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mRootWindowContainer.getDisplayContent(displayId); if (displayContent == null) { // Call might come when display is not yet added or has been removed. - if (DEBUG_CONFIGURATION) { - Slog.w(TAG, "Trying to update display configuration for non-existing " - + "displayId=" + displayId); - } + ProtoLog.w(WM_DEBUG_CONFIGURATION, "Trying to update display " + + "configuration for non-existing displayId=%d", displayId); return; } final WindowProcessController process = mProcessMap.getProcess(pid); if (process == null) { - if (DEBUG_CONFIGURATION) { - Slog.w(TAG, "Trying to update display configuration for invalid " - + "process, pid=" + pid); - } + ProtoLog.w(WM_DEBUG_CONFIGURATION, "Trying to update display " + + "configuration for invalid process, pid=%d", pid); return; } process.registerDisplayConfigurationListener(displayContent); diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java index c1447553ba31..8568d5fc1d64 100644 --- a/services/core/java/com/android/server/wm/BarController.java +++ b/services/core/java/com/android/server/wm/BarController.java @@ -222,12 +222,12 @@ public class BarController { } protected boolean skipAnimation() { - return !mWin.isDrawnLw(); + return !mWin.isDrawn(); } private @StatusBarManager.WindowVisibleState int computeStateLw( boolean wasVis, boolean wasAnim, WindowState win, boolean change) { - if (win.isDrawnLw()) { + if (win.isDrawn()) { final boolean vis = win.isVisibleLw(); final boolean anim = win.isAnimatingLw(); if (mState == StatusBarManager.WINDOW_STATE_HIDING && !change && !vis) { @@ -264,7 +264,7 @@ public class BarController { } boolean checkHiddenLw() { - if (mWin != null && mWin.isDrawnLw()) { + if (mWin != null && mWin.isDrawn()) { if (!mWin.isVisibleLw() && !mWin.isAnimatingLw()) { updateStateLw(StatusBarManager.WINDOW_STATE_HIDDEN); } @@ -291,7 +291,7 @@ public class BarController { } else if (mWin == null) { if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar doesn't exist"); return false; - } else if (mWin.isDisplayedLw()) { + } else if (mWin.isDisplayed()) { if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar already visible"); return false; } else { diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java index 167afab9db0e..7e55f0aa2aa6 100644 --- a/services/core/java/com/android/server/wm/CompatModePackages.java +++ b/services/core/java/com/android/server/wm/CompatModePackages.java @@ -16,8 +16,8 @@ package com.android.server.wm; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -37,6 +37,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.Xml; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.FastXmlSerializer; import org.xmlpull.v1.XmlPullParser; @@ -333,8 +334,8 @@ public final class CompatModePackages { } try { if (app.hasThread()) { - if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc " - + app.mName + " new compat " + ci); + ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending to proc %s " + + "new compat %s", app.mName, ci); app.getThread().updatePackageCompatibilityInfo(packageName, ci); } } catch (Exception e) { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 0215ead7e5de..2f7cc69b01a7 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -694,7 +694,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // Don't do layout of a window if it is not visible, or soon won't be visible, to avoid // wasting time and funky changes while a window is animating away. final boolean gone = (mTmpWindow != null && mWmService.mPolicy.canBeHiddenByKeyguardLw(w)) - || w.isGoneForLayoutLw(); + || w.isGoneForLayout(); if (DEBUG_LAYOUT && !w.mLayoutAttached) { Slog.v(TAG, "1ST PASS " + w + ": gone=" + gone + " mHaveFrame=" + w.mHaveFrame @@ -742,7 +742,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp if (firstLayout) { // The client may compute its actual requested size according to the first layout, // so we still request the window to resize if the current frame is empty. - if (!w.getFrameLw().isEmpty()) { + if (!w.getFrame().isEmpty()) { w.updateLastFrames(); } w.updateLastInsetValues(); @@ -753,9 +753,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp w.mActivityRecord.layoutLetterbox(w); } - if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrameLw() + if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrame() + " mContainingFrame=" + w.getContainingFrame() - + " mDisplayFrame=" + w.getDisplayFrameLw()); + + " mDisplayFrame=" + w.getDisplayFrame()); } }; @@ -780,9 +780,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp w.prelayout(); getDisplayPolicy().layoutWindowLw(w, w.getParentWindow(), mDisplayFrames); w.mLayoutSeq = mLayoutSeq; - if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrameLw() + if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrame() + " mContainingFrame=" + w.getContainingFrame() - + " mDisplayFrame=" + w.getDisplayFrameLw()); + + " mDisplayFrame=" + w.getDisplayFrame()); } } }; @@ -807,7 +807,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp w.mObscured = mTmpApplySurfaceChangesTransactionState.obscured; if (!mTmpApplySurfaceChangesTransactionState.obscured) { - final boolean isDisplayed = w.isDisplayedLw(); + final boolean isDisplayed = w.isDisplayed(); if (isDisplayed && w.isObscuringDisplay()) { // This window completely covers everything behind it, so we want to leave all @@ -2549,7 +2549,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return; } - if (w.isOnScreen() && w.isVisibleLw() && w.getFrameLw().contains(x, y)) { + if (w.isOnScreen() && w.isVisibleLw() && w.getFrame().contains(x, y)) { targetWindowType[0] = w.mAttrs.type; return; } @@ -2747,7 +2747,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp void adjustForImeIfNeeded() { final WindowState imeWin = mInputMethodWindow; final boolean imeVisible = imeWin != null && imeWin.isVisibleLw() - && imeWin.isDisplayedLw(); + && imeWin.isDisplayed(); final int imeHeight = mDisplayFrames.getInputMethodWindowVisibleHeight(); mPinnedStackControllerLocked.setAdjustedForIme(imeVisible, imeHeight); } @@ -3364,7 +3364,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // 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. The exception is if the // current target is home since we want opening apps to become the IME target right away. - if (curTarget != null && !curTarget.mRemoved && curTarget.isDisplayedLw() + if (curTarget != null && !curTarget.mRemoved && curTarget.isDisplayed() && curTarget.isClosing() && !curTarget.isActivityTypeHome()) { if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Not changing target till current window is" + " closing and not removed"); @@ -3647,7 +3647,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp final WindowState visibleNotDrawnWindow = getWindow(w -> { final boolean isVisible = w.isVisible() && !w.mObscured; - final boolean isDrawn = w.isDrawnLw(); + final boolean isDrawn = w.isDrawn(); if (isVisible && !isDrawn) { ProtoLog.d(WM_DEBUG_BOOT, "DisplayContent: boot is waiting for window of type %d to be drawn", @@ -4599,9 +4599,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp DisplayContent dc = this; do { final WindowState displayParent = dc.getParentWindow(); - location.x += displayParent.getFrameLw().left + location.x += displayParent.getFrame().left + (dc.getLocationInParentWindow().x * displayParent.mGlobalScale + 0.5f); - location.y += displayParent.getFrameLw().top + location.y += displayParent.getFrame().top + (dc.getLocationInParentWindow().y * displayParent.mGlobalScale + 0.5f); dc = displayParent.getDisplayContent(); } while (dc != null && dc.getParentWindow() != null); diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 40fc25b41d9f..1c147c259f07 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -195,13 +195,13 @@ import com.android.internal.widget.PointerLocationView; import com.android.server.LocalServices; import com.android.server.UiThread; import com.android.server.policy.WindowManagerPolicy; -import com.android.server.policy.WindowManagerPolicy.InputConsumer; import com.android.server.policy.WindowManagerPolicy.NavigationBarPosition; import com.android.server.policy.WindowManagerPolicy.ScreenOnListener; import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs; import com.android.server.policy.WindowOrientationListener; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.wallpaper.WallpaperManagerInternal; +import com.android.server.wm.InputMonitor.EventReceiverInputConsumer; import com.android.server.wm.utils.InsetUtils; import java.io.PrintWriter; @@ -416,7 +416,7 @@ public class DisplayPolicy { private boolean mAllowLockscreenWhenOn; @VisibleForTesting - InputConsumer mInputConsumer = null; + EventReceiverInputConsumer mInputConsumer; private PointerLocationView mPointerLocationView; @@ -462,7 +462,7 @@ public class DisplayPolicy { } break; case MSG_DISPOSE_INPUT_CONSUMER: - disposeInputConsumer((InputConsumer) msg.obj); + disposeInputConsumer((EventReceiverInputConsumer) msg.obj); break; case MSG_ENABLE_POINTER_LOCATION: enablePointerLocation(); @@ -1126,7 +1126,7 @@ public class DisplayPolicy { // For IME we use regular frame. (displayFrames, windowState, inOutFrame) -> - inOutFrame.set(windowState.getFrameLw())); + inOutFrame.set(windowState.getFrame())); mDisplayContent.setInsetProvider(ITYPE_BOTTOM_GESTURES, win, (displayFrames, windowState, inOutFrame) -> { @@ -1203,11 +1203,11 @@ public class DisplayPolicy { // IME should not provide frame which is smaller than the nav bar frame. Otherwise, // nav bar might be overlapped with the content of the client when IME is shown. sTmpRect.set(inOutFrame); - sTmpRect.intersectUnchecked(mNavigationBar.getFrameLw()); - inOutFrame.inset(windowState.getGivenContentInsetsLw()); + sTmpRect.intersectUnchecked(mNavigationBar.getFrame()); + inOutFrame.inset(windowState.mGivenContentInsets); inOutFrame.union(sTmpRect); } else { - inOutFrame.inset(windowState.getGivenContentInsetsLw()); + inOutFrame.inset(windowState.mGivenContentInsets); } }; } @@ -2075,7 +2075,7 @@ public class DisplayPolicy { // In case we forced the window to draw behind the navigation bar, restrict df to // DF.Restricted to simulate old compat behavior. - Rect parentDisplayFrame = attached.getDisplayFrameLw(); + Rect parentDisplayFrame = attached.getDisplayFrame(); final WindowManager.LayoutParams attachedAttrs = attached.mAttrs; if ((attachedAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0 && (attachedAttrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0 @@ -2096,14 +2096,14 @@ public class DisplayPolicy { // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag. // Otherwise, use the overscan frame. cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0 - ? attached.getContentFrameLw() : parentDisplayFrame); + ? attached.getContentFrame() : parentDisplayFrame); } else { // If the window is resizing, then we want to base the content frame on our attached // content frame to resize...however, things can be tricky if the attached window is // NOT in resize mode, in which case its content frame will be larger. // Ungh. So to deal with that, make sure the content frame we end up using is not // covering the IM dock. - cf.set(attached.getContentFrameLw()); + cf.set(attached.getContentFrame()); if (attached.isVoiceInteraction()) { cf.intersectUnchecked(displayFrames.mVoiceContent); } else if (win.isInputMethodTarget() || attached.isInputMethodTarget()) { @@ -2111,11 +2111,11 @@ public class DisplayPolicy { } } df.set(insetDecors ? parentDisplayFrame : cf); - vf.set(attached.getVisibleFrameLw()); + vf.set(attached.getVisibleFrame()); } // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be // positioned relative to its parent or the entire screen. - pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df); + pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrame() : df); } private void applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames) { @@ -2217,8 +2217,8 @@ public class DisplayPolicy { vf.set(adjust != SOFT_INPUT_ADJUST_NOTHING ? displayFrames.mCurrent : displayFrames.mDock); } else { - pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df); - vf.set(attached.getVisibleFrameLw()); + pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrame() : df); + vf.set(attached.getVisibleFrame()); } cf.set(adjust != SOFT_INPUT_ADJUST_RESIZE ? displayFrames.mDock : displayFrames.mContent); @@ -2623,12 +2623,10 @@ public class DisplayPolicy { win.computeFrame(displayFrames); // Dock windows carve out the bottom of the screen, so normal windows // can't appear underneath them. - if (type == TYPE_INPUT_METHOD && win.isVisibleLw() - && !win.getGivenInsetsPendingLw()) { + if (type == TYPE_INPUT_METHOD && win.isVisibleLw() && !win.mGivenInsetsPending) { offsetInputMethodWindowLw(win, displayFrames); } - if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw() - && !win.getGivenInsetsPendingLw()) { + if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw() && !win.mGivenInsetsPending) { offsetVoiceInputWindowLw(win, displayFrames); } } @@ -2645,8 +2643,8 @@ public class DisplayPolicy { final int navBarPosition = navigationBarPosition(displayFrames.mDisplayWidth, displayFrames.mDisplayHeight, rotation); - int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top); - top += win.getGivenContentInsetsLw().top; + int top = Math.max(win.getDisplayFrame().top, win.getContentFrame().top); + top += win.mGivenContentInsets.top; displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom, top); if (navBarPosition == NAV_BAR_BOTTOM) { // Always account for the nav bar frame height on the bottom since in all navigation @@ -2658,8 +2656,8 @@ public class DisplayPolicy { displayFrames.mUnrestricted.bottom - navFrameHeight); } displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top); - top = win.getVisibleFrameLw().top; - top += win.getGivenVisibleInsetsLw().top; + top = win.getVisibleFrame().top; + top += win.mGivenVisibleInsets.top; displayFrames.mCurrent.bottom = Math.min(displayFrames.mCurrent.bottom, top); if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom=" + displayFrames.mDock.bottom + " mContentBottom=" @@ -2667,8 +2665,8 @@ public class DisplayPolicy { } private void offsetVoiceInputWindowLw(WindowState win, DisplayFrames displayFrames) { - int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top); - top += win.getGivenContentInsetsLw().top; + int top = Math.max(win.getDisplayFrame().top, win.getContentFrame().top); + top += win.mGivenContentInsets.top; displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top); } @@ -2729,8 +2727,7 @@ public class DisplayPolicy { if (win.isDreamWindow()) { // If the lockscreen was showing when the dream started then wait // for the dream to draw before hiding the lockscreen. - if (!mDreamingLockscreen - || (win.isVisibleLw() && win.hasDrawnLw())) { + if (!mDreamingLockscreen || (win.isVisibleLw() && win.hasDrawn())) { mShowingDream = true; appWindow = true; } @@ -2916,7 +2913,7 @@ public class DisplayPolicy { final InsetsSource request = mTopFullscreenOpaqueWindowState.getRequestedInsetsState() .peekSource(ITYPE_STATUS_BAR); if (WindowManagerDebugConfig.DEBUG) { - Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()); + Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrame()); Slog.d(TAG, "attr: " + attrs + " request: " + request); } return (fl & LayoutParams.FLAG_FULLSCREEN) != 0 @@ -3398,7 +3395,7 @@ public class DisplayPolicy { mImmersiveModeConfirmation.confirmCurrentPrompt(); } - private void disposeInputConsumer(InputConsumer inputConsumer) { + private void disposeInputConsumer(EventReceiverInputConsumer inputConsumer) { if (inputConsumer != null) { inputConsumer.dispose(); } @@ -4171,6 +4168,6 @@ public class DisplayPolicy { return false; } - return Rect.intersects(targetWindow.getFrameLw(), navBarWindow.getFrameLw()); + return Rect.intersects(targetWindow.getFrame(), navBarWindow.getFrame()); } } diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java index 86e2698302aa..f0f338534ed2 100644 --- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java @@ -93,7 +93,7 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider { || (mImeTargetFromIme != null && isImeTargetFromDisplayContentAndImeSame() && mWin != null - && mWin.isDrawnLw() + && mWin.isDrawn() && !mWin.mGivenInsetsPending)) { mIsImeLayoutDrawn = true; // show IME if InputMethodService requested it to be shown. diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 16c4942ee972..fb511e032c98 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -61,7 +61,6 @@ import android.view.InputWindowHandle; import android.view.SurfaceControl; import com.android.internal.protolog.common.ProtoLog; -import com.android.server.policy.WindowManagerPolicy; import java.io.PrintWriter; import java.util.Set; @@ -95,8 +94,11 @@ final class InputMonitor { */ private final ArrayMap<String, InputConsumerImpl> mInputConsumers = new ArrayMap(); - private static final class EventReceiverInputConsumer extends InputConsumerImpl - implements WindowManagerPolicy.InputConsumer { + /** + * Representation of a input consumer that the policy has added to the window manager to consume + * input events going to windows below it. + */ + static final class EventReceiverInputConsumer extends InputConsumerImpl { private InputMonitor mInputMonitor; private final InputEventReceiver mInputEventReceiver; @@ -111,8 +113,8 @@ final class InputMonitor { mClientChannel, looper); } - @Override - public void dismiss() { + /** Removes the input consumer from the window manager. */ + void dismiss() { synchronized (mService.mGlobalLock) { mInputMonitor.mInputConsumers.remove(mName); hide(mInputMonitor.mInputTransaction); @@ -120,8 +122,8 @@ final class InputMonitor { } } - @Override - public void dispose() { + /** Disposes the input consumer and input receiver from the associated thread. */ + void dispose() { synchronized (mService.mGlobalLock) { disposeChannelsLw(mInputMonitor.mInputTransaction); mInputEventReceiver.dispose(); @@ -225,7 +227,7 @@ final class InputMonitor { } } - WindowManagerPolicy.InputConsumer createInputConsumer(Looper looper, String name, + EventReceiverInputConsumer createInputConsumer(Looper looper, String name, InputEventReceiver.Factory inputEventReceiverFactory) { if (!name.contentEquals(INPUT_CONSUMER_NAVIGATION)) { throw new IllegalArgumentException("Illegal input consumer : " + name @@ -289,7 +291,7 @@ final class InputMonitor { inputWindowHandle.inputFeatures = child.mAttrs.inputFeatures; inputWindowHandle.displayId = child.getDisplayId(); - final Rect frame = child.getFrameLw(); + final Rect frame = child.getFrame(); inputWindowHandle.frameLeft = frame.left; inputWindowHandle.frameTop = frame.top; inputWindowHandle.frameRight = frame.right; diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index d1eb79556d1d..e00c9e7ac38b 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -173,7 +173,7 @@ class InsetsSourceProvider { // frame may not yet determined that server side doesn't think the window is ready to // visible. (i.e. No surface, pending insets that were given during layout, etc..) if (mServerVisible) { - mTmpRect.set(mWin.getFrameLw()); + mTmpRect.set(mWin.getFrame()); if (mFrameProvider != null) { mFrameProvider.accept(mWin.getDisplayContent().mDisplayFrames, mWin, mTmpRect); } else { @@ -185,14 +185,14 @@ class InsetsSourceProvider { mSource.setFrame(mTmpRect); if (mImeFrameProvider != null) { - mImeOverrideFrame.set(mWin.getFrameLw()); + mImeOverrideFrame.set(mWin.getFrame()); mImeFrameProvider.accept(mWin.getDisplayContent().mDisplayFrames, mWin, mImeOverrideFrame); } if (mWin.mGivenVisibleInsets.left != 0 || mWin.mGivenVisibleInsets.top != 0 || mWin.mGivenVisibleInsets.right != 0 || mWin.mGivenVisibleInsets.bottom != 0) { - mTmpRect.set(mWin.getFrameLw()); + mTmpRect.set(mWin.getFrame()); mTmpRect.inset(mWin.mGivenVisibleInsets); mSource.setVisibleFrame(mTmpRect); } else { diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java index 8ef57f726658..c8d7693c9229 100644 --- a/services/core/java/com/android/server/wm/LockTaskController.java +++ b/services/core/java/com/android/server/wm/LockTaskController.java @@ -29,7 +29,7 @@ import static android.os.UserHandle.USER_ALL; import static android.os.UserHandle.USER_CURRENT; import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -65,6 +65,7 @@ import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.IKeyguardDismissCallback; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.widget.LockPatternUtils; import com.android.server.LocalServices; @@ -448,7 +449,7 @@ public class LockTaskController { * unlike {@link #stopLockTaskMode(Task, boolean, int)}, it doesn't perform the checks. */ void clearLockedTasks(String reason) { - if (DEBUG_LOCKTASK) Slog.i(TAG_LOCKTASK, "clearLockedTasks: " + reason); + ProtoLog.i(WM_DEBUG_LOCKTASK, "clearLockedTasks: %s", reason); if (!mLockTaskModeTasks.isEmpty()) { clearLockedTask(mLockTaskModeTasks.get(0)); } @@ -490,10 +491,10 @@ public class LockTaskController { if (!mLockTaskModeTasks.remove(task)) { return; } - if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "removeLockedTask: removed " + task); + ProtoLog.d(WM_DEBUG_LOCKTASK, "removeLockedTask: removed %s", task); if (mLockTaskModeTasks.isEmpty()) { - if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "removeLockedTask: task=" + task + - " last task, reverting locktask mode. Callers=" + Debug.getCallers(3)); + ProtoLog.d(WM_DEBUG_LOCKTASK, "removeLockedTask: task=%s last task, " + + "reverting locktask mode. Callers=%s", task, Debug.getCallers(3)); mHandler.post(() -> performStopLockTask(task.mUserId)); } } @@ -558,7 +559,7 @@ public class LockTaskController { if (task.mLockTaskAuth == LOCK_TASK_AUTH_PINNABLE) { // startLockTask() called by app, but app is not part of lock task allowlist. Show // app pinning request. We will come back here with isSystemCaller true. - if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Mode default, asking user"); + ProtoLog.w(WM_DEBUG_LOCKTASK, "Mode default, asking user"); StatusBarManagerInternal statusBarManager = LocalServices.getService( StatusBarManagerInternal.class); if (statusBarManager != null) { @@ -569,8 +570,7 @@ public class LockTaskController { } // System can only initiate screen pinning, not full lock task mode - if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, - isSystemCaller ? "Locking pinned" : "Locking fully"); + ProtoLog.w(WM_DEBUG_LOCKTASK, "%s", isSystemCaller ? "Locking pinned" : "Locking fully"); setLockTaskMode(task, isSystemCaller ? LOCK_TASK_MODE_PINNED : LOCK_TASK_MODE_LOCKED, "startLockTask", true); } @@ -584,7 +584,7 @@ public class LockTaskController { String reason, boolean andResume) { // Should have already been checked, but do it again. if (task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) { - if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, + ProtoLog.w(WM_DEBUG_LOCKTASK, "setLockTaskMode: Can't lock due to auth"); return; } @@ -602,8 +602,8 @@ public class LockTaskController { task.mUserId, lockTaskModeState)); } - if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "setLockTaskMode: Locking to " + task + - " Callers=" + Debug.getCallers(4)); + ProtoLog.w(WM_DEBUG_LOCKTASK, "setLockTaskMode: Locking to %s Callers=%s", + task, Debug.getCallers(4)); if (!mLockTaskModeTasks.contains(task)) { mLockTaskModeTasks.add(task); @@ -672,8 +672,8 @@ public class LockTaskController { } // Terminate locked tasks that have recently lost allowlist authorization. - if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "onLockTaskPackagesUpdated: removing " + - lockedTask + " mLockTaskAuth()=" + lockedTask.lockTaskAuthToString()); + ProtoLog.d(WM_DEBUG_LOCKTASK, "onLockTaskPackagesUpdated: removing %s" + + " mLockTaskAuth()=%s", lockedTask, lockedTask.lockTaskAuthToString()); removeLockedTask(lockedTask); lockedTask.performClearTaskLocked(); taskChanged = true; @@ -686,8 +686,8 @@ public class LockTaskController { if (mLockTaskModeTasks.isEmpty() && task!= null && task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) { // This task must have just been authorized. - if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, - "onLockTaskPackagesUpdated: starting new locktask task=" + task); + ProtoLog.d(WM_DEBUG_LOCKTASK, "onLockTaskPackagesUpdated: starting new " + + "locktask task=%s", task); setLockTaskMode(task, LOCK_TASK_MODE_LOCKED, "package updated", false); taskChanged = true; } diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java index cc5ed36e0f47..c3953b4efa16 100644 --- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java +++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java @@ -16,9 +16,8 @@ package com.android.server.wm; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE; +import static com.android.internal.protolog.ProtoLogGroup.WM_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; @@ -27,6 +26,7 @@ import android.content.pm.ActivityInfo; import android.os.Debug; import android.util.Slog; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledFunction; import com.android.internal.util.function.pooled.PooledLambda; @@ -218,8 +218,8 @@ class ResetTargetTaskHelper { if (takeOptions) { noOptions = takeOption(p, noOptions); } - if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing activity " + p + " from task=" - + mTask + " adding to task=" + targetTask + " Callers=" + Debug.getCallers(4)); + ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing activity %s from task=%s " + + "adding to task=%s Callers=%s", p, mTask, targetTask, Debug.getCallers(4)); if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Pushing next activity " + p + " out to target's task " + target); p.reparent(targetTask, position, "resetTargetTaskIfNeeded"); diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 0bf3dd9ca4a0..21e30ce0a495 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -1106,14 +1106,14 @@ class RootWindowContainer extends WindowContainer<DisplayContent> final WindowManager.LayoutParams attrs = w.mAttrs; final int attrFlags = attrs.flags; final boolean onScreen = w.isOnScreen(); - final boolean canBeSeen = w.isDisplayedLw(); + final boolean canBeSeen = w.isDisplayed(); final int privateflags = attrs.privateFlags; boolean displayHasContent = false; ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON, "handleNotObscuredLocked w: %s, w.mHasSurface: %b, w.isOnScreen(): %b, w" + ".isDisplayedLw(): %b, w.mAttrs.userActivityTimeout: %d", - w, w.mHasSurface, onScreen, w.isDisplayedLw(), w.mAttrs.userActivityTimeout); + w, w.mHasSurface, onScreen, w.isDisplayed(), w.mAttrs.userActivityTimeout); if (w.mHasSurface && onScreen) { if (!syswin && w.mAttrs.userActivityTimeout >= 0 && mUserActivityTimeout < 0) { mUserActivityTimeout = w.mAttrs.userActivityTimeout; @@ -3124,7 +3124,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> FinishDisabledPackageActivitiesHelper mFinishDisabledPackageActivitiesHelper = new FinishDisabledPackageActivitiesHelper(); class FinishDisabledPackageActivitiesHelper { - private boolean mDidSomething; private String mPackageName; private Set<String> mFilterByClasses; private boolean mDoit; @@ -3132,11 +3131,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent> private int mUserId; private boolean mOnlyRemoveNoProcess; private Task mLastTask; - private ComponentName mHomeActivity; + private final ArrayList<ActivityRecord> mCollectedActivities = new ArrayList<>(); private void reset(String packageName, Set<String> filterByClasses, boolean doit, boolean evenPersistent, int userId, boolean onlyRemoveNoProcess) { - mDidSomething = false; mPackageName = packageName; mFilterByClasses = filterByClasses; mDoit = doit; @@ -3144,7 +3142,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> mUserId = userId; mOnlyRemoveNoProcess = onlyRemoveNoProcess; mLastTask = null; - mHomeActivity = null; } boolean process(String packageName, Set<String> filterByClasses, @@ -3152,14 +3149,35 @@ class RootWindowContainer extends WindowContainer<DisplayContent> reset(packageName, filterByClasses, doit, evenPersistent, userId, onlyRemoveNoProcess); final PooledFunction f = PooledLambda.obtainFunction( - FinishDisabledPackageActivitiesHelper::processActivity, this, + FinishDisabledPackageActivitiesHelper::collectActivity, this, PooledLambda.__(ActivityRecord.class)); forAllActivities(f); f.recycle(); - return mDidSomething; + + boolean didSomething = false; + final int size = mCollectedActivities.size(); + // Keep the finishing order from top to bottom. + for (int i = 0; i < size; i++) { + final ActivityRecord r = mCollectedActivities.get(i); + if (mOnlyRemoveNoProcess) { + if (!r.hasProcess()) { + didSomething = true; + Slog.i(TAG, " Force removing " + r); + r.cleanUp(false /* cleanServices */, false /* setState */); + r.removeFromHistory("force-stop"); + } + } else { + didSomething = true; + Slog.i(TAG, " Force finishing " + r); + r.finishIfPossible("force-stop", true /* oomAdj */); + } + } + mCollectedActivities.clear(); + + return didSomething; } - private boolean processActivity(ActivityRecord r) { + private boolean collectActivity(ActivityRecord r) { final boolean sameComponent = (r.packageName.equals(mPackageName) && (mFilterByClasses == null || mFilterByClasses.contains(r.mActivityComponent.getClassName()))) @@ -3176,26 +3194,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } return true; } - if (r.isActivityTypeHome()) { - if (mHomeActivity != null && mHomeActivity.equals(r.mActivityComponent)) { - Slog.i(TAG, "Skip force-stop again " + r); - return false; - } else { - mHomeActivity = r.mActivityComponent; - } - } - 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 */); - } + mCollectedActivities.add(r); mLastTask = r.getTask(); } diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java index 6cf9432089b4..7b5b0ad870dd 100644 --- a/services/core/java/com/android/server/wm/RunningTasks.java +++ b/services/core/java/com/android/server/wm/RunningTasks.java @@ -99,9 +99,8 @@ class RunningTasks { // the task's profile return; } - if (!mAllowed && !task.isActivityTypeHome()) { - // Skip if the caller isn't allowed to fetch this task, except for the home - // task which we always return. + if (!mAllowed) { + // Skip if the caller isn't allowed to fetch this task return; } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 4dbbbc6de32c..19bf451cec05 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -79,6 +79,7 @@ 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.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN; import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME; @@ -87,9 +88,7 @@ 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_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; @@ -1651,8 +1650,8 @@ class Task extends WindowContainer<WindowContainer> { * Reorder the history stack so that the passed activity is brought to the front. */ final void moveActivityToFrontLocked(ActivityRecord newTop) { - if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing and adding activity " - + newTop + " to stack at top callers=" + Debug.getCallers(4)); + ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing and adding activity %s to stack at top " + + "callers=%s", newTop, Debug.getCallers(4)); positionChildAtTop(newTop); updateEffectiveIntent(); @@ -1951,8 +1950,8 @@ class Task extends WindowContainer<WindowContainer> { ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE; break; } - if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this - + " mLockTaskAuth=" + lockTaskAuthToString()); + ProtoLog.d(WM_DEBUG_LOCKTASK, "setLockTaskAuth: task=%s mLockTaskAuth=%s", this, + lockTaskAuthToString()); } @Override @@ -6190,10 +6189,6 @@ class Task extends WindowContainer<WindowContainer> { 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; @@ -6374,7 +6369,8 @@ class Task extends WindowContainer<WindowContainer> { // 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, + ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Adding activity %s to task %s " + + "callers: %s", r, task, new RuntimeException("here").fillInStackTrace()); rTask.positionChildAtTop(r); ActivityOptions.abort(options); @@ -6396,8 +6392,8 @@ class Task extends WindowContainer<WindowContainer> { 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()); + ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Adding activity %s to stack to task %s " + + "callers: %s", r, task, new RuntimeException("here").fillInStackTrace()); task.positionChildAtTop(r); // The transition animation and starting window are not needed if {@code allowMoveToFront} diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index dbbb7ff69b3b..e3112efdead2 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -483,7 +483,7 @@ class TaskSnapshotController { final InsetsState insetsState = new InsetsState(insetsPolicy.getInsetsForDispatch(mainWindow)); mergeInsetsSources(insetsState, mainWindow.getRequestedInsetsState()); - final Rect systemBarInsets = getSystemBarInsets(mainWindow.getFrameLw(), insetsState); + final Rect systemBarInsets = getSystemBarInsets(mainWindow.getFrame(), insetsState); final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags, attrs.privateFlags, attrs.systemUiVisibility, task.getTaskDescription(), mHighResTaskSnapshotScale, insetsState); diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index 6e00ab4939fa..ce138674cb93 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -308,7 +308,7 @@ class WallpaperController { float defaultWallpaperX = wallpaperWin.isRtl() ? 1f : 0f; float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : defaultWallpaperX; float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f; - int availw = wallpaperWin.getFrameLw().right - wallpaperWin.getFrameLw().left - dw; + int availw = wallpaperWin.getFrame().right - wallpaperWin.getFrame().left - dw; int offset = availw > 0 ? -(int)(availw * wpx + .5f) : 0; if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) { offset += mLastWallpaperDisplayOffsetX; @@ -323,7 +323,7 @@ class WallpaperController { float wpy = mLastWallpaperY >= 0 ? mLastWallpaperY : 0.5f; float wpys = mLastWallpaperYStep >= 0 ? mLastWallpaperYStep : -1.0f; - int availh = wallpaperWin.getFrameLw().bottom - wallpaperWin.getFrameLw().top - dh; + int availh = wallpaperWin.getFrame().bottom - wallpaperWin.getFrame().top - dh; offset = availh > 0 ? -(int)(availh * wpy + .5f) : 0; if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) { offset += mLastWallpaperDisplayOffsetY; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 2ce16b2fdd79..c45ccb6e17e3 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1848,7 +1848,7 @@ public class WindowManagerService extends IWindowManager.Stub } // We use the visible frame, because we want the animation to morph the window from what // was visible to the user to the final destination of the new window. - Rect frame = replacedWindow.getVisibleFrameLw(); + Rect frame = replacedWindow.getVisibleFrame(); // We treat this as if this activity was opening, so we can trigger the app transition // animation and piggy-back on existing transition animation infrastructure. final DisplayContent dc = activity.getDisplayContent(); @@ -2069,7 +2069,7 @@ public class WindowManagerService extends IWindowManager.Stub outDisplayFrame.setEmpty(); return; } - outDisplayFrame.set(win.getDisplayFrameLw()); + outDisplayFrame.set(win.getDisplayFrame()); if (win.inSizeCompatMode()) { outDisplayFrame.scale(win.mInvGlobalScale); } @@ -2389,7 +2389,7 @@ public class WindowManagerService extends IWindowManager.Stub if (displayPolicy.areSystemBarsForcedShownLw(win)) { result |= WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS; } - if (!win.isGoneForLayoutLw()) { + if (!win.isGoneForLayout()) { win.mResizedWhileGone = false; } @@ -2419,7 +2419,7 @@ public class WindowManagerService extends IWindowManager.Stub win.getInsetsForRelayout(outContentInsets, outVisibleInsets, outStableInsets); outCutout.set(win.getWmDisplayCutout().getDisplayCutout()); - outBackdropFrame.set(win.getBackdropFrame(win.getFrameLw())); + outBackdropFrame.set(win.getBackdropFrame(win.getFrame())); outInsetsState.set(win.getInsetsState(), win.isClientLocal()); if (DEBUG) { Slog.v(TAG_WM, "Relayout given client " + client.asBinder() @@ -2883,11 +2883,6 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public WindowManagerPolicy.WindowState getInputMethodWindowLw() { - return mRoot.getCurrentInputMethodWindow(); - } - - @Override public void notifyKeyguardTrustedChanged() { mAtmInternal.notifyKeyguardTrustedChanged(); } @@ -5481,7 +5476,7 @@ public class WindowManagerService extends IWindowManager.Stub // Window has been removed or hidden; no draw will now happen, so stop waiting. ProtoLog.w(WM_DEBUG_SCREEN_ON, "Aborted waiting for drawn: %s", win); container.mWaitingForDrawn.remove(win); - } else if (win.hasDrawnLw()) { + } else if (win.hasDrawn()) { // Window is now drawn (and shown). ProtoLog.d(WM_DEBUG_SCREEN_ON, "Window drawn win=%s", win); container.mWaitingForDrawn.remove(win); @@ -7356,7 +7351,7 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { WindowState windowState = mWindowMap.get(token); if (windowState != null) { - outBounds.set(windowState.getFrameLw()); + outBounds.set(windowState.getFrame()); } else { outBounds.setEmpty(); } diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index bb9cf2e2ac05..c5ebace78261 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -22,9 +22,9 @@ import static android.os.Build.VERSION_CODES.Q; import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; import static android.view.Display.INVALID_DISPLAY; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; import static com.android.server.am.ActivityManagerService.MY_PID; 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; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE; @@ -72,6 +72,7 @@ import android.view.IRemoteAnimationRunner; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.HeavyWeightSwitcherActivity; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.Watchdog; import com.android.server.wm.ActivityTaskManagerService.HotPath; @@ -1348,9 +1349,8 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio } return; } - if (DEBUG_CONFIGURATION) { - Slog.v(TAG_CONFIGURATION, "Sending to proc " + mName + " new config " + config); - } + ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending to proc %s new config %s", mName, + config); if (Build.IS_DEBUGGABLE && mHasImeService) { // TODO (b/135719017): Temporary log for debugging IME service. Slog.v(TAG_CONFIGURATION, "Sending to IME proc " + mName + " new config " + config); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index f262c5ad7b2b..9ff33b18cb89 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1009,8 +1009,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP getDisplayContent().reapplyMagnificationSpec(); } - @Override - public int getOwningUid() { + /** Returns the uid of the app that owns this window. */ + int getOwningUid() { return mOwnerUid; } @@ -1024,8 +1024,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return mOwnerCanAddInternalSystemWindow; } - @Override - public boolean canAcquireSleepToken() { + /** + * Returns {@code true} if the window owner has the permission to acquire a sleep token when + * it's visible. That is, they have the permission + * {@link androidManifest.permission#DEVICE_POWER}. + */ + boolean canAcquireSleepToken() { return mSession.mCanAcquireSleepToken; } @@ -1046,7 +1050,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP void computeFrame(DisplayFrames displayFrames) { getLayoutingWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout); - computeFrameLw(); + computeFrame(); // Update the source frame to provide insets to other windows during layout. If the // simulated frames exist, then this is not computing a stable result so just skip. if (mControllableInsetProvider != null && mSimulatedWindowFrames == null) { @@ -1054,8 +1058,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } - @Override - public void computeFrameLw() { + /** + * Perform standard frame computation. The result can be obtained with getFrame() if so desired. + */ + void computeFrame() { if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) { // This window is being replaced and either already got information that it's being // removed or we are still waiting for some information. Because of this we don't @@ -1283,32 +1289,41 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } - @Override - public Rect getFrameLw() { + /** Retrieves the current frame of the window that the application sees. */ + Rect getFrame() { return mWindowFrames.mFrame; } /** Accessor for testing */ - Rect getRelativeFrameLw() { + Rect getRelativeFrame() { return mWindowFrames.mRelFrame; } - @Override - public Rect getDisplayFrameLw() { + /** Retrieves the frame of the display that this window was last laid out in. */ + Rect getDisplayFrame() { return mWindowFrames.mDisplayFrame; } - @Override - public Rect getContentFrameLw() { + /** + * Retrieves the frame of the content area that this window was last laid out in. This is the + * area in which the content of the window should be placed. It will be smaller than the display + * frame to account for screen decorations such as a status bar or soft keyboard. + */ + Rect getContentFrame() { return mWindowFrames.mContentFrame; } - @Override - public Rect getVisibleFrameLw() { + /** + * Retrieves the frame of the visible area that this window was last laid out in. This is the + * area of the screen in which the window will actually be fully visible. It will be smaller + * than the content frame to account for transient UI elements blocking it such as an input + * method's candidates UI. + */ + Rect getVisibleFrame() { return mWindowFrames.mVisibleFrame; } - Rect getStableFrameLw() { + Rect getStableFrame() { return mWindowFrames.mStableFrame; } @@ -1337,32 +1352,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } @Override - public boolean getGivenInsetsPendingLw() { - return mGivenInsetsPending; - } - - @Override - public Rect getGivenContentInsetsLw() { - return mGivenContentInsets; - } - - @Override - public Rect getGivenVisibleInsetsLw() { - return mGivenVisibleInsets; - } - - @Override public WindowManager.LayoutParams getAttrs() { return mAttrs; } - @Override - public int getSystemUiVisibility() { + /** Retrieves the current system UI visibility flags associated with this window. */ + int getSystemUiVisibility() { return mSystemUiVisibility; } - @Override - public int getSurfaceLayer() { + /** Gets the layer at which this window's surface will be Z-ordered. */ + int getSurfaceLayer() { return mLayer; } @@ -1376,8 +1376,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return mActivityRecord != null ? mActivityRecord.appToken : null; } - @Override - public boolean isVoiceInteraction() { + /** Returns true if this window is participating in voice interaction. */ + boolean isVoiceInteraction() { return mActivityRecord != null && mActivityRecord.mVoiceInteraction; } @@ -1391,7 +1391,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP */ void updateResizingWindowIfNeeded() { final WindowStateAnimator winAnimator = mWinAnimator; - if (!mHasSurface || getDisplayContent().mLayoutSeq != mLayoutSeq || isGoneForLayoutLw()) { + if (!mHasSurface || getDisplayContent().mLayoutSeq != mLayoutSeq || isGoneForLayout()) { return; } @@ -1464,7 +1464,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mWmService.mResizingWindows.add(this); } } else if (getOrientationChanging()) { - if (isDrawnLw()) { + if (isDrawn()) { ProtoLog.v(WM_DEBUG_ORIENTATION, "Orientation not waiting for draw in %s, surfaceController %s", this, winAnimator.mSurfaceController); @@ -1639,9 +1639,16 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP : DEFAULT_DISPATCHING_TIMEOUT_MILLIS; } - @Override - public boolean hasAppShownWindows() { - return mActivityRecord != null && (mActivityRecord.firstWindowDrawn || mActivityRecord.startingDisplayed); + /** + * Returns true if, at any point, the application token associated with this window has actually + * displayed any windows. This is most useful with the "starting up" window to determine if any + * windows were displayed when it is closed. + * + * @return {@code true} if one or more windows have been displayed, else false. + */ + boolean hasAppShownWindows() { + return mActivityRecord != null + && (mActivityRecord.firstWindowDrawn || mActivityRecord.startingDisplayed); } boolean isIdentityMatrix(float dsdx, float dtdx, float dsdy, float dtdy) { @@ -1663,7 +1670,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @Override boolean hasContentToDisplay() { - if (!mAppFreezing && isDrawnLw() && (mViewVisibility == View.VISIBLE + if (!mAppFreezing && isDrawn() && (mViewVisibility == View.VISIBLE || (isAnimating(TRANSITION | PARENTS) && !getDisplayContent().mAppTransition.isTransitionSet()))) { return true; @@ -1851,10 +1858,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * Like isOnScreen, but returns false if the surface hasn't yet * been drawn. */ - @Override - public boolean isDisplayedLw() { + boolean isDisplayed() { final ActivityRecord atoken = mActivityRecord; - return isDrawnLw() && isVisibleByPolicy() + return isDrawn() && isVisibleByPolicy() && ((!isParentWindowHidden() && (atoken == null || atoken.mVisibleRequested)) || isAnimating(TRANSITION | PARENTS)); } @@ -1867,8 +1873,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return isAnimating(TRANSITION | PARENTS); } - @Override - public boolean isGoneForLayoutLw() { + /** Returns {@code true} if this window considered to be gone for purposes of layout. */ + boolean isGoneForLayout() { final ActivityRecord atoken = mActivityRecord; return mViewVisibility == View.GONE || !mRelayoutCalled @@ -1895,11 +1901,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } /** - * Returns true if the window has a surface that it has drawn a - * complete UI in to. + * Returns true if the window has a surface that it has drawn a complete UI in to. Note that + * this is different from {@link #hasDrawn()} in that it also returns true if the window is + * READY_TO_SHOW, but was not yet promoted to HAS_DRAWN. */ - @Override - public boolean isDrawnLw() { + boolean isDrawn() { return mHasSurface && !mDestroying && (mWinAnimator.mDrawState == READY_TO_SHOW || mWinAnimator.mDrawState == HAS_DRAWN); } @@ -1914,7 +1920,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // to determine if it's occluding apps. return ((!mIsWallpaper && mAttrs.format == PixelFormat.OPAQUE) || (mIsWallpaper && mWallpaperVisible)) - && isDrawnLw() && !isAnimating(TRANSITION | PARENTS); + && isDrawn() && !isAnimating(TRANSITION | PARENTS); } /** @see WindowManagerInternal#waitForAllWindowsDrawn */ @@ -1929,7 +1935,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return; } if (mAttrs.type == TYPE_APPLICATION_STARTING) { - if (isDrawnLw()) { + if (isDrawn()) { // Unnecessary to redraw a drawn starting window. return; } @@ -2016,11 +2022,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @Override void onResize() { final ArrayList<WindowState> resizingWindows = mWmService.mResizingWindows; - if (mHasSurface && !isGoneForLayoutLw() && !resizingWindows.contains(this)) { + if (mHasSurface && !isGoneForLayout() && !resizingWindows.contains(this)) { ProtoLog.d(WM_DEBUG_RESIZE, "onResize: Resizing %s", this); resizingWindows.add(this); } - if (isGoneForLayoutLw()) { + if (isGoneForLayout()) { mResizedWhileGone = true; } @@ -2514,7 +2520,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP /** Returns true if the replacement window was removed. */ boolean removeReplacedWindowIfNeeded(WindowState replacement) { - if (mWillReplaceWindow && mReplacementWindow == replacement && replacement.hasDrawnLw()) { + if (mWillReplaceWindow && mReplacementWindow == replacement && replacement.hasDrawn()) { replacement.mSkipEnterAnimationForSeamlessReplacement = false; removeReplacedWindow(); return true; @@ -2748,7 +2754,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mLayoutNeeded = true; } - if (isDrawnLw() && mToken.okToAnimate()) { + if (isDrawn() && mToken.okToAnimate()) { mWinAnimator.applyEnterAnimationLocked(); } } @@ -2873,8 +2879,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return getWindowConfiguration().keepVisibleDeadAppWindowOnScreen(); } - @Override - public boolean canReceiveKeys() { + /** Returns {@code true} if this window desires key events. */ + boolean canReceiveKeys() { return canReceiveKeys(false /* fromUserTouch */); } @@ -2923,8 +2929,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP && recentsAnimationController.shouldApplyInputConsumer(mActivityRecord); } - @Override - public boolean hasDrawnLw() { + /** + * Returns {@code true} if this window has been shown on screen at some time in the past. + * + * @deprecated Use {@link #isDrawnLw} or any of the other drawn/visibility methods. + */ + @Deprecated + boolean hasDrawn() { return mWinAnimator.mDrawState == WindowStateAnimator.HAS_DRAWN; } @@ -3158,8 +3169,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } - @Override - public boolean isAlive() { + /** Checks whether the process hosting this window is currently alive. */ + boolean isAlive() { return mClient.asBinder().isBinderAlive(); } @@ -3339,16 +3350,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mLastExclusionLogUptimeMillis[EXCLUSION_RIGHT] = now; } - @Override - public boolean isDefaultDisplay() { - final DisplayContent displayContent = getDisplayContent(); - if (displayContent == null) { - // Only a window that was on a non-default display can be detached from it. - return false; - } - return displayContent.isDefaultDisplay; - } - /** @return {@code true} if this window can be shown to all users. */ boolean showForAllUsers() { @@ -3408,10 +3409,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // All window frames that are fullscreen extend above status bar, but some don't extend // below navigation bar. Thus, check for display frame for top/left and stable frame for // bottom right. - if (win.getFrameLw().left <= win.getDisplayFrameLw().left - && win.getFrameLw().top <= win.getDisplayFrameLw().top - && win.getFrameLw().right >= win.getStableFrameLw().right - && win.getFrameLw().bottom >= win.getStableFrameLw().bottom) { + if (win.getFrame().left <= win.getDisplayFrame().left + && win.getFrame().top <= win.getDisplayFrame().top + && win.getFrame().right >= win.getStableFrame().right + && win.getFrame().bottom >= win.getStableFrame().bottom) { // Is a fullscreen window, like the clock alarm. Show to everyone. return true; } @@ -3569,6 +3570,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } void reportResized() { + // If the activity is scheduled to relaunch, skip sending the resized to ViewRootImpl now + // since it will be destroyed anyway. This also prevents the client from receiving + // windowing mode change before it is destroyed. + if (mActivityRecord != null && mActivityRecord.isRelaunching()) { + return; + } + if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.reportResized_" + getWindowTag()); } @@ -3774,11 +3782,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * is transitioning into/out-of fullscreen. */ boolean isLetterboxedAppWindow() { return !inMultiWindowMode() && !matchesDisplayBounds() - || isLetterboxedForDisplayCutoutLw(); + || isLetterboxedForDisplayCutout(); } - @Override - public boolean isLetterboxedForDisplayCutoutLw() { + /** Returns {@code true} if the window is letterboxed for the display cutout. */ + boolean isLetterboxedForDisplayCutout() { if (mActivityRecord == null) { // Only windows with an ActivityRecord are letterboxed. return false; @@ -3882,7 +3890,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // background. return (getDisplayContent().mDividerControllerLocked.isResizing() || mActivityRecord != null && !mActivityRecord.mFrozenBounds.isEmpty()) && - !task.inFreeformWindowingMode() && !isGoneForLayoutLw(); + !task.inFreeformWindowingMode() && !isGoneForLayout(); } @@ -4298,7 +4306,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP private boolean isParentWindowGoneForLayout() { final WindowState parent = getParentWindow(); - return parent != null && parent.isGoneForLayoutLw(); + return parent != null && parent.isGoneForLayout(); } void setWillReplaceWindow(boolean animate) { @@ -4411,8 +4419,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return null; } - @Override - public int getRotationAnimationHint() { + int getRotationAnimationHint() { if (mActivityRecord != null) { return mActivityRecord.mRotationAnimationHint; } else { @@ -4868,7 +4875,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } boolean hasVisibleNotDrawnWallpaper() { - if (mWallpaperVisible && !isDrawnLw()) { + if (mWallpaperVisible && !isDrawn()) { return true; } for (int j = mChildren.size() - 1; j >= 0; --j) { @@ -4892,9 +4899,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return; } if (DEBUG_VISIBILITY) { - Slog.v(TAG, "Win " + this + ": isDrawn=" + isDrawnLw() + Slog.v(TAG, "Win " + this + ": isDrawn=" + isDrawn() + ", animating=" + isAnimating(TRANSITION | PARENTS)); - if (!isDrawnLw()) { + if (!isDrawn()) { Slog.v(TAG, "Not displayed: s=" + mWinAnimator.mSurfaceController + " pv=" + isVisibleByPolicy() + " mDrawState=" + mWinAnimator.mDrawState @@ -4905,7 +4912,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } results.numInteresting++; - if (isDrawnLw()) { + if (isDrawn()) { results.numDrawn++; if (!isAnimating(TRANSITION | PARENTS)) { results.numVisible++; @@ -5041,7 +5048,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP int relayoutVisibleWindow(int result, int attrChanges) { final boolean wasVisible = isVisibleLw(); - result |= (!wasVisible || !isDrawnLw()) ? RELAYOUT_RES_FIRST_TIME : 0; + result |= (!wasVisible || !isDrawn()) ? RELAYOUT_RES_FIRST_TIME : 0; if (mAnimatingExit) { Slog.d(TAG, "relayoutVisibleWindow: " + this + " mAnimatingExit=true, mRemoveOnExit=" @@ -5613,15 +5620,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return !mTapExcludeRegion.isEmpty(); } - @Override - public boolean isInputMethodTarget() { + boolean isInputMethodTarget() { return getDisplayContent().mInputMethodTarget == this; } long getFrameNumber() { // Return the frame number in which changes requested in this layout will be rendered or // -1 if we do not expect the frame to be rendered. - return getFrameLw().isEmpty() ? -1 : mFrameNumber; + return getFrame().isEmpty() ? -1 : mFrameNumber; } void setFrameNumber(long frameNumber) { @@ -5684,8 +5690,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return mWindowFrames.mVisibleInsets; } - @Override - public WindowFrames getWindowFrames() { + /** Returns the {@link WindowFrames} associated with this {@link WindowState}. */ + WindowFrames getWindowFrames() { return mWindowFrames; } @@ -5793,7 +5799,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // won't exactly match the final freeform window frame (e.g. when overlapping with // the status bar). In that case we need to use the final frame. if (inFreeformWindowingMode()) { - outFrame.set(getFrameLw()); + outFrame.set(getFrame()); } else if (isLetterboxedAppWindow() || mToken.isFixedRotationTransforming()) { // 1. The letterbox surfaces should be animated with the owner activity, so use task // bounds to include them. diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 6f483428eaec..1bd712c3638b 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -526,13 +526,13 @@ class WindowStateAnimator { if (DEBUG) { Slog.v(TAG, "Got surface: " + mSurfaceController - + ", set left=" + w.getFrameLw().left + " top=" + w.getFrameLw().top); + + ", set left=" + w.getFrame().left + " top=" + w.getFrame().top); } if (SHOW_LIGHT_TRANSACTIONS) { Slog.i(TAG, ">>> OPEN TRANSACTION createSurfaceLocked"); WindowManagerService.logSurface(w, "CREATE pos=(" - + w.getFrameLw().left + "," + w.getFrameLw().top + ") (" + + w.getFrame().left + "," + w.getFrame().top + ") (" + width + "x" + height + ")" + " HIDE", false); } @@ -896,7 +896,7 @@ class WindowStateAnimator { // There is no need to wait for an animation change if our window is gone for layout // already as we'll never be visible. - if (w.getOrientationChanging() && w.isGoneForLayoutLw()) { + if (w.getOrientationChanging() && w.isGoneForLayout()) { ProtoLog.v(WM_DEBUG_ORIENTATION, "Orientation change skips hidden %s", w); w.setOrientationChanging(false); } @@ -920,7 +920,7 @@ class WindowStateAnimator { // really hidden (gone for layout), there is no point in still waiting for it. // Note that this does introduce a potential glitch if the window becomes unhidden // before it has drawn for the new orientation. - if (w.getOrientationChanging() && w.isGoneForLayoutLw()) { + if (w.getOrientationChanging() && w.isGoneForLayout()) { w.setOrientationChanging(false); ProtoLog.v(WM_DEBUG_ORIENTATION, "Orientation change skips hidden %s", w); @@ -998,7 +998,7 @@ class WindowStateAnimator { } if (w.getOrientationChanging()) { - if (!w.isDrawnLw()) { + if (!w.isDrawn()) { mAnimator.mBulkUpdateParams &= ~SET_ORIENTATION_CHANGE_COMPLETE; mAnimator.mLastWindowFreezeSource = w; ProtoLog.v(WM_DEBUG_ORIENTATION, diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp index b3f3a5e1ff72..9aca84849fc6 100644 --- a/services/core/jni/com_android_server_VibratorService.cpp +++ b/services/core/jni/com_android_server_VibratorService.cpp @@ -40,14 +40,12 @@ namespace aidl = android::hardware::vibrator; namespace android { static JavaVM* sJvm = nullptr; - static jmethodID sMethodIdOnComplete; - static struct { jfieldID id; jfieldID scale; jfieldID delay; -} gPrimitiveClassInfo; +} sPrimitiveClassInfo; static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) == static_cast<uint8_t>(aidl::EffectStrength::LIGHT)); @@ -77,100 +75,117 @@ static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) == static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) == static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK)); -static inline void callVibrationOnComplete(jobject vibration) { - if (vibration == nullptr) { - return; +class NativeVibratorService { +public: + NativeVibratorService(JNIEnv* env, jobject callbackListener) + : mController(std::make_unique<vibrator::HalController>()), + mCallbackListener(env->NewGlobalRef(callbackListener)) { + LOG_ALWAYS_FATAL_IF(mCallbackListener == nullptr, + "Unable to create global reference to vibration callback handler"); } - auto jniEnv = GetOrAttachJNIEnvironment(sJvm); - jniEnv->CallVoidMethod(vibration, sMethodIdOnComplete); - jniEnv->DeleteGlobalRef(vibration); -} + + ~NativeVibratorService() { + auto jniEnv = GetOrAttachJNIEnvironment(sJvm); + jniEnv->DeleteGlobalRef(mCallbackListener); + } + + vibrator::HalController* controller() const { return mController.get(); } + + std::function<void()> createCallback(jlong vibrationId) { + return [vibrationId, this]() { + auto jniEnv = GetOrAttachJNIEnvironment(sJvm); + jniEnv->CallVoidMethod(mCallbackListener, sMethodIdOnComplete, vibrationId); + }; + } + +private: + const std::unique_ptr<vibrator::HalController> mController; + const jobject mCallbackListener; +}; static aidl::CompositeEffect effectFromJavaPrimitive(JNIEnv* env, jobject primitive) { aidl::CompositeEffect effect; effect.primitive = static_cast<aidl::CompositePrimitive>( - env->GetIntField(primitive, gPrimitiveClassInfo.id)); - effect.scale = static_cast<float>(env->GetFloatField(primitive, gPrimitiveClassInfo.scale)); - effect.delayMs = static_cast<int32_t>(env->GetIntField(primitive, gPrimitiveClassInfo.delay)); + env->GetIntField(primitive, sPrimitiveClassInfo.id)); + effect.scale = static_cast<float>(env->GetFloatField(primitive, sPrimitiveClassInfo.scale)); + effect.delayMs = static_cast<int32_t>(env->GetIntField(primitive, sPrimitiveClassInfo.delay)); return effect; } -static void destroyVibratorController(void* rawVibratorController) { - vibrator::HalController* vibratorController = - reinterpret_cast<vibrator::HalController*>(rawVibratorController); - if (vibratorController) { - delete vibratorController; +static void destroyNativeService(void* servicePtr) { + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service) { + delete service; } } -static jlong vibratorInit(JNIEnv* /* env */, jclass /* clazz */) { - std::unique_ptr<vibrator::HalController> controller = - std::make_unique<vibrator::HalController>(); - controller->init(); - return reinterpret_cast<jlong>(controller.release()); +static jlong vibratorInit(JNIEnv* env, jclass /* clazz */, jobject callbackListener) { + std::unique_ptr<NativeVibratorService> service = + std::make_unique<NativeVibratorService>(env, callbackListener); + service->controller()->init(); + return reinterpret_cast<jlong>(service.release()); } static jlong vibratorGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) { - return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyVibratorController)); + return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyNativeService)); } -static jboolean vibratorExists(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorExists failed because controller was not initialized"); +static jboolean vibratorExists(JNIEnv* env, jclass /* clazz */, jlong servicePtr) { + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorExists failed because native service was not initialized"); return JNI_FALSE; } - return controller->ping().isOk() ? JNI_TRUE : JNI_FALSE; + return service->controller()->ping().isOk() ? JNI_TRUE : JNI_FALSE; } -static void vibratorOn(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, jlong timeoutMs, - jobject vibration) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorOn failed because controller was not initialized"); +static void vibratorOn(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong timeoutMs, + jlong vibrationId) { + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorOn failed because native service was not initialized"); return; } - jobject vibrationRef = vibration == nullptr ? vibration : MakeGlobalRefOrDie(env, vibration); - auto callback = [vibrationRef]() { callVibrationOnComplete(vibrationRef); }; - controller->on(std::chrono::milliseconds(timeoutMs), callback); + auto callback = service->createCallback(vibrationId); + service->controller()->on(std::chrono::milliseconds(timeoutMs), callback); } -static void vibratorOff(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorOff failed because controller was not initialized"); +static void vibratorOff(JNIEnv* env, jclass /* clazz */, jlong servicePtr) { + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorOff failed because native service was not initialized"); return; } - controller->off(); + service->controller()->off(); } -static void vibratorSetAmplitude(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, +static void vibratorSetAmplitude(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jint amplitude) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorSetAmplitude failed because controller was not initialized"); + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorSetAmplitude failed because native service was not initialized"); return; } - controller->setAmplitude(static_cast<int32_t>(amplitude)); + service->controller()->setAmplitude(static_cast<int32_t>(amplitude)); } -static void vibratorSetExternalControl(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, +static void vibratorSetExternalControl(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jboolean enabled) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorSetExternalControl failed because controller was not initialized"); + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorSetExternalControl failed because native service was not initialized"); return; } - controller->setExternalControl(enabled); + service->controller()->setExternalControl(enabled); } -static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorGetSupportedEffects failed because controller was not initialized"); +static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jlong servicePtr) { + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorGetSupportedEffects failed because native service was not initialized"); return nullptr; } - auto result = controller->getSupportedEffects(); + auto result = service->controller()->getSupportedEffects(); if (!result.isOk()) { return nullptr; } @@ -181,14 +196,13 @@ static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jl return effects; } -static jintArray vibratorGetSupportedPrimitives(JNIEnv* env, jclass /* clazz */, - jlong controllerPtr) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorGetSupportedPrimitives failed because controller was not initialized"); +static jintArray vibratorGetSupportedPrimitives(JNIEnv* env, jclass /* clazz */, jlong servicePtr) { + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorGetSupportedPrimitives failed because native service was not initialized"); return nullptr; } - auto result = controller->getSupportedPrimitives(); + auto result = service->controller()->getSupportedPrimitives(); if (!result.isOk()) { return nullptr; } @@ -199,26 +213,25 @@ static jintArray vibratorGetSupportedPrimitives(JNIEnv* env, jclass /* clazz */, return primitives; } -static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, - jlong effect, jlong strength, jobject vibration) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorPerformEffect failed because controller was not initialized"); +static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong effect, + jlong strength, jlong vibrationId) { + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorPerformEffect failed because native service was not initialized"); return -1; } aidl::Effect effectType = static_cast<aidl::Effect>(effect); aidl::EffectStrength effectStrength = static_cast<aidl::EffectStrength>(strength); - jobject vibrationRef = vibration == nullptr ? vibration : MakeGlobalRefOrDie(env, vibration); - auto callback = [vibrationRef]() { callVibrationOnComplete(vibrationRef); }; - auto result = controller->performEffect(effectType, effectStrength, callback); + auto callback = service->createCallback(vibrationId); + auto result = service->controller()->performEffect(effectType, effectStrength, callback); return result.isOk() ? result.value().count() : -1; } -static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, - jobjectArray composition, jobject vibration) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorPerformComposedEffect failed because controller was not initialized"); +static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong servicePtr, + jobjectArray composition, jlong vibrationId) { + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorPerformComposedEffect failed because native service was not initialized"); return; } size_t size = env->GetArrayLength(composition); @@ -227,54 +240,52 @@ static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong jobject element = env->GetObjectArrayElement(composition, i); effects.push_back(effectFromJavaPrimitive(env, element)); } - jobject vibrationRef = vibration == nullptr ? vibration : MakeGlobalRefOrDie(env, vibration); - auto callback = [vibrationRef]() { callVibrationOnComplete(vibrationRef); }; - controller->performComposedEffect(effects, callback); + auto callback = service->createCallback(vibrationId); + service->controller()->performComposedEffect(effects, callback); } -static jlong vibratorGetCapabilities(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorGetCapabilities failed because controller was not initialized"); +static jlong vibratorGetCapabilities(JNIEnv* env, jclass /* clazz */, jlong servicePtr) { + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorGetCapabilities failed because native service was not initialized"); return 0; } - auto result = controller->getCapabilities(); + auto result = service->controller()->getCapabilities(); return result.isOk() ? static_cast<jlong>(result.value()) : 0; } -static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, jlong id, +static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong id, jlong effect, jlong strength) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorAlwaysOnEnable failed because controller was not initialized"); + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorAlwaysOnEnable failed because native service was not initialized"); return; } - controller->alwaysOnEnable(static_cast<int32_t>(id), static_cast<aidl::Effect>(effect), - static_cast<aidl::EffectStrength>(strength)); + service->controller()->alwaysOnEnable(static_cast<int32_t>(id), + static_cast<aidl::Effect>(effect), + static_cast<aidl::EffectStrength>(strength)); } -static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, - jlong id) { - vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); - if (controller == nullptr) { - ALOGE("vibratorAlwaysOnDisable failed because controller was not initialized"); +static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong id) { + NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr); + if (service == nullptr) { + ALOGE("vibratorAlwaysOnDisable failed because native service was not initialized"); return; } - controller->alwaysOnDisable(static_cast<int32_t>(id)); + service->controller()->alwaysOnDisable(static_cast<int32_t>(id)); } static const JNINativeMethod method_table[] = { - {"vibratorInit", "()J", (void*)vibratorInit}, + {"vibratorInit", "(Lcom/android/server/VibratorService$OnCompleteListener;)J", + (void*)vibratorInit}, {"vibratorGetFinalizer", "()J", (void*)vibratorGetFinalizer}, {"vibratorExists", "(J)Z", (void*)vibratorExists}, - {"vibratorOn", "(JJLcom/android/server/VibratorService$Vibration;)V", (void*)vibratorOn}, + {"vibratorOn", "(JJJ)V", (void*)vibratorOn}, {"vibratorOff", "(J)V", (void*)vibratorOff}, {"vibratorSetAmplitude", "(JI)V", (void*)vibratorSetAmplitude}, - {"vibratorPerformEffect", "(JJJLcom/android/server/VibratorService$Vibration;)J", - (void*)vibratorPerformEffect}, + {"vibratorPerformEffect", "(JJJJ)J", (void*)vibratorPerformEffect}, {"vibratorPerformComposedEffect", - "(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;Lcom/android/server/" - "VibratorService$Vibration;)V", + "(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;J)V", (void*)vibratorPerformComposedEffect}, {"vibratorGetSupportedEffects", "(J)[I", (void*)vibratorGetSupportedEffects}, {"vibratorGetSupportedPrimitives", "(J)[I", (void*)vibratorGetSupportedPrimitives}, @@ -284,18 +295,17 @@ static const JNINativeMethod method_table[] = { {"vibratorAlwaysOnDisable", "(JJ)V", (void*)vibratorAlwaysOnDisable}, }; -int register_android_server_VibratorService(JavaVM* vm, JNIEnv* env) { - sJvm = vm; - sMethodIdOnComplete = - GetMethodIDOrDie(env, - FindClassOrDie(env, "com/android/server/VibratorService$Vibration"), - "onComplete", "()V"); +int register_android_server_VibratorService(JavaVM* jvm, JNIEnv* env) { + sJvm = jvm; + jclass listenerClass = + FindClassOrDie(env, "com/android/server/VibratorService$OnCompleteListener"); + sMethodIdOnComplete = GetMethodIDOrDie(env, listenerClass, "onComplete", "(J)V"); jclass primitiveClass = FindClassOrDie(env, "android/os/VibrationEffect$Composition$PrimitiveEffect"); - gPrimitiveClassInfo.id = GetFieldIDOrDie(env, primitiveClass, "id", "I"); - gPrimitiveClassInfo.scale = GetFieldIDOrDie(env, primitiveClass, "scale", "F"); - gPrimitiveClassInfo.delay = GetFieldIDOrDie(env, primitiveClass, "delay", "I"); + sPrimitiveClassInfo.id = GetFieldIDOrDie(env, primitiveClass, "id", "I"); + sPrimitiveClassInfo.scale = GetFieldIDOrDie(env, primitiveClass, "scale", "F"); + sPrimitiveClassInfo.delay = GetFieldIDOrDie(env, primitiveClass, "delay", "I"); return jniRegisterNativeMethods(env, "com/android/server/VibratorService", method_table, NELEM(method_table)); diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java index b7a36f2eaed2..8d4f2aa69d68 100644 --- a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java @@ -20,12 +20,13 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.AdditionalMatchers.gt; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.intThat; -import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.ArgumentMatchers.notNull; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; @@ -167,7 +168,7 @@ public class VibratorServiceTest { @Test public void createService_initializesNativeService() { createService(); - verify(mNativeWrapperMock).vibratorInit(); + verify(mNativeWrapperMock).vibratorInit(notNull()); verify(mNativeWrapperMock).vibratorOff(); } @@ -294,7 +295,7 @@ public class VibratorServiceTest { assertTrue(service.isVibrating()); verify(mNativeWrapperMock).vibratorOff(); - verify(mNativeWrapperMock).vibratorOn(eq(100L), any(VibratorService.Vibration.class)); + verify(mNativeWrapperMock).vibratorOn(eq(100L), gt(0L)); verify(mNativeWrapperMock).vibratorSetAmplitude(eq(128)); } @@ -307,7 +308,7 @@ public class VibratorServiceTest { assertTrue(service.isVibrating()); verify(mNativeWrapperMock).vibratorOff(); - verify(mNativeWrapperMock).vibratorOn(eq(100L), any(VibratorService.Vibration.class)); + verify(mNativeWrapperMock).vibratorOn(eq(100L), gt(0L)); verify(mNativeWrapperMock, never()).vibratorSetAmplitude(anyInt()); } @@ -321,10 +322,8 @@ public class VibratorServiceTest { vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)); verify(mNativeWrapperMock).vibratorOff(); - verify(mNativeWrapperMock).vibratorPerformEffect( - eq((long) VibrationEffect.EFFECT_CLICK), - eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), - any(VibratorService.Vibration.class)); + verify(mNativeWrapperMock).vibratorPerformEffect(eq((long) VibrationEffect.EFFECT_CLICK), + eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), gt(0L)); } @Test @@ -343,7 +342,7 @@ public class VibratorServiceTest { verify(mNativeWrapperMock).vibratorOff(); verify(mNativeWrapperMock).vibratorPerformComposedEffect( - primitivesCaptor.capture(), any(VibratorService.Vibration.class)); + primitivesCaptor.capture(), gt(0L)); // Check all primitive effect fields are passed down to the HAL. assertEquals(1, primitivesCaptor.getValue().length); @@ -368,7 +367,7 @@ public class VibratorServiceTest { // Wait for VibrateThread to turn vibrator ON with total timing and no callback. Thread.sleep(5); - verify(mNativeWrapperMock).vibratorOn(eq(30L), isNull()); + verify(mNativeWrapperMock).vibratorOn(eq(30L), eq(0L)); // First amplitude set right away. verify(mNativeWrapperMock).vibratorSetAmplitude(eq(100)); @@ -384,11 +383,11 @@ public class VibratorServiceTest { @Test public void vibrate_withOneShotAndNativeCallbackTriggered_finishesVibration() { + VibratorService service = createService(); doAnswer(invocation -> { - ((VibratorService.Vibration) invocation.getArgument(1)).onComplete(); + service.onVibrationComplete(invocation.getArgument(1)); return null; - }).when(mNativeWrapperMock).vibratorOn(anyLong(), any(VibratorService.Vibration.class)); - VibratorService service = createService(); + }).when(mNativeWrapperMock).vibratorOn(anyLong(), anyLong()); Mockito.clearInvocations(mNativeWrapperMock); vibrate(service, VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE)); @@ -396,7 +395,7 @@ public class VibratorServiceTest { InOrder inOrderVerifier = inOrder(mNativeWrapperMock); inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(100L), - any(VibratorService.Vibration.class)); + gt(0L)); inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); } @@ -404,12 +403,11 @@ public class VibratorServiceTest { public void vibrate_withPrebakedAndNativeCallbackTriggered_finishesVibration() { when(mNativeWrapperMock.vibratorGetSupportedEffects()) .thenReturn(new int[]{VibrationEffect.EFFECT_CLICK}); + VibratorService service = createService(); doAnswer(invocation -> { - ((VibratorService.Vibration) invocation.getArgument(2)).onComplete(); + service.onVibrationComplete(invocation.getArgument(2)); return 10_000L; // 10s - }).when(mNativeWrapperMock).vibratorPerformEffect( - anyLong(), anyLong(), any(VibratorService.Vibration.class)); - VibratorService service = createService(); + }).when(mNativeWrapperMock).vibratorPerformEffect(anyLong(), anyLong(), anyLong()); Mockito.clearInvocations(mNativeWrapperMock); vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)); @@ -419,7 +417,7 @@ public class VibratorServiceTest { inOrderVerifier.verify(mNativeWrapperMock).vibratorPerformEffect( eq((long) VibrationEffect.EFFECT_CLICK), eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), - any(VibratorService.Vibration.class)); + gt(0L)); inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); } @@ -436,44 +434,19 @@ public class VibratorServiceTest { Thread.sleep(15); InOrder inOrderVerifier = inOrder(mNativeWrapperMock); inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); - inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(3L), isNull()); - inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(2L), isNull()); + inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(3L), eq(0L)); + inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(2L), eq(0L)); inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); } @Test public void vibrate_withComposedAndNativeCallbackTriggered_finishesVibration() { mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); - doAnswer(invocation -> { - ((VibratorService.Vibration) invocation.getArgument(1)).onComplete(); - return null; - }).when(mNativeWrapperMock).vibratorPerformComposedEffect( - any(), any(VibratorService.Vibration.class)); VibratorService service = createService(); - Mockito.clearInvocations(mNativeWrapperMock); - - VibrationEffect effect = VibrationEffect.startComposition() - .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 10) - .compose(); - vibrate(service, effect); - - InOrder inOrderVerifier = inOrder(mNativeWrapperMock); - inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); - inOrderVerifier.verify(mNativeWrapperMock).vibratorPerformComposedEffect( - any(VibrationEffect.Composition.PrimitiveEffect[].class), - any(VibratorService.Vibration.class)); - inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); - } - - @Test - public void vibrate_whenBinderDies_cancelsVibration() { - mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); doAnswer(invocation -> { - ((VibratorService.Vibration) invocation.getArgument(1)).binderDied(); + service.onVibrationComplete(invocation.getArgument(1)); return null; - }).when(mNativeWrapperMock).vibratorPerformComposedEffect( - any(), any(VibratorService.Vibration.class)); - VibratorService service = createService(); + }).when(mNativeWrapperMock).vibratorPerformComposedEffect(any(), anyLong()); Mockito.clearInvocations(mNativeWrapperMock); VibrationEffect effect = VibrationEffect.startComposition() @@ -484,8 +457,7 @@ public class VibratorServiceTest { InOrder inOrderVerifier = inOrder(mNativeWrapperMock); inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); inOrderVerifier.verify(mNativeWrapperMock).vibratorPerformComposedEffect( - any(VibrationEffect.Composition.PrimitiveEffect[].class), - any(VibratorService.Vibration.class)); + any(VibrationEffect.Composition.PrimitiveEffect[].class), gt(0L)); inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); } @@ -513,12 +485,11 @@ public class VibratorServiceTest { @Test public void registerVibratorStateListener_callbacksAreTriggered() throws Exception { + VibratorService service = createService(); doAnswer(invocation -> { - ((VibratorService.Vibration) invocation.getArgument(1)).onComplete(); + service.onVibrationComplete(invocation.getArgument(1)); return null; - }).when(mNativeWrapperMock).vibratorOn(anyLong(), any(VibratorService.Vibration.class)); - VibratorService service = createService(); - + }).when(mNativeWrapperMock).vibratorOn(anyLong(), anyLong()); service.registerVibratorStateListener(mVibratorStateListenerMock); verify(mVibratorStateListenerMock).onVibrating(false); Mockito.clearInvocations(mVibratorStateListenerMock); @@ -569,15 +540,15 @@ public class VibratorServiceTest { verify(mNativeWrapperMock).vibratorPerformEffect( eq((long) VibrationEffect.EFFECT_CLICK), - eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), any()); + eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), anyLong()); verify(mNativeWrapperMock).vibratorPerformEffect( eq((long) VibrationEffect.EFFECT_TICK), - eq((long) VibrationEffect.EFFECT_STRENGTH_MEDIUM), any()); + eq((long) VibrationEffect.EFFECT_STRENGTH_MEDIUM), anyLong()); verify(mNativeWrapperMock).vibratorPerformEffect( eq((long) VibrationEffect.EFFECT_DOUBLE_CLICK), - eq((long) VibrationEffect.EFFECT_STRENGTH_LIGHT), any()); + eq((long) VibrationEffect.EFFECT_STRENGTH_LIGHT), anyLong()); verify(mNativeWrapperMock, never()).vibratorPerformEffect( - eq((long) VibrationEffect.EFFECT_HEAVY_CLICK), anyLong(), any()); + eq((long) VibrationEffect.EFFECT_HEAVY_CLICK), anyLong(), anyLong()); } @Test @@ -644,7 +615,7 @@ public class VibratorServiceTest { // Ringtone vibration is off, so only the other 3 are propagated to native. verify(mNativeWrapperMock, times(3)).vibratorPerformComposedEffect( - primitivesCaptor.capture(), any()); + primitivesCaptor.capture(), anyLong()); List<VibrationEffect.Composition.PrimitiveEffect[]> values = primitivesCaptor.getAllValues(); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java index 763654d24047..dda81ffded4f 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java @@ -187,7 +187,7 @@ public class TouchExplorerTest { moveEachPointers(mLastEvent, p(10, 10), p(10, 10)); send(mLastEvent); goToStateClearFrom(STATE_DRAGGING_2FINGERS); - assertCapturedEvents(ACTION_DOWN, ACTION_MOVE, ACTION_MOVE, ACTION_UP); + assertCapturedEvents(ACTION_DOWN, ACTION_MOVE, ACTION_MOVE, ACTION_MOVE, ACTION_UP); } @Test @@ -288,7 +288,7 @@ public class TouchExplorerTest { assertState(STATE_DRAGGING); goToStateClearFrom(STATE_DRAGGING_2FINGERS); assertState(STATE_CLEAR); - assertCapturedEvents(ACTION_DOWN, ACTION_UP); + assertCapturedEvents(ACTION_DOWN, ACTION_MOVE, ACTION_UP); assertCapturedEventsNoHistory(); } @@ -301,6 +301,7 @@ public class TouchExplorerTest { assertState(STATE_CLEAR); assertCapturedEvents( /* goto dragging state */ ACTION_DOWN, + ACTION_MOVE, /* leave dragging state */ ACTION_UP, ACTION_DOWN, ACTION_POINTER_DOWN, diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java index 53c4d6faf0b9..f17173f61b69 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java @@ -62,6 +62,32 @@ public class HdmiCecMessageBuilderTest { assertThat(message).isEqualTo(buildMessage("5F:81:21:00")); } + @Test + public void buildSetOsdName_short() { + String deviceName = "abc"; + HdmiCecMessage message = HdmiCecMessageBuilder.buildSetOsdNameCommand(ADDR_PLAYBACK_1, + ADDR_TV, deviceName); + assertThat(message).isEqualTo(buildMessage("40:47:61:62:63")); + } + + @Test + public void buildSetOsdName_maximumLength() { + String deviceName = "abcdefghijklmn"; + HdmiCecMessage message = HdmiCecMessageBuilder.buildSetOsdNameCommand(ADDR_PLAYBACK_1, + ADDR_TV, deviceName); + assertThat(message).isEqualTo( + buildMessage("40:47:61:62:63:64:65:66:67:68:69:6A:6B:6C:6D:6E")); + } + + @Test + public void buildSetOsdName_tooLong() { + String deviceName = "abcdefghijklmnop"; + HdmiCecMessage message = HdmiCecMessageBuilder.buildSetOsdNameCommand(ADDR_PLAYBACK_1, + ADDR_TV, deviceName); + assertThat(message).isEqualTo( + buildMessage("40:47:61:62:63:64:65:66:67:68:69:6A:6B:6C:6D:6E")); + } + /** * Build a CEC message from a hex byte string with bytes separated by {@code :}. * diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java new file mode 100644 index 000000000000..d7ed96fd5833 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java @@ -0,0 +1,182 @@ +/* + * 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.timezonedetector; + +import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED; +import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE; +import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED; +import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.app.timezonedetector.TimeZoneCapabilities; + +import org.junit.Test; + +/** + * Tests for {@link ConfigurationInternal} and the {@link TimeZoneCapabilities} and + * {@link android.app.timezonedetector.TimeZoneConfiguration} that can be generated from it. + */ +public class ConfigurationInternalTest { + + private static final int ARBITRARY_USER_ID = 99999; + + /** + * Tests when {@link ConfigurationInternal#isUserConfigAllowed()} and + * {@link ConfigurationInternal#isAutoDetectionSupported()} are both true. + */ + @Test + public void test_unrestricted() { + ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID) + .setUserConfigAllowed(true) + .setAutoDetectionSupported(true) + .setAutoDetectionEnabled(true) + .setLocationEnabled(true) + .setGeoDetectionEnabled(true) + .build(); + { + ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig) + .setAutoDetectionEnabled(true) + .build(); + assertTrue(autoOnConfig.getAutoDetectionEnabledSetting()); + assertTrue(autoOnConfig.getGeoDetectionEnabledSetting()); + assertTrue(autoOnConfig.getAutoDetectionEnabledBehavior()); + assertTrue(autoOnConfig.getGeoDetectionEnabledBehavior()); + + TimeZoneCapabilities capabilities = autoOnConfig.createCapabilities(); + assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled()); + assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled()); + assertEquals(CAPABILITY_NOT_APPLICABLE, capabilities.getSuggestManualTimeZone()); + assertEquals(autoOnConfig.asConfiguration(), capabilities.getConfiguration()); + assertTrue(capabilities.getConfiguration().isAutoDetectionEnabled()); + assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled()); + } + + { + ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig) + .setAutoDetectionEnabled(false) + .build(); + assertFalse(autoOffConfig.getAutoDetectionEnabledSetting()); + assertTrue(autoOffConfig.getGeoDetectionEnabledSetting()); + assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior()); + assertFalse(autoOffConfig.getGeoDetectionEnabledBehavior()); + + TimeZoneCapabilities capabilities = autoOffConfig.createCapabilities(); + assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled()); + assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled()); + assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone()); + assertEquals(autoOffConfig.asConfiguration(), capabilities.getConfiguration()); + assertFalse(capabilities.getConfiguration().isAutoDetectionEnabled()); + assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled()); + } + } + + /** Tests when {@link ConfigurationInternal#isUserConfigAllowed()} is false */ + @Test + public void test_restricted() { + ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID) + .setUserConfigAllowed(false) + .setAutoDetectionSupported(true) + .setAutoDetectionEnabled(true) + .setLocationEnabled(true) + .setGeoDetectionEnabled(true) + .build(); + { + ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig) + .setAutoDetectionEnabled(true) + .build(); + assertTrue(autoOnConfig.getAutoDetectionEnabledSetting()); + assertTrue(autoOnConfig.getGeoDetectionEnabledSetting()); + assertTrue(autoOnConfig.getAutoDetectionEnabledBehavior()); + assertTrue(autoOnConfig.getGeoDetectionEnabledBehavior()); + + TimeZoneCapabilities capabilities = autoOnConfig.createCapabilities(); + assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled()); + assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled()); + assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone()); + assertEquals(autoOnConfig.asConfiguration(), capabilities.getConfiguration()); + assertTrue(capabilities.getConfiguration().isAutoDetectionEnabled()); + assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled()); + } + + { + ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig) + .setAutoDetectionEnabled(false) + .build(); + assertFalse(autoOffConfig.getAutoDetectionEnabledSetting()); + assertTrue(autoOffConfig.getGeoDetectionEnabledSetting()); + assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior()); + assertFalse(autoOffConfig.getGeoDetectionEnabledBehavior()); + + TimeZoneCapabilities capabilities = autoOffConfig.createCapabilities(); + assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled()); + assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled()); + assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone()); + assertEquals(autoOffConfig.asConfiguration(), capabilities.getConfiguration()); + assertFalse(capabilities.getConfiguration().isAutoDetectionEnabled()); + assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled()); + } + } + + /** Tests when {@link ConfigurationInternal#isAutoDetectionSupported()} is false. */ + @Test + public void test_autoDetectNotSupported() { + ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID) + .setUserConfigAllowed(true) + .setAutoDetectionSupported(false) + .setAutoDetectionEnabled(true) + .setLocationEnabled(true) + .setGeoDetectionEnabled(true) + .build(); + { + ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig) + .setAutoDetectionEnabled(true) + .build(); + assertTrue(autoOnConfig.getAutoDetectionEnabledSetting()); + assertTrue(autoOnConfig.getGeoDetectionEnabledSetting()); + assertFalse(autoOnConfig.getAutoDetectionEnabledBehavior()); + assertFalse(autoOnConfig.getGeoDetectionEnabledBehavior()); + + TimeZoneCapabilities capabilities = autoOnConfig.createCapabilities(); + assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled()); + assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled()); + assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone()); + assertEquals(autoOnConfig.asConfiguration(), capabilities.getConfiguration()); + assertTrue(capabilities.getConfiguration().isAutoDetectionEnabled()); + assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled()); + } + { + ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig) + .setAutoDetectionEnabled(false) + .build(); + assertFalse(autoOffConfig.getAutoDetectionEnabledSetting()); + assertTrue(autoOffConfig.getGeoDetectionEnabledSetting()); + assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior()); + assertFalse(autoOffConfig.getGeoDetectionEnabledBehavior()); + + TimeZoneCapabilities capabilities = autoOffConfig.createCapabilities(); + assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled()); + assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled()); + assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone()); + assertEquals(autoOffConfig.asConfiguration(), capabilities.getConfiguration()); + assertFalse(capabilities.getConfiguration().isAutoDetectionEnabled()); + assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled()); + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java index e5e931115c05..4ef20829f2dc 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java @@ -18,6 +18,7 @@ package com.android.server.timezonedetector; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import android.annotation.NonNull; import android.annotation.UserIdInt; @@ -32,56 +33,64 @@ import java.util.List; class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy { - private StrategyListener mListener; + private ConfigurationChangeListener mConfigurationChangeListener; // Fake state - private TimeZoneCapabilities mCapabilities; - private TimeZoneConfiguration mConfiguration; + private ConfigurationInternal mConfigurationInternal; // Call tracking. private GeolocationTimeZoneSuggestion mLastGeolocationSuggestion; private ManualTimeZoneSuggestion mLastManualSuggestion; private TelephonyTimeZoneSuggestion mLastTelephonySuggestion; - private boolean mHandleAutoTimeZoneConfigChangedCalled; private boolean mDumpCalled; private final List<Dumpable> mDumpables = new ArrayList<>(); @Override - public void setStrategyListener(@NonNull StrategyListener listener) { - mListener = listener; + public void addConfigChangeListener(@NonNull ConfigurationChangeListener listener) { + if (mConfigurationChangeListener != null) { + fail("Fake only supports one listener"); + } + mConfigurationChangeListener = listener; + } + + @Override + public ConfigurationInternal getConfigurationInternal(int userId) { + if (mConfigurationInternal.getUserId() != userId) { + fail("Fake only supports one user"); + } + return mConfigurationInternal; } @Override - public TimeZoneCapabilities getCapabilities(@UserIdInt int userId) { - return mCapabilities; + public ConfigurationInternal getCurrentUserConfigurationInternal() { + return mConfigurationInternal; } @Override - public boolean updateConfiguration( - @UserIdInt int userId, @NonNull TimeZoneConfiguration configuration) { - assertNotNull(mConfiguration); - assertNotNull(configuration); - - // Simulate the strategy's behavior: the new configuration will be the old configuration - // merged with the new. - TimeZoneConfiguration oldConfiguration = mConfiguration; - TimeZoneConfiguration newConfiguration = - new TimeZoneConfiguration.Builder(mConfiguration) - .mergeProperties(configuration) - .build(); - - if (newConfiguration.equals(oldConfiguration)) { + public boolean updateConfiguration(@NonNull TimeZoneConfiguration requestedChanges) { + assertNotNull(mConfigurationInternal); + assertNotNull(requestedChanges); + + // Simulate the real strategy's behavior: the new configuration will be updated to be the + // old configuration merged with the new if the user has the capability to up the settings. + // Then, if the configuration changed, the change listener is invoked. + TimeZoneCapabilities capabilities = mConfigurationInternal.createCapabilities(); + TimeZoneConfiguration newConfiguration = capabilities.applyUpdate(requestedChanges); + if (newConfiguration == null) { return false; } - mConfiguration = newConfiguration; - mListener.onConfigurationChanged(); + + if (!newConfiguration.equals(capabilities.getConfiguration())) { + mConfigurationInternal = mConfigurationInternal.merge(newConfiguration); + + // Note: Unlike the real strategy, the listeners is invoked synchronously. + mConfigurationChangeListener.onChange(); + } return true; } - @Override - @NonNull - public TimeZoneConfiguration getConfiguration(@UserIdInt int userId) { - return mConfiguration; + public void simulateConfigurationChangeForTests() { + mConfigurationChangeListener.onChange(); } @Override @@ -103,11 +112,6 @@ class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy { } @Override - public void handleAutoTimeZoneConfigChanged() { - mHandleAutoTimeZoneConfigChangedCalled = true; - } - - @Override public void addDumpable(Dumpable dumpable) { mDumpables.add(dumpable); } @@ -117,19 +121,14 @@ class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy { mDumpCalled = true; } - void initializeConfiguration(TimeZoneConfiguration configuration) { - mConfiguration = configuration; - } - - void initializeCapabilities(TimeZoneCapabilities capabilities) { - mCapabilities = capabilities; + void initializeConfiguration(ConfigurationInternal configurationInternal) { + mConfigurationInternal = configurationInternal; } void resetCallTracking() { mLastGeolocationSuggestion = null; mLastManualSuggestion = null; mLastTelephonySuggestion = null; - mHandleAutoTimeZoneConfigChangedCalled = false; mDumpCalled = false; } @@ -146,10 +145,6 @@ class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy { assertEquals(expectedSuggestion, mLastTelephonySuggestion); } - void verifyHandleAutoTimeZoneConfigChangedCalled() { - assertTrue(mHandleAutoTimeZoneConfigChangedCalled); - } - void verifyDumpCalled() { assertTrue(mDumpCalled); } diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TestCallerIdentityInjector.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TestCallerIdentityInjector.java new file mode 100644 index 000000000000..f45b3a822f1a --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TestCallerIdentityInjector.java @@ -0,0 +1,53 @@ +/* + * 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.timezonedetector; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import android.annotation.UserIdInt; + +/** A fake {@link CallerIdentityInjector} used in tests. */ +public class TestCallerIdentityInjector implements CallerIdentityInjector { + + private long mToken = 9999L; + private int mCallingUserId; + private Integer mCurrentCallingUserId; + + public void initializeCallingUserId(@UserIdInt int userId) { + mCallingUserId = userId; + mCurrentCallingUserId = userId; + } + + @Override + public int getCallingUserId() { + assertNotNull("callingUserId has been cleared", mCurrentCallingUserId); + return mCurrentCallingUserId; + } + + @Override + public long clearCallingIdentity() { + mCurrentCallingUserId = null; + return mToken; + } + + @Override + public void restoreCallingIdentity(long token) { + assertEquals(token, mToken); + mCurrentCallingUserId = mCallingUserId; + } +} diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java index e9d57e52ce69..918babca677e 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java @@ -16,6 +16,7 @@ package com.android.server.timezonedetector; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import android.content.Context; @@ -85,6 +86,18 @@ public class TimeZoneDetectorInternalImplTest { mFakeTimeZoneDetectorStrategy.verifyHasDumpable(stubbedDumpable); } + @Test + public void testAddConfigurationListener() throws Exception { + boolean[] changeCalled = new boolean[2]; + mTimeZoneDetectorInternal.addConfigurationListener(() -> changeCalled[0] = true); + mTimeZoneDetectorInternal.addConfigurationListener(() -> changeCalled[1] = true); + + mFakeTimeZoneDetectorStrategy.simulateConfigurationChangeForTests(); + + assertTrue(changeCalled[0]); + assertTrue(changeCalled[1]); + } + private static GeolocationTimeZoneSuggestion createGeolocationTimeZoneSuggestion() { return new GeolocationTimeZoneSuggestion(ARBITRARY_ZONE_IDS); } 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 3a1ec4f90d7a..27b04b6ab17d 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java @@ -16,8 +16,6 @@ package com.android.server.timezonedetector; -import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; @@ -36,7 +34,6 @@ import static org.mockito.Mockito.when; import android.app.timezonedetector.ITimeZoneConfigurationListener; import android.app.timezonedetector.ManualTimeZoneSuggestion; import android.app.timezonedetector.TelephonyTimeZoneSuggestion; -import android.app.timezonedetector.TimeZoneCapabilities; import android.app.timezonedetector.TimeZoneConfiguration; import android.content.Context; import android.content.pm.PackageManager; @@ -65,6 +62,7 @@ public class TimeZoneDetectorServiceTest { private TimeZoneDetectorService mTimeZoneDetectorService; private HandlerThread mHandlerThread; private TestHandler mTestHandler; + private TestCallerIdentityInjector mTestCallerIdentityInjector; @Before @@ -76,10 +74,14 @@ public class TimeZoneDetectorServiceTest { mHandlerThread.start(); mTestHandler = new TestHandler(mHandlerThread.getLooper()); + mTestCallerIdentityInjector = new TestCallerIdentityInjector(); + mTestCallerIdentityInjector.initializeCallingUserId(ARBITRARY_USER_ID); + mFakeTimeZoneDetectorStrategy = new FakeTimeZoneDetectorStrategy(); mTimeZoneDetectorService = new TimeZoneDetectorService( - mMockContext, mTestHandler, mFakeTimeZoneDetectorStrategy); + mMockContext, mTestHandler, mTestCallerIdentityInjector, + mFakeTimeZoneDetectorStrategy); } @After @@ -107,40 +109,12 @@ public class TimeZoneDetectorServiceTest { public void testGetCapabilities() { doNothing().when(mMockContext).enforceCallingPermission(anyString(), any()); - TimeZoneCapabilities capabilities = createTimeZoneCapabilities(); - mFakeTimeZoneDetectorStrategy.initializeCapabilities(capabilities); - - assertEquals(capabilities, mTimeZoneDetectorService.getCapabilities()); - - verify(mMockContext).enforceCallingPermission( - eq(android.Manifest.permission.WRITE_SECURE_SETTINGS), - anyString()); - } - - @Test(expected = SecurityException.class) - public void testGetConfiguration_withoutPermission() { - doThrow(new SecurityException("Mock")) - .when(mMockContext).enforceCallingPermission(anyString(), any()); - - try { - mTimeZoneDetectorService.getConfiguration(); - fail(); - } finally { - verify(mMockContext).enforceCallingPermission( - eq(android.Manifest.permission.WRITE_SECURE_SETTINGS), - anyString()); - } - } - - @Test - public void testGetConfiguration() { - doNothing().when(mMockContext).enforceCallingPermission(anyString(), any()); - - TimeZoneConfiguration configuration = - createTimeZoneConfiguration(false /* autoDetectionEnabled */); + ConfigurationInternal configuration = + createConfigurationInternal(true /* autoDetectionEnabled*/); mFakeTimeZoneDetectorStrategy.initializeConfiguration(configuration); - assertEquals(configuration, mTimeZoneDetectorService.getConfiguration()); + assertEquals(configuration.createCapabilities(), + mTimeZoneDetectorService.getCapabilities()); verify(mMockContext).enforceCallingPermission( eq(android.Manifest.permission.WRITE_SECURE_SETTINGS), @@ -181,10 +155,9 @@ public class TimeZoneDetectorServiceTest { @Test public void testConfigurationChangeListenerRegistrationAndCallbacks() throws Exception { - TimeZoneConfiguration autoDetectDisabledConfiguration = - createTimeZoneConfiguration(false /* autoDetectionEnabled */); - - mFakeTimeZoneDetectorStrategy.initializeConfiguration(autoDetectDisabledConfiguration); + ConfigurationInternal initialConfiguration = + createConfigurationInternal(false /* autoDetectionEnabled */); + mFakeTimeZoneDetectorStrategy.initializeConfiguration(initialConfiguration); IBinder mockListenerBinder = mock(IBinder.class); ITimeZoneConfigurationListener mockListener = mock(ITimeZoneConfigurationListener.class); @@ -210,13 +183,12 @@ public class TimeZoneDetectorServiceTest { // 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); + verify(mockListener).onChange(); verifyNoMoreInteractions(mockListenerBinder, mockListener, mMockContext); reset(mockListenerBinder, mockListener, mMockContext); } @@ -242,12 +214,14 @@ public class TimeZoneDetectorServiceTest { { doNothing().when(mMockContext).enforceCallingPermission(anyString(), any()); + TimeZoneConfiguration autoDetectDisabledConfiguration = + createTimeZoneConfiguration(false /* autoDetectionEnabled */); mTimeZoneDetectorService.updateConfiguration(autoDetectDisabledConfiguration); verify(mMockContext).enforceCallingPermission( eq(android.Manifest.permission.WRITE_SECURE_SETTINGS), anyString()); - verify(mockListener, never()).onChange(any()); + verify(mockListener, never()).onChange(); verifyNoMoreInteractions(mockListenerBinder, mockListener, mMockContext); reset(mockListenerBinder, mockListener, mMockContext); } @@ -379,33 +353,22 @@ public class TimeZoneDetectorServiceTest { mFakeTimeZoneDetectorStrategy.verifyDumpCalled(); } - @Test - public void testHandleAutoTimeZoneConfigChanged() throws Exception { - mTimeZoneDetectorService.handleAutoTimeZoneConfigChanged(); - mTestHandler.assertTotalMessagesEnqueued(1); - mTestHandler.waitForMessagesToBeProcessed(); - mFakeTimeZoneDetectorStrategy.verifyHandleAutoTimeZoneConfigChangedCalled(); - - mFakeTimeZoneDetectorStrategy.resetCallTracking(); - - mTimeZoneDetectorService.handleAutoTimeZoneConfigChanged(); - mTestHandler.assertTotalMessagesEnqueued(2); - mTestHandler.waitForMessagesToBeProcessed(); - mFakeTimeZoneDetectorStrategy.verifyHandleAutoTimeZoneConfigChangedCalled(); - } - - private static TimeZoneConfiguration createTimeZoneConfiguration( - boolean autoDetectionEnabled) { - return new TimeZoneConfiguration.Builder() + private static TimeZoneConfiguration createTimeZoneConfiguration(boolean autoDetectionEnabled) { + return new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID) .setAutoDetectionEnabled(autoDetectionEnabled) .build(); } - private static TimeZoneCapabilities createTimeZoneCapabilities() { - return new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID) - .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED) - .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED) - .setSuggestManualTimeZone(CAPABILITY_POSSESSED) + private static ConfigurationInternal createConfigurationInternal(boolean autoDetectionEnabled) { + // Default geo detection settings from auto detection settings - they are not important to + // the tests. + final boolean geoDetectionEnabled = autoDetectionEnabled; + return new ConfigurationInternal.Builder(ARBITRARY_USER_ID) + .setAutoDetectionSupported(true) + .setUserConfigAllowed(true) + .setAutoDetectionEnabled(autoDetectionEnabled) + .setLocationEnabled(geoDetectionEnabled) + .setGeoDetectionEnabled(geoDetectionEnabled) .build(); } diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java index a6caa4299ef6..2bee5e5e7295 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java @@ -23,10 +23,6 @@ import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYP import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS; import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET; import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE; -import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED; -import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE; -import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED; -import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED; import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.TELEPHONY_SCORE_HIGH; import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.TELEPHONY_SCORE_HIGHEST; @@ -37,9 +33,9 @@ import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.T import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import android.annotation.Nullable; import android.annotation.UserIdInt; @@ -47,7 +43,6 @@ import android.app.timezonedetector.ManualTimeZoneSuggestion; import android.app.timezonedetector.TelephonyTimeZoneSuggestion; import android.app.timezonedetector.TelephonyTimeZoneSuggestion.MatchType; import android.app.timezonedetector.TelephonyTimeZoneSuggestion.Quality; -import android.app.timezonedetector.TimeZoneCapabilities; import android.app.timezonedetector.TimeZoneConfiguration; import android.util.IndentingPrintWriter; @@ -61,7 +56,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; -import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -94,192 +88,149 @@ public class TimeZoneDetectorStrategyImplTest { TELEPHONY_SCORE_HIGHEST), }; - private static final TimeZoneConfiguration CONFIG_AUTO_ENABLED = - new TimeZoneConfiguration.Builder() + private static final ConfigurationInternal CONFIG_INT_USER_RESTRICTED_AUTO_DISABLED = + new ConfigurationInternal.Builder(USER_ID) + .setUserConfigAllowed(false) + .setAutoDetectionSupported(true) + .setAutoDetectionEnabled(false) + .setLocationEnabled(true) + .setGeoDetectionEnabled(false) + .build(); + + private static final ConfigurationInternal CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED = + new ConfigurationInternal.Builder(USER_ID) + .setUserConfigAllowed(false) + .setAutoDetectionSupported(true) .setAutoDetectionEnabled(true) + .setLocationEnabled(true) + .setGeoDetectionEnabled(true) .build(); - private static final TimeZoneConfiguration CONFIG_AUTO_DISABLED = - new TimeZoneConfiguration.Builder() + private static final ConfigurationInternal CONFIG_INT_AUTO_DETECT_NOT_SUPPORTED = + new ConfigurationInternal.Builder(USER_ID) + .setUserConfigAllowed(true) + .setAutoDetectionSupported(false) .setAutoDetectionEnabled(false) + .setLocationEnabled(true) + .setGeoDetectionEnabled(false) .build(); - private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_DISABLED = - new TimeZoneConfiguration.Builder() + private static final ConfigurationInternal CONFIG_INT_AUTO_DISABLED_GEO_DISABLED = + new ConfigurationInternal.Builder(USER_ID) + .setUserConfigAllowed(true) + .setAutoDetectionSupported(true) + .setAutoDetectionEnabled(false) + .setLocationEnabled(true) .setGeoDetectionEnabled(false) .build(); - private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_ENABLED = - new TimeZoneConfiguration.Builder() + private static final ConfigurationInternal CONFIG_INT_AUTO_DISABLED_GEO_ENABLED = + new ConfigurationInternal.Builder(USER_ID) + .setUserConfigAllowed(true) + .setAutoDetectionSupported(true) + .setAutoDetectionEnabled(false) + .setLocationEnabled(true) .setGeoDetectionEnabled(true) .build(); + private static final ConfigurationInternal CONFIG_INT_AUTO_ENABLED_GEO_DISABLED = + new ConfigurationInternal.Builder(USER_ID) + .setAutoDetectionSupported(true) + .setUserConfigAllowed(true) + .setAutoDetectionEnabled(true) + .setLocationEnabled(true) + .setGeoDetectionEnabled(false) + .build(); + + private static final ConfigurationInternal CONFIG_INT_AUTO_ENABLED_GEO_ENABLED = + new ConfigurationInternal.Builder(USER_ID) + .setAutoDetectionSupported(true) + .setUserConfigAllowed(true) + .setAutoDetectionEnabled(true) + .setLocationEnabled(true) + .setGeoDetectionEnabled(true) + .build(); + + private static final TimeZoneConfiguration CONFIG_AUTO_DISABLED = + createConfig(false /* autoDetection */, null); + private static final TimeZoneConfiguration CONFIG_AUTO_ENABLED = + createConfig(true /* autoDetection */, null); + private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_ENABLED = + createConfig(null, true /* geoDetection */); + private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_DISABLED = + createConfig(null, false /* geoDetection */); + private TimeZoneDetectorStrategyImpl mTimeZoneDetectorStrategy; private FakeCallback mFakeCallback; - private MockStrategyListener mMockStrategyListener; + private MockConfigChangeListener mMockConfigChangeListener; + @Before public void setUp() { mFakeCallback = new FakeCallback(); - mMockStrategyListener = new MockStrategyListener(); + mMockConfigChangeListener = new MockConfigChangeListener(); mTimeZoneDetectorStrategy = new TimeZoneDetectorStrategyImpl(mFakeCallback); - mFakeCallback.setStrategyForSettingsCallbacks(mTimeZoneDetectorStrategy); - mTimeZoneDetectorStrategy.setStrategyListener(mMockStrategyListener); - } - - @Test - public void testGetCapabilities() { - new Script() - .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); - TimeZoneCapabilities expectedCapabilities = mFakeCallback.getCapabilities(USER_ID); - assertEquals(expectedCapabilities, mTimeZoneDetectorStrategy.getCapabilities(USER_ID)); + mTimeZoneDetectorStrategy.addConfigChangeListener(mMockConfigChangeListener); } @Test - public void testGetConfiguration() { - new Script() - .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); - TimeZoneConfiguration expectedConfiguration = mFakeCallback.getConfiguration(USER_ID); - assertTrue(expectedConfiguration.isComplete()); - assertEquals(expectedConfiguration, mTimeZoneDetectorStrategy.getConfiguration(USER_ID)); - } - - @Test - public void testCapabilitiesTestInfra_unrestricted() { - Script script = new Script(); - - script.initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); - { - // Check the fake test infra is doing what is expected. - TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID); - assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled()); - assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled()); - assertEquals(CAPABILITY_NOT_APPLICABLE, capabilities.getSuggestManualTimeZone()); - } - - script.initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED)); - { - // Check the fake test infra is doing what is expected. - TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID); - assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled()); - assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled()); - assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone()); - } - } - - @Test - public void testCapabilitiesTestInfra_restricted() { - Script script = new Script(); - - script.initializeUser(USER_ID, UserCase.RESTRICTED, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); - { - // Check the fake test infra is doing what is expected. - TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID); - assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled()); - assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled()); - assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone()); - } - - script.initializeUser(USER_ID, UserCase.RESTRICTED, - CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED)); - { - // Check the fake test infra is doing what is expected. - TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID); - assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled()); - assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled()); - assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone()); - } - } - - @Test - public void testCapabilitiesTestInfra_autoDetectNotSupported() { - Script script = new Script(); - - script.initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); - { - // Check the fake test infra is doing what is expected. - TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID); - assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled()); - assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled()); - assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone()); - } - - script.initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED, - CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED)); - { - // Check the fake test infra is doing what is expected. - TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID); - assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled()); - assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled()); - assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone()); - } + public void testGetCurrentUserConfiguration() { + new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED); + ConfigurationInternal expectedConfiguration = + mFakeCallback.getConfigurationInternal(USER_ID); + assertEquals(expectedConfiguration, + mTimeZoneDetectorStrategy.getCurrentUserConfigurationInternal()); } @Test public void testUpdateConfiguration_unrestricted() { - Script script = new Script() - .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); + Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED); // Set the configuration with auto detection enabled. - script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */); + script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */); // Nothing should have happened: it was initialized in this state. script.verifyConfigurationNotChanged(); // Update the configuration with auto detection disabled. - script.simulateUpdateConfiguration( - USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */); + script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */); // The settings should have been changed and the StrategyListener onChange() called. - script.verifyConfigurationChangedAndReset(USER_ID, - CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED)); + script.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED); // Update the configuration with auto detection enabled. - script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */); + script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */); // The settings should have been changed and the StrategyListener onChange() called. - script.verifyConfigurationChangedAndReset(USER_ID, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); + script.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED); // Update the configuration to enable geolocation time zone detection. script.simulateUpdateConfiguration( - USER_ID, CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */); + CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */); // The settings should have been changed and the StrategyListener onChange() called. - script.verifyConfigurationChangedAndReset(USER_ID, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED)); + script.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED); } @Test public void testUpdateConfiguration_restricted() { - Script script = new Script() - .initializeUser(USER_ID, UserCase.RESTRICTED, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); + Script script = new Script().initializeConfig(CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED); // Try to update the configuration with auto detection disabled. - script.simulateUpdateConfiguration( - USER_ID, CONFIG_AUTO_DISABLED, false /* expectedResult */); + script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, false /* expectedResult */); // The settings should not have been changed: user shouldn't have the capabilities. script.verifyConfigurationNotChanged(); // Update the configuration with auto detection enabled. - script.simulateUpdateConfiguration( - USER_ID, CONFIG_AUTO_ENABLED, false /* expectedResult */); + script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, false /* expectedResult */); // The settings should not have been changed: user shouldn't have the capabilities. script.verifyConfigurationNotChanged(); - // Update the configuration to enable geolocation time zone detection. + // Try to update the configuration to enable geolocation time zone detection. script.simulateUpdateConfiguration( - USER_ID, CONFIG_GEO_DETECTION_ENABLED, false /* expectedResult */); + CONFIG_GEO_DETECTION_ENABLED, false /* expectedResult */); // The settings should not have been changed: user shouldn't have the capabilities. script.verifyConfigurationNotChanged(); @@ -287,20 +238,16 @@ public class TimeZoneDetectorStrategyImplTest { @Test public void testUpdateConfiguration_autoDetectNotSupported() { - Script script = new Script() - .initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); + Script script = new Script().initializeConfig(CONFIG_INT_AUTO_DETECT_NOT_SUPPORTED); // Try to update the configuration with auto detection disabled. - script.simulateUpdateConfiguration( - USER_ID, CONFIG_AUTO_DISABLED, false /* expectedResult */); + script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, false /* expectedResult */); // The settings should not have been changed: user shouldn't have the capabilities. script.verifyConfigurationNotChanged(); // Update the configuration with auto detection enabled. - script.simulateUpdateConfiguration( - USER_ID, CONFIG_AUTO_ENABLED, false /* expectedResult */); + script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, false /* expectedResult */); // The settings should not have been changed: user shouldn't have the capabilities. script.verifyConfigurationNotChanged(); @@ -313,8 +260,7 @@ public class TimeZoneDetectorStrategyImplTest { TelephonyTimeZoneSuggestion slotIndex2TimeZoneSuggestion = createEmptySlotIndex2Suggestion(); Script script = new Script() - .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)) + .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); script.simulateTelephonyTimeZoneSuggestion(slotIndex1TimeZoneSuggestion) @@ -359,9 +305,7 @@ public class TimeZoneDetectorStrategyImplTest { TelephonyTestCase testCase2 = newTelephonyTestCase(MATCH_TYPE_NETWORK_COUNTRY_ONLY, QUALITY_SINGLE_ZONE, TELEPHONY_SCORE_HIGH); - Script script = new Script() - .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); + Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED); // A low quality suggestions will not be taken: The device time zone setting is left // uninitialized. @@ -426,8 +370,7 @@ public class TimeZoneDetectorStrategyImplTest { for (TelephonyTestCase testCase : TELEPHONY_TEST_CASES) { // Start with the device in a known state. - script.initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED)) + script.initializeConfig(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); TelephonyTimeZoneSuggestion suggestion = @@ -447,8 +390,7 @@ public class TimeZoneDetectorStrategyImplTest { mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests()); // Toggling the time zone setting on should cause the device setting to be set. - script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, - true /* expectedResult */); + script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */); // When time zone detection is already enabled the suggestion (if it scores highly // enough) should be set immediately. @@ -465,8 +407,7 @@ public class TimeZoneDetectorStrategyImplTest { mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests()); // Toggling the time zone setting should off should do nothing. - script.simulateUpdateConfiguration( - USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */) + script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */) .verifyTimeZoneNotChanged(); // Assert internal service state. @@ -480,8 +421,7 @@ public class TimeZoneDetectorStrategyImplTest { @Test public void testTelephonySuggestionsSingleSlotId() { Script script = new Script() - .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)) + .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); for (TelephonyTestCase testCase : TELEPHONY_TEST_CASES) { @@ -546,8 +486,7 @@ public class TimeZoneDetectorStrategyImplTest { TELEPHONY_SCORE_NONE); Script script = new Script() - .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)) + .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID) // Initialize the latest suggestions as empty so we don't need to worry about nulls // below for the first loop. @@ -632,9 +571,7 @@ public class TimeZoneDetectorStrategyImplTest { */ @Test public void testTelephonySuggestionStrategyDoesNotAssumeCurrentSetting_autoTelephony() { - Script script = new Script() - .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); + Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED); TelephonyTestCase testCase = newTelephonyTestCase( MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, QUALITY_SINGLE_ZONE, TELEPHONY_SCORE_HIGH); @@ -652,40 +589,39 @@ public class TimeZoneDetectorStrategyImplTest { // Toggling time zone detection should set the device time zone only if the current setting // value is different from the most recent telephony suggestion. - script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */) + script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */) .verifyTimeZoneNotChanged() - .simulateUpdateConfiguration( - USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */) + .simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */) .verifyTimeZoneNotChanged(); // Simulate a user turning auto detection off, a new suggestion being made while auto // detection is off, and the user turning it on again. - script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */) + script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */) .simulateTelephonyTimeZoneSuggestion(newYorkSuggestion) .verifyTimeZoneNotChanged(); // Latest suggestion should be used. - script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */) + script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */) .verifyTimeZoneChangedAndReset(newYorkSuggestion); } @Test - public void testManualSuggestion_autoDetectionEnabled_autoTelephony() { - checkManualSuggestion_autoDetectionEnabled(false /* geoDetectionEnabled */); + public void testManualSuggestion_unrestricted_autoDetectionEnabled_autoTelephony() { + checkManualSuggestion_unrestricted_autoDetectionEnabled(false /* geoDetectionEnabled */); } @Test - public void testManualSuggestion_autoDetectionEnabled_autoGeo() { - checkManualSuggestion_autoDetectionEnabled(true /* geoDetectionEnabled */); + public void testManualSuggestion_unrestricted_autoDetectionEnabled_autoGeo() { + checkManualSuggestion_unrestricted_autoDetectionEnabled(true /* geoDetectionEnabled */); } - private void checkManualSuggestion_autoDetectionEnabled(boolean geoDetectionEnabled) { - TimeZoneConfiguration geoTzEnabledConfig = - new TimeZoneConfiguration.Builder() + private void checkManualSuggestion_unrestricted_autoDetectionEnabled( + boolean geoDetectionEnabled) { + ConfigurationInternal geoTzEnabledConfig = + new ConfigurationInternal.Builder(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED) .setGeoDetectionEnabled(geoDetectionEnabled) .build(); Script script = new Script() - .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_ENABLED.with(geoTzEnabledConfig)) + .initializeConfig(geoTzEnabledConfig) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); // Auto time zone detection is enabled so the manual suggestion should be ignored. @@ -697,35 +633,19 @@ public class TimeZoneDetectorStrategyImplTest { @Test public void testManualSuggestion_restricted_simulateAutoTimeZoneEnabled() { Script script = new Script() - .initializeUser(USER_ID, UserCase.RESTRICTED, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)) + .initializeConfig(CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); - // Auto time zone detection is enabled so the manual suggestion should be ignored. + // User is restricted so the manual suggestion should be ignored. script.simulateManualTimeZoneSuggestion( USER_ID, createManualSuggestion("Europe/Paris"), false /* expectedResult */) - .verifyTimeZoneNotChanged(); - } - - @Test - public void testManualSuggestion_autoDetectNotSupported_simulateAutoTimeZoneEnabled() { - Script script = new Script() - .initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)) - .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); - - // Auto time zone detection is enabled so the manual suggestion should be ignored. - ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Europe/Paris"); - script.simulateManualTimeZoneSuggestion( - USER_ID, manualSuggestion, true /* expectedResult */) - .verifyTimeZoneChangedAndReset(manualSuggestion); + .verifyTimeZoneNotChanged(); } @Test public void testManualSuggestion_unrestricted_autoTimeZoneDetectionDisabled() { Script script = new Script() - .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED)) + .initializeConfig(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); // Auto time zone detection is disabled so the manual suggestion should be used. @@ -738,8 +658,7 @@ public class TimeZoneDetectorStrategyImplTest { @Test public void testManualSuggestion_restricted_autoTimeZoneDetectionDisabled() { Script script = new Script() - .initializeUser(USER_ID, UserCase.RESTRICTED, - CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED)) + .initializeConfig(CONFIG_INT_USER_RESTRICTED_AUTO_DISABLED) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); // Restricted users do not have the capability. @@ -750,10 +669,9 @@ public class TimeZoneDetectorStrategyImplTest { } @Test - public void testManualSuggestion_autoDetectNotSupported_autoTimeZoneDetectionDisabled() { + public void testManualSuggestion_autoDetectNotSupported() { Script script = new Script() - .initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED, - CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED)) + .initializeConfig(CONFIG_INT_AUTO_DETECT_NOT_SUPPORTED) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); // Unrestricted users have the capability. @@ -765,9 +683,7 @@ public class TimeZoneDetectorStrategyImplTest { @Test public void testGeoSuggestion_uncertain() { - Script script = new Script() - .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED)) + Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); GeolocationTimeZoneSuggestion uncertainSuggestion = createUncertainGeoLocationSuggestion(); @@ -783,8 +699,7 @@ public class TimeZoneDetectorStrategyImplTest { @Test public void testGeoSuggestion_noZones() { Script script = new Script() - .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED)) + .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); GeolocationTimeZoneSuggestion noZonesSuggestion = createGeoLocationSuggestion(list()); @@ -802,8 +717,7 @@ public class TimeZoneDetectorStrategyImplTest { createGeoLocationSuggestion(list("Europe/London")); Script script = new Script() - .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED)) + .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); script.simulateGeolocationTimeZoneSuggestion(suggestion) @@ -828,8 +742,7 @@ public class TimeZoneDetectorStrategyImplTest { createGeoLocationSuggestion(list("Europe/Paris")); Script script = new Script() - .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED)) + .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); script.simulateGeolocationTimeZoneSuggestion(londonOnlySuggestion) @@ -856,72 +769,27 @@ public class TimeZoneDetectorStrategyImplTest { mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion()); } - /** - * Confirms that toggling the auto time zone detection enabled setting has the expected behavior - * when the strategy is "opinionated" and "un-opinionated" when in geolocation detection is - * enabled. - */ @Test - public void testTogglingAutoDetectionEnabled_autoGeo() { - GeolocationTimeZoneSuggestion geolocationSuggestion = + public void testGeoSuggestion_togglingGeoDetectionClearsLastSuggestion() { + GeolocationTimeZoneSuggestion suggestion = createGeoLocationSuggestion(list("Europe/London")); - GeolocationTimeZoneSuggestion uncertainGeolocationSuggestion = - createUncertainGeoLocationSuggestion(); - ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Europe/Paris"); Script script = new Script() - .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_ENABLED)) + .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); - script.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion); - - // When time zone detection is not enabled, the time zone suggestion will not be set. - script.verifyTimeZoneNotChanged(); - - // Assert internal service state. - assertEquals(geolocationSuggestion, - mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion()); - - // Toggling the time zone setting on should cause the device setting to be set. - script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */) + script.simulateGeolocationTimeZoneSuggestion(suggestion) .verifyTimeZoneChangedAndReset("Europe/London"); - // Toggling the time zone setting should off should do nothing because the device is now - // set to that time zone. - script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */) - .verifyTimeZoneNotChanged() - .simulateUpdateConfiguration( - USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */) - .verifyTimeZoneNotChanged(); - - // Now toggle auto time zone setting, and confirm it is opinionated. - script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */) - .simulateManualTimeZoneSuggestion( - USER_ID, manualSuggestion, true /* expectedResult */) - .verifyTimeZoneChangedAndReset(manualSuggestion) - .simulateUpdateConfiguration( - USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */) - .verifyTimeZoneChangedAndReset("Europe/London"); + // Assert internal service state. + assertEquals(suggestion, mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion()); - // Now withdraw the geolocation suggestion, and assert the strategy is no longer - // opinionated. - /* expectedResult */ - script.simulateGeolocationTimeZoneSuggestion(uncertainGeolocationSuggestion) - .verifyTimeZoneNotChanged() - .simulateUpdateConfiguration( - USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */) - .verifyTimeZoneNotChanged() - .simulateManualTimeZoneSuggestion( - USER_ID, manualSuggestion, true /* expectedResult */) - .verifyTimeZoneChangedAndReset(manualSuggestion) - .simulateUpdateConfiguration( - USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */) - .verifyTimeZoneNotChanged(); + // Turn off geo detection and verify the latest suggestion is cleared. + script.simulateUpdateConfiguration(CONFIG_GEO_DETECTION_DISABLED, true) + .verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED); // Assert internal service state. - assertEquals(uncertainGeolocationSuggestion, - mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion()); + assertNull(mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion()); } /** @@ -937,88 +805,48 @@ public class TimeZoneDetectorStrategyImplTest { "Europe/Paris"); Script script = new Script() - .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED)) + .initializeConfig(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); // Add suggestions. Nothing should happen as time zone detection is disabled. script.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion) .verifyTimeZoneNotChanged(); + + // Geolocation suggestions are only stored when geolocation detection is enabled. + assertNull(mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion()); + script.simulateTelephonyTimeZoneSuggestion(telephonySuggestion) .verifyTimeZoneNotChanged(); - // Assert internal service state. - assertEquals(geolocationSuggestion, - mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion()); + // Telephony suggestions are always stored. assertEquals(telephonySuggestion, mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1).suggestion); // Toggling the time zone detection enabled setting on should cause the device setting to be // set from the telephony signal, as we've started with geolocation time zone detection // disabled. - script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */) + script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */) .verifyTimeZoneChangedAndReset(telephonySuggestion); - // Changing the detection to enable geo detection should cause the device tz setting to - // change to the geo suggestion. - script.simulateUpdateConfiguration( - USER_ID, CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */) + // Changing the detection to enable geo detection won't cause the device tz setting to + // change because the geo suggestion is empty. + script.simulateUpdateConfiguration(CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */) + .verifyTimeZoneNotChanged() + .simulateGeolocationTimeZoneSuggestion(geolocationSuggestion) .verifyTimeZoneChangedAndReset(geolocationSuggestion.getZoneIds().get(0)); // Changing the detection to disable geo detection should cause the device tz setting to // change to the telephony suggestion. - script.simulateUpdateConfiguration( - USER_ID, CONFIG_GEO_DETECTION_DISABLED, true /* expectedResult */) + script.simulateUpdateConfiguration(CONFIG_GEO_DETECTION_DISABLED, true /* expectedResult */) .verifyTimeZoneChangedAndReset(telephonySuggestion); - } - /** - * The {@link TimeZoneDetectorStrategyImpl.Callback} is left to detect whether changing the time - * zone is actually necessary. This test proves that the strategy doesn't assume it knows the - * current setting. - */ - @Test - public void testTimeZoneDetectorStrategyDoesNotAssumeCurrentSetting_autoGeo() { - GeolocationTimeZoneSuggestion losAngelesSuggestion = - createGeoLocationSuggestion(list("America/Los_Angeles")); - GeolocationTimeZoneSuggestion newYorkSuggestion = - createGeoLocationSuggestion(list("America/New_York")); - - Script script = new Script() - .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED)); - - // Initialization. - script.simulateGeolocationTimeZoneSuggestion(losAngelesSuggestion) - .verifyTimeZoneChangedAndReset("America/Los_Angeles"); - // Suggest it again - it should not be set because it is already set. - script.simulateGeolocationTimeZoneSuggestion(losAngelesSuggestion) - .verifyTimeZoneNotChanged(); - - // Toggling time zone detection should set the device time zone only if the current setting - // value is different from the most recent telephony suggestion. - /* expectedResult */ - script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */) - .verifyTimeZoneNotChanged() - .simulateUpdateConfiguration( - USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */) - .verifyTimeZoneNotChanged(); - - // Simulate a user turning auto detection off, a new suggestion being made while auto - // detection is off, and the user turning it on again. - script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */) - .simulateGeolocationTimeZoneSuggestion(newYorkSuggestion) - .verifyTimeZoneNotChanged(); - // Latest suggestion should be used. - script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */) - .verifyTimeZoneChangedAndReset("America/New_York"); + assertNull(mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion()); } @Test public void testAddDumpable() { new Script() - .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED)) + .initializeConfig(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); AtomicBoolean dumpCalled = new AtomicBoolean(false); @@ -1069,25 +897,26 @@ public class TimeZoneDetectorStrategyImplTest { return suggestion; } + private static TimeZoneConfiguration createConfig( + @Nullable Boolean autoDetection, @Nullable Boolean geoDetection) { + TimeZoneConfiguration.Builder builder = new TimeZoneConfiguration.Builder(USER_ID); + if (autoDetection != null) { + builder.setAutoDetectionEnabled(autoDetection); + } + if (geoDetection != null) { + builder.setGeoDetectionEnabled(geoDetection); + } + return builder.build(); + } + static class FakeCallback implements TimeZoneDetectorStrategyImpl.Callback { - private TimeZoneCapabilities mCapabilities; - private final TestState<UserConfiguration> mConfiguration = new TestState<>(); + private final TestState<ConfigurationInternal> mConfigurationInternal = new TestState<>(); private final TestState<String> mTimeZoneId = new TestState<>(); - private TimeZoneDetectorStrategyImpl mStrategy; - - void setStrategyForSettingsCallbacks(TimeZoneDetectorStrategyImpl strategy) { - assertNotNull(strategy); - mStrategy = strategy; - } + private ConfigurationChangeListener mConfigChangeListener; - void initializeUser(@UserIdInt int userId, TimeZoneCapabilities capabilities, - TimeZoneConfiguration configuration) { - assertEquals(userId, capabilities.getUserId()); - mCapabilities = capabilities; - assertTrue("Configuration must be complete when initializing, config=" + configuration, - configuration.isComplete()); - mConfiguration.init(new UserConfiguration(userId, configuration)); + void initializeConfig(ConfigurationInternal configurationInternal) { + mConfigurationInternal.init(configurationInternal); } void initializeTimeZoneSetting(String zoneId) { @@ -1095,43 +924,22 @@ public class TimeZoneDetectorStrategyImplTest { } @Override - public TimeZoneCapabilities getCapabilities(@UserIdInt int userId) { - assertEquals(userId, mCapabilities.getUserId()); - return mCapabilities; + public void setConfigChangeListener(ConfigurationChangeListener listener) { + mConfigChangeListener = listener; } @Override - public TimeZoneConfiguration getConfiguration(@UserIdInt int userId) { - UserConfiguration latest = mConfiguration.getLatest(); - assertEquals(userId, latest.userId); - return latest.configuration; - } - - @Override - public void setConfiguration(@UserIdInt int userId, TimeZoneConfiguration newConfig) { - assertNotNull(newConfig); - assertTrue(newConfig.isComplete()); - - UserConfiguration latestUserConfig = mConfiguration.getLatest(); - assertEquals(userId, latestUserConfig.userId); - TimeZoneConfiguration oldConfig = latestUserConfig.configuration; - - mConfiguration.set(new UserConfiguration(userId, newConfig)); - - if (!newConfig.equals(oldConfig)) { - // Simulate what happens when the auto detection configuration is changed. - mStrategy.handleAutoTimeZoneConfigChanged(); + public ConfigurationInternal getConfigurationInternal(int userId) { + ConfigurationInternal configuration = mConfigurationInternal.getLatest(); + if (userId != configuration.getUserId()) { + fail("FakeCallback does not support multiple users."); } + return configuration; } @Override - public boolean isAutoDetectionEnabled() { - return mConfiguration.getLatest().configuration.isAutoDetectionEnabled(); - } - - @Override - public boolean isGeoDetectionEnabled() { - return mConfiguration.getLatest().configuration.isGeoDetectionEnabled(); + public int getCurrentUserId() { + return mConfigurationInternal.getLatest().getUserId(); } @Override @@ -1149,9 +957,25 @@ public class TimeZoneDetectorStrategyImplTest { mTimeZoneId.set(zoneId); } + @Override + public void storeConfiguration(TimeZoneConfiguration newConfiguration) { + ConfigurationInternal oldConfiguration = mConfigurationInternal.getLatest(); + if (newConfiguration.getUserId() != oldConfiguration.getUserId()) { + fail("FakeCallback does not support multiple users"); + } + + ConfigurationInternal mergedConfiguration = oldConfiguration.merge(newConfiguration); + if (!mergedConfiguration.equals(oldConfiguration)) { + mConfigurationInternal.set(mergedConfiguration); + + // Note: Unlike the real callback impl, the listener is invoked synchronously. + mConfigChangeListener.onChange(); + } + } + void assertKnownUser(int userId) { - assertEquals(userId, mCapabilities.getUserId()); - assertEquals(userId, mConfiguration.getLatest().userId); + assertEquals("FakeCallback does not support multiple users", + mConfigurationInternal.getLatest().getUserId(), userId); } void assertTimeZoneNotChanged() { @@ -1166,43 +990,7 @@ public class TimeZoneDetectorStrategyImplTest { void commitAllChanges() { mTimeZoneId.commitLatest(); - mConfiguration.commitLatest(); - } - } - - private static final class UserConfiguration { - public final @UserIdInt int userId; - public final TimeZoneConfiguration configuration; - - UserConfiguration(int userId, TimeZoneConfiguration configuration) { - this.userId = userId; - this.configuration = configuration; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - UserConfiguration that = (UserConfiguration) o; - return userId == that.userId - && Objects.equals(configuration, that.configuration); - } - - @Override - public int hashCode() { - return Objects.hash(userId, configuration); - } - - @Override - public String toString() { - return "UserConfiguration{" - + "userId=" + userId - + ", configuration=" + configuration - + '}'; + mConfigurationInternal.commitLatest(); } } @@ -1255,64 +1043,14 @@ public class TimeZoneDetectorStrategyImplTest { } } - /** Simulated user test cases. */ - enum UserCase { - /** A catch-all for users that can set auto time zone config. */ - UNRESTRICTED, - /** A catch-all for users that can't set auto time zone config. */ - RESTRICTED, - /** - * Like {@link #UNRESTRICTED}, but auto tz detection is not - * supported on the device. - */ - AUTO_DETECT_NOT_SUPPORTED, - } - - /** - * Creates a {@link TimeZoneCapabilities} object for a user in the specific role with the - * supplied configuration. - */ - private static TimeZoneCapabilities createCapabilities( - int userId, UserCase userCase, TimeZoneConfiguration configuration) { - switch (userCase) { - case UNRESTRICTED: { - int suggestManualTimeZoneCapability = configuration.isAutoDetectionEnabled() - ? CAPABILITY_NOT_APPLICABLE : CAPABILITY_POSSESSED; - return new TimeZoneCapabilities.Builder(userId) - .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED) - .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED) - .setSuggestManualTimeZone(suggestManualTimeZoneCapability) - .build(); - } - case RESTRICTED: { - return new TimeZoneCapabilities.Builder(userId) - .setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED) - .setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED) - .setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED) - .build(); - } - case AUTO_DETECT_NOT_SUPPORTED: { - return new TimeZoneCapabilities.Builder(userId) - .setConfigureAutoDetectionEnabled(CAPABILITY_NOT_SUPPORTED) - .setConfigureGeoDetectionEnabled(CAPABILITY_NOT_SUPPORTED) - .setSuggestManualTimeZone(CAPABILITY_POSSESSED) - .build(); - } - default: - throw new AssertionError(userCase + " not recognized"); - } - } - /** * A "fluent" class allows reuse of code in tests: initialization, simulation and verification * logic. */ private class Script { - Script initializeUser( - @UserIdInt int userId, UserCase userCase, TimeZoneConfiguration configuration) { - TimeZoneCapabilities capabilities = createCapabilities(userId, userCase, configuration); - mFakeCallback.initializeUser(userId, capabilities, configuration); + Script initializeConfig(ConfigurationInternal configuration) { + mFakeCallback.initializeConfig(configuration); return this; } @@ -1326,10 +1064,9 @@ public class TimeZoneDetectorStrategyImplTest { * the return value. */ Script simulateUpdateConfiguration( - @UserIdInt int userId, TimeZoneConfiguration configuration, - boolean expectedResult) { + TimeZoneConfiguration configuration, boolean expectedResult) { assertEquals(expectedResult, - mTimeZoneDetectorStrategy.updateConfiguration(userId, configuration)); + mTimeZoneDetectorStrategy.updateConfiguration(configuration)); return this; } @@ -1392,16 +1129,14 @@ public class TimeZoneDetectorStrategyImplTest { /** * Verifies that the configuration has been changed to the expected value. */ - Script verifyConfigurationChangedAndReset( - @UserIdInt int userId, TimeZoneConfiguration expected) { - mFakeCallback.mConfiguration.assertHasBeenSet(); - UserConfiguration expectedUserConfig = new UserConfiguration(userId, expected); - assertEquals(expectedUserConfig, mFakeCallback.mConfiguration.getLatest()); + Script verifyConfigurationChangedAndReset(ConfigurationInternal expected) { + mFakeCallback.mConfigurationInternal.assertHasBeenSet(); + assertEquals(expected, mFakeCallback.mConfigurationInternal.getLatest()); mFakeCallback.commitAllChanges(); // Also confirm the listener triggered. - mMockStrategyListener.verifyOnConfigurationChangedCalled(); - mMockStrategyListener.reset(); + mMockConfigChangeListener.verifyOnChangeCalled(); + mMockConfigChangeListener.reset(); return this; } @@ -1410,10 +1145,10 @@ public class TimeZoneDetectorStrategyImplTest { * {@link TimeZoneConfiguration} have been changed. */ Script verifyConfigurationNotChanged() { - mFakeCallback.mConfiguration.assertHasNotBeenSet(); + mFakeCallback.mConfigurationInternal.assertHasNotBeenSet(); // Also confirm the listener did not trigger. - mMockStrategyListener.verifyOnConfigurationChangedNotCalled(); + mMockConfigChangeListener.verifyOnChangeNotCalled(); return this; } @@ -1448,24 +1183,24 @@ public class TimeZoneDetectorStrategyImplTest { return new TelephonyTestCase(matchType, quality, expectedScore); } - private static class MockStrategyListener implements TimeZoneDetectorStrategy.StrategyListener { - private boolean mOnConfigurationChangedCalled; + private static class MockConfigChangeListener implements ConfigurationChangeListener { + private boolean mOnChangeCalled; @Override - public void onConfigurationChanged() { - mOnConfigurationChangedCalled = true; + public void onChange() { + mOnChangeCalled = true; } - void verifyOnConfigurationChangedCalled() { - assertTrue(mOnConfigurationChangedCalled); + void verifyOnChangeCalled() { + assertTrue(mOnChangeCalled); } - void verifyOnConfigurationChangedNotCalled() { - assertFalse(mOnConfigurationChangedCalled); + void verifyOnChangeNotCalled() { + assertFalse(mOnChangeCalled); } void reset() { - mOnConfigurationChangedCalled = false; + mOnChangeCalled = false; } } 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 6358c0dba471..59f0a7987bda 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -1714,6 +1714,27 @@ public class ActivityRecordTests extends WindowTestsBase { } + @Test + public void testProcessInfoUpdateWhenSetState() { + spyOn(mActivity.app); + verifyProcessInfoUpdate(RESUMED, true /* shouldUpdate */, true /* activityChange */); + verifyProcessInfoUpdate(PAUSED, false /* shouldUpdate */, false /* activityChange */); + verifyProcessInfoUpdate(STOPPED, false /* shouldUpdate */, false /* activityChange */); + verifyProcessInfoUpdate(STARTED, true /* shouldUpdate */, true /* activityChange */); + + mActivity.app.removeActivity(mActivity, true /* keepAssociation */); + verifyProcessInfoUpdate(DESTROYING, true /* shouldUpdate */, false /* activityChange */); + verifyProcessInfoUpdate(DESTROYED, true /* shouldUpdate */, false /* activityChange */); + } + + private void verifyProcessInfoUpdate(ActivityState state, boolean shouldUpdate, + boolean activityChange) { + reset(mActivity.app); + mActivity.setState(state, "test"); + verify(mActivity.app, times(shouldUpdate ? 1 : 0)).updateProcessInfo(anyBoolean(), + eq(activityChange), anyBoolean(), anyBoolean()); + } + /** * Creates an activity on display. For non-default display request it will also create a new * display with custom DisplayInfo. 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 d54b4a0a72f6..f8baf8497069 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -1110,7 +1110,7 @@ public class DisplayContentTests extends WindowTestsBase { performLayout(mDisplayContent); // The frame is empty because the requested height is zero. - assertTrue(win.getFrameLw().isEmpty()); + assertTrue(win.getFrame().isEmpty()); // The window should be scheduled to resize then the client may report a new non-empty size. win.updateResizingWindowIfNeeded(); assertThat(mWm.mResizingWindows).contains(win); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java index 0675c6d04422..2d834ac57f51 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java @@ -114,7 +114,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mWindow = spy(createWindow(null, TYPE_APPLICATION, "window")); // We only test window frames set by DisplayPolicy, so here prevents computeFrameLw from // changing those frames. - doNothing().when(mWindow).computeFrameLw(); + doNothing().when(mWindow).computeFrame(); final WindowManager.LayoutParams attrs = mWindow.mAttrs; attrs.width = MATCH_PARENT; @@ -179,7 +179,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { WindowState win = createWindow(null, TYPE_STATUS_BAR_SUB_PANEL, "StatusBarSubPanel"); win.mAttrs.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR, ITYPE_TOP_GESTURES}; - win.getFrameLw().set(0, 0, 500, 100); + win.getFrame().set(0, 0, 500, 100); addWindow(win); InsetsStateController controller = mDisplayContent.getInsetsStateController(); @@ -207,7 +207,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.removeWindowLw(mStatusBarWindow); // Removes the existing one. WindowState win = createWindow(null, TYPE_STATUS_BAR, "StatusBar"); win.mAttrs.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR}; - win.getFrameLw().set(0, 0, 500, 100); + win.getFrame().set(0, 0, 500, 100); addWindow(win); mDisplayContent.getInsetsStateController().onPostLayout(); @@ -232,7 +232,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { WindowState win1 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel1"); win1.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR}; win1.mAttrs.gravity = Gravity.TOP; - win1.getFrameLw().set(0, 0, 200, 500); + win1.getFrame().set(0, 0, 200, 500); addWindow(win1); assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_TOP); @@ -241,7 +241,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { WindowState win2 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel2"); win2.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR}; win2.mAttrs.gravity = Gravity.BOTTOM; - win2.getFrameLw().set(0, 0, 200, 500); + win2.getFrame().set(0, 0, 200, 500); addWindow(win2); assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_BOTTOM); @@ -250,7 +250,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { WindowState win3 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel3"); win3.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR}; win3.mAttrs.gravity = Gravity.LEFT; - win3.getFrameLw().set(0, 0, 200, 500); + win3.getFrame().set(0, 0, 200, 500); addWindow(win3); assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_LEFT); @@ -259,7 +259,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { WindowState win4 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel4"); win4.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR}; win4.mAttrs.gravity = Gravity.RIGHT; - win4.getFrameLw().set(0, 0, 200, 500); + win4.getFrame().set(0, 0, 200, 500); addWindow(win4); assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_RIGHT); @@ -274,11 +274,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */); mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); - assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0); + assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0); assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0); - assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0); } @@ -290,11 +290,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */); mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); - assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, NAV_BAR_HEIGHT); assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0); } @@ -306,11 +306,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */); mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); - assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0); } @@ -322,11 +322,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */); mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); - assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0); + assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0); assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0); - assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0); } @@ -342,11 +342,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */); mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); - assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0); } @@ -362,11 +362,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */); mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); - assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0); + assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0); assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0); - assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0); } @@ -381,11 +381,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */); mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); - assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0); + assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0); assertInsetByTopBottom(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0); - assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0); } @@ -402,10 +402,10 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0); - assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0); - assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0); + assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0); } @Test @@ -422,10 +422,10 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0); - assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0); - assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0); + assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0); } @Test @@ -442,10 +442,10 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0); - assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); - assertInsetBy(mWindow.getContentFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); + assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); + assertInsetBy(mWindow.getContentFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0); - assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0); + assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0); } @Test @@ -462,10 +462,10 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0); - assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); - assertInsetBy(mWindow.getContentFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); + assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); + assertInsetBy(mWindow.getContentFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0); - assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0); + assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0); } @Test @@ -484,10 +484,10 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0); - assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0); - assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0); + assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0); } @Test @@ -506,10 +506,10 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0); - assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0); - assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0); + assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0); } @Test @@ -529,10 +529,10 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0); - assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0); - assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0); + assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0); } @@ -549,11 +549,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0); - assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0); - assertInsetBy(mWindow.getContentFrameLw(), + assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0); + assertInsetBy(mWindow.getContentFrame(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0); assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0); - assertInsetBy(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0); + assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0); } @Test @@ -570,11 +570,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); assertInsetBy(mWindow.getParentFrame(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0); - assertInsetBy(mWindow.getStableFrameLw(), NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, 0, 0); - assertInsetBy(mWindow.getContentFrameLw(), + assertInsetBy(mWindow.getStableFrame(), NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, 0, 0); + assertInsetBy(mWindow.getContentFrame(), NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, DISPLAY_CUTOUT_HEIGHT, 0); assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0); - assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0); + assertInsetBy(mWindow.getDisplayFrame(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0); } @Test @@ -594,8 +594,8 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0); - assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0); - assertInsetBy(mWindow.getContentFrameLw(), + assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0); + assertInsetBy(mWindow.getContentFrame(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0); assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0); } @@ -615,7 +615,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); } @Test @@ -636,8 +636,8 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0); - assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0); - assertInsetBy(mWindow.getContentFrameLw(), + assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0); + assertInsetBy(mWindow.getContentFrame(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0); assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0); } @@ -655,11 +655,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0); - assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); - assertInsetBy(mWindow.getContentFrameLw(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0, + assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); + assertInsetBy(mWindow.getContentFrame(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0); - assertInsetBy(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0); + assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0); } @Test @@ -676,12 +676,12 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0); - assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0, + assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); - assertInsetBy(mWindow.getContentFrameLw(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0, + assertInsetBy(mWindow.getContentFrame(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0); - assertInsetBy(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0); + assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0); } @Test @@ -698,11 +698,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0); - assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); - assertInsetBy(mWindow.getContentFrameLw(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0, + assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); + assertInsetBy(mWindow.getContentFrame(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0); - assertInsetBy(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0); + assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0); } @Test @@ -719,11 +719,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0); - assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); - assertInsetBy(mWindow.getContentFrameLw(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0, + assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); + assertInsetBy(mWindow.getContentFrame(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0); - assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0); + assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0); } @Test @@ -740,11 +740,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0); - assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); - assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0); - assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0); + assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0); } @Test @@ -904,34 +904,34 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { updateDecorWindow(decorWindow, MATCH_PARENT, DECOR_WINDOW_INSET, TOP); mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */); mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); - assertInsetByTopBottom(mWindow.getContentFrameLw(), DECOR_WINDOW_INSET, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getContentFrame(), DECOR_WINDOW_INSET, NAV_BAR_HEIGHT); // Decor on bottom updateDecorWindow(decorWindow, MATCH_PARENT, DECOR_WINDOW_INSET, BOTTOM); mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */); mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); - assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, + assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, DECOR_WINDOW_INSET); // Decor on the left updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, MATCH_PARENT, LEFT); mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */); mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); - assertInsetBy(mWindow.getContentFrameLw(), DECOR_WINDOW_INSET, STATUS_BAR_HEIGHT, 0, + assertInsetBy(mWindow.getContentFrame(), DECOR_WINDOW_INSET, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); // Decor on the right updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, MATCH_PARENT, RIGHT); mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */); mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); - assertInsetBy(mWindow.getContentFrameLw(), 0, STATUS_BAR_HEIGHT, DECOR_WINDOW_INSET, + assertInsetBy(mWindow.getContentFrame(), 0, STATUS_BAR_HEIGHT, DECOR_WINDOW_INSET, NAV_BAR_HEIGHT); // Decor not allowed as inset updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, DECOR_WINDOW_INSET, TOP); mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */); mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); - assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); } private void updateDecorWindow(WindowState decorWindow, int width, int height, int gravity) { diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java index 4483f8c341cf..b50530ed3059 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java @@ -297,7 +297,7 @@ public class DisplayPolicyTests extends WindowTestsBase { final WindowState navigationBar = createNavigationBarWindow(); - navigationBar.getFrameLw().set(new Rect(100, 200, 200, 300)); + navigationBar.getFrame().set(new Rect(100, 200, 200, 300)); assertFalse("Freeform is overlapping with navigation bar", DisplayPolicy.isOverlappingWithNavBar(targetWin, navigationBar)); @@ -377,7 +377,7 @@ public class DisplayPolicyTests extends WindowTestsBase { mDisplayContent.setInputMethodWindowLocked(mImeWindow); mImeWindow.mAttrs.setFitInsetsSides(Side.all() & ~Side.BOTTOM); - mImeWindow.getGivenContentInsetsLw().set(0, displayInfo.logicalHeight, 0, 0); + mImeWindow.mGivenContentInsets.set(0, displayInfo.logicalHeight, 0, 0); mImeWindow.getControllableInsetProvider().setServerVisible(true); displayPolicy.beginLayoutLw(mDisplayContent.mDisplayFrames, 0 /* UI mode */); diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java index 1d6dd0b566a1..a0fa9369e7a8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java @@ -61,7 +61,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { @Test public void testPostLayout() { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); - statusBar.getFrameLw().set(0, 0, 500, 100); + statusBar.getFrame().set(0, 0, 500, 100); statusBar.mHasSurface = true; mProvider.setWindow(statusBar, null, null); mProvider.onPostLayout(); @@ -76,9 +76,9 @@ public class InsetsSourceProviderTest extends WindowTestsBase { @Test public void testPostLayout_givenInsets() { final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime"); - ime.getFrameLw().set(0, 0, 500, 100); - ime.getGivenContentInsetsLw().set(0, 0, 0, 60); - ime.getGivenVisibleInsetsLw().set(0, 0, 0, 75); + ime.getFrame().set(0, 0, 500, 100); + ime.mGivenContentInsets.set(0, 0, 0, 60); + ime.mGivenVisibleInsets.set(0, 0, 0, 75); ime.mHasSurface = true; mProvider.setWindow(ime, null, null); mProvider.onPostLayout(); @@ -94,7 +94,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { @Test public void testPostLayout_invisible() { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); - statusBar.getFrameLw().set(0, 0, 500, 100); + statusBar.getFrame().set(0, 0, 500, 100); mProvider.setWindow(statusBar, null, null); mProvider.onPostLayout(); assertEquals(Insets.NONE, mProvider.getSource().calculateInsets(new Rect(0, 0, 500, 500), @@ -104,7 +104,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { @Test public void testPostLayout_frameProvider() { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); - statusBar.getFrameLw().set(0, 0, 500, 100); + statusBar.getFrame().set(0, 0, 500, 100); statusBar.mHasSurface = true; mProvider.setWindow(statusBar, (displayFrames, windowState, rect) -> { @@ -118,7 +118,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { public void testUpdateControlForTarget() { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState target = createWindow(null, TYPE_APPLICATION, "target"); - statusBar.getFrameLw().set(0, 0, 500, 100); + statusBar.getFrame().set(0, 0, 500, 100); // We must not have control or control target before we have the insets source window. mProvider.updateControlForTarget(target, true /* force */); @@ -163,7 +163,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { public void testUpdateControlForFakeTarget() { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState target = createWindow(null, TYPE_APPLICATION, "target"); - statusBar.getFrameLw().set(0, 0, 500, 100); + statusBar.getFrame().set(0, 0, 500, 100); mProvider.setWindow(statusBar, null, null); mProvider.updateControlForFakeTarget(target); assertNotNull(mProvider.getControl(target)); @@ -176,7 +176,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { public void testUpdateSourceFrameForIme() { final WindowState inputMethod = createWindow(null, TYPE_INPUT_METHOD, "inputMethod"); - inputMethod.getFrameLw().set(new Rect(0, 400, 500, 500)); + inputMethod.getFrame().set(new Rect(0, 400, 500, 500)); mImeProvider.setWindow(inputMethod, null, null); mImeProvider.setServerVisible(false); @@ -190,7 +190,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { mImeProvider.setServerVisible(true); mImeSource.setVisible(true); mImeProvider.updateSourceFrame(); - assertEquals(inputMethod.getFrameLw(), mImeSource.getFrame()); + assertEquals(inputMethod.getFrame(), mImeSource.getFrame()); insets = mImeSource.calculateInsets(new Rect(0, 0, 500, 500), false /* ignoreVisibility */); assertEquals(Insets.of(0, 0, 0, 100), insets); @@ -200,7 +200,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { public void testInsetsModified() { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState target = createWindow(null, TYPE_APPLICATION, "target"); - statusBar.getFrameLw().set(0, 0, 500, 100); + statusBar.getFrame().set(0, 0, 500, 100); mProvider.setWindow(statusBar, null, null); mProvider.updateControlForTarget(target, false /* force */); InsetsState state = new InsetsState(); @@ -213,7 +213,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { public void testInsetsModified_noControl() { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState target = createWindow(null, TYPE_APPLICATION, "target"); - statusBar.getFrameLw().set(0, 0, 500, 100); + statusBar.getFrame().set(0, 0, 500, 100); mProvider.setWindow(statusBar, null, null); InsetsState state = new InsetsState(); state.getSource(ITYPE_STATUS_BAR).setVisible(false); @@ -224,7 +224,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { @Test public void testInsetGeometries() { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); - statusBar.getFrameLw().set(0, 0, 500, 100); + statusBar.getFrame().set(0, 0, 500, 100); statusBar.mHasSurface = true; mProvider.setWindow(statusBar, null, null); mProvider.onPostLayout(); @@ -236,7 +236,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { false /* ignoreVisibility */)); // Don't apply left insets if window is left-of inset-window but still overlaps - statusBar.getFrameLw().set(100, 0, 0, 0); + statusBar.getFrame().set(100, 0, 0, 0); assertEquals(Insets.of(0, 0, 0, 0), mProvider.getSource().calculateInsets(new Rect(-100, 0, 400, 500), false /* ignoreVisibility */)); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java index bce1142c99be..ca3f815698e8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java @@ -53,7 +53,6 @@ import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import com.android.compatibility.common.util.SystemUtil; -import com.android.internal.annotations.GuardedBy; import org.junit.After; import org.junit.Before; @@ -76,14 +75,10 @@ public class TaskStackChangedListenerTest { private static final int WAIT_TIMEOUT_MS = 5000; private static final Object sLock = new Object(); - @GuardedBy("sLock") - private static boolean sTaskStackChangedCalled; - private static boolean sActivityBResumed; @Before public void setUp() throws Exception { mService = ActivityManager.getService(); - sTaskStackChangedCalled = false; } @After @@ -94,47 +89,33 @@ public class TaskStackChangedListenerTest { @Test @Presubmit - @FlakyTest(bugId = 130388819) public void testTaskStackChanged_afterFinish() throws Exception { + final TestActivity activity = startTestActivity(ActivityA.class); + final CountDownLatch latch = new CountDownLatch(1); registerTaskStackChangedListener(new TaskStackListener() { @Override public void onTaskStackChanged() throws RemoteException { - synchronized (sLock) { - sTaskStackChangedCalled = true; - } + latch.countDown(); } }); - Context context = getInstrumentation().getContext(); - context.startActivity( - new Intent(context, ActivityA.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); - UiDevice.getInstance(getInstrumentation()).waitForIdle(); - synchronized (sLock) { - assertTrue(sTaskStackChangedCalled); - } - assertTrue(sActivityBResumed); + activity.finish(); + waitForCallback(latch); } @Test @Presubmit public void testTaskStackChanged_resumeWhilePausing() throws Exception { + final CountDownLatch latch = new CountDownLatch(1); registerTaskStackChangedListener(new TaskStackListener() { @Override public void onTaskStackChanged() throws RemoteException { - synchronized (sLock) { - sTaskStackChangedCalled = true; - } + latch.countDown(); } }); - final Context context = getInstrumentation().getContext(); - context.startActivity(new Intent(context, ResumeWhilePausingActivity.class).addFlags( - Intent.FLAG_ACTIVITY_NEW_TASK)); - UiDevice.getInstance(getInstrumentation()).waitForIdle(); - - synchronized (sLock) { - assertTrue(sTaskStackChangedCalled); - } + startTestActivity(ResumeWhilePausingActivity.class); + waitForCallback(latch); } @Test @@ -512,7 +493,7 @@ public class TaskStackChangedListenerTest { try { final boolean result = latch.await(WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS); if (!result) { - throw new RuntimeException("Timed out waiting for task stack change notification"); + throw new AssertionError("Timed out waiting for task stack change notification"); } } catch (InterruptedException e) { } @@ -569,19 +550,6 @@ public class TaskStackChangedListenerTest { } public static class ActivityA extends TestActivity { - - private boolean mActivityBLaunched = false; - - @Override - protected void onPostResume() { - super.onPostResume(); - if (mActivityBLaunched) { - return; - } - mActivityBLaunched = true; - finish(); - startActivity(new Intent(this, ActivityB.class)); - } } public static class ActivityB extends TestActivity { @@ -589,10 +557,6 @@ public class TaskStackChangedListenerTest { @Override protected void onPostResume() { super.onPostResume(); - synchronized (sLock) { - sTaskStackChangedCalled = false; - } - sActivityBResumed = true; finish(); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java index 4a8e8dafb57d..dc859046db42 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -86,11 +86,6 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { } @Override - public int getMaxWallpaperLayer() { - return 0; - } - - @Override public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs) { return attrs.type == TYPE_NOTIFICATION_SHADE; } @@ -377,11 +372,6 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { } @Override - public boolean isTopLevelWindow(int windowType) { - return false; - } - - @Override public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) { } diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java index ed9e2707ae39..63367ac2badf 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java @@ -133,8 +133,8 @@ public class WallpaperControllerTests extends WindowTestsBase { int expectedWidth = (int) (wallpaperWidth * (displayHeight / (double) wallpaperHeight)); // Check that the wallpaper is correctly scaled - assertEquals(new Rect(0, 0, expectedWidth, displayHeight), wallpaperWindow.getFrameLw()); - Rect portraitFrame = wallpaperWindow.getFrameLw(); + assertEquals(new Rect(0, 0, expectedWidth, displayHeight), wallpaperWindow.getFrame()); + Rect portraitFrame = wallpaperWindow.getFrame(); // Rotate the display dc.getDisplayRotation().updateOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, true); @@ -149,7 +149,7 @@ public class WallpaperControllerTests extends WindowTestsBase { // Check that the wallpaper has the same frame in landscape than in portrait assertEquals(Configuration.ORIENTATION_LANDSCAPE, dc.getConfiguration().orientation); - assertEquals(portraitFrame, wallpaperWindow.getFrameLw()); + assertEquals(portraitFrame, wallpaperWindow.getFrame()); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java index eb2aa41192c2..ca3626d09062 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java @@ -89,29 +89,29 @@ public class WindowFrameTests extends WindowTestsBase { } private void assertFrame(WindowState w, Rect frame) { - assertEquals(w.getFrameLw(), frame); + assertEquals(w.getFrame(), frame); } private void assertFrame(WindowState w, int left, int top, int right, int bottom) { - assertRect(w.getFrameLw(), left, top, right, bottom); + assertRect(w.getFrame(), left, top, right, bottom); } private void assertRelFrame(WindowState w, int left, int top, int right, int bottom) { - assertRect(w.getRelativeFrameLw(), left, top, right, bottom); + assertRect(w.getRelativeFrame(), left, top, right, bottom); } private void assertContentFrame(WindowState w, Rect expectedRect) { - assertRect(w.getContentFrameLw(), expectedRect.left, expectedRect.top, expectedRect.right, + assertRect(w.getContentFrame(), expectedRect.left, expectedRect.top, expectedRect.right, expectedRect.bottom); } private void assertVisibleFrame(WindowState w, Rect expectedRect) { - assertRect(w.getVisibleFrameLw(), expectedRect.left, expectedRect.top, expectedRect.right, + assertRect(w.getVisibleFrame(), expectedRect.left, expectedRect.top, expectedRect.right, expectedRect.bottom); } private void assertStableFrame(WindowState w, Rect expectedRect) { - assertRect(w.getStableFrameLw(), expectedRect.left, expectedRect.top, expectedRect.right, + assertRect(w.getStableFrame(), expectedRect.left, expectedRect.top, expectedRect.right, expectedRect.bottom); } @@ -155,7 +155,7 @@ public class WindowFrameTests extends WindowTestsBase { // the difference between mFrame and ContentFrame. Visible // and stable frames work the same way. w.getWindowFrames().setFrames(pf, df, cf, vf, dcf, sf); - w.computeFrameLw(); + w.computeFrame(); assertFrame(w, 0, 0, 1000, 1000); assertRelFrame(w, 0, 0, 1000, 1000); assertContentInset(w, 0, topContentInset, 0, bottomContentInset); @@ -170,14 +170,14 @@ public class WindowFrameTests extends WindowTestsBase { w.mAttrs.width = 100; w.mAttrs.height = 100; //have to clear MATCH_PARENT w.mRequestedWidth = 100; w.mRequestedHeight = 100; - w.computeFrameLw(); + w.computeFrame(); assertFrame(w, 100, 100, 200, 200); assertRelFrame(w, 100, 100, 200, 200); assertContentInset(w, 0, 0, 0, 0); // In this case the frames are shrunk to the window frame. - assertContentFrame(w, w.getFrameLw()); - assertVisibleFrame(w, w.getFrameLw()); - assertStableFrame(w, w.getFrameLw()); + assertContentFrame(w, w.getFrame()); + assertVisibleFrame(w, w.getFrame()); + assertStableFrame(w, w.getFrame()); } @Test @@ -193,7 +193,7 @@ public class WindowFrameTests extends WindowTestsBase { // Here the window has FILL_PARENT, FILL_PARENT // so we expect it to fill the entire available frame. w.getWindowFrames().setFrames(pf, pf, pf, pf, pf, pf); - w.computeFrameLw(); + w.computeFrame(); assertFrame(w, 0, 0, 1000, 1000); assertRelFrame(w, 0, 0, 1000, 1000); @@ -202,14 +202,14 @@ public class WindowFrameTests extends WindowTestsBase { // and we use mRequestedWidth/mRequestedHeight w.mAttrs.width = 300; w.mAttrs.height = 300; - w.computeFrameLw(); + w.computeFrame(); // Explicit width and height without requested width/height // gets us nothing. assertFrame(w, 0, 0, 0, 0); w.mRequestedWidth = 300; w.mRequestedHeight = 300; - w.computeFrameLw(); + w.computeFrame(); // With requestedWidth/Height we can freely choose our size within the // parent bounds. assertFrame(w, 0, 0, 300, 300); @@ -222,14 +222,14 @@ public class WindowFrameTests extends WindowTestsBase { w.mRequestedWidth = -1; w.mAttrs.width = 100; w.mAttrs.height = 100; - w.computeFrameLw(); + w.computeFrame(); assertFrame(w, 0, 0, 100, 100); w.mAttrs.flags = 0; // But sizes too large will be clipped to the containing frame w.mRequestedWidth = 1200; w.mRequestedHeight = 1200; - w.computeFrameLw(); + w.computeFrame(); assertFrame(w, 0, 0, 1000, 1000); // Before they are clipped though windows will be shifted @@ -237,7 +237,7 @@ public class WindowFrameTests extends WindowTestsBase { w.mAttrs.y = 300; w.mRequestedWidth = 1000; w.mRequestedHeight = 1000; - w.computeFrameLw(); + w.computeFrame(); assertFrame(w, 0, 0, 1000, 1000); // If there is room to move around in the parent frame the window will be shifted according @@ -247,18 +247,18 @@ public class WindowFrameTests extends WindowTestsBase { w.mRequestedWidth = 300; w.mRequestedHeight = 300; w.mAttrs.gravity = Gravity.RIGHT | Gravity.TOP; - w.computeFrameLw(); + w.computeFrame(); assertFrame(w, 700, 0, 1000, 300); assertRelFrame(w, 700, 0, 1000, 300); w.mAttrs.gravity = Gravity.RIGHT | Gravity.BOTTOM; - w.computeFrameLw(); + w.computeFrame(); assertFrame(w, 700, 700, 1000, 1000); assertRelFrame(w, 700, 700, 1000, 1000); // Window specified x and y are interpreted as offsets in the opposite // direction of gravity w.mAttrs.x = 100; w.mAttrs.y = 100; - w.computeFrameLw(); + w.computeFrame(); assertFrame(w, 600, 600, 900, 900); assertRelFrame(w, 600, 600, 900, 900); } @@ -285,12 +285,12 @@ public class WindowFrameTests extends WindowTestsBase { final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight); final WindowFrames windowFrames = w.getWindowFrames(); windowFrames.setFrames(pf, pf, pf, pf, pf, pf); - w.computeFrameLw(); + w.computeFrame(); // For non fullscreen tasks the containing frame is based off the // task bounds not the parent frame. - assertEquals(resolvedTaskBounds, w.getFrameLw()); - assertEquals(0, w.getRelativeFrameLw().left); - assertEquals(0, w.getRelativeFrameLw().top); + assertEquals(resolvedTaskBounds, w.getFrame()); + assertEquals(0, w.getRelativeFrame().left); + assertEquals(0, w.getRelativeFrame().top); assertContentFrame(w, resolvedTaskBounds); assertContentInset(w, 0, 0, 0, 0); @@ -300,10 +300,10 @@ public class WindowFrameTests extends WindowTestsBase { final int cfBottom = logicalHeight / 2; final Rect cf = new Rect(0, 0, cfRight, cfBottom); windowFrames.setFrames(pf, pf, cf, cf, pf, cf); - w.computeFrameLw(); - assertEquals(resolvedTaskBounds, w.getFrameLw()); - assertEquals(0, w.getRelativeFrameLw().left); - assertEquals(0, w.getRelativeFrameLw().top); + w.computeFrame(); + assertEquals(resolvedTaskBounds, w.getFrame()); + assertEquals(0, w.getRelativeFrame().left); + assertEquals(0, w.getRelativeFrame().top); int contentInsetRight = resolvedTaskBounds.right - cfRight; int contentInsetBottom = resolvedTaskBounds.bottom - cfBottom; assertContentInset(w, 0, 0, contentInsetRight, contentInsetBottom); @@ -334,12 +334,12 @@ public class WindowFrameTests extends WindowTestsBase { final WindowFrames windowFrames = w.getWindowFrames(); windowFrames.setFrames(pf, df, cf, vf, dcf, sf); - w.computeFrameLw(); + w.computeFrame(); assertPolicyCrop(w, 0, cf.top, logicalWidth, cf.bottom); windowFrames.mDecorFrame.setEmpty(); // Likewise with no decor frame we would get no crop - w.computeFrameLw(); + w.computeFrame(); assertPolicyCrop(w, 0, 0, logicalWidth, logicalHeight); // Now we set up a window which doesn't fill the entire decor frame. @@ -353,7 +353,7 @@ public class WindowFrameTests extends WindowTestsBase { w.mAttrs.height = logicalHeight / 2; w.mRequestedWidth = logicalWidth / 2; w.mRequestedHeight = logicalHeight / 2; - w.computeFrameLw(); + w.computeFrame(); // Normally the crop is shrunk from the decor frame // to the computed window frame. @@ -390,7 +390,7 @@ public class WindowFrameTests extends WindowTestsBase { final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight); final WindowFrames windowFrames = w.getWindowFrames(); windowFrames.setFrames(pf, pf, pf, pf, pf, pf); - w.computeFrameLw(); + w.computeFrame(); // For non fullscreen tasks the containing frame is based off the // task bounds not the parent frame. assertFrame(w, taskLeft, taskTop, taskRight, taskBottom); @@ -408,7 +408,7 @@ public class WindowFrameTests extends WindowTestsBase { task.setWindowingMode(WINDOWING_MODE_FULLSCREEN); task.setBounds(null); windowFrames.setFrames(pf, pf, cf, cf, pf, cf); - w.computeFrameLw(); + w.computeFrame(); assertFrame(w, cf); assertContentFrame(w, cf); assertContentInset(w, 0, 0, 0, 0); @@ -430,7 +430,7 @@ public class WindowFrameTests extends WindowTestsBase { final WindowFrames windowFrames = w.getWindowFrames(); windowFrames.setFrames(pf, pf, pf, pf, pf, pf); windowFrames.setDisplayCutout(cutout); - w.computeFrameLw(); + w.computeFrame(); assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetTop(), 50); assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetBottom(), 0); @@ -469,20 +469,20 @@ public class WindowFrameTests extends WindowTestsBase { task.setBounds(winRect); w.getWindowFrames().setFrames(pf, df, cf, vf, dcf, sf); - w.computeFrameLw(); + w.computeFrame(); final Rect expected = new Rect(winRect.left, cf.bottom - winRect.height(), winRect.right, cf.bottom); - assertEquals(expected, w.getFrameLw()); - assertEquals(expected, w.getContentFrameLw()); - assertEquals(expected, w.getVisibleFrameLw()); + assertEquals(expected, w.getFrame()); + assertEquals(expected, w.getContentFrame()); + assertEquals(expected, w.getVisibleFrame()); // Now check that it won't get moved beyond the top and then has appropriate insets winRect.bottom = 600; task.setBounds(winRect); w.setBounds(winRect); w.getWindowFrames().setFrames(pf, df, cf, vf, dcf, sf); - w.computeFrameLw(); + w.computeFrame(); assertFrame(w, winRect.left, 0, winRect.right, winRect.height()); expected.top = 0; @@ -492,8 +492,8 @@ public class WindowFrameTests extends WindowTestsBase { // Check that it's moved back without ime insets w.getWindowFrames().setFrames(pf, df, pf, pf, dcf, sf); - w.computeFrameLw(); - assertEquals(winRect, w.getFrameLw()); + w.computeFrame(); + assertEquals(winRect, w.getFrame()); } private WindowState createWindow() { 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 f095fd42900b..9603d28c286b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -479,7 +479,7 @@ public class WindowStateTests extends WindowTestsBase { app.mHasSurface = true; app.mSurfaceControl = mock(SurfaceControl.class); try { - app.getFrameLw().set(10, 20, 60, 80); + app.getFrame().set(10, 20, 60, 80); app.updateSurfacePosition(t); app.seamlesslyRotateIfAllowed(t, ROTATION_0, ROTATION_90, true); @@ -519,7 +519,7 @@ public class WindowStateTests extends WindowTestsBase { new Rect(95, 378, 105, 400)); wf.setDisplayCutout(new WmDisplayCutout(cutout, new Size(200, 400))); - app.computeFrameLw(); + app.computeFrame(); assertThat(app.getWmDisplayCutout().getDisplayCutout(), is(cutout.inset(7, 10, 5, 20))); } @@ -633,7 +633,7 @@ public class WindowStateTests extends WindowTestsBase { final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0"); final DisplayContent dc = createNewDisplay(); - win0.getFrameLw().offsetTo(PARENT_WINDOW_OFFSET, 0); + win0.getFrame().offsetTo(PARENT_WINDOW_OFFSET, 0); dc.reparentDisplayContent(win0, win0.getSurfaceControl()); dc.updateLocation(win0, DISPLAY_IN_PARENT_WINDOW_OFFSET, 0); @@ -644,7 +644,7 @@ public class WindowStateTests extends WindowTestsBase { win1.mHasSurface = true; win1.mSurfaceControl = mock(SurfaceControl.class); win1.mAttrs.surfaceInsets.set(1, 2, 3, 4); - win1.getFrameLw().offsetTo(WINDOW_OFFSET, 0); + win1.getFrame().offsetTo(WINDOW_OFFSET, 0); win1.updateSurfacePosition(t); win1.getTransformationMatrix(values, matrix); 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 f86d8f15353e..38c4e0a7de02 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -1131,7 +1131,7 @@ class WindowTestsBase extends SystemServiceTestsBase { } @Override - public boolean isGoneForLayoutLw() { + public boolean isGoneForLayout() { return false; } diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp index 229a9aa65166..f55d4d474bfb 100644 --- a/tests/StagedInstallTest/Android.bp +++ b/tests/StagedInstallTest/Android.bp @@ -26,7 +26,7 @@ android_test_helper_app { java_test_host { name: "StagedInstallInternalTest", srcs: ["src/**/*.java"], - libs: ["tradefed"], + libs: ["tradefed", "cts-shim-host-lib"], static_libs: [ "testng", "compatibility-tradefed", diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java index d7b07967f979..f50d2e134730 100644 --- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java @@ -16,6 +16,8 @@ package com.android.tests.stagedinstallinternal.host; +import static com.android.cts.shim.lib.ShimPackage.SHIM_APEX_PACKAGE_NAME; + import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertTrue; @@ -151,43 +153,78 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { runPhase("testSystemServerRestartDoesNotAffectStagedSessions_Verify"); } + // Test waiting time for staged session to be ready using adb staged install can be altered @Test - public void testAdbStagedInstallWaitForReadyFlagWorks() throws Exception { + public void testAdbStagdReadyTimeoutFlagWorks() throws Exception { assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); - File apexFile = mTestUtils.getTestFile(SHIM_V2); - String output = getDevice().executeAdbCommand("install", "--staged", - "--wait-for-staged-ready", "60000", apexFile.getAbsolutePath()); + final File apexFile = mTestUtils.getTestFile(SHIM_V2); + final String output = getDevice().executeAdbCommand("install", "--staged", + "--staged-ready-timeout", "60000", apexFile.getAbsolutePath()); assertThat(output).contains("Reboot device to apply staged session"); - String sessionId = getDevice().executeShellCommand( + final String sessionId = getDevice().executeShellCommand( "pm get-stagedsessions --only-ready --only-parent --only-sessionid").trim(); assertThat(sessionId).isNotEmpty(); } + // Test adb staged installation wait for session to be ready by default @Test - public void testAdbStagedInstallNoWaitFlagWorks() throws Exception { + public void testAdbStagedInstallWaitsTillReadyByDefault() throws Exception { assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); - File apexFile = mTestUtils.getTestFile(SHIM_V2); - String output = getDevice().executeAdbCommand("install", "--staged", - "--no-wait", apexFile.getAbsolutePath()); + final File apexFile = mTestUtils.getTestFile(SHIM_V2); + final String output = getDevice().executeAdbCommand("install", "--staged", + apexFile.getAbsolutePath()); + assertThat(output).contains("Reboot device to apply staged session"); + final String sessionId = getDevice().executeShellCommand( + "pm get-stagedsessions --only-ready --only-parent --only-sessionid").trim(); + assertThat(sessionId).isNotEmpty(); + } + + // Test we can skip waiting for staged session to be ready + @Test + public void testAdbStagedReadyWaitCanBeSkipped() throws Exception { + assumeTrue("Device does not support updating APEX", + mHostUtils.isApexUpdateSupported()); + + final File apexFile = mTestUtils.getTestFile(SHIM_V2); + final String output = getDevice().executeAdbCommand("install", "--staged", + "--staged-ready-timeout", "0", apexFile.getAbsolutePath()); assertThat(output).doesNotContain("Reboot device to apply staged session"); assertThat(output).contains("Success"); - String sessionId = getDevice().executeShellCommand( + final String sessionId = getDevice().executeShellCommand( "pm get-stagedsessions --only-ready --only-parent --only-sessionid").trim(); assertThat(sessionId).isEmpty(); } + // Test rollback-app command waits for staged sessions to be ready + @Test + public void testAdbRollbackAppWaitsForStagedReady() throws Exception { + assumeTrue("Device does not support updating APEX", + mHostUtils.isApexUpdateSupported()); + + final File apexFile = mTestUtils.getTestFile(SHIM_V2); + String output = getDevice().executeAdbCommand("install", "--staged", + "--enable-rollback", apexFile.getAbsolutePath()); + assertThat(output).contains("Reboot device to apply staged session"); + getDevice().reboot(); + output = getDevice().executeShellCommand("pm rollback-app " + SHIM_APEX_PACKAGE_NAME); + assertThat(output).contains("Reboot device to apply staged session"); + final String sessionId = getDevice().executeShellCommand( + "pm get-stagedsessions --only-ready --only-parent --only-sessionid").trim(); + assertThat(sessionId).isNotEmpty(); + } + @Test public void testAdbInstallMultiPackageCommandWorks() throws Exception { assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); - File apexFile = mTestUtils.getTestFile(SHIM_V2); - File apkFile = mTestUtils.getTestFile(APK_A); - String output = getDevice().executeAdbCommand("install-multi-package", + final File apexFile = mTestUtils.getTestFile(SHIM_V2); + final File apkFile = mTestUtils.getTestFile(APK_A); + final String output = getDevice().executeAdbCommand("install-multi-package", apexFile.getAbsolutePath(), apkFile.getAbsolutePath()); assertThat(output).contains("Created parent session"); assertThat(output).contains("Created child session"); @@ -227,16 +264,16 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { private void restartSystemServer() throws Exception { // Restart the system server - ProcessInfo oldPs = getDevice().getProcessByName("system_server"); + final ProcessInfo oldPs = getDevice().getProcessByName("system_server"); getDevice().enableAdbRoot(); // Need root to restart system server assertThat(getDevice().executeShellCommand("am restart")).contains("Restart the system"); getDevice().disableAdbRoot(); // Wait for new system server process to start - long start = System.currentTimeMillis(); + final long start = System.currentTimeMillis(); while (System.currentTimeMillis() < start + SYSTEM_SERVER_TIMEOUT_MS) { - ProcessInfo newPs = getDevice().getProcessByName("system_server"); + final ProcessInfo newPs = getDevice().getProcessByName("system_server"); if (newPs != null) { if (newPs.getPid() != oldPs.getPid()) { getDevice().waitForDeviceAvailable(); diff --git a/tools/preload-check/Android.bp b/tools/preload-check/Android.bp index 87b31d22af32..aaa6d76b39e3 100644 --- a/tools/preload-check/Android.bp +++ b/tools/preload-check/Android.bp @@ -15,7 +15,7 @@ java_test_host { name: "PreloadCheck", srcs: ["src/**/*.java"], - java_resources: [":preloaded-classes-blacklist"], + java_resources: [":preloaded-classes-denylist"], libs: ["tradefed"], test_suites: ["general-tests"], required: ["preload-check-device"], diff --git a/tools/preload-check/src/com/android/preload/check/PreloadCheck.java b/tools/preload-check/src/com/android/preload/check/PreloadCheck.java index 00fd414e3ee2..3d851531d7e7 100644 --- a/tools/preload-check/src/com/android/preload/check/PreloadCheck.java +++ b/tools/preload-check/src/com/android/preload/check/PreloadCheck.java @@ -69,13 +69,13 @@ public class PreloadCheck implements IDeviceTest { } /** - * Test the classes mentioned in the embedded preloaded-classes blacklist. + * Test the classes mentioned in the embedded preloaded-classes denylist. */ @Test - public void testBlackList() throws Exception { + public void testDenyList() throws Exception { StringBuilder sb = new StringBuilder(); try (BufferedReader br = new BufferedReader(new InputStreamReader(getClass() - .getResourceAsStream("/preloaded-classes-blacklist")))) { + .getResourceAsStream("/preloaded-classes-denylist")))) { String s; while ((s = br.readLine()) != null) { s = s.trim(); |