Merge "Revert "Cache the UserInfo for the system user on UserManagerService.""
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 2fd2e33..fc5efc6 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -6,6 +6,7 @@
clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
cmds/hid/
cmds/input/
+ cmds/uinput/
core/jni/
libs/input/
services/core/jni/
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 2bd5aee..bb65387 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -299,6 +299,7 @@
static_libs: [
// License notices from art module
"art-notices-for-framework-stubs-jar",
+ "framework-res-package-jar", // Export package of framework-res
],
errorprone: {
javacflags: [
@@ -311,6 +312,15 @@
compile_dex: true,
}
+java_defaults {
+ name: "android_stubs_dists_default",
+ dist: {
+ targets: ["sdk", "win_sdk"],
+ tag: ".jar",
+ dest: "android.jar",
+ },
+}
+
java_library_static {
name: "android_monolith_stubs_current",
srcs: [ ":api-stubs-docs" ],
@@ -346,7 +356,21 @@
name: "android_system_monolith_stubs_current",
srcs: [ ":system-api-stubs-docs" ],
static_libs: [ "private-stub-annotations-jar" ],
- defaults: ["android_defaults_stubs_current"],
+ defaults: [
+ "android_defaults_stubs_current",
+ "android_stubs_dists_default",
+ ],
+ dist: {
+ dir: "apistubs/android/system",
+ },
+ dists: [
+ {
+ // Legacy dist path
+ targets: ["sdk", "win_sdk"],
+ tag: ".jar",
+ dest: "android_system.jar",
+ },
+ ],
}
java_library_static {
@@ -378,14 +402,34 @@
name: "android_test_stubs_current",
srcs: [ ":test-api-stubs-docs" ],
static_libs: [ "private-stub-annotations-jar" ],
- defaults: ["android_defaults_stubs_current"],
+ defaults: [
+ "android_defaults_stubs_current",
+ "android_stubs_dists_default",
+ ],
+ dist: {
+ dir: "apistubs/android/test",
+ },
+ dists: [
+ {
+ // Legacy dist path
+ targets: ["sdk", "win_sdk"],
+ tag: ".jar",
+ dest: "android_test.jar",
+ },
+ ],
}
java_library_static {
name: "android_module_lib_stubs_current",
srcs: [ ":module-lib-api-stubs-docs-non-updatable" ],
- defaults: ["android_defaults_stubs_current"],
+ defaults: [
+ "android_defaults_stubs_current",
+ "android_stubs_dists_default",
+ ],
libs: ["sdk_system_29_android"],
+ dist: {
+ dir: "apistubs/android/module-lib",
+ },
}
java_library_static {
diff --git a/apct-tests/perftests/multiuser/AndroidTest.xml b/apct-tests/perftests/multiuser/AndroidTest.xml
index c7929af..fbe5892 100644
--- a/apct-tests/perftests/multiuser/AndroidTest.xml
+++ b/apct-tests/perftests/multiuser/AndroidTest.xml
@@ -27,6 +27,9 @@
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
+ <!--Install the content provider automatically when we push some file in sdcard folder.-->
+ <!--Needed to avoid the installation during the test suite.-->
+ <option name="push-file" key="trace_config_detailed.textproto" value="/sdcard/sample.textproto" />
</target_preparer>
<!-- Needed for pulling the collected trace config on to the host -->
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 93bf541..e192861 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 @@
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 @@
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 @@
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 @@
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 @@
"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 @@
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 85fd7176c..95ede34 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 aee02c7a..6ac9f93 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 05fa627..8b5292f 100644
--- a/apct-tests/perftests/windowmanager/README.md
+++ b/apct-tests/perftests/windowmanager/README.md
@@ -25,3 +25,11 @@
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 4ed3b4e..5c09ec2 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 @@
/** 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 @@
"finishActivity",
"startActivityInner");
+ private boolean mIsProfiling;
+ private boolean mIsTraceStarted;
+
@Test
@ManualBenchmarkTest(
targetTestDurationNs = 20 * TIME_1_S_IN_NS,
@@ -76,13 +80,13 @@
| 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 @@
measuredTimeNs = SystemClock.elapsedRealtimeNanos() - startTime;
}
- stopAsyncAtrace();
+ if (mIsTraceStarted) {
+ stopAsyncAtrace();
+ }
mTraceMarkParser.forAllSlices((key, slices) -> {
for (TraceMarkSlice slice : slices) {
@@ -108,7 +114,7 @@
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 @@
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 6122ef2..efcabd8 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 @@
@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 @@
| 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 @@
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 cff5663..2697428 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 @@
@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 @@
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 c72cc9d..c52b130 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 @@
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 @@
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 @@
@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 cc0e939a..b51a9a8 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.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 @@
/**
* 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 @@
.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 @@
}
/** 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 6eb85aa..d955289 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.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 @@
/** Prepare the preconditions before running performance test. */
public class WmPerfRunListener extends RunListener {
+ private static final String TAG = WmPerfRunListener.class.getSimpleName();
- private static final String OPTION_KILL_BACKGROUND = "kill-bg";
+ 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 @@
@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 @@
});
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/apex/jobscheduler/service/java/com/android/server/JobSchedulerBackgroundThread.java b/apex/jobscheduler/service/java/com/android/server/JobSchedulerBackgroundThread.java
index 91d254d..a413f7b 100644
--- a/apex/jobscheduler/service/java/com/android/server/JobSchedulerBackgroundThread.java
+++ b/apex/jobscheduler/service/java/com/android/server/JobSchedulerBackgroundThread.java
@@ -17,10 +17,13 @@
package com.android.server;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Trace;
+import java.util.concurrent.Executor;
+
/**
* Shared singleton background thread.
*
@@ -31,6 +34,7 @@
private static final long SLOW_DELIVERY_THRESHOLD_MS = 30_000;
private static JobSchedulerBackgroundThread sInstance;
private static Handler sHandler;
+ private static Executor sHandlerExecutor;
private JobSchedulerBackgroundThread() {
super("jobscheduler.bg", android.os.Process.THREAD_PRIORITY_BACKGROUND);
@@ -45,6 +49,7 @@
looper.setSlowLogThresholdMs(
SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
sHandler = new Handler(sInstance.getLooper());
+ sHandlerExecutor = new HandlerExecutor(sHandler);
}
}
@@ -63,4 +68,12 @@
return sHandler;
}
}
+
+ /** Returns the singleton handler executor for JobSchedulerBackgroundThread */
+ public static Executor getExecutor() {
+ synchronized (JobSchedulerBackgroundThread.class) {
+ ensureThreadLocked();
+ return sHandlerExecutor;
+ }
+ }
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index a1a5004..b35a7be 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -166,7 +166,7 @@
// Note: we can't directly do postDelayed(this::rampUpForScreenOn), because
// we need the exact same instance for removeCallbacks().
mHandler.postDelayed(mRampUpForScreenOff,
- mConstants.SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS.getValue());
+ mConstants.SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS);
}
}
}
@@ -189,7 +189,7 @@
}
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
if ((mLastScreenOffRealtime
- + mConstants.SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS.getValue())
+ + mConstants.SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS)
> now) {
return;
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 3234b27..cf4caea 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -39,7 +39,6 @@
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -50,7 +49,6 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
import android.content.pm.ServiceInfo;
-import android.database.ContentObserver;
import android.net.Uri;
import android.os.BatteryStats;
import android.os.BatteryStatsInternal;
@@ -67,11 +65,10 @@
import android.os.UserHandle;
import android.os.UserManagerInternal;
import android.os.WorkSource;
-import android.provider.Settings;
+import android.provider.DeviceConfig;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.IndentingPrintWriter;
-import android.util.KeyValueListParser;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -88,6 +85,7 @@
import com.android.server.AppStateTracker;
import com.android.server.AppStateTrackerImpl;
import com.android.server.DeviceIdleInternal;
+import com.android.server.JobSchedulerBackgroundThread;
import com.android.server.LocalServices;
import com.android.server.SystemService.TargetUser;
import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
@@ -329,39 +327,70 @@
// -- Pre-allocated temporaries only for use in assignJobsToContextsLocked --
- private class ConstantsObserver extends ContentObserver {
- private ContentResolver mResolver;
-
- public ConstantsObserver(Handler handler) {
- super(handler);
- }
-
- public void start(ContentResolver resolver) {
- mResolver = resolver;
- mResolver.registerContentObserver(Settings.Global.getUriFor(
- Settings.Global.JOB_SCHEDULER_CONSTANTS), false, this);
- updateConstants();
+ private class ConstantsObserver implements DeviceConfig.OnPropertiesChangedListener {
+ public void start() {
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ JobSchedulerBackgroundThread.getExecutor(), this);
+ // Load all the constants.
+ onPropertiesChanged(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_JOB_SCHEDULER));
}
@Override
- public void onChange(boolean selfChange, Uri uri) {
- updateConstants();
- }
-
- private void updateConstants() {
+ public void onPropertiesChanged(DeviceConfig.Properties properties) {
+ boolean apiQuotaScheduleUpdated = false;
+ boolean concurrencyUpdated = false;
synchronized (mLock) {
- try {
- mConstants.updateConstantsLocked(Settings.Global.getString(mResolver,
- Settings.Global.JOB_SCHEDULER_CONSTANTS));
- for (int controller = 0; controller < mControllers.size(); controller++) {
- final StateController sc = mControllers.get(controller);
- sc.onConstantsUpdatedLocked();
+ for (String name : properties.getKeyset()) {
+ if (name == null) {
+ continue;
}
- updateQuotaTracker();
- } catch (IllegalArgumentException e) {
- // Failed to parse the settings string, log this and move on
- // with defaults.
- Slog.e(TAG, "Bad jobscheduler settings", e);
+ switch (name) {
+ case Constants.KEY_ENABLE_API_QUOTAS:
+ case Constants.KEY_API_QUOTA_SCHEDULE_COUNT:
+ case Constants.KEY_API_QUOTA_SCHEDULE_WINDOW_MS:
+ case Constants.KEY_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT:
+ case Constants.KEY_API_QUOTA_SCHEDULE_THROW_EXCEPTION:
+ if (!apiQuotaScheduleUpdated) {
+ mConstants.updateApiQuotaConstantsLocked();
+ updateQuotaTracker();
+ apiQuotaScheduleUpdated = true;
+ }
+ break;
+ case Constants.KEY_MIN_READY_NON_ACTIVE_JOBS_COUNT:
+ case Constants.KEY_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS:
+ mConstants.updateBatchingConstantsLocked();
+ break;
+ case Constants.KEY_HEAVY_USE_FACTOR:
+ case Constants.KEY_MODERATE_USE_FACTOR:
+ mConstants.updateUseFactorConstantsLocked();
+ break;
+ case Constants.KEY_SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS:
+ if (!concurrencyUpdated) {
+ mConstants.updateConcurrencyConstantsLocked();
+ concurrencyUpdated = true;
+ }
+ break;
+ case Constants.KEY_MIN_LINEAR_BACKOFF_TIME_MS:
+ case Constants.KEY_MIN_EXP_BACKOFF_TIME_MS:
+ mConstants.updateBackoffConstantsLocked();
+ break;
+ case Constants.KEY_CONN_CONGESTION_DELAY_FRAC:
+ case Constants.KEY_CONN_PREFETCH_RELAX_FRAC:
+ mConstants.updateConnectivityConstantsLocked();
+ break;
+ default:
+ // Too many max_job_* strings to list.
+ if (name.startsWith(Constants.KEY_PREFIX_MAX_JOB)
+ && !concurrencyUpdated) {
+ mConstants.updateConcurrencyConstantsLocked();
+ concurrencyUpdated = true;
+ }
+ break;
+ }
+ }
+ for (int controller = 0; controller < mControllers.size(); controller++) {
+ final StateController sc = mControllers.get(controller);
+ sc.onConstantsUpdatedLocked();
}
}
}
@@ -376,53 +405,52 @@
}
static class MaxJobCounts {
- private final KeyValueListParser.IntValue mTotal;
- private final KeyValueListParser.IntValue mMaxBg;
- private final KeyValueListParser.IntValue mMinBg;
+ private final int mTotalDefault;
+ private final String mTotalKey;
+ private final int mMaxBgDefault;
+ private final String mMaxBgKey;
+ private final int mMinBgDefault;
+ private final String mMinBgKey;
+ private int mTotal;
+ private int mMaxBg;
+ private int mMinBg;
MaxJobCounts(int totalDefault, String totalKey,
int maxBgDefault, String maxBgKey, int minBgDefault, String minBgKey) {
- mTotal = new KeyValueListParser.IntValue(totalKey, totalDefault);
- mMaxBg = new KeyValueListParser.IntValue(maxBgKey, maxBgDefault);
- mMinBg = new KeyValueListParser.IntValue(minBgKey, minBgDefault);
+ mTotalKey = totalKey;
+ mTotal = mTotalDefault = totalDefault;
+ mMaxBgKey = maxBgKey;
+ mMaxBg = mMaxBgDefault = maxBgDefault;
+ mMinBgKey = minBgKey;
+ mMinBg = mMinBgDefault = minBgDefault;
}
- public void parse(KeyValueListParser parser) {
- mTotal.parse(parser);
- mMaxBg.parse(parser);
- mMinBg.parse(parser);
+ public void update() {
+ mTotal = DeviceConfig.getInt(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ mTotalKey, mTotalDefault);
+ mMaxBg = DeviceConfig.getInt(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ mMaxBgKey, mMaxBgDefault);
+ mMinBg = DeviceConfig.getInt(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ mMinBgKey, mMinBgDefault);
- if (mTotal.getValue() < 1) {
- mTotal.setValue(1);
- } else if (mTotal.getValue() > MAX_JOB_CONTEXTS_COUNT) {
- mTotal.setValue(MAX_JOB_CONTEXTS_COUNT);
- }
+ // Ensure total in the range [1, MAX_JOB_CONTEXTS_COUNT].
+ mTotal = Math.min(Math.max(1, mTotal), MAX_JOB_CONTEXTS_COUNT);
- if (mMaxBg.getValue() < 1) {
- mMaxBg.setValue(1);
- } else if (mMaxBg.getValue() > mTotal.getValue()) {
- mMaxBg.setValue(mTotal.getValue());
- }
- if (mMinBg.getValue() < 0) {
- mMinBg.setValue(0);
- } else {
- if (mMinBg.getValue() > mMaxBg.getValue()) {
- mMinBg.setValue(mMaxBg.getValue());
- }
- if (mMinBg.getValue() >= mTotal.getValue()) {
- mMinBg.setValue(mTotal.getValue() - 1);
- }
- }
+ // Ensure maxBg in the range [1, total].
+ mMaxBg = Math.min(Math.max(1, mMaxBg), mTotal);
+
+ // Ensure minBg in the range [0, min(maxBg, total - 1)]
+ mMinBg = Math.min(Math.max(0, mMinBg), Math.min(mMaxBg, mTotal - 1));
}
/** Total number of jobs to run simultaneously. */
public int getMaxTotal() {
- return mTotal.getValue();
+ return mTotal;
}
/** Max number of BG (== owned by non-TOP apps) jobs to run simultaneously. */
public int getMaxBg() {
- return mMaxBg.getValue();
+ return mMaxBg;
}
/**
@@ -430,20 +458,34 @@
* pending, rather than always running the TOTAL number of FG jobs.
*/
public int getMinBg() {
- return mMinBg.getValue();
+ return mMinBg;
}
public void dump(PrintWriter pw, String prefix) {
- mTotal.dump(pw, prefix);
- mMaxBg.dump(pw, prefix);
- mMinBg.dump(pw, prefix);
+ pw.print(prefix);
+ pw.print(mTotalKey);
+ pw.print("=");
+ pw.print(mTotal);
+ pw.println();
+
+ pw.print(prefix);
+ pw.print(mMaxBgKey);
+ pw.print("=");
+ pw.print(mMaxBg);
+ pw.println();
+
+ pw.print(prefix);
+ pw.print(mMinBgKey);
+ pw.print("=");
+ pw.print(mMinBg);
+ pw.println();
}
public void dumpProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
- mTotal.dumpProto(proto, MaxJobCountsProto.TOTAL_JOBS);
- mMaxBg.dumpProto(proto, MaxJobCountsProto.MAX_BG);
- mMinBg.dumpProto(proto, MaxJobCountsProto.MIN_BG);
+ proto.write(MaxJobCountsProto.TOTAL_JOBS, mTotal);
+ proto.write(MaxJobCountsProto.MAX_BG, mMaxBg);
+ proto.write(MaxJobCountsProto.MIN_BG, mMinBg);
proto.end(token);
}
}
@@ -476,23 +518,11 @@
}
/**
- * All times are in milliseconds. These constants are kept synchronized with the system
- * global Settings. Any access to this class or its fields should be done while
+ * All times are in milliseconds. Any access to this class or its fields should be done while
* holding the JobSchedulerService.mLock lock.
*/
public static class Constants {
// Key names stored in the settings value.
- // TODO(124466289): remove deprecated flags when we migrate to DeviceConfig
- private static final String DEPRECATED_KEY_MIN_IDLE_COUNT = "min_idle_count";
- private static final String DEPRECATED_KEY_MIN_CHARGING_COUNT = "min_charging_count";
- private static final String DEPRECATED_KEY_MIN_BATTERY_NOT_LOW_COUNT =
- "min_battery_not_low_count";
- private static final String DEPRECATED_KEY_MIN_STORAGE_NOT_LOW_COUNT =
- "min_storage_not_low_count";
- private static final String DEPRECATED_KEY_MIN_CONNECTIVITY_COUNT =
- "min_connectivity_count";
- private static final String DEPRECATED_KEY_MIN_CONTENT_COUNT = "min_content_count";
- private static final String DEPRECATED_KEY_MIN_READY_JOBS_COUNT = "min_ready_jobs_count";
private static final String KEY_MIN_READY_NON_ACTIVE_JOBS_COUNT =
"min_ready_non_active_jobs_count";
private static final String KEY_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS =
@@ -500,28 +530,10 @@
private static final String KEY_HEAVY_USE_FACTOR = "heavy_use_factor";
private static final String KEY_MODERATE_USE_FACTOR = "moderate_use_factor";
- // The following values used to be used on P and below. Do not reuse them.
- private static final String DEPRECATED_KEY_FG_JOB_COUNT = "fg_job_count";
- private static final String DEPRECATED_KEY_BG_NORMAL_JOB_COUNT = "bg_normal_job_count";
- private static final String DEPRECATED_KEY_BG_MODERATE_JOB_COUNT = "bg_moderate_job_count";
- private static final String DEPRECATED_KEY_BG_LOW_JOB_COUNT = "bg_low_job_count";
- private static final String DEPRECATED_KEY_BG_CRITICAL_JOB_COUNT = "bg_critical_job_count";
-
- private static final String DEPRECATED_KEY_MAX_STANDARD_RESCHEDULE_COUNT
- = "max_standard_reschedule_count";
- private static final String DEPRECATED_KEY_MAX_WORK_RESCHEDULE_COUNT =
- "max_work_reschedule_count";
- private static final String KEY_MIN_LINEAR_BACKOFF_TIME = "min_linear_backoff_time";
- private static final String KEY_MIN_EXP_BACKOFF_TIME = "min_exp_backoff_time";
- private static final String DEPRECATED_KEY_STANDBY_HEARTBEAT_TIME =
- "standby_heartbeat_time";
- private static final String DEPRECATED_KEY_STANDBY_WORKING_BEATS = "standby_working_beats";
- private static final String DEPRECATED_KEY_STANDBY_FREQUENT_BEATS =
- "standby_frequent_beats";
- private static final String DEPRECATED_KEY_STANDBY_RARE_BEATS = "standby_rare_beats";
+ private static final String KEY_MIN_LINEAR_BACKOFF_TIME_MS = "min_linear_backoff_time_ms";
+ private static final String KEY_MIN_EXP_BACKOFF_TIME_MS = "min_exp_backoff_time_ms";
private static final String KEY_CONN_CONGESTION_DELAY_FRAC = "conn_congestion_delay_frac";
private static final String KEY_CONN_PREFETCH_RELAX_FRAC = "conn_prefetch_relax_frac";
- private static final String DEPRECATED_KEY_USE_HEARTBEATS = "use_heartbeats";
private static final String KEY_ENABLE_API_QUOTAS = "enable_api_quotas";
private static final String KEY_API_QUOTA_SCHEDULE_COUNT = "aq_schedule_count";
private static final String KEY_API_QUOTA_SCHEDULE_WINDOW_MS = "aq_schedule_window_ms";
@@ -530,12 +542,15 @@
private static final String KEY_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT =
"aq_schedule_return_failure";
+ private static final String KEY_SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS =
+ "screen_off_job_concurrency_increase_delay_ms";
+
private static final int DEFAULT_MIN_READY_NON_ACTIVE_JOBS_COUNT = 5;
private static final long DEFAULT_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS = 31 * MINUTE_IN_MILLIS;
private static final float DEFAULT_HEAVY_USE_FACTOR = .9f;
private static final float DEFAULT_MODERATE_USE_FACTOR = .5f;
- private static final long DEFAULT_MIN_LINEAR_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS;
- private static final long DEFAULT_MIN_EXP_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS;
+ private static final long DEFAULT_MIN_LINEAR_BACKOFF_TIME_MS = JobInfo.MIN_BACKOFF_MILLIS;
+ private static final long DEFAULT_MIN_EXP_BACKOFF_TIME_MS = JobInfo.MIN_BACKOFF_MILLIS;
private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f;
private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f;
private static final boolean DEFAULT_ENABLE_API_QUOTAS = true;
@@ -543,6 +558,7 @@
private static final long DEFAULT_API_QUOTA_SCHEDULE_WINDOW_MS = MINUTE_IN_MILLIS;
private static final boolean DEFAULT_API_QUOTA_SCHEDULE_THROW_EXCEPTION = true;
private static final boolean DEFAULT_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = false;
+ private static final long DEFAULT_SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS = 30_000;
/**
* Minimum # of non-ACTIVE jobs for which the JMS will be happy running some work early.
@@ -564,59 +580,61 @@
*/
float MODERATE_USE_FACTOR = DEFAULT_MODERATE_USE_FACTOR;
+ /** Prefix for all of the max_job constants. */
+ private static final String KEY_PREFIX_MAX_JOB = "max_job_";
+
// Max job counts for screen on / off, for each memory trim level.
final MaxJobCountsPerMemoryTrimLevel MAX_JOB_COUNTS_SCREEN_ON =
new MaxJobCountsPerMemoryTrimLevel(
new MaxJobCounts(
- 8, "max_job_total_on_normal",
- 6, "max_job_max_bg_on_normal",
- 2, "max_job_min_bg_on_normal"),
+ 8, KEY_PREFIX_MAX_JOB + "total_on_normal",
+ 6, KEY_PREFIX_MAX_JOB + "max_bg_on_normal",
+ 2, KEY_PREFIX_MAX_JOB + "min_bg_on_normal"),
new MaxJobCounts(
- 8, "max_job_total_on_moderate",
- 4, "max_job_max_bg_on_moderate",
- 2, "max_job_min_bg_on_moderate"),
+ 8, KEY_PREFIX_MAX_JOB + "total_on_moderate",
+ 4, KEY_PREFIX_MAX_JOB + "max_bg_on_moderate",
+ 2, KEY_PREFIX_MAX_JOB + "min_bg_on_moderate"),
new MaxJobCounts(
- 5, "max_job_total_on_low",
- 1, "max_job_max_bg_on_low",
- 1, "max_job_min_bg_on_low"),
+ 5, KEY_PREFIX_MAX_JOB + "total_on_low",
+ 1, KEY_PREFIX_MAX_JOB + "max_bg_on_low",
+ 1, KEY_PREFIX_MAX_JOB + "min_bg_on_low"),
new MaxJobCounts(
- 5, "max_job_total_on_critical",
- 1, "max_job_max_bg_on_critical",
- 1, "max_job_min_bg_on_critical"));
+ 5, KEY_PREFIX_MAX_JOB + "total_on_critical",
+ 1, KEY_PREFIX_MAX_JOB + "max_bg_on_critical",
+ 1, KEY_PREFIX_MAX_JOB + "min_bg_on_critical"));
final MaxJobCountsPerMemoryTrimLevel MAX_JOB_COUNTS_SCREEN_OFF =
new MaxJobCountsPerMemoryTrimLevel(
new MaxJobCounts(
- 10, "max_job_total_off_normal",
- 6, "max_job_max_bg_off_normal",
- 2, "max_job_min_bg_off_normal"),
+ 10, KEY_PREFIX_MAX_JOB + "total_off_normal",
+ 6, KEY_PREFIX_MAX_JOB + "max_bg_off_normal",
+ 2, KEY_PREFIX_MAX_JOB + "min_bg_off_normal"),
new MaxJobCounts(
- 10, "max_job_total_off_moderate",
- 4, "max_job_max_bg_off_moderate",
- 2, "max_job_min_bg_off_moderate"),
+ 10, KEY_PREFIX_MAX_JOB + "total_off_moderate",
+ 4, KEY_PREFIX_MAX_JOB + "max_bg_off_moderate",
+ 2, KEY_PREFIX_MAX_JOB + "min_bg_off_moderate"),
new MaxJobCounts(
- 5, "max_job_total_off_low",
- 1, "max_job_max_bg_off_low",
- 1, "max_job_min_bg_off_low"),
+ 5, KEY_PREFIX_MAX_JOB + "total_off_low",
+ 1, KEY_PREFIX_MAX_JOB + "max_bg_off_low",
+ 1, KEY_PREFIX_MAX_JOB + "min_bg_off_low"),
new MaxJobCounts(
- 5, "max_job_total_off_critical",
- 1, "max_job_max_bg_off_critical",
- 1, "max_job_min_bg_off_critical"));
+ 5, KEY_PREFIX_MAX_JOB + "total_off_critical",
+ 1, KEY_PREFIX_MAX_JOB + "max_bg_off_critical",
+ 1, KEY_PREFIX_MAX_JOB + "min_bg_off_critical"));
/** Wait for this long after screen off before increasing the job concurrency. */
- final KeyValueListParser.IntValue SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS =
- new KeyValueListParser.IntValue(
- "screen_off_job_concurrency_increase_delay_ms", 30_000);
+ long SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS =
+ DEFAULT_SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS;
/**
* The minimum backoff time to allow for linear backoff.
*/
- long MIN_LINEAR_BACKOFF_TIME = DEFAULT_MIN_LINEAR_BACKOFF_TIME;
+ long MIN_LINEAR_BACKOFF_TIME_MS = DEFAULT_MIN_LINEAR_BACKOFF_TIME_MS;
/**
* The minimum backoff time to allow for exponential backoff.
*/
- long MIN_EXP_BACKOFF_TIME = DEFAULT_MIN_EXP_BACKOFF_TIME;
+ long MIN_EXP_BACKOFF_TIME_MS = DEFAULT_MIN_EXP_BACKOFF_TIME_MS;
/**
* The fraction of a job's running window that must pass before we
@@ -652,61 +670,78 @@
public boolean API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT =
DEFAULT_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT;
- private final KeyValueListParser mParser = new KeyValueListParser(',');
-
- void updateConstantsLocked(String value) {
- try {
- mParser.setString(value);
- } catch (Exception e) {
- // Failed to parse the settings string, log this and move on
- // with defaults.
- Slog.e(TAG, "Bad jobscheduler settings", e);
- }
-
- MIN_READY_NON_ACTIVE_JOBS_COUNT = mParser.getInt(
+ private void updateBatchingConstantsLocked() {
+ MIN_READY_NON_ACTIVE_JOBS_COUNT = DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER,
KEY_MIN_READY_NON_ACTIVE_JOBS_COUNT,
DEFAULT_MIN_READY_NON_ACTIVE_JOBS_COUNT);
- MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS = mParser.getLong(
+ MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER,
KEY_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS,
DEFAULT_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS);
- HEAVY_USE_FACTOR = mParser.getFloat(KEY_HEAVY_USE_FACTOR,
+ }
+
+ private void updateUseFactorConstantsLocked() {
+ HEAVY_USE_FACTOR = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_HEAVY_USE_FACTOR,
DEFAULT_HEAVY_USE_FACTOR);
- MODERATE_USE_FACTOR = mParser.getFloat(KEY_MODERATE_USE_FACTOR,
+ MODERATE_USE_FACTOR = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_MODERATE_USE_FACTOR,
DEFAULT_MODERATE_USE_FACTOR);
+ }
- MAX_JOB_COUNTS_SCREEN_ON.normal.parse(mParser);
- MAX_JOB_COUNTS_SCREEN_ON.moderate.parse(mParser);
- MAX_JOB_COUNTS_SCREEN_ON.low.parse(mParser);
- MAX_JOB_COUNTS_SCREEN_ON.critical.parse(mParser);
+ void updateConcurrencyConstantsLocked() {
+ MAX_JOB_COUNTS_SCREEN_ON.normal.update();
+ MAX_JOB_COUNTS_SCREEN_ON.moderate.update();
+ MAX_JOB_COUNTS_SCREEN_ON.low.update();
+ MAX_JOB_COUNTS_SCREEN_ON.critical.update();
- MAX_JOB_COUNTS_SCREEN_OFF.normal.parse(mParser);
- MAX_JOB_COUNTS_SCREEN_OFF.moderate.parse(mParser);
- MAX_JOB_COUNTS_SCREEN_OFF.low.parse(mParser);
- MAX_JOB_COUNTS_SCREEN_OFF.critical.parse(mParser);
+ MAX_JOB_COUNTS_SCREEN_OFF.normal.update();
+ MAX_JOB_COUNTS_SCREEN_OFF.moderate.update();
+ MAX_JOB_COUNTS_SCREEN_OFF.low.update();
+ MAX_JOB_COUNTS_SCREEN_OFF.critical.update();
- SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS.parse(mParser);
+ SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS,
+ DEFAULT_SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS);
+ }
- MIN_LINEAR_BACKOFF_TIME = mParser.getDurationMillis(KEY_MIN_LINEAR_BACKOFF_TIME,
- DEFAULT_MIN_LINEAR_BACKOFF_TIME);
- MIN_EXP_BACKOFF_TIME = mParser.getDurationMillis(KEY_MIN_EXP_BACKOFF_TIME,
- DEFAULT_MIN_EXP_BACKOFF_TIME);
- CONN_CONGESTION_DELAY_FRAC = mParser.getFloat(KEY_CONN_CONGESTION_DELAY_FRAC,
+ private void updateBackoffConstantsLocked() {
+ MIN_LINEAR_BACKOFF_TIME_MS = DeviceConfig.getLong(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_MIN_LINEAR_BACKOFF_TIME_MS,
+ DEFAULT_MIN_LINEAR_BACKOFF_TIME_MS);
+ MIN_EXP_BACKOFF_TIME_MS = DeviceConfig.getLong(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_MIN_EXP_BACKOFF_TIME_MS,
+ DEFAULT_MIN_EXP_BACKOFF_TIME_MS);
+ }
+
+ private void updateConnectivityConstantsLocked() {
+ CONN_CONGESTION_DELAY_FRAC = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_CONN_CONGESTION_DELAY_FRAC,
DEFAULT_CONN_CONGESTION_DELAY_FRAC);
- CONN_PREFETCH_RELAX_FRAC = mParser.getFloat(KEY_CONN_PREFETCH_RELAX_FRAC,
+ CONN_PREFETCH_RELAX_FRAC = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_CONN_PREFETCH_RELAX_FRAC,
DEFAULT_CONN_PREFETCH_RELAX_FRAC);
+ }
- ENABLE_API_QUOTAS = mParser.getBoolean(KEY_ENABLE_API_QUOTAS,
- DEFAULT_ENABLE_API_QUOTAS);
+ private void updateApiQuotaConstantsLocked() {
+ ENABLE_API_QUOTAS = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_ENABLE_API_QUOTAS, DEFAULT_ENABLE_API_QUOTAS);
// Set a minimum value on the quota limit so it's not so low that it interferes with
// legitimate use cases.
API_QUOTA_SCHEDULE_COUNT = Math.max(250,
- mParser.getInt(KEY_API_QUOTA_SCHEDULE_COUNT, DEFAULT_API_QUOTA_SCHEDULE_COUNT));
- API_QUOTA_SCHEDULE_WINDOW_MS = mParser.getDurationMillis(
+ DeviceConfig.getInt(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_API_QUOTA_SCHEDULE_COUNT, DEFAULT_API_QUOTA_SCHEDULE_COUNT));
+ API_QUOTA_SCHEDULE_WINDOW_MS = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER,
KEY_API_QUOTA_SCHEDULE_WINDOW_MS, DEFAULT_API_QUOTA_SCHEDULE_WINDOW_MS);
- API_QUOTA_SCHEDULE_THROW_EXCEPTION = mParser.getBoolean(
+ API_QUOTA_SCHEDULE_THROW_EXCEPTION = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER,
KEY_API_QUOTA_SCHEDULE_THROW_EXCEPTION,
DEFAULT_API_QUOTA_SCHEDULE_THROW_EXCEPTION);
- API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = mParser.getBoolean(
+ API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER,
KEY_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT,
DEFAULT_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT);
}
@@ -731,10 +766,11 @@
MAX_JOB_COUNTS_SCREEN_OFF.low.dump(pw, "");
MAX_JOB_COUNTS_SCREEN_OFF.critical.dump(pw, "");
- SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS.dump(pw, "");
+ pw.print(KEY_SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS,
+ SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS).println();
- pw.print(KEY_MIN_LINEAR_BACKOFF_TIME, MIN_LINEAR_BACKOFF_TIME).println();
- pw.print(KEY_MIN_EXP_BACKOFF_TIME, MIN_EXP_BACKOFF_TIME).println();
+ pw.print(KEY_MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME_MS).println();
+ pw.print(KEY_MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME_MS).println();
pw.print(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println();
pw.print(KEY_CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC).println();
@@ -760,11 +796,11 @@
MAX_JOB_COUNTS_SCREEN_ON.dumpProto(proto, ConstantsProto.MAX_JOB_COUNTS_SCREEN_ON);
MAX_JOB_COUNTS_SCREEN_OFF.dumpProto(proto, ConstantsProto.MAX_JOB_COUNTS_SCREEN_OFF);
- SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS.dumpProto(proto,
- ConstantsProto.SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS);
+ proto.write(ConstantsProto.SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS,
+ SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS);
- proto.write(ConstantsProto.MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME);
- proto.write(ConstantsProto.MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME);
+ proto.write(ConstantsProto.MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME_MS);
+ proto.write(ConstantsProto.MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME_MS);
proto.write(ConstantsProto.CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC);
proto.write(ConstantsProto.CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC);
@@ -1407,7 +1443,7 @@
mHandler = new JobHandler(context.getMainLooper());
mConstants = new Constants();
- mConstantsObserver = new ConstantsObserver(mHandler);
+ mConstantsObserver = new ConstantsObserver();
mJobSchedulerStub = new JobSchedulerStub();
mConcurrencyManager = new JobConcurrencyManager(this);
@@ -1521,7 +1557,7 @@
@Override
public void onBootPhase(int phase) {
if (PHASE_SYSTEM_SERVICES_READY == phase) {
- mConstantsObserver.start(getContext().getContentResolver());
+ mConstantsObserver.start();
for (StateController controller : mControllers) {
controller.onSystemServicesReady();
}
@@ -1693,8 +1729,8 @@
switch (job.getBackoffPolicy()) {
case JobInfo.BACKOFF_POLICY_LINEAR: {
long backoff = initialBackoffMillis;
- if (backoff < mConstants.MIN_LINEAR_BACKOFF_TIME) {
- backoff = mConstants.MIN_LINEAR_BACKOFF_TIME;
+ if (backoff < mConstants.MIN_LINEAR_BACKOFF_TIME_MS) {
+ backoff = mConstants.MIN_LINEAR_BACKOFF_TIME_MS;
}
delayMillis = backoff * backoffAttempts;
} break;
@@ -1704,8 +1740,8 @@
}
case JobInfo.BACKOFF_POLICY_EXPONENTIAL: {
long backoff = initialBackoffMillis;
- if (backoff < mConstants.MIN_EXP_BACKOFF_TIME) {
- backoff = mConstants.MIN_EXP_BACKOFF_TIME;
+ if (backoff < mConstants.MIN_EXP_BACKOFF_TIME_MS) {
+ backoff = mConstants.MIN_EXP_BACKOFF_TIME_MS;
}
delayMillis = (long) Math.scalb(backoff, backoffAttempts - 1);
} break;
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 6bc95bf..c033138 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -2131,7 +2131,7 @@
}
public List<UserHandle> getValidCrossProfileTargets(String pkg, int userId) {
- final int uid = mPackageManagerInternal.getPackageUidInternal(pkg, 0, userId);
+ final int uid = mPackageManagerInternal.getPackageUid(pkg, /* flags= */ 0, userId);
final AndroidPackage aPkg = mPackageManagerInternal.getPackage(uid);
if (uid < 0
|| aPkg == null
diff --git a/api/current.txt b/api/current.txt
index 9e0d88e..c6af6be 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11901,8 +11901,8 @@
field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionInfo> CREATOR;
field public static final int INVALID_ID = -1; // 0xffffffff
field public static final int STAGED_SESSION_ACTIVATION_FAILED = 2; // 0x2
+ field public static final int STAGED_SESSION_CONFLICT = 4; // 0x4
field public static final int STAGED_SESSION_NO_ERROR = 0; // 0x0
- field public static final int STAGED_SESSION_OTHER_ERROR = 4; // 0x4
field public static final int STAGED_SESSION_UNKNOWN = 3; // 0x3
field public static final int STAGED_SESSION_VERIFICATION_FAILED = 1; // 0x1
}
@@ -14250,6 +14250,10 @@
enum_constant public static final android.graphics.BlurMaskFilter.Blur SOLID;
}
+ public final class BlurShader extends android.graphics.Shader {
+ ctor public BlurShader(float, float, @Nullable android.graphics.Shader);
+ }
+
public class Camera {
ctor public Camera();
method public void applyToCanvas(android.graphics.Canvas);
@@ -31620,6 +31624,7 @@
method @Nullable public String getPassphrase();
method @Nullable public android.net.wifi.hotspot2.PasspointConfiguration getPasspointConfig();
method @IntRange(from=0) public int getPriority();
+ method public int getPriorityGroup();
method @Nullable public String getSsid();
method public boolean isAppInteractionRequired();
method public boolean isCredentialSharedWithUser();
@@ -31646,6 +31651,7 @@
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsUserInteractionRequired(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPasspointConfig(@NonNull android.net.wifi.hotspot2.PasspointConfiguration);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriority(@IntRange(from=0) int);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriorityGroup(int);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setSsid(@NonNull String);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setUntrusted(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWapiEnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
@@ -36733,9 +36739,11 @@
public final class PowerManager {
method public void addThermalStatusListener(@NonNull android.os.PowerManager.OnThermalStatusChangedListener);
method public void addThermalStatusListener(@NonNull java.util.concurrent.Executor, @NonNull android.os.PowerManager.OnThermalStatusChangedListener);
+ method @Nullable public java.time.Duration getBatteryDischargePrediction();
method public int getCurrentThermalStatus();
method public int getLocationPowerSaveMode();
method public float getThermalHeadroom(@IntRange(from=0, to=60) int);
+ method public boolean isBatteryDischargePredictionPersonalized();
method public boolean isDeviceIdleMode();
method public boolean isIgnoringBatteryOptimizations(String);
method public boolean isInteractive();
@@ -47836,6 +47844,7 @@
method public void onDataConnectionStateChanged(int);
method public void onDataConnectionStateChanged(int, int);
method @RequiresPermission("android.permission.READ_PHONE_STATE") public void onDisplayInfoChanged(@NonNull android.telephony.TelephonyDisplayInfo);
+ method public void onEmergencyNumberListChanged(@NonNull java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>);
method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
method public void onMessageWaitingIndicatorChanged(boolean);
method @RequiresPermission("android.permission.MODIFY_PHONE_STATE") public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
@@ -48352,7 +48361,9 @@
method @Deprecated public String iccTransmitApduBasicChannel(int, int, int, int, int, String);
method @Deprecated public String iccTransmitApduLogicalChannel(int, int, int, int, int, int, String);
method public boolean isConcurrentVoiceAndDataSupported();
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public boolean isDataConnectionAllowed();
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean isDataEnabled();
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabledForReason(int);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataRoamingEnabled();
method public boolean isEmergencyNumber(@NonNull String);
method public boolean isHearingAidCompatibilitySupported();
@@ -48374,6 +48385,7 @@
method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
method public void sendVisualVoicemailSms(String, int, String, android.app.PendingIntent);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(boolean);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabledForReason(int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setForbiddenPlmns(@NonNull java.util.List<java.lang.String>);
method public boolean setLine1NumberForDisplay(String, String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setNetworkSelectionModeAutomatic();
@@ -48421,6 +48433,10 @@
field public static final int DATA_CONNECTING = 1; // 0x1
field public static final int DATA_DISCONNECTED = 0; // 0x0
field public static final int DATA_DISCONNECTING = 4; // 0x4
+ field public static final int DATA_ENABLED_REASON_CARRIER = 2; // 0x2
+ field public static final int DATA_ENABLED_REASON_POLICY = 1; // 0x1
+ field public static final int DATA_ENABLED_REASON_THERMAL = 3; // 0x3
+ field public static final int DATA_ENABLED_REASON_USER = 0; // 0x0
field public static final int DATA_SUSPENDED = 3; // 0x3
field public static final int DATA_UNKNOWN = -1; // 0xffffffff
field public static final String EXTRA_ACTIVE_SIM_SUPPORTED_COUNT = "android.telephony.extra.ACTIVE_SIM_SUPPORTED_COUNT";
@@ -55185,7 +55201,7 @@
}
public class ViewPropertyAnimator {
- method public android.view.ViewPropertyAnimator alpha(float);
+ method public android.view.ViewPropertyAnimator alpha(@FloatRange(from=0.0f, to=1.0f) float);
method public android.view.ViewPropertyAnimator alphaBy(float);
method public void cancel();
method public long getDuration();
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 7cd8a62..17545a4 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -46,6 +46,13 @@
field public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 65536; // 0x10000
}
+ public final class MediaSessionManager {
+ method public void dispatchMediaKeyEventAsSystemService(@NonNull android.view.KeyEvent);
+ method public boolean dispatchMediaKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
+ method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.view.KeyEvent, int);
+ method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
+ }
+
}
package android.net {
diff --git a/api/system-current.txt b/api/system-current.txt
index 3ab1645..41e8593 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -8394,6 +8394,7 @@
method @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE) public boolean isAmbientDisplaySuppressedForToken(@NonNull String);
method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setAdaptivePowerSaveEnabled(boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setAdaptivePowerSavePolicy(@NonNull android.os.BatterySaverPolicyConfig);
+ method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void setBatteryDischargePrediction(@NonNull java.time.Duration, boolean);
method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public boolean setDynamicPowerSaveHint(boolean, int);
method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setPowerSaveModeEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void suppressAmbientDisplay(@NonNull String, boolean);
@@ -10816,7 +10817,8 @@
public class PhoneStateListener {
method public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
- method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber);
+ method @Deprecated public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber);
+ method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
method public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber);
method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
method public void onRadioPowerStateChanged(int);
@@ -11233,10 +11235,8 @@
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAnyRadioPoweredOn();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApnMetered(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataConnectionAllowed();
method public boolean isDataConnectivityPossible();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataEnabledForApn(int);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabledWithReason(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean isIccLockEnabled();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
@@ -11268,7 +11268,6 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabledWithReason(int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunisticNetworkState(boolean);
@@ -11306,10 +11305,6 @@
field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
- field public static final int DATA_ENABLED_REASON_CARRIER = 2; // 0x2
- field public static final int DATA_ENABLED_REASON_POLICY = 1; // 0x1
- field public static final int DATA_ENABLED_REASON_THERMAL = 3; // 0x3
- field public static final int DATA_ENABLED_REASON_USER = 0; // 0x0
field public static final String EXTRA_ANOMALY_DESCRIPTION = "android.telephony.extra.ANOMALY_DESCRIPTION";
field public static final String EXTRA_ANOMALY_ID = "android.telephony.extra.ANOMALY_ID";
field public static final String EXTRA_PHONE_IN_ECM_STATE = "android.telephony.extra.PHONE_IN_ECM_STATE";
@@ -12744,8 +12739,8 @@
public interface PacProcessor {
method @Nullable public String findProxyForUrl(@NonNull String);
method @NonNull public static android.webkit.PacProcessor getInstance();
- method @NonNull public static android.webkit.PacProcessor getInstanceForNetwork(long);
- method public default long getNetworkHandle();
+ method @NonNull public static android.webkit.PacProcessor getInstanceForNetwork(@Nullable android.net.Network);
+ method @Nullable public default android.net.Network getNetwork();
method public default void releasePacProcessor();
method public boolean setProxyScript(@NonNull String);
}
@@ -12886,7 +12881,7 @@
method public android.webkit.CookieManager getCookieManager();
method public android.webkit.GeolocationPermissions getGeolocationPermissions();
method @NonNull public default android.webkit.PacProcessor getPacProcessor();
- method @NonNull public default android.webkit.PacProcessor getPacProcessorForNetwork(long);
+ method @NonNull public default android.webkit.PacProcessor getPacProcessorForNetwork(@Nullable android.net.Network);
method public android.webkit.ServiceWorkerController getServiceWorkerController();
method public android.webkit.WebViewFactoryProvider.Statics getStatics();
method @Deprecated public android.webkit.TokenBindingService getTokenBindingService();
diff --git a/api/test-current.txt b/api/test-current.txt
index 620c5b3..529dcf7 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1305,6 +1305,8 @@
method public android.graphics.Point getStableDisplaySize();
method public boolean isMinimalPostProcessingRequested(int);
method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
+ field public static final int VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS = 512; // 0x200
+ field public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1024; // 0x400
}
}
@@ -2797,8 +2799,10 @@
public final class PowerManager {
method @RequiresPermission("android.permission.POWER_SAVER") public int getPowerSaveModeTrigger();
+ method @RequiresPermission("android.permission.DEVICE_POWER") public void setBatteryDischargePrediction(@NonNull java.time.Duration, boolean);
method @RequiresPermission("android.permission.POWER_SAVER") public boolean setDynamicPowerSaveHint(boolean, int);
method @RequiresPermission(anyOf={"android.permission.DEVICE_POWER", "android.permission.POWER_SAVER"}) public boolean setPowerSaveModeEnabled(boolean);
+ field public static final String ACTION_ENHANCED_DISCHARGE_PREDICTION_CHANGED = "android.os.action.ENHANCED_DISCHARGE_PREDICTION_CHANGED";
field public static final int POWER_SAVE_MODE_TRIGGER_DYNAMIC = 1; // 0x1
field public static final int POWER_SAVE_MODE_TRIGGER_PERCENTAGE = 0; // 0x0
}
@@ -3236,6 +3240,7 @@
field public static final String NAMESPACE_AUTOFILL = "autofill";
field public static final String NAMESPACE_BIOMETRICS = "biometrics";
field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
+ field public static final String NAMESPACE_JOB_SCHEDULER = "jobscheduler";
field public static final String NAMESPACE_PERMISSIONS = "permissions";
field public static final String NAMESPACE_PRIVACY = "privacy";
field public static final String NAMESPACE_ROLLBACK = "rollback";
@@ -4071,7 +4076,8 @@
}
public class PhoneStateListener {
- method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber);
+ method @Deprecated public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber);
+ method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
method public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber);
field @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 268435456; // 0x10000000
field @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 536870912; // 0x20000000
@@ -5572,7 +5578,7 @@
method @BinderThread public void onTaskAppeared(@NonNull android.app.ActivityManager.RunningTaskInfo, @NonNull android.view.SurfaceControl);
method @BinderThread public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo);
method @BinderThread public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void registerOrganizer(int);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void registerOrganizer();
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setInterceptBackPressedOnTaskRoot(boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static void setLaunchRoot(int, @NonNull android.window.WindowContainerToken);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void unregisterOrganizer();
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index dc16125..13bf197 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -554,6 +554,10 @@
return NO_ERROR;
}
if (!args[0].compare(String8("section"))) {
+ if (argCount == 1) {
+ fprintf(out, "Not enough arguments for section\n");
+ return NO_ERROR;
+ }
int id = atoi(args[1]);
int idx = 0;
while (SECTION_LIST[idx] != NULL) {
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 6b335ee..e6e22ba 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -485,6 +485,9 @@
NetworkTetheringReported network_tethering_reported =
303 [(module) = "network_tethering"];
ImeTouchReported ime_touch_reported = 304 [(module) = "sysui"];
+ UIInteractionFrameInfoReported ui_interaction_frame_info_reported =
+ 305 [(module) = "framework"];
+ UIActionLatencyReported ui_action_latency_reported = 306 [(module) = "framework"];
// StatsdStats tracks platform atoms with ids upto 500.
// Update StatsdStats::kMaxPushedAtomId when atom ids here approach that value.
@@ -4004,7 +4007,7 @@
optional bool is_group_summary = 5;
// The section of the shade that the notification is in.
- // See NotificationSectionsManager.PriorityBucket.
+ // See SystemUI Notifications.proto.
enum NotificationSection {
SECTION_UNKNOWN = 0;
SECTION_HEADS_UP = 1;
@@ -4012,6 +4015,7 @@
SECTION_PEOPLE = 3;
SECTION_ALERTING = 4;
SECTION_SILENT = 5;
+ SECTION_FOREGROUND_SERVICE = 6;
}
optional NotificationSection section = 6;
}
@@ -5054,6 +5058,54 @@
optional Result result = 4;
}
+/**
+ * Event to track Jank for various system interactions.
+ *
+ * Logged from:
+ * frameworks/base/core/java/android/os/aot/FrameTracker.java
+ */
+message UIInteractionFrameInfoReported {
+ enum InteractionType {
+ UNKNOWN = 0;
+ NOTIFICATION_SHADE_SWIPE = 1;
+ }
+
+ optional InteractionType interaction_type = 1;
+
+ // Number of frames rendered during the interaction.
+ optional int64 total_frames = 2;
+
+ // Number of frames that were skipped in rendering during the interaction.
+ optional int64 missed_frames = 3;
+
+ // Maximum time it took to render a single frame during the interaction.
+ optional int64 max_frame_time_nanos = 4;
+}
+
+/**
+ * Event to track various latencies in SystemUI.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/util/LatencyTracker.java
+ */
+message UIActionLatencyReported {
+ enum ActionType {
+ UNKNOWN = 0;
+ ACTION_EXPAND_PANEL = 1;
+ ACTION_TOGGLE_RECENTS = 2;
+ ACTION_FINGERPRINT_WAKE_AND_UNLOCK = 3;
+ ACTION_CHECK_CREDENTIAL = 4;
+ ACTION_CHECK_CREDENTIAL_UNLOCKED = 5;
+ ACTION_TURN_ON_SCREEN = 6;
+ ACTION_ROTATE_SCREEN = 7;
+ ACTION_FACE_WAKE_AND_UNLOCK = 8;
+ }
+
+ optional ActionType action = 1;
+
+ optional int64 latency_millis = 2;
+}
+
//////////////////////////////////////////////////////////////////////
// Pulled atoms below this line //
//////////////////////////////////////////////////////////////////////
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
index 7a1ece9..3b65f82 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
@@ -38,9 +38,23 @@
const vector<sp<ConditionTracker>>& allConditionTrackers,
const unordered_map<int64_t, int>& conditionIdIndexMap,
vector<bool>& stack,
- vector<ConditionState>& initialConditionCache) {
+ vector<ConditionState>& conditionCache) {
VLOG("Combination predicate init() %lld", (long long)mConditionId);
if (mInitialized) {
+ // All the children are guaranteed to be initialized, but the recursion is needed to
+ // fill the conditionCache properly, since another combination condition or metric
+ // might rely on this. The recursion is needed to compute the current condition.
+
+ // Init is called instead of isConditionMet so that the ConditionKey can be filled with the
+ // default key for sliced conditions, since we do not know all indirect descendants here.
+ for (const int childIndex : mChildren) {
+ if (conditionCache[childIndex] == ConditionState::kNotEvaluated) {
+ allConditionTrackers[childIndex]->init(allConditionConfig, allConditionTrackers,
+ conditionIdIndexMap, stack, conditionCache);
+ }
+ }
+ conditionCache[mIndex] =
+ evaluateCombinationCondition(mChildren, mLogicalOperation, conditionCache);
return true;
}
@@ -74,9 +88,8 @@
return false;
}
- bool initChildSucceeded =
- childTracker->init(allConditionConfig, allConditionTrackers, conditionIdIndexMap,
- stack, initialConditionCache);
+ bool initChildSucceeded = childTracker->init(allConditionConfig, allConditionTrackers,
+ conditionIdIndexMap, stack, conditionCache);
if (!initChildSucceeded) {
ALOGW("Child initialization failed %lld ", (long long)child);
@@ -96,10 +109,10 @@
childTracker->getAtomMatchingTrackerIndex().end());
}
- mUnSlicedPartCondition = evaluateCombinationCondition(mUnSlicedChildren, mLogicalOperation,
- initialConditionCache);
- initialConditionCache[mIndex] =
- evaluateCombinationCondition(mChildren, mLogicalOperation, initialConditionCache);
+ mUnSlicedPartCondition =
+ evaluateCombinationCondition(mUnSlicedChildren, mLogicalOperation, conditionCache);
+ conditionCache[mIndex] =
+ evaluateCombinationCondition(mChildren, mLogicalOperation, conditionCache);
// unmark this node in the recursion stack.
stack[mIndex] = false;
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h
index 39ff0ab..a7fac3d 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.h
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.h
@@ -33,7 +33,7 @@
bool init(const std::vector<Predicate>& allConditionConfig,
const std::vector<sp<ConditionTracker>>& allConditionTrackers,
const std::unordered_map<int64_t, int>& conditionIdIndexMap, std::vector<bool>& stack,
- std::vector<ConditionState>& initialConditionCache) override;
+ std::vector<ConditionState>& conditionCache) override;
void evaluateCondition(const LogEvent& event,
const std::vector<MatchingState>& eventMatcherValues,
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
index 9da1af4..4e12535 100644
--- a/cmds/statsd/src/condition/ConditionTracker.h
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -46,17 +46,19 @@
// Initialize this ConditionTracker. This initialization is done recursively (DFS). It can also
// be done in the constructor, but we do it separately because (1) easy to return a bool to
// indicate whether the initialization is successful. (2) makes unit test easier.
+ // This function can also be called on config updates, in which case it does nothing other than
+ // fill the condition cache with the current condition.
// allConditionConfig: the list of all Predicate config from statsd_config.
// allConditionTrackers: the list of all ConditionTrackers (this is needed because we may also
// need to call init() on children conditions)
// conditionIdIndexMap: the mapping from condition id to its index.
// stack: a bit map to keep track which nodes have been visited on the stack in the recursion.
- // initialConditionCache: tracks initial conditions of all ConditionTrackers.
+ // conditionCache: tracks initial conditions of all ConditionTrackers. returns the
+ // current condition if called on a config update.
virtual bool init(const std::vector<Predicate>& allConditionConfig,
const std::vector<sp<ConditionTracker>>& allConditionTrackers,
const std::unordered_map<int64_t, int>& conditionIdIndexMap,
- std::vector<bool>& stack,
- std::vector<ConditionState>& initialConditionCache) = 0;
+ std::vector<bool>& stack, std::vector<ConditionState>& conditionCache) = 0;
// evaluate current condition given the new event.
// event: the new log event
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index efb4d49..f45759b 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -95,11 +95,14 @@
bool SimpleConditionTracker::init(const vector<Predicate>& allConditionConfig,
const vector<sp<ConditionTracker>>& allConditionTrackers,
const unordered_map<int64_t, int>& conditionIdIndexMap,
- vector<bool>& stack,
- vector<ConditionState>& initialConditionCache) {
+ vector<bool>& stack, vector<ConditionState>& conditionCache) {
// SimpleConditionTracker does not have dependency on other conditions, thus we just return
// if the initialization was successful.
- initialConditionCache[mIndex] = mInitialValue;
+ ConditionKey conditionKey;
+ if (mSliced) {
+ conditionKey[mConditionId] = DEFAULT_DIMENSION_KEY;
+ }
+ isConditionMet(conditionKey, allConditionTrackers, mSliced, conditionCache);
return mInitialized;
}
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h
index ea7f87b..1a9e35e 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.h
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.h
@@ -38,7 +38,7 @@
bool init(const std::vector<Predicate>& allConditionConfig,
const std::vector<sp<ConditionTracker>>& allConditionTrackers,
const std::unordered_map<int64_t, int>& conditionIdIndexMap, std::vector<bool>& stack,
- std::vector<ConditionState>& initialConditionCache) override;
+ std::vector<ConditionState>& conditionCache) override;
void evaluateCondition(const LogEvent& event,
const std::vector<MatchingState>& eventMatcherValues,
diff --git a/cmds/statsd/src/matchers/AtomMatchingTracker.h b/cmds/statsd/src/matchers/AtomMatchingTracker.h
index 5194f99..c138497 100644
--- a/cmds/statsd/src/matchers/AtomMatchingTracker.h
+++ b/cmds/statsd/src/matchers/AtomMatchingTracker.h
@@ -52,6 +52,15 @@
const std::unordered_map<int64_t, int>& matcherMap,
std::vector<bool>& stack) = 0;
+ // Update appropriate state on config updates. Primarily, all indices need to be updated.
+ // This matcher and all of its children are guaranteed to be preserved across the update.
+ // matcher: the AtomMatcher proto from the config.
+ // index: the index of this matcher in mAllAtomMatchingTrackers.
+ // atomMatchingTrackerMap: map from matcher id to index in mAllAtomMatchingTrackers
+ virtual bool onConfigUpdated(
+ const AtomMatcher& matcher, const int index,
+ const std::unordered_map<int64_t, int>& atomMatchingTrackerMap) = 0;
+
// Called when a log event comes.
// event: the log event.
// allAtomMatchingTrackers: the list of all AtomMatchingTrackers. This is needed because the log
@@ -83,7 +92,7 @@
const int64_t mId;
// Index of this AtomMatchingTracker in MetricsManager's container.
- const int mIndex;
+ int mIndex;
// Whether this AtomMatchingTracker has been properly initialized.
bool mInitialized;
diff --git a/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.cpp b/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.cpp
index 19637a4..45685ce 100644
--- a/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.cpp
+++ b/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.cpp
@@ -93,6 +93,23 @@
return true;
}
+bool CombinationAtomMatchingTracker::onConfigUpdated(
+ const AtomMatcher& matcher, const int index,
+ const unordered_map<int64_t, int>& atomMatchingTrackerMap) {
+ mIndex = index;
+ mChildren.clear();
+ AtomMatcher_Combination combinationMatcher = matcher.combination();
+ for (const int64_t child : combinationMatcher.matcher()) {
+ const auto& pair = atomMatchingTrackerMap.find(child);
+ if (pair == atomMatchingTrackerMap.end()) {
+ ALOGW("Matcher %lld not found in the config", (long long)child);
+ return false;
+ }
+ mChildren.push_back(pair->second);
+ }
+ return true;
+}
+
void CombinationAtomMatchingTracker::onLogEvent(
const LogEvent& event, const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
vector<MatchingState>& matcherResults) {
diff --git a/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.h b/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.h
index 06a4932..3160448 100644
--- a/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.h
+++ b/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.h
@@ -27,7 +27,7 @@
namespace statsd {
// Represents a AtomMatcher_Combination in the StatsdConfig.
-class CombinationAtomMatchingTracker : public virtual AtomMatchingTracker {
+class CombinationAtomMatchingTracker : public AtomMatchingTracker {
public:
CombinationAtomMatchingTracker(const int64_t& id, const int index, const uint64_t protoHash);
@@ -35,6 +35,9 @@
const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
const std::unordered_map<int64_t, int>& matcherMap, std::vector<bool>& stack);
+ bool onConfigUpdated(const AtomMatcher& matcher, const int index,
+ const std::unordered_map<int64_t, int>& atomMatchingTrackerMap) override;
+
~CombinationAtomMatchingTracker();
void onLogEvent(const LogEvent& event,
@@ -45,6 +48,8 @@
LogicalOperation mLogicalOperation;
std::vector<int> mChildren;
+
+ FRIEND_TEST(ConfigUpdateTest, TestUpdateMatchers);
};
} // namespace statsd
diff --git a/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.cpp b/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.cpp
index 86b148d..423da5b 100644
--- a/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.cpp
+++ b/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.cpp
@@ -50,6 +50,14 @@
return mInitialized;
}
+bool SimpleAtomMatchingTracker::onConfigUpdated(
+ const AtomMatcher& matcher, const int index,
+ const unordered_map<int64_t, int>& atomMatchingTrackerMap) {
+ mIndex = index;
+ // Do not need to update mMatcher since the matcher must be identical across the update.
+ return mInitialized;
+}
+
void SimpleAtomMatchingTracker::onLogEvent(
const LogEvent& event, const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
vector<MatchingState>& matcherResults) {
diff --git a/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.h b/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.h
index 49cbe09..b67e6c2 100644
--- a/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.h
+++ b/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.h
@@ -28,7 +28,7 @@
namespace os {
namespace statsd {
-class SimpleAtomMatchingTracker : public virtual AtomMatchingTracker {
+class SimpleAtomMatchingTracker : public AtomMatchingTracker {
public:
SimpleAtomMatchingTracker(const int64_t& id, const int index, const uint64_t protoHash,
const SimpleAtomMatcher& matcher, const sp<UidMap>& uidMap);
@@ -40,6 +40,9 @@
const std::unordered_map<int64_t, int>& matcherMap,
std::vector<bool>& stack) override;
+ bool onConfigUpdated(const AtomMatcher& matcher, const int index,
+ const std::unordered_map<int64_t, int>& atomMatchingTrackerMap) override;
+
void onLogEvent(const LogEvent& event,
const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
std::vector<MatchingState>& matcherResults) override;
diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
index a9ae5a4..0983dc0 100644
--- a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
+++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
@@ -148,8 +148,13 @@
(long long)id);
return false;
}
- const int oldIndex = oldAtomMatchingTrackerIt->second;
- newAtomMatchingTrackers.push_back(oldAtomMatchingTrackers[oldIndex]);
+ const sp<AtomMatchingTracker>& tracker =
+ oldAtomMatchingTrackers[oldAtomMatchingTrackerIt->second];
+ if (!tracker->onConfigUpdated(matcherProtos[i], i, newAtomMatchingTrackerMap)) {
+ ALOGW("Config update failed for matcher %lld", (long long)id);
+ return false;
+ }
+ newAtomMatchingTrackers.push_back(tracker);
break;
}
case UPDATE_REPLACE: {
diff --git a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
index daf67e9..e40fbdb 100644
--- a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
@@ -303,8 +303,7 @@
const int conditionTrackerCount = config.predicate_size();
conditionConfigs.reserve(conditionTrackerCount);
allConditionTrackers.reserve(conditionTrackerCount);
- initialConditionCache.reserve(conditionTrackerCount);
- std::fill(initialConditionCache.begin(), initialConditionCache.end(), ConditionState::kUnknown);
+ initialConditionCache.assign(conditionTrackerCount, ConditionState::kNotEvaluated);
for (int i = 0; i < conditionTrackerCount; i++) {
const Predicate& condition = config.predicate(i);
diff --git a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
index f6d3061..8c698eb 100644
--- a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
+++ b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
@@ -23,6 +23,7 @@
#include <vector>
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "src/matchers/CombinationAtomMatchingTracker.h"
#include "src/metrics/parsing_utils/metrics_manager_util.h"
#include "tests/statsd_test_util.h"
@@ -370,13 +371,40 @@
EXPECT_NE(oldAtomMatchingTrackers[oldAtomMatchingTrackerMap.at(combination2Id)],
newAtomMatchingTrackers[newAtomMatchingTrackerMap.at(combination2Id)]);
- // Validation, make sure the matchers have the proper ids. Could do more checks here.
+ // Validation, make sure the matchers have the proper ids/indices. Could do more checks here.
EXPECT_EQ(newAtomMatchingTrackers[0]->getId(), combination3Id);
+ EXPECT_EQ(newAtomMatchingTrackers[0]->mIndex, 0);
EXPECT_EQ(newAtomMatchingTrackers[1]->getId(), simple2Id);
+ EXPECT_EQ(newAtomMatchingTrackers[1]->mIndex, 1);
EXPECT_EQ(newAtomMatchingTrackers[2]->getId(), combination2Id);
+ EXPECT_EQ(newAtomMatchingTrackers[2]->mIndex, 2);
EXPECT_EQ(newAtomMatchingTrackers[3]->getId(), simple1Id);
+ EXPECT_EQ(newAtomMatchingTrackers[3]->mIndex, 3);
EXPECT_EQ(newAtomMatchingTrackers[4]->getId(), simple4Id);
+ EXPECT_EQ(newAtomMatchingTrackers[4]->mIndex, 4);
EXPECT_EQ(newAtomMatchingTrackers[5]->getId(), combination1Id);
+ EXPECT_EQ(newAtomMatchingTrackers[5]->mIndex, 5);
+
+ // Verify child indices of Combination Matchers are correct.
+ CombinationAtomMatchingTracker* combinationTracker1 =
+ static_cast<CombinationAtomMatchingTracker*>(newAtomMatchingTrackers[5].get());
+ vector<int>* childMatchers = &combinationTracker1->mChildren;
+ EXPECT_EQ(childMatchers->size(), 1);
+ EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 3), childMatchers->end());
+
+ CombinationAtomMatchingTracker* combinationTracker2 =
+ static_cast<CombinationAtomMatchingTracker*>(newAtomMatchingTrackers[2].get());
+ childMatchers = &combinationTracker2->mChildren;
+ EXPECT_EQ(childMatchers->size(), 2);
+ EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 1), childMatchers->end());
+ EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 3), childMatchers->end());
+
+ CombinationAtomMatchingTracker* combinationTracker3 =
+ static_cast<CombinationAtomMatchingTracker*>(newAtomMatchingTrackers[0].get());
+ childMatchers = &combinationTracker3->mChildren;
+ EXPECT_EQ(childMatchers->size(), 2);
+ EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 1), childMatchers->end());
+ EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 4), childMatchers->end());
}
} // namespace statsd
diff --git a/cmds/uinput/Android.bp b/cmds/uinput/Android.bp
new file mode 100644
index 0000000..0d7fed2
--- /dev/null
+++ b/cmds/uinput/Android.bp
@@ -0,0 +1,18 @@
+// Copyright 2020 The Android Open Source Project
+//
+
+java_binary {
+ name: "uinput",
+ wrapper: "uinput",
+ srcs: ["**/*.java",
+ ":uinputcommand_aidl"
+ ],
+ required: ["libuinputcommand_jni"],
+}
+
+filegroup {
+ name: "uinputcommand_aidl",
+ srcs: [
+ "src/com/android/commands/uinput/InputAbsInfo.aidl",
+ ],
+}
\ No newline at end of file
diff --git a/cmds/uinput/MODULE_LICENSE_APACHE2 b/cmds/uinput/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cmds/uinput/MODULE_LICENSE_APACHE2
diff --git a/cmds/uinput/NOTICE b/cmds/uinput/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/cmds/uinput/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2008, 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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/cmds/uinput/README.md b/cmds/uinput/README.md
new file mode 100644
index 0000000..47e1dad
--- /dev/null
+++ b/cmds/uinput/README.md
@@ -0,0 +1,166 @@
+# Usage
+## Two options to use the uinput command:
+### 1. Interactive through stdin:
+type `uinput -` into the terminal, then type/paste commands to send to the binary.
+Use Ctrl+D to signal end of stream to the binary (EOF).
+
+This mode can be also used from an app to send uinput events.
+For an example, see the cts test case at: [InputTestCase.java][2]
+
+When using another program to control uinput in interactive mode, registering a
+new input device (for example, a bluetooth joystick) should be the first step.
+After the device is added, you need to wait for the _onInputDeviceAdded_
+(see [InputDeviceListener][1]) notification before issuing commands
+to the device.
+Failure to do so will cause missed events and inconsistent behavior.
+
+### 2. Using a file as an input:
+type `uinput <filename>`, and the file will be used an an input to the binary.
+You must add a sufficient delay after a "register" command to ensure device
+is ready. The interactive mode is the recommended method of communicating
+with the uinput binary.
+
+All of the input commands should be in pseudo-JSON format as documented below.
+See examples [here][3].
+
+The file can have multiple commands one after the other (which is not strictly
+legal JSON format, as this would imply multiple root elements).
+
+## Command description
+
+1. `register`
+Register a new uinput device
+
+| Field | Type | Description |
+|:-------------:|:-------------:|:-------------------------- |
+| id | integer | Device id |
+| command | string | Must be set to "register" |
+| name | string | Device name |
+| vid | 16-bit integer| Vendor id |
+| pid | 16-bit integer| Product id |
+| bus | string | Bus that device should use |
+| configuration | int array | uinput device configuration|
+| ff_effects_max| integer | ff_effects_max value |
+| abs_info | array | ABS axes information |
+
+Device ID is used for matching the subsequent commands to a specific device
+to avoid ambiguity when multiple devices are registered.
+
+Device bus is used to determine how the uinput device is connected to the host.
+The options are "usb" and "bluetooth".
+
+Device configuration is used to configure uinput device. "type" field provides the UI_SET_*
+control code, and data is a vector of control values to be sent to uinput device, depends on
+the control code.
+
+| Field | Type | Description |
+|:-------------:|:-------------:|:-------------------------- |
+| type | integer | UI_SET_ control type |
+| data | int array | control values |
+
+Device ff_effects_max must be provided if FFBIT is set.
+
+Device abs_info fields are provided to set the device axes information. It is an array of below
+objects:
+| Field | Type | Description |
+|:-------------:|:-------------:|:-------------------------- |
+| code | integer | Axis code |
+| info | object | ABS information object |
+
+ABS information object is defined as below:
+| Field | Type | Description |
+|:-------------:|:-------------:|:-------------------------- |
+| value | integer | Latest reported value |
+| minimum | integer | Minimum value for the axis |
+| maximum | integer | Maximum value for the axis |
+| fuzz | integer | fuzz value for noise filter|
+| flat | integer | values to be discarded |
+| resolution | integer | resolution of axis |
+
+See [struct input_absinfo][4]) definitions.
+
+Example:
+```json
+
+{
+ "id": 1,
+ "command": "register",
+ "name": "Keyboard (Test)",
+ "vid": 0x18d2,
+ "pid": 0x2c42,
+ "bus": "usb",
+ "configuration":[
+ {"type":100, "data":[1, 21]}, // UI_SET_EVBIT : EV_KEY and EV_FF
+ {"type":101, "data":[11, 2, 3, 4]}, // UI_SET_KEYBIT : KEY_0 KEY_1 KEY_2 KEY_3
+ {"type":107, "data":[80]} // UI_SET_FFBIT : FF_RUMBLE
+ ],
+ "ff_effects_max" : 1,
+ "abs_info": [
+ {"code":1, "info": {"value":20, "minimum":-255,
+ "maximum":255, "fuzz":0, "flat":0, "resolution":1}
+ },
+ {"code":8, "info": {"value":-50, "minimum":-255,
+ "maximum":255, "fuzz":0, "flat":0, "resolution":1}
+ }
+ ]
+}
+
+```
+2. `delay`
+Add a delay to command processing
+
+| Field | Type | Description |
+|:-------------:|:-------------:|:-------------------------- |
+| id | integer | Device id |
+| command | string | Must be set to "delay" |
+| duration | integer | Delay in milliseconds |
+
+Example:
+```json
+{
+ "id": 1,
+ "command": "delay",
+ "duration": 10
+}
+```
+
+3. `inject`
+Send an array of uinput event packets [type, code, value] to the uinput device
+
+| Field | Type | Description |
+|:-------------:|:-------------:|:-------------------------- |
+| id | integer | Device id |
+| command | string | Must be set to "inject" |
+| events | integer array | events to inject |
+
+The "events" parameter is an array of integers, encapsulates evdev input_event type, code and value,
+see the example below.
+
+Example:
+```json
+{
+ "id": 1,
+ "command": "inject",
+ "events": [0x01, 0xb, 0x1, // EV_KEY, KEY_0, DOWN
+ 0x00, 0x00, 0x00, // EV_SYN, SYN_REPORT, 0
+ 0x01, 0x0b, 0x00, // EV_KEY, KEY_0, UP
+ 0x00, 0x00, 0x00, // EV_SYN, SYN_REPORT, 0
+ 0x01, 0x2, 0x1, // EV_KEY, KEY_1, DOWN
+ 0x00, 0x00, 0x01, // EV_SYN, SYN_REPORT, 0
+ 0x01, 0x02, 0x00, // EV_KEY, KEY_1, UP
+ 0x00, 0x00, 0x01 // EV_SYN, SYN_REPORT, 0
+ ]
+}
+```
+
+### Notes
+1. As soon as EOF is reached (either in interactive mode, or in file mode),
+the device that was created will be unregistered. There is no
+explicit command for unregistering a device.
+2. The `getevent` utility can used to print out the key events
+for debugging purposes.
+
+[1]: https://developer.android.com/reference/android/hardware/input/InputManager.InputDeviceListener.html
+[2]: ../../../../cts/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java
+[3]: ../../../../cts/tests/tests/hardware/res/raw/
+[4]: ../../../../bionic/libc/kernel/uapi/linux/input.h
diff --git a/cmds/uinput/jni/Android.bp b/cmds/uinput/jni/Android.bp
new file mode 100644
index 0000000..199bbbd
--- /dev/null
+++ b/cmds/uinput/jni/Android.bp
@@ -0,0 +1,23 @@
+cc_library_shared {
+ name: "libuinputcommand_jni",
+
+ srcs: [
+ "com_android_commands_uinput_Device.cpp",
+ ":uinputcommand_aidl",
+ ],
+
+ shared_libs: [
+ "libandroid",
+ "libandroid_runtime_lazy",
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libnativehelper",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+}
diff --git a/cmds/uinput/jni/com_android_commands_uinput_Device.cpp b/cmds/uinput/jni/com_android_commands_uinput_Device.cpp
new file mode 100644
index 0000000..06fa2aa
--- /dev/null
+++ b/cmds/uinput/jni/com_android_commands_uinput_Device.cpp
@@ -0,0 +1,351 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "UinputCommandDevice"
+
+#include <linux/uinput.h>
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <time.h>
+#include <unistd.h>
+#include <algorithm>
+#include <array>
+#include <cstdio>
+#include <cstring>
+#include <iterator>
+#include <memory>
+#include <vector>
+
+#include <android/looper.h>
+#include <android_os_Parcel.h>
+#include <jni.h>
+#include <log/log.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/ScopedUtfChars.h>
+
+#include <android-base/stringprintf.h>
+
+#include "com_android_commands_uinput_Device.h"
+
+namespace android {
+namespace uinput {
+
+using src::com::android::commands::uinput::InputAbsInfo;
+
+static constexpr const char* UINPUT_PATH = "/dev/uinput";
+
+static struct {
+ jmethodID onDeviceConfigure;
+ jmethodID onDeviceVibrating;
+ jmethodID onDeviceError;
+} gDeviceCallbackClassInfo;
+
+static void checkAndClearException(JNIEnv* env, const char* methodName) {
+ if (env->ExceptionCheck()) {
+ ALOGE("An exception was thrown by callback '%s'.", methodName);
+ env->ExceptionClear();
+ }
+}
+
+DeviceCallback::DeviceCallback(JNIEnv* env, jobject callback)
+ : mCallbackObject(env->NewGlobalRef(callback)) {
+ env->GetJavaVM(&mJavaVM);
+}
+
+DeviceCallback::~DeviceCallback() {
+ JNIEnv* env = getJNIEnv();
+ env->DeleteGlobalRef(mCallbackObject);
+}
+
+void DeviceCallback::onDeviceError() {
+ JNIEnv* env = getJNIEnv();
+ env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceError);
+ checkAndClearException(env, "onDeviceError");
+}
+
+void DeviceCallback::onDeviceConfigure(int handle) {
+ JNIEnv* env = getJNIEnv();
+ env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceConfigure, handle);
+ checkAndClearException(env, "onDeviceConfigure");
+}
+
+void DeviceCallback::onDeviceVibrating(int value) {
+ JNIEnv* env = getJNIEnv();
+ env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceVibrating, value);
+ checkAndClearException(env, "onDeviceVibrating");
+}
+
+JNIEnv* DeviceCallback::getJNIEnv() {
+ JNIEnv* env;
+ mJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
+ return env;
+}
+
+std::unique_ptr<UinputDevice> UinputDevice::open(int32_t id, const char* name, int32_t vid,
+ int32_t pid, uint16_t bus, uint32_t ffEffectsMax,
+ std::unique_ptr<DeviceCallback> callback) {
+ android::base::unique_fd fd(::open(UINPUT_PATH, O_RDWR | O_NONBLOCK | O_CLOEXEC));
+ if (!fd.ok()) {
+ ALOGE("Failed to open uinput: %s", strerror(errno));
+ return nullptr;
+ }
+
+ int32_t version;
+ ::ioctl(fd, UI_GET_VERSION, &version);
+ if (version < 5) {
+ ALOGE("Kernel version %d older than 5 is not supported", version);
+ return nullptr;
+ }
+
+ struct uinput_setup setupDescriptor;
+ memset(&setupDescriptor, 0, sizeof(setupDescriptor));
+ strlcpy(setupDescriptor.name, name, UINPUT_MAX_NAME_SIZE);
+ setupDescriptor.id.version = 1;
+ setupDescriptor.id.bustype = bus;
+ setupDescriptor.id.vendor = vid;
+ setupDescriptor.id.product = pid;
+ setupDescriptor.ff_effects_max = ffEffectsMax;
+
+ // Request device configuration.
+ callback->onDeviceConfigure(fd.get());
+
+ // register the input device
+ if (::ioctl(fd, UI_DEV_SETUP, &setupDescriptor)) {
+ ALOGE("UI_DEV_SETUP ioctl failed on fd %d: %s.", fd.get(), strerror(errno));
+ return nullptr;
+ }
+
+ if (::ioctl(fd, UI_DEV_CREATE) != 0) {
+ ALOGE("Unable to create uinput device: %s.", strerror(errno));
+ return nullptr;
+ }
+
+ // using 'new' to access non-public constructor
+ return std::unique_ptr<UinputDevice>(new UinputDevice(id, std::move(fd), std::move(callback)));
+}
+
+UinputDevice::UinputDevice(int32_t id, android::base::unique_fd fd,
+ std::unique_ptr<DeviceCallback> callback)
+ : mId(id), mFd(std::move(fd)), mDeviceCallback(std::move(callback)) {
+ ALooper* aLooper = ALooper_forThread();
+ if (aLooper == nullptr) {
+ ALOGE("Could not get ALooper, ALooper_forThread returned NULL");
+ aLooper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
+ }
+ ALooper_addFd(
+ aLooper, mFd, 0, ALOOPER_EVENT_INPUT,
+ [](int, int events, void* data) {
+ UinputDevice* d = reinterpret_cast<UinputDevice*>(data);
+ return d->handleEvents(events);
+ },
+ reinterpret_cast<void*>(this));
+ ALOGI("uinput device %d created: version = %d, fd = %d", mId, UINPUT_VERSION, mFd.get());
+}
+
+UinputDevice::~UinputDevice() {
+ ::ioctl(mFd, UI_DEV_DESTROY);
+}
+
+void UinputDevice::injectEvent(uint16_t type, uint16_t code, int32_t value) {
+ struct input_event event = {};
+ event.type = type;
+ event.code = code;
+ event.value = value;
+ timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ TIMESPEC_TO_TIMEVAL(&event.time, &ts);
+
+ if (::write(mFd, &event, sizeof(input_event)) < 0) {
+ ALOGE("Could not write event %" PRIu16 " %" PRIu16 " with value %" PRId32 " : %s", type,
+ code, value, strerror(errno));
+ }
+}
+
+int UinputDevice::handleEvents(int events) {
+ if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
+ ALOGE("uinput node was closed or an error occurred. events=0x%x", events);
+ mDeviceCallback->onDeviceError();
+ return 0;
+ }
+ struct input_event ev;
+ ssize_t ret = ::read(mFd, &ev, sizeof(ev));
+ if (ret < 0) {
+ ALOGE("Failed to read from uinput node: %s", strerror(errno));
+ mDeviceCallback->onDeviceError();
+ return 0;
+ }
+
+ switch (ev.type) {
+ case EV_UINPUT: {
+ if (ev.code == UI_FF_UPLOAD) {
+ struct uinput_ff_upload ff_upload;
+ ff_upload.request_id = ev.value;
+ ::ioctl(mFd, UI_BEGIN_FF_UPLOAD, &ff_upload);
+ ff_upload.retval = 0;
+ ::ioctl(mFd, UI_END_FF_UPLOAD, &ff_upload);
+ } else if (ev.code == UI_FF_ERASE) {
+ struct uinput_ff_erase ff_erase;
+ ff_erase.request_id = ev.value;
+ ::ioctl(mFd, UI_BEGIN_FF_ERASE, &ff_erase);
+ ff_erase.retval = 0;
+ ::ioctl(mFd, UI_END_FF_ERASE, &ff_erase);
+ }
+ break;
+ }
+ case EV_FF: {
+ ALOGI("EV_FF effect = %d value = %d", ev.code, ev.value);
+ mDeviceCallback->onDeviceVibrating(ev.value);
+ break;
+ }
+ default: {
+ ALOGI("Unhandled event type: %" PRIu32, ev.type);
+ break;
+ }
+ }
+
+ return 1;
+}
+
+} // namespace uinput
+
+std::vector<int32_t> toVector(JNIEnv* env, jintArray javaArray) {
+ std::vector<int32_t> data;
+ if (javaArray == nullptr) {
+ return data;
+ }
+
+ ScopedIntArrayRO scopedArray(env, javaArray);
+ size_t size = scopedArray.size();
+ data.reserve(size);
+ for (size_t i = 0; i < size; i++) {
+ data.push_back(static_cast<int32_t>(scopedArray[i]));
+ }
+ return data;
+}
+
+static jlong openUinputDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id, jint vid,
+ jint pid, jint bus, jint ffEffectsMax, jobject callback) {
+ ScopedUtfChars name(env, rawName);
+ if (name.c_str() == nullptr) {
+ return 0;
+ }
+
+ std::unique_ptr<uinput::DeviceCallback> cb =
+ std::make_unique<uinput::DeviceCallback>(env, callback);
+
+ std::unique_ptr<uinput::UinputDevice> d =
+ uinput::UinputDevice::open(id, name.c_str(), vid, pid, bus, ffEffectsMax,
+ std::move(cb));
+ return reinterpret_cast<jlong>(d.release());
+}
+
+static void closeUinputDevice(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) {
+ uinput::UinputDevice* d = reinterpret_cast<uinput::UinputDevice*>(ptr);
+ if (d != nullptr) {
+ delete d;
+ }
+}
+
+static void injectEvent(JNIEnv* /* env */, jclass /* clazz */, jlong ptr, jint type, jint code,
+ jint value) {
+ uinput::UinputDevice* d = reinterpret_cast<uinput::UinputDevice*>(ptr);
+ if (d != nullptr) {
+ d->injectEvent(static_cast<uint16_t>(type), static_cast<uint16_t>(code),
+ static_cast<int32_t>(value));
+ } else {
+ ALOGE("Could not inject event, Device* is null!");
+ }
+}
+
+static void configure(JNIEnv* env, jclass /* clazz */, jint handle, jint code,
+ jintArray rawConfigs) {
+ std::vector<int32_t> configs = toVector(env, rawConfigs);
+ // Configure uinput device, with user specified code and value.
+ for (auto& config : configs) {
+ ::ioctl(static_cast<int>(handle), _IOW(UINPUT_IOCTL_BASE, code, int), config);
+ }
+}
+
+static void setAbsInfo(JNIEnv* env, jclass /* clazz */, jint handle, jint axisCode,
+ jobject infoObj) {
+ Parcel* parcel = parcelForJavaObject(env, infoObj);
+ uinput::InputAbsInfo info;
+
+ info.readFromParcel(parcel);
+
+ struct uinput_abs_setup absSetup;
+ absSetup.code = axisCode;
+ absSetup.absinfo.maximum = info.maximum;
+ absSetup.absinfo.minimum = info.minimum;
+ absSetup.absinfo.value = info.value;
+ absSetup.absinfo.fuzz = info.fuzz;
+ absSetup.absinfo.flat = info.flat;
+ absSetup.absinfo.resolution = info.resolution;
+
+ ::ioctl(static_cast<int>(handle), UI_ABS_SETUP, &absSetup);
+}
+
+static JNINativeMethod sMethods[] = {
+ {"nativeOpenUinputDevice",
+ "(Ljava/lang/String;IIIII"
+ "Lcom/android/commands/uinput/Device$DeviceCallback;)J",
+ reinterpret_cast<void*>(openUinputDevice)},
+ {"nativeInjectEvent", "(JIII)V", reinterpret_cast<void*>(injectEvent)},
+ {"nativeConfigure", "(II[I)V", reinterpret_cast<void*>(configure)},
+ {"nativeSetAbsInfo", "(IILandroid/os/Parcel;)V", reinterpret_cast<void*>(setAbsInfo)},
+ {"nativeCloseUinputDevice", "(J)V", reinterpret_cast<void*>(closeUinputDevice)},
+};
+
+int register_com_android_commands_uinput_Device(JNIEnv* env) {
+ jclass clazz = env->FindClass("com/android/commands/uinput/Device$DeviceCallback");
+ if (clazz == nullptr) {
+ ALOGE("Unable to find class 'DeviceCallback'");
+ return JNI_ERR;
+ }
+
+ uinput::gDeviceCallbackClassInfo.onDeviceConfigure =
+ env->GetMethodID(clazz, "onDeviceConfigure", "(I)V");
+ uinput::gDeviceCallbackClassInfo.onDeviceVibrating =
+ env->GetMethodID(clazz, "onDeviceVibrating", "(I)V");
+ uinput::gDeviceCallbackClassInfo.onDeviceError =
+ env->GetMethodID(clazz, "onDeviceError", "()V");
+ if (uinput::gDeviceCallbackClassInfo.onDeviceConfigure == nullptr ||
+ uinput::gDeviceCallbackClassInfo.onDeviceError == nullptr ||
+ uinput::gDeviceCallbackClassInfo.onDeviceVibrating == nullptr) {
+ ALOGE("Unable to obtain onDeviceConfigure or onDeviceError or onDeviceVibrating methods");
+ return JNI_ERR;
+ }
+ return jniRegisterNativeMethods(env, "com/android/commands/uinput/Device", sMethods,
+ NELEM(sMethods));
+}
+
+} // namespace android
+
+jint JNI_OnLoad(JavaVM* jvm, void*) {
+ JNIEnv* env = nullptr;
+ if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6)) {
+ return JNI_ERR;
+ }
+
+ if (android::register_com_android_commands_uinput_Device(env) < 0) {
+ return JNI_ERR;
+ }
+
+ return JNI_VERSION_1_6;
+}
diff --git a/cmds/uinput/jni/com_android_commands_uinput_Device.h b/cmds/uinput/jni/com_android_commands_uinput_Device.h
new file mode 100644
index 0000000..5a9a06c
--- /dev/null
+++ b/cmds/uinput/jni/com_android_commands_uinput_Device.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <memory>
+#include <vector>
+
+#include <jni.h>
+#include <linux/input.h>
+
+#include <android-base/unique_fd.h>
+#include "src/com/android/commands/uinput/InputAbsInfo.h"
+
+namespace android {
+namespace uinput {
+
+class DeviceCallback {
+public:
+ DeviceCallback(JNIEnv* env, jobject callback);
+ ~DeviceCallback();
+
+ void onDeviceOpen();
+ void onDeviceGetReport(uint32_t requestId, uint8_t reportId);
+ void onDeviceOutput(const std::vector<uint8_t>& data);
+ void onDeviceConfigure(int handle);
+ void onDeviceVibrating(int value);
+ void onDeviceError();
+
+private:
+ JNIEnv* getJNIEnv();
+ jobject mCallbackObject;
+ JavaVM* mJavaVM;
+};
+
+class UinputDevice {
+public:
+ static std::unique_ptr<UinputDevice> open(int32_t id, const char* name, int32_t vid,
+ int32_t pid, uint16_t bus, uint32_t ff_effects_max,
+ std::unique_ptr<DeviceCallback> callback);
+
+ virtual ~UinputDevice();
+
+ void injectEvent(uint16_t type, uint16_t code, int32_t value);
+ int handleEvents(int events);
+
+private:
+ UinputDevice(int32_t id, android::base::unique_fd fd, std::unique_ptr<DeviceCallback> callback);
+
+ int32_t mId;
+ android::base::unique_fd mFd;
+ std::unique_ptr<DeviceCallback> mDeviceCallback;
+};
+
+} // namespace uinput
+} // namespace android
diff --git a/cmds/uinput/src/com/android/commands/uinput/Device.java b/cmds/uinput/src/com/android/commands/uinput/Device.java
new file mode 100644
index 0000000..62bee7b
--- /dev/null
+++ b/cmds/uinput/src/com/android/commands/uinput/Device.java
@@ -0,0 +1,232 @@
+/*
+ * 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.commands.uinput;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Parcel;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.os.SomeArgs;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import src.com.android.commands.uinput.InputAbsInfo;
+
+/**
+ * Device class defines uinput device interfaces of device operations, for device open, close,
+ * configuration, events injection.
+ */
+public class Device {
+ private static final String TAG = "UinputDevice";
+
+ private static final int MSG_OPEN_UINPUT_DEVICE = 1;
+ private static final int MSG_CLOSE_UINPUT_DEVICE = 2;
+ private static final int MSG_INJECT_EVENT = 3;
+
+ private final int mId;
+ private final HandlerThread mThread;
+ private final DeviceHandler mHandler;
+ // mConfiguration is sparse array of ioctl code and array of values.
+ private final SparseArray<int[]> mConfiguration;
+ private final SparseArray<InputAbsInfo> mAbsInfo;
+ private final OutputStream mOutputStream;
+ private final Object mCond = new Object();
+ private long mTimeToSend;
+
+ static {
+ System.loadLibrary("uinputcommand_jni");
+ }
+
+ private static native long nativeOpenUinputDevice(String name, int id, int vid, int pid,
+ int bus, int ffEffectsMax, DeviceCallback callback);
+ private static native void nativeCloseUinputDevice(long ptr);
+ private static native void nativeInjectEvent(long ptr, int type, int code, int value);
+ private static native void nativeConfigure(int handle, int code, int[] configs);
+ private static native void nativeSetAbsInfo(int handle, int axisCode, Parcel axisParcel);
+
+ public Device(int id, String name, int vid, int pid, int bus,
+ SparseArray<int[]> configuration, int ffEffectsMax,
+ SparseArray<InputAbsInfo> absInfo) {
+ mId = id;
+ mThread = new HandlerThread("UinputDeviceHandler");
+ mThread.start();
+ mHandler = new DeviceHandler(mThread.getLooper());
+ mConfiguration = configuration;
+ mAbsInfo = absInfo;
+ mOutputStream = System.out;
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = id;
+ args.argi2 = vid;
+ args.argi3 = pid;
+ args.argi4 = bus;
+ args.argi5 = ffEffectsMax;
+ if (name != null) {
+ args.arg1 = name;
+ } else {
+ args.arg1 = id + ":" + vid + ":" + pid;
+ }
+
+ mHandler.obtainMessage(MSG_OPEN_UINPUT_DEVICE, args).sendToTarget();
+ mTimeToSend = SystemClock.uptimeMillis();
+ }
+
+ /**
+ * Inject uinput events to device
+ *
+ * @param events Array of raw uinput events.
+ */
+ public void injectEvent(int[] events) {
+ // if two messages are sent at identical time, they will be processed in order received
+ Message msg = mHandler.obtainMessage(MSG_INJECT_EVENT, events);
+ mHandler.sendMessageAtTime(msg, mTimeToSend);
+ }
+
+ /**
+ * Impose a delay to the device for execution.
+ *
+ * @param delay Time to delay in unit of milliseconds.
+ */
+ public void addDelay(int delay) {
+ mTimeToSend = Math.max(SystemClock.uptimeMillis(), mTimeToSend) + delay;
+ }
+
+ /**
+ * Close an uinput device.
+ *
+ */
+ public void close() {
+ Message msg = mHandler.obtainMessage(MSG_CLOSE_UINPUT_DEVICE);
+ mHandler.sendMessageAtTime(msg, Math.max(SystemClock.uptimeMillis(), mTimeToSend) + 1);
+ try {
+ synchronized (mCond) {
+ mCond.wait();
+ }
+ } catch (InterruptedException ignore) {
+ }
+ }
+
+ private class DeviceHandler extends Handler {
+ private long mPtr;
+ private int mBarrierToken;
+
+ DeviceHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_OPEN_UINPUT_DEVICE:
+ SomeArgs args = (SomeArgs) msg.obj;
+ mPtr = nativeOpenUinputDevice((String) args.arg1, args.argi1, args.argi2,
+ args.argi3, args.argi4, args.argi5,
+ new DeviceCallback());
+ break;
+ case MSG_INJECT_EVENT:
+ if (mPtr != 0) {
+ int[] events = (int[]) msg.obj;
+ for (int pos = 0; pos + 2 < events.length; pos += 3) {
+ nativeInjectEvent(mPtr, events[pos], events[pos + 1], events[pos + 2]);
+ }
+ }
+ break;
+ case MSG_CLOSE_UINPUT_DEVICE:
+ if (mPtr != 0) {
+ nativeCloseUinputDevice(mPtr);
+ getLooper().quitSafely();
+ mPtr = 0;
+ } else {
+ Log.e(TAG, "Tried to close already closed device.");
+ }
+ Log.i(TAG, "Device closed.");
+ synchronized (mCond) {
+ mCond.notify();
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown device message");
+ }
+ }
+
+ public void pauseEvents() {
+ mBarrierToken = getLooper().myQueue().postSyncBarrier();
+ }
+
+ public void resumeEvents() {
+ getLooper().myQueue().removeSyncBarrier(mBarrierToken);
+ mBarrierToken = 0;
+ }
+ }
+
+ private class DeviceCallback {
+ public void onDeviceOpen() {
+ mHandler.resumeEvents();
+ }
+
+ public void onDeviceConfigure(int handle) {
+ for (int i = 0; i < mConfiguration.size(); i++) {
+ int key = mConfiguration.keyAt(i);
+ int[] data = mConfiguration.get(key);
+ nativeConfigure(handle, key, data);
+ }
+
+ if (mAbsInfo != null) {
+ for (int i = 0; i < mAbsInfo.size(); i++) {
+ int key = mAbsInfo.keyAt(i);
+ InputAbsInfo info = mAbsInfo.get(key);
+ Parcel parcel = Parcel.obtain();
+ info.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ nativeSetAbsInfo(handle, key, parcel);
+ }
+ }
+ }
+
+ public void onDeviceVibrating(int value) {
+ JSONObject json = new JSONObject();
+ try {
+ json.put("reason", "vibrating");
+ json.put("id", mId);
+ json.put("status", value);
+ } catch (JSONException e) {
+ throw new RuntimeException("Could not create JSON object ", e);
+ }
+ try {
+ mOutputStream.write(json.toString().getBytes());
+ mOutputStream.flush();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void onDeviceError() {
+ Log.e(TAG, "Device error occurred, closing /dev/uinput");
+ Message msg = mHandler.obtainMessage(MSG_CLOSE_UINPUT_DEVICE);
+ msg.setAsynchronous(true);
+ msg.sendToTarget();
+ }
+ }
+}
diff --git a/cmds/uinput/src/com/android/commands/uinput/Event.java b/cmds/uinput/src/com/android/commands/uinput/Event.java
new file mode 100644
index 0000000..c4ba050
--- /dev/null
+++ b/cmds/uinput/src/com/android/commands/uinput/Event.java
@@ -0,0 +1,454 @@
+/*
+ * 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.commands.uinput;
+
+import android.util.JsonReader;
+import android.util.JsonToken;
+import android.util.Log;
+import android.util.SparseArray;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import src.com.android.commands.uinput.InputAbsInfo;
+
+/**
+ * An event is a JSON file defined action event to instruct uinput to perform a command like
+ * device registration or uinput events injection.
+ */
+public class Event {
+ private static final String TAG = "UinputEvent";
+
+ public static final String COMMAND_REGISTER = "register";
+ public static final String COMMAND_DELAY = "delay";
+ public static final String COMMAND_INJECT = "inject";
+ private static final int ABS_CNT = 64;
+
+ // These constants come from "include/uapi/linux/input.h" in the kernel
+ enum Bus {
+ USB(0x03), BLUETOOTH(0x05);
+ private final int mValue;
+
+ Bus(int value) {
+ mValue = value;
+ }
+
+ int getValue() {
+ return mValue;
+ }
+ }
+
+ private int mId;
+ private String mCommand;
+ private String mName;
+ private int mVid;
+ private int mPid;
+ private Bus mBus;
+ private int[] mInjections;
+ private SparseArray<int[]> mConfiguration;
+ private int mDuration;
+ private int mFfEffectsMax = 0;
+ private SparseArray<InputAbsInfo> mAbsInfo;
+
+ public int getId() {
+ return mId;
+ }
+
+ public String getCommand() {
+ return mCommand;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public int getVendorId() {
+ return mVid;
+ }
+
+ public int getProductId() {
+ return mPid;
+ }
+
+ public int getBus() {
+ return mBus.getValue();
+ }
+
+ public int[] getInjections() {
+ return mInjections;
+ }
+
+ public SparseArray<int[]> getConfiguration() {
+ return mConfiguration;
+ }
+
+ public int getDuration() {
+ return mDuration;
+ }
+
+ public int getFfEffectsMax() {
+ return mFfEffectsMax;
+ }
+
+ public SparseArray<InputAbsInfo> getAbsInfo() {
+ return mAbsInfo;
+ }
+
+ /**
+ * Convert an event to String.
+ */
+ public String toString() {
+ return "Event{id=" + mId
+ + ", command=" + mCommand
+ + ", name=" + mName
+ + ", vid=" + mVid
+ + ", pid=" + mPid
+ + ", bus=" + mBus
+ + ", events=" + Arrays.toString(mInjections)
+ + ", configuration=" + mConfiguration
+ + ", duration=" + mDuration
+ + ", ff_effects_max=" + mFfEffectsMax
+ + "}";
+ }
+
+ private static class Builder {
+ private Event mEvent;
+
+ Builder() {
+ mEvent = new Event();
+ }
+
+ public void setId(int id) {
+ mEvent.mId = id;
+ }
+
+ private void setCommand(String command) {
+ mEvent.mCommand = command;
+ }
+
+ public void setName(String name) {
+ mEvent.mName = name;
+ }
+
+ public void setInjections(int[] events) {
+ mEvent.mInjections = events;
+ }
+
+ public void setConfiguration(SparseArray<int[]> configuration) {
+ mEvent.mConfiguration = configuration;
+ }
+
+ public void setVid(int vid) {
+ mEvent.mVid = vid;
+ }
+
+ public void setPid(int pid) {
+ mEvent.mPid = pid;
+ }
+
+ public void setBus(Bus bus) {
+ mEvent.mBus = bus;
+ }
+
+ public void setDuration(int duration) {
+ mEvent.mDuration = duration;
+ }
+
+ public void setFfEffectsMax(int ffEffectsMax) {
+ mEvent.mFfEffectsMax = ffEffectsMax;
+ }
+
+ public void setAbsInfo(SparseArray<InputAbsInfo> absInfo) {
+ mEvent.mAbsInfo = absInfo;
+ }
+
+ public Event build() {
+ if (mEvent.mId == -1) {
+ throw new IllegalStateException("No event id");
+ } else if (mEvent.mCommand == null) {
+ throw new IllegalStateException("Event does not contain a command");
+ }
+ if (COMMAND_REGISTER.equals(mEvent.mCommand)) {
+ if (mEvent.mConfiguration == null) {
+ throw new IllegalStateException(
+ "Device registration is missing configuration");
+ }
+ } else if (COMMAND_DELAY.equals(mEvent.mCommand)) {
+ if (mEvent.mDuration <= 0) {
+ throw new IllegalStateException("Delay has missing or invalid duration");
+ }
+ } else if (COMMAND_INJECT.equals(mEvent.mCommand)) {
+ if (mEvent.mInjections == null) {
+ throw new IllegalStateException("Inject command is missing injection data");
+ }
+ } else {
+ throw new IllegalStateException("Unknown command " + mEvent.mCommand);
+ }
+ return mEvent;
+ }
+ }
+
+ /**
+ * A class that parses the JSON event format from an input stream to build device events.
+ */
+ public static class Reader {
+ private JsonReader mReader;
+
+ public Reader(InputStreamReader in) {
+ mReader = new JsonReader(in);
+ mReader.setLenient(true);
+ }
+
+ /**
+ * Get next event entry from JSON file reader.
+ */
+ public Event getNextEvent() throws IOException {
+ Event e = null;
+ while (e == null && mReader.peek() != JsonToken.END_DOCUMENT) {
+ Event.Builder eb = new Event.Builder();
+ try {
+ mReader.beginObject();
+ while (mReader.hasNext()) {
+ String name = mReader.nextName();
+ switch (name) {
+ case "id":
+ eb.setId(readInt());
+ break;
+ case "command":
+ eb.setCommand(mReader.nextString());
+ break;
+ case "name":
+ eb.setName(mReader.nextString());
+ break;
+ case "vid":
+ eb.setVid(readInt());
+ break;
+ case "pid":
+ eb.setPid(readInt());
+ break;
+ case "bus":
+ eb.setBus(readBus());
+ break;
+ case "events":
+ int[] injections = readIntList().stream()
+ .mapToInt(Integer::intValue).toArray();
+ eb.setInjections(injections);
+ break;
+ case "configuration":
+ eb.setConfiguration(readConfiguration());
+ break;
+ case "ff_effects_max":
+ eb.setFfEffectsMax(readInt());
+ break;
+ case "abs_info":
+ eb.setAbsInfo(readAbsInfoArray());
+ break;
+ case "duration":
+ eb.setDuration(readInt());
+ break;
+ default:
+ mReader.skipValue();
+ }
+ }
+ mReader.endObject();
+ } catch (IllegalStateException ex) {
+ error("Error reading in object, ignoring.", ex);
+ consumeRemainingElements();
+ mReader.endObject();
+ continue;
+ }
+ e = eb.build();
+ }
+
+ return e;
+ }
+
+ private ArrayList<Integer> readIntList() throws IOException {
+ ArrayList<Integer> data = new ArrayList<Integer>();
+ try {
+ mReader.beginArray();
+ while (mReader.hasNext()) {
+ data.add(Integer.decode(mReader.nextString()));
+ }
+ mReader.endArray();
+ } catch (IllegalStateException | NumberFormatException e) {
+ consumeRemainingElements();
+ mReader.endArray();
+ throw new IllegalStateException("Encountered malformed data.", e);
+ }
+ return data;
+ }
+
+ private byte[] readData() throws IOException {
+ ArrayList<Integer> data = readIntList();
+ byte[] rawData = new byte[data.size()];
+ for (int i = 0; i < data.size(); i++) {
+ int d = data.get(i);
+ if ((d & 0xFF) != d) {
+ throw new IllegalStateException("Invalid data, all values must be byte-sized");
+ }
+ rawData[i] = (byte) d;
+ }
+ return rawData;
+ }
+
+ private int readInt() throws IOException {
+ String val = mReader.nextString();
+ return Integer.decode(val);
+ }
+
+ private Bus readBus() throws IOException {
+ String val = mReader.nextString();
+ return Bus.valueOf(val.toUpperCase());
+ }
+
+ private SparseArray<int[]> readConfiguration()
+ throws IllegalStateException, IOException {
+ SparseArray<int[]> configuration = new SparseArray<>();
+ try {
+ mReader.beginArray();
+ while (mReader.hasNext()) {
+ int type = 0;
+ int[] data = null;
+ mReader.beginObject();
+ while (mReader.hasNext()) {
+ String name = mReader.nextName();
+ switch (name) {
+ case "type":
+ type = readInt();
+ break;
+ case "data":
+ data = readIntList().stream()
+ .mapToInt(Integer::intValue).toArray();
+ break;
+ default:
+ consumeRemainingElements();
+ mReader.endObject();
+ throw new IllegalStateException(
+ "Invalid key in device configuration: " + name);
+ }
+ }
+ mReader.endObject();
+ if (data != null) {
+ configuration.put(type, data);
+ }
+ }
+ mReader.endArray();
+ } catch (IllegalStateException | NumberFormatException e) {
+ consumeRemainingElements();
+ mReader.endArray();
+ throw new IllegalStateException("Encountered malformed data.", e);
+ }
+ return configuration;
+ }
+
+ private InputAbsInfo readAbsInfo() throws IllegalStateException, IOException {
+ InputAbsInfo absInfo = new InputAbsInfo();
+ try {
+ mReader.beginObject();
+ while (mReader.hasNext()) {
+ String name = mReader.nextName();
+ switch (name) {
+ case "value":
+ absInfo.value = readInt();
+ break;
+ case "minimum":
+ absInfo.minimum = readInt();
+ break;
+ case "maximum":
+ absInfo.maximum = readInt();
+ break;
+ case "fuzz":
+ absInfo.fuzz = readInt();
+ break;
+ case "flat":
+ absInfo.flat = readInt();
+ break;
+ case "resolution":
+ absInfo.resolution = readInt();
+ break;
+ default:
+ consumeRemainingElements();
+ mReader.endObject();
+ throw new IllegalStateException("Invalid key in abs info: " + name);
+ }
+ }
+ mReader.endObject();
+ } catch (IllegalStateException | NumberFormatException e) {
+ consumeRemainingElements();
+ mReader.endObject();
+ throw new IllegalStateException("Encountered malformed data.", e);
+ }
+ return absInfo;
+ }
+
+ private SparseArray<InputAbsInfo> readAbsInfoArray()
+ throws IllegalStateException, IOException {
+ SparseArray<InputAbsInfo> infoArray = new SparseArray<>();
+ try {
+ mReader.beginArray();
+ while (mReader.hasNext()) {
+ int type = 0;
+ InputAbsInfo absInfo = null;
+ mReader.beginObject();
+ while (mReader.hasNext()) {
+ String name = mReader.nextName();
+ switch (name) {
+ case "code":
+ type = readInt();
+ break;
+ case "info":
+ absInfo = readAbsInfo();
+ break;
+ default:
+ consumeRemainingElements();
+ mReader.endObject();
+ throw new IllegalStateException("Invalid key in abs info array: "
+ + name);
+ }
+ }
+ mReader.endObject();
+ if (absInfo != null) {
+ infoArray.put(type, absInfo);
+ }
+ }
+ mReader.endArray();
+ } catch (IllegalStateException | NumberFormatException e) {
+ consumeRemainingElements();
+ mReader.endArray();
+ throw new IllegalStateException("Encountered malformed data.", e);
+ }
+ return infoArray;
+ }
+
+ private void consumeRemainingElements() throws IOException {
+ while (mReader.hasNext()) {
+ mReader.skipValue();
+ }
+ }
+ }
+
+ private static void error(String msg, Exception e) {
+ System.out.println(msg);
+ Log.e(TAG, msg);
+ if (e != null) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ }
+ }
+}
diff --git a/cmds/uinput/src/com/android/commands/uinput/InputAbsInfo.aidl b/cmds/uinput/src/com/android/commands/uinput/InputAbsInfo.aidl
new file mode 100644
index 0000000..88c57f2
--- /dev/null
+++ b/cmds/uinput/src/com/android/commands/uinput/InputAbsInfo.aidl
@@ -0,0 +1,26 @@
+/*
+**
+** 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 src.com.android.commands.uinput;
+
+parcelable InputAbsInfo {
+ int value;
+ int minimum;
+ int maximum;
+ int fuzz;
+ int flat;
+ int resolution;
+}
diff --git a/cmds/uinput/src/com/android/commands/uinput/Uinput.java b/cmds/uinput/src/com/android/commands/uinput/Uinput.java
new file mode 100644
index 0000000..f7601a2
--- /dev/null
+++ b/cmds/uinput/src/com/android/commands/uinput/Uinput.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.commands.uinput;
+
+import android.util.Log;
+import android.util.SparseArray;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Uinput class encapsulates execution of "uinput" command. It parses the provided input stream
+ * parameters as JSON file format, extract event entries and perform commands of event entries.
+ * Uinput device will be created when performing registration command and used to inject events.
+ */
+public class Uinput {
+ private static final String TAG = "UINPUT";
+
+ private final Event.Reader mReader;
+ private final SparseArray<Device> mDevices;
+
+ private static void usage() {
+ error("Usage: uinput [FILE]");
+ }
+
+ /**
+ * Commandline "uinput" binary main entry
+ */
+ public static void main(String[] args) {
+ if (args.length != 1) {
+ usage();
+ System.exit(1);
+ }
+
+ InputStream stream = null;
+ try {
+ if (args[0].equals("-")) {
+ stream = System.in;
+ } else {
+ File f = new File(args[0]);
+ stream = new FileInputStream(f);
+ }
+ (new Uinput(stream)).run();
+ } catch (Exception e) {
+ error("Uinput injection failed.", e);
+ System.exit(1);
+ } finally {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ private Uinput(InputStream in) {
+ mDevices = new SparseArray<Device>();
+ try {
+ mReader = new Event.Reader(new InputStreamReader(in, "UTF-8"));
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void run() {
+ try {
+ Event e = null;
+ while ((e = mReader.getNextEvent()) != null) {
+ process(e);
+ }
+ } catch (IOException ex) {
+ error("Error reading in events.", ex);
+ }
+
+ for (int i = 0; i < mDevices.size(); i++) {
+ mDevices.valueAt(i).close();
+ }
+ }
+
+ private void process(Event e) {
+ final int index = mDevices.indexOfKey(e.getId());
+ if (index >= 0) {
+ Device d = mDevices.valueAt(index);
+ if (Event.COMMAND_DELAY.equals(e.getCommand())) {
+ d.addDelay(e.getDuration());
+ } else if (Event.COMMAND_INJECT.equals(e.getCommand())) {
+ d.injectEvent(e.getInjections());
+ } else {
+ if (Event.COMMAND_REGISTER.equals(e.getCommand())) {
+ error("Device id=" + e.getId() + " is already registered. Ignoring event.");
+ } else {
+ error("Unknown command \"" + e.getCommand() + "\". Ignoring event.");
+ }
+ }
+ } else if (Event.COMMAND_REGISTER.equals(e.getCommand())) {
+ registerDevice(e);
+ } else {
+ Log.e(TAG, "Unknown device id specified. Ignoring event.");
+ }
+ }
+
+ private void registerDevice(Event e) {
+ if (!Event.COMMAND_REGISTER.equals(e.getCommand())) {
+ throw new IllegalStateException(
+ "Tried to send command \"" + e.getCommand() + "\" to an unregistered device!");
+ }
+ int id = e.getId();
+ Device d = new Device(id, e.getName(), e.getVendorId(), e.getProductId(), e.getBus(),
+ e.getConfiguration(), e.getFfEffectsMax(), e.getAbsInfo());
+ mDevices.append(id, d);
+ }
+
+ private static void error(String msg) {
+ error(msg, null);
+ }
+
+ private static void error(String msg, Exception e) {
+ Log.e(TAG, msg);
+ if (e != null) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ }
+ }
+}
diff --git a/cmds/uinput/uinput b/cmds/uinput/uinput
new file mode 100755
index 0000000..ab2770e
--- /dev/null
+++ b/cmds/uinput/uinput
@@ -0,0 +1,9 @@
+#!/system/bin/sh
+
+# Preload the native portion libuinputcommand_jni.so to bypass the dependency
+# checks in the Java classloader, which prohibit dependencies that aren't
+# listed in system/core/rootdir/etc/public.libraries.android.txt.
+export LD_PRELOAD=libuinputcommand_jni.so
+
+export CLASSPATH=/system/framework/uinput.jar
+exec app_process /system/bin com.android.commands.uinput.Uinput "$@"
diff --git a/config/Android.bp b/config/Android.bp
index 0fb56cb..8dd409b 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 0ad3a02..b17a366 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 @@
#"
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
similarity index 100%
rename from config/preloaded-classes-blacklist
rename to config/preloaded-classes-denylist
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d67b986..caca05a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2242,9 +2242,9 @@
* Resources if one has already been created.
*/
Resources getTopLevelResources(String resDir, String[] splitResDirs, String[] overlayDirs,
- String[] libDirs, int displayId, LoadedApk pkgInfo) {
+ String[] libDirs, LoadedApk pkgInfo) {
return mResourcesManager.getResources(null, resDir, splitResDirs, overlayDirs, libDirs,
- displayId, null, pkgInfo.getCompatibilityInfo(), pkgInfo.getClassLoader(), null);
+ null, null, pkgInfo.getCompatibilityInfo(), pkgInfo.getClassLoader(), null);
}
@UnsupportedAppUsage
@@ -5656,6 +5656,11 @@
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) {
@@ -5692,8 +5697,7 @@
// many places.
final Configuration finalOverrideConfig = createNewConfigAndUpdateIfNotNull(
amOverrideConfig, contextThemeWrapperOverrideConfig);
- mResourcesManager.updateResourcesForActivity(activityToken, finalOverrideConfig,
- displayId, movedToDifferentDisplay);
+ mResourcesManager.updateResourcesForActivity(activityToken, finalOverrideConfig, displayId);
activity.mConfigChangeFlags = 0;
activity.mCurrentConfig = new Configuration(newConfig);
@@ -5709,11 +5713,6 @@
}
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) {
@@ -6014,6 +6013,11 @@
r.mPendingOverrideConfig = null;
}
+ if (displayId == INVALID_DISPLAY) {
+ // If INVALID_DISPLAY is passed assume that the activity should keep its current
+ // display.
+ displayId = r.activity.getDisplayId();
+ }
final boolean movedToDifferentDisplay = isDifferentDisplay(r.activity, displayId);
if (r.overrideConfig != null && !r.overrideConfig.isOtherSeqNewer(overrideConfig)
&& !movedToDifferentDisplay) {
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 98a23f2..3cb6293 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -105,7 +105,8 @@
public ActivityView(
@NonNull Context context, @NonNull AttributeSet attrs, int defStyle,
boolean singleTaskInstance, boolean usePublicVirtualDisplay) {
- this(context, attrs, defStyle, singleTaskInstance, usePublicVirtualDisplay, false);
+ this(context, attrs, defStyle, singleTaskInstance, usePublicVirtualDisplay,
+ false /* disableSurfaceViewBackgroundLayer */);
}
/** @hide */
@@ -113,12 +114,22 @@
@NonNull Context context, @NonNull AttributeSet attrs, int defStyle,
boolean singleTaskInstance, boolean usePublicVirtualDisplay,
boolean disableSurfaceViewBackgroundLayer) {
+ this(context, attrs, defStyle, singleTaskInstance, usePublicVirtualDisplay,
+ disableSurfaceViewBackgroundLayer, false /* useTrustedDisplay */);
+ }
+
+ // TODO(b/162901735): Refactor ActivityView with Builder
+ /** @hide */
+ public ActivityView(
+ @NonNull Context context, @NonNull AttributeSet attrs, int defStyle,
+ boolean singleTaskInstance, boolean usePublicVirtualDisplay,
+ boolean disableSurfaceViewBackgroundLayer, boolean useTrustedDisplay) {
super(context, attrs, defStyle);
if (useTaskOrganizer()) {
mTaskEmbedder = new TaskOrganizerTaskEmbedder(context, this);
} else {
mTaskEmbedder = new VirtualDisplayTaskEmbedder(context, this, singleTaskInstance,
- usePublicVirtualDisplay);
+ usePublicVirtualDisplay, useTrustedDisplay);
}
mSurfaceView = new SurfaceView(context, null, 0, 0, disableSurfaceViewBackgroundLayer);
// Since ActivityView#getAlpha has been overridden, we should use parent class's alpha
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 95136bb..0055711 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1145,9 +1145,24 @@
/** @hide */
public static final int OP_NO_ISOLATED_STORAGE = AppProtoEnums.APP_OP_NO_ISOLATED_STORAGE;
+ /**
+ * Phone call is using microphone
+ *
+ * @hide
+ */
+ // TODO: Add as AppProtoEnums
+ public static final int OP_PHONE_CALL_MICROPHONE = 100;
+ /**
+ * Phone call is using camera
+ *
+ * @hide
+ */
+ // TODO: Add as AppProtoEnums
+ public static final int OP_PHONE_CALL_CAMERA = 101;
+
/** @hide */
@UnsupportedAppUsage
- public static final int _NUM_OP = 100;
+ public static final int _NUM_OP = 102;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1469,6 +1484,19 @@
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final String OPSTR_NO_ISOLATED_STORAGE = "android:no_isolated_storage";
+ /**
+ * Phone call is using microphone
+ *
+ * @hide
+ */
+ public static final String OPSTR_PHONE_CALL_MICROPHONE = "android:phone_call_microphone";
+ /**
+ * Phone call is using camera
+ *
+ * @hide
+ */
+ public static final String OPSTR_PHONE_CALL_CAMERA = "android:phone_call_camera";
+
/** {@link #sAppOpsToNote} not initialized yet for this op */
private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
/** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
@@ -1658,6 +1686,8 @@
OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, //AUTO_REVOKE_PERMISSIONS_IF_UNUSED
OP_AUTO_REVOKE_MANAGED_BY_INSTALLER, //OP_AUTO_REVOKE_MANAGED_BY_INSTALLER
OP_NO_ISOLATED_STORAGE, // NO_ISOLATED_STORAGE
+ OP_PHONE_CALL_MICROPHONE, // OP_PHONE_CALL_MICROPHONE
+ OP_PHONE_CALL_CAMERA, // OP_PHONE_CALL_CAMERA
};
/**
@@ -1764,6 +1794,8 @@
OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
OPSTR_AUTO_REVOKE_MANAGED_BY_INSTALLER,
OPSTR_NO_ISOLATED_STORAGE,
+ OPSTR_PHONE_CALL_MICROPHONE,
+ OPSTR_PHONE_CALL_CAMERA,
};
/**
@@ -1871,6 +1903,8 @@
"AUTO_REVOKE_PERMISSIONS_IF_UNUSED",
"AUTO_REVOKE_MANAGED_BY_INSTALLER",
"NO_ISOLATED_STORAGE",
+ "PHONE_CALL_MICROPHONE",
+ "PHONE_CALL_CAMERA",
};
/**
@@ -1979,6 +2013,8 @@
null, // no permission for OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
null, // no permission for OP_AUTO_REVOKE_MANAGED_BY_INSTALLER
null, // no permission for OP_NO_ISOLATED_STORAGE
+ null, // no permission for OP_PHONE_CALL_MICROPHONE
+ null, // no permission for OP_PHONE_CALL_CAMERA
};
/**
@@ -2087,6 +2123,8 @@
null, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
null, // AUTO_REVOKE_MANAGED_BY_INSTALLER
null, // NO_ISOLATED_STORAGE
+ null, // PHONE_CALL_MICROPHONE
+ null, // PHONE_CALL_MICROPHONE
};
/**
@@ -2194,6 +2232,8 @@
null, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
null, // AUTO_REVOKE_MANAGED_BY_INSTALLER
null, // NO_ISOLATED_STORAGE
+ null, // PHONE_CALL_MICROPHONE
+ null, // PHONE_CALL_CAMERA
};
/**
@@ -2300,6 +2340,8 @@
AppOpsManager.MODE_DEFAULT, // OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
AppOpsManager.MODE_ALLOWED, // OP_AUTO_REVOKE_MANAGED_BY_INSTALLER
AppOpsManager.MODE_ERRORED, // OP_NO_ISOLATED_STORAGE
+ AppOpsManager.MODE_ALLOWED, // PHONE_CALL_MICROPHONE
+ AppOpsManager.MODE_ALLOWED, // PHONE_CALL_CAMERA
};
/**
@@ -2410,6 +2452,8 @@
false, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
false, // AUTO_REVOKE_MANAGED_BY_INSTALLER
true, // NO_ISOLATED_STORAGE
+ false, // PHONE_CALL_MICROPHONE
+ false, // PHONE_CALL_CAMERA
};
/**
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 676c6c0..340d5a1 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -96,7 +96,6 @@
import android.util.DebugUtils;
import android.util.LauncherIcons;
import android.util.Log;
-import android.view.Display;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.Immutable;
@@ -1748,7 +1747,7 @@
final Resources r = mContext.mMainThread.getTopLevelResources(
sameUid ? app.sourceDir : app.publicSourceDir,
sameUid ? app.splitSourceDirs : app.splitPublicSourceDirs,
- app.resourceDirs, app.sharedLibraryFiles, Display.DEFAULT_DISPLAY,
+ app.resourceDirs, app.sharedLibraryFiles,
mContext.mPackageInfo);
if (r != null) {
return r;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index f6b5334..cee607f 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -187,6 +187,16 @@
private static final String XATTR_INODE_CODE_CACHE = "user.inode_code_cache";
/**
+ * Special intent extra that critical system apps can use to hide the notification for a
+ * foreground service. This extra should be placed in the intent passed into {@link
+ * #startForegroundService(Intent)}.
+ *
+ * @hide
+ */
+ private static final String EXTRA_HIDDEN_FOREGROUND_SERVICE =
+ "android.intent.extra.HIDDEN_FOREGROUND_SERVICE";
+
+ /**
* Map from package name, to preference name, to cached preferences.
*/
@GuardedBy("ContextImpl.class")
@@ -227,6 +237,15 @@
private @NonNull Resources mResources;
private @Nullable Display mDisplay; // may be null if invalid display or not initialized yet.
+ /**
+ * If set to {@code true} the resources for this context will be configured for mDisplay which
+ * will override the display configuration inherited from {@link #mToken} (or the global
+ * configuration if mToken is null). Typically set for display contexts and contexts derived
+ * from display contexts where changes to the activity display and the global configuration
+ * display should not impact their resources.
+ */
+ private boolean mForceDisplayOverrideInResources;
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final int mFlags;
@@ -1698,9 +1717,12 @@
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
+ final boolean hideForegroundNotification = requireForeground
+ && service.getBooleanExtra(EXTRA_HIDDEN_FOREGROUND_SERVICE, false);
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
+ hideForegroundNotification,
getOpPackageName(), getAttributionTag(), user.getIdentifier());
if (cn != null) {
if (cn.getPackageName().equals("!")) {
@@ -2246,8 +2268,8 @@
}
private static Resources createResources(IBinder activityToken, LoadedApk pi, String splitName,
- int displayId, Configuration overrideConfig, CompatibilityInfo compatInfo,
- List<ResourcesLoader> resourcesLoader) {
+ @Nullable Integer overrideDisplayId, Configuration overrideConfig,
+ CompatibilityInfo compatInfo, List<ResourcesLoader> resourcesLoader) {
final String[] splitResDirs;
final ClassLoader classLoader;
try {
@@ -2261,7 +2283,7 @@
splitResDirs,
pi.getOverlayDirs(),
pi.getApplicationInfo().sharedLibraryFiles,
- displayId,
+ overrideDisplayId,
overrideConfig,
compatInfo,
classLoader,
@@ -2278,8 +2300,10 @@
new UserHandle(UserHandle.getUserId(application.uid)), flags, null, null);
final int displayId = getDisplayId();
+ final Integer overrideDisplayId = mForceDisplayOverrideInResources
+ ? displayId : null;
- c.setResources(createResources(mToken, pi, null, displayId, null,
+ c.setResources(createResources(mToken, pi, null, overrideDisplayId, null,
getDisplayAdjustments(displayId).getCompatibilityInfo(), null));
if (c.mResources != null) {
return c;
@@ -2313,8 +2337,10 @@
mToken, user, flags, null, null);
final int displayId = getDisplayId();
+ final Integer overrideDisplayId = mForceDisplayOverrideInResources
+ ? displayId : null;
- c.setResources(createResources(mToken, pi, null, displayId, null,
+ c.setResources(createResources(mToken, pi, null, overrideDisplayId, null,
getDisplayAdjustments(displayId).getCompatibilityInfo(), null));
if (c.mResources != null) {
return c;
@@ -2348,15 +2374,13 @@
final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo,
mAttributionTag, splitName, mToken, mUser, mFlags, classLoader, null);
- final int displayId = getDisplayId();
-
context.setResources(ResourcesManager.getInstance().getResources(
mToken,
mPackageInfo.getResDir(),
paths,
mPackageInfo.getOverlayDirs(),
mPackageInfo.getApplicationInfo().sharedLibraryFiles,
- displayId,
+ mForceDisplayOverrideInResources ? getDisplayId() : null,
null,
mPackageInfo.getCompatibilityInfo(),
classLoader,
@@ -2370,12 +2394,23 @@
throw new IllegalArgumentException("overrideConfiguration must not be null");
}
+ if (mForceDisplayOverrideInResources) {
+ // Ensure the resources display metrics are adjusted to match the display this context
+ // is based on.
+ Configuration displayAdjustedConfig = new Configuration();
+ displayAdjustedConfig.setTo(mDisplay.getDisplayAdjustments().getConfiguration(),
+ ActivityInfo.CONFIG_WINDOW_CONFIGURATION, 1);
+ displayAdjustedConfig.updateFrom(overrideConfiguration);
+ overrideConfiguration = displayAdjustedConfig;
+ }
+
ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag,
mSplitName, mToken, mUser, mFlags, mClassLoader, null);
final int displayId = getDisplayId();
-
- context.setResources(createResources(mToken, mPackageInfo, mSplitName, displayId,
+ final Integer overrideDisplayId = mForceDisplayOverrideInResources
+ ? displayId : null;
+ context.setResources(createResources(mToken, mPackageInfo, mSplitName, overrideDisplayId,
overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo(),
mResources.getLoaders()));
context.mIsUiContext = isUiContext() || isOuterUiContext();
@@ -2393,11 +2428,20 @@
final int displayId = display.getDisplayId();
+ // Ensure the resources display metrics are adjusted to match the provided display.
+ Configuration overrideConfig = new Configuration();
+ overrideConfig.setTo(display.getDisplayAdjustments().getConfiguration(),
+ ActivityInfo.CONFIG_WINDOW_CONFIGURATION, 1);
+
context.setResources(createResources(mToken, mPackageInfo, mSplitName, displayId,
- null, getDisplayAdjustments(displayId).getCompatibilityInfo(),
+ overrideConfig, display.getDisplayAdjustments().getCompatibilityInfo(),
mResources.getLoaders()));
context.mDisplay = display;
context.mIsAssociatedWithDisplay = true;
+ // Display contexts and any context derived from a display context should always override
+ // the display that would otherwise be inherited from mToken (or the global configuration if
+ // mToken is null).
+ context.mForceDisplayOverrideInResources = true;
return context;
}
@@ -2415,8 +2459,10 @@
ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag,
mSplitName, token, mUser, mFlags, mClassLoader, null);
context.mIsUiContext = true;
-
context.mIsAssociatedWithDisplay = true;
+ // Window contexts receive configurations directly from the server and as such do not
+ // need to override their display in ResourcesManager.
+ context.mForceDisplayOverrideInResources = false;
return context;
}
@@ -2759,6 +2805,7 @@
mDisplay = container.mDisplay;
mIsAssociatedWithDisplay = container.mIsAssociatedWithDisplay;
mIsSystemOrSystemUiContext = container.mIsSystemOrSystemUiContext;
+ mForceDisplayOverrideInResources = container.mForceDisplayOverrideInResources;
} else {
mBasePackageName = packageInfo.mPackageName;
ApplicationInfo ainfo = packageInfo.getApplicationInfo();
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index f37ca61b..0a47248 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -156,7 +156,8 @@
boolean refContentProvider(in IBinder connection, int stableDelta, int unstableDelta);
PendingIntent getRunningServiceControlPanel(in ComponentName service);
ComponentName startService(in IApplicationThread caller, in Intent service,
- in String resolvedType, boolean requireForeground, in String callingPackage,
+ in String resolvedType, boolean requireForeground,
+ boolean hideForegroundNotification, in String callingPackage,
in String callingFeatureId, int userId);
@UnsupportedAppUsage
int stopService(in IApplicationThread caller, in Intent service,
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index aa6a08b..202b615 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -56,7 +56,6 @@
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
-import android.view.Display;
import android.view.DisplayAdjustments;
import com.android.internal.util.ArrayUtils;
@@ -367,7 +366,7 @@
mResources = ResourcesManager.getInstance().getResources(null, mResDir,
splitPaths, mOverlayDirs, mApplicationInfo.sharedLibraryFiles,
- Display.DEFAULT_DISPLAY, null, getCompatibilityInfo(),
+ null, null, getCompatibilityInfo(),
getClassLoader(), mApplication == null ? null
: mApplication.getResources().getLoaders());
}
@@ -1231,7 +1230,7 @@
mResources = ResourcesManager.getInstance().getResources(null, mResDir,
splitPaths, mOverlayDirs, mApplicationInfo.sharedLibraryFiles,
- Display.DEFAULT_DISPLAY, null, getCompatibilityInfo(),
+ null, null, getCompatibilityInfo(),
getClassLoader(), null);
}
return mResources;
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index fb2120e..7cd3fca 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -17,6 +17,8 @@
package android.app;
import static android.app.ActivityThread.DEBUG_CONFIGURATION;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -61,6 +63,7 @@
import java.util.Objects;
import java.util.WeakHashMap;
import java.util.function.Consumer;
+import java.util.function.Function;
/** @hide */
public class ResourcesManager {
@@ -82,6 +85,12 @@
private final Configuration mResConfiguration = new Configuration();
/**
+ * The display upon which all Resources are based. Activity, window token, and display context
+ * resources apply their overrides to this display id.
+ */
+ private int mResDisplayId = DEFAULT_DISPLAY;
+
+ /**
* A mapping of ResourceImpls and their configurations. These are heavy weight objects
* which should be reused as much as possible.
*/
@@ -155,20 +164,79 @@
private final ArrayMap<ApkKey, WeakReference<ApkAssets>> mCachedApkAssets = new ArrayMap<>();
/**
- * Resources and base configuration override associated with an Activity.
+ * Class containing the base configuration override and set of resources associated with an
+ * Activity or {@link WindowContext}.
*/
private static class ActivityResources {
- @UnsupportedAppUsage
- private ActivityResources() {
- }
+ /**
+ * Override config to apply to all resources associated with the token this instance is
+ * based on.
+ *
+ * @see #activityResources
+ * @see #getResources(IBinder, String, String[], String[], String[], Integer, Configuration,
+ * CompatibilityInfo, ClassLoader, List)
+ */
public final Configuration overrideConfig = new Configuration();
- public final ArrayList<WeakReference<Resources>> activityResources = new ArrayList<>();
- final ReferenceQueue<Resources> activityResourcesQueue = new ReferenceQueue<>();
+
+ /**
+ * The display to apply to all resources associated with the token this instance is based
+ * on.
+ */
+ public int overrideDisplayId;
+
+ /** List of {@link ActivityResource} associated with the token this instance is based on. */
+ public final ArrayList<ActivityResource> activityResources = new ArrayList<>();
+
+ public final ReferenceQueue<Resources> activityResourcesQueue = new ReferenceQueue<>();
+
+ @UnsupportedAppUsage
+ private ActivityResources() {}
+
+ /** Returns the number of live resource references within {@code activityResources}. */
+ public int countLiveReferences() {
+ int count = 0;
+ for (int i = 0; i < activityResources.size(); i++) {
+ WeakReference<Resources> resources = activityResources.get(i).resources;
+ if (resources != null && resources.get() != null) {
+ count++;
+ }
+ }
+ return count;
+ }
}
/**
- * Each Activity may has a base override configuration that is applied to each Resources object,
- * which in turn may have their own override configuration specified.
+ * Contains a resource derived from an {@link Activity} or {@link WindowContext} and information
+ * about how this resource expects its configuration to differ from the token's.
+ *
+ * @see ActivityResources
+ */
+ // TODO: Ideally this class should be called something token related, like TokenBasedResource.
+ private static class ActivityResource {
+ /**
+ * The override configuration applied on top of the token's override config for this
+ * resource.
+ */
+ public final Configuration overrideConfig = new Configuration();
+
+ /**
+ * If non-null this resource expects its configuration to override the display from the
+ * token's configuration.
+ *
+ * @see #applyDisplayMetricsToConfiguration(DisplayMetrics, Configuration)
+ */
+ @Nullable
+ public Integer overrideDisplayId;
+
+ @Nullable
+ public WeakReference<Resources> resources;
+
+ private ActivityResource() {}
+ }
+
+ /**
+ * Each Activity or WindowToken may has a base override configuration that is applied to each
+ * Resources object, which in turn may have their own override configuration specified.
*/
@UnsupportedAppUsage
private final WeakHashMap<IBinder, ActivityResources> mActivityResourceReferences =
@@ -241,8 +309,7 @@
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public DisplayMetrics getDisplayMetrics() {
- return getDisplayMetrics(Display.DEFAULT_DISPLAY,
- DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
+ return getDisplayMetrics(mResDisplayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
}
/**
@@ -260,8 +327,8 @@
return dm;
}
- private static void applyNonDefaultDisplayMetricsToConfiguration(
- @NonNull DisplayMetrics dm, @NonNull Configuration config) {
+ private static void applyDisplayMetricsToConfiguration(@NonNull DisplayMetrics dm,
+ @NonNull Configuration config) {
config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
config.densityDpi = dm.densityDpi;
config.screenWidthDp = (int) (dm.widthPixels / dm.density);
@@ -502,7 +569,7 @@
int references = countLiveReferences(mResourceReferences);
for (ActivityResources activityResources : mActivityResourceReferences.values()) {
- references += countLiveReferences(activityResources.activityResources);
+ references += activityResources.countLiveReferences();
}
pw.println(references);
@@ -511,38 +578,36 @@
}
}
- private Configuration generateConfig(@NonNull ResourcesKey key, @NonNull DisplayMetrics dm) {
+ private Configuration generateConfig(@NonNull ResourcesKey key) {
Configuration config;
- final boolean isDefaultDisplay = (key.mDisplayId == Display.DEFAULT_DISPLAY);
final boolean hasOverrideConfig = key.hasOverrideConfiguration();
- if (!isDefaultDisplay || hasOverrideConfig) {
+ if (hasOverrideConfig) {
config = new Configuration(getConfiguration());
- if (!isDefaultDisplay) {
- applyNonDefaultDisplayMetricsToConfiguration(dm, config);
- }
- if (hasOverrideConfig) {
- config.updateFrom(key.mOverrideConfiguration);
- if (DEBUG) Slog.v(TAG, "Applied overrideConfig=" + key.mOverrideConfiguration);
- }
+ config.updateFrom(key.mOverrideConfiguration);
+ if (DEBUG) Slog.v(TAG, "Applied overrideConfig=" + key.mOverrideConfiguration);
} else {
config = getConfiguration();
}
return config;
}
+ private int generateDisplayId(@NonNull ResourcesKey key) {
+ return key.mDisplayId != INVALID_DISPLAY ? key.mDisplayId : mResDisplayId;
+ }
+
private @Nullable ResourcesImpl createResourcesImpl(@NonNull ResourcesKey key,
@Nullable ApkAssetsSupplier apkSupplier) {
- final DisplayAdjustments daj = new DisplayAdjustments(key.mOverrideConfiguration);
- daj.setCompatibilityInfo(key.mCompatInfo);
-
final AssetManager assets = createAssetManager(key, apkSupplier);
if (assets == null) {
return null;
}
- final DisplayMetrics dm = getDisplayMetrics(key.mDisplayId, daj);
- final Configuration config = generateConfig(key, dm);
- final ResourcesImpl impl = new ResourcesImpl(assets, dm, config, daj);
+ final DisplayAdjustments daj = new DisplayAdjustments(key.mOverrideConfiguration);
+ daj.setCompatibilityInfo(key.mCompatInfo);
+
+ final Configuration config = generateConfig(key);
+ final DisplayMetrics displayMetrics = getDisplayMetrics(generateDisplayId(key), daj);
+ final ResourcesImpl impl = new ResourcesImpl(assets, displayMetrics, config, daj);
if (DEBUG) {
Slog.d(TAG, "- creating impl=" + impl + " with key: " + key);
@@ -652,8 +717,8 @@
final int size = activityResources.activityResources.size();
for (int index = 0; index < size; index++) {
- WeakReference<Resources> ref = activityResources.activityResources.get(index);
- Resources resources = ref.get();
+ ActivityResource activityResource = activityResources.activityResources.get(index);
+ Resources resources = activityResource.resources.get();
ResourcesKey key = resources == null ? null : findKeyForResourceImplLocked(
resources.getImpl());
@@ -667,20 +732,28 @@
return null;
}
- private @NonNull Resources createResourcesForActivityLocked(@NonNull IBinder activityToken,
+ @NonNull
+ private Resources createResourcesForActivityLocked(@NonNull IBinder activityToken,
+ @NonNull Configuration initialOverrideConfig, @Nullable Integer overrideDisplayId,
@NonNull ClassLoader classLoader, @NonNull ResourcesImpl impl,
@NonNull CompatibilityInfo compatInfo) {
final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
activityToken);
cleanupReferences(activityResources.activityResources,
- activityResources.activityResourcesQueue);
+ activityResources.activityResourcesQueue,
+ (r) -> r.resources);
Resources resources = compatInfo.needsCompatResources() ? new CompatResources(classLoader)
: new Resources(classLoader);
resources.setImpl(impl);
resources.setCallbacks(mUpdateCallbacks);
- activityResources.activityResources.add(
- new WeakReference<>(resources, activityResources.activityResourcesQueue));
+
+ ActivityResource activityResource = new ActivityResource();
+ activityResource.resources = new WeakReference<>(resources,
+ activityResources.activityResourcesQueue);
+ activityResource.overrideConfig.setTo(initialOverrideConfig);
+ activityResource.overrideDisplayId = overrideDisplayId;
+ activityResources.activityResources.add(activityResource);
if (DEBUG) {
Slog.d(TAG, "- creating new ref=" + resources);
Slog.d(TAG, "- setting ref=" + resources + " with impl=" + impl);
@@ -706,7 +779,7 @@
/**
* Creates base resources for a binder token. Calls to
- * {@link #getResources(IBinder, String, String[], String[], String[], int, Configuration,
+ * {@link #getResources(IBinder, String, String[], String[], String[], Integer, Configuration,
* CompatibilityInfo, ClassLoader, List)} with the same binder token will have their override
* configurations merged with the one specified here.
*
@@ -743,7 +816,7 @@
overlayDirs,
libDirs,
displayId,
- overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
+ overrideConfig,
compatInfo,
loaders == null ? null : loaders.toArray(new ResourcesLoader[0]));
classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
@@ -759,10 +832,7 @@
}
// Update any existing Activity Resources references.
- updateResourcesForActivity(token, overrideConfig, displayId,
- false /* movedToDifferentDisplay */);
-
- rebaseKeyForActivity(token, key);
+ updateResourcesForActivity(token, overrideConfig, displayId);
synchronized (this) {
Resources resources = findResourcesForActivityLocked(token, key,
@@ -773,7 +843,9 @@
}
// Now request an actual Resources object.
- return createResources(token, key, classLoader, /* apkSupplier */ null);
+ return createResourcesForActivity(token, key,
+ /* initialOverrideConfig */ Configuration.EMPTY, /* overrideDisplayId */ null,
+ classLoader, /* apkSupplier */ null);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
@@ -781,39 +853,94 @@
/**
* Rebases a key's override config on top of the Activity's base override.
+ *
+ * @param activityToken the token the supplied {@code key} is derived from.
+ * @param key the key to rebase
+ * @param overridesActivityDisplay whether this key is overriding the display from the token
*/
- private void rebaseKeyForActivity(IBinder activityToken, ResourcesKey key) {
+ private void rebaseKeyForActivity(IBinder activityToken, ResourcesKey key,
+ boolean overridesActivityDisplay) {
synchronized (this) {
final ActivityResources activityResources =
getOrCreateActivityResourcesStructLocked(activityToken);
- // Rebase the key's override config on top of the Activity's base override.
- if (key.hasOverrideConfiguration()
- && !activityResources.overrideConfig.equals(Configuration.EMPTY)) {
- final Configuration temp = new Configuration(activityResources.overrideConfig);
- temp.updateFrom(key.mOverrideConfiguration);
- key.mOverrideConfiguration.setTo(temp);
+ if (key.mDisplayId == INVALID_DISPLAY) {
+ key.mDisplayId = activityResources.overrideDisplayId;
}
+
+ Configuration config;
+ if (key.hasOverrideConfiguration()) {
+ config = new Configuration(activityResources.overrideConfig);
+ config.updateFrom(key.mOverrideConfiguration);
+ } else {
+ config = activityResources.overrideConfig;
+ }
+
+ if (overridesActivityDisplay
+ && key.mOverrideConfiguration.windowConfiguration.getAppBounds() == null) {
+ if (!key.hasOverrideConfiguration()) {
+ // Make a copy to handle the case where the override config is set to defaults.
+ config = new Configuration(config);
+ }
+
+ // If this key is overriding the display from the token and the key's
+ // window config app bounds is null we need to explicitly override this to
+ // ensure the display adjustments are as expected.
+ config.windowConfiguration.setAppBounds(null);
+ }
+
+ key.mOverrideConfiguration.setTo(config);
}
}
/**
+ * Rebases a key's override config with display metrics of the {@code overrideDisplay} paired
+ * with the {code displayAdjustments}.
+ *
+ * @see #applyDisplayMetricsToConfiguration(DisplayMetrics, Configuration)
+ */
+ private void rebaseKeyForDisplay(ResourcesKey key, int overrideDisplay) {
+ final Configuration temp = new Configuration();
+
+ DisplayAdjustments daj = new DisplayAdjustments(key.mOverrideConfiguration);
+ daj.setCompatibilityInfo(key.mCompatInfo);
+
+ final DisplayMetrics dm = getDisplayMetrics(overrideDisplay, daj);
+ applyDisplayMetricsToConfiguration(dm, temp);
+
+ if (key.hasOverrideConfiguration()) {
+ temp.updateFrom(key.mOverrideConfiguration);
+ }
+ key.mOverrideConfiguration.setTo(temp);
+ }
+
+ /**
* Check WeakReferences and remove any dead references so they don't pile up.
*/
private static <T> void cleanupReferences(ArrayList<WeakReference<T>> references,
ReferenceQueue<T> referenceQueue) {
- Reference<? extends T> enduedRef = referenceQueue.poll();
- if (enduedRef == null) {
+ cleanupReferences(references, referenceQueue, Function.identity());
+ }
+
+ /**
+ * Check WeakReferences and remove any dead references so they don't pile up.
+ */
+ private static <C, T> void cleanupReferences(ArrayList<C> referenceContainers,
+ ReferenceQueue<T> referenceQueue, Function<C, WeakReference<T>> unwrappingFunction) {
+ Reference<? extends T> enqueuedRef = referenceQueue.poll();
+ if (enqueuedRef == null) {
return;
}
final HashSet<Reference<? extends T>> deadReferences = new HashSet<>();
- for (; enduedRef != null; enduedRef = referenceQueue.poll()) {
- deadReferences.add(enduedRef);
+ for (; enqueuedRef != null; enqueuedRef = referenceQueue.poll()) {
+ deadReferences.add(enqueuedRef);
}
- ArrayUtils.unstableRemoveIf(references,
- (ref) -> ref == null || deadReferences.contains(ref));
+ ArrayUtils.unstableRemoveIf(referenceContainers, (refContainer) -> {
+ WeakReference<T> ref = unwrappingFunction.apply(refContainer);
+ return ref == null || deadReferences.contains(ref);
+ });
}
/**
@@ -825,8 +952,8 @@
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
"ResourcesManager#createApkAssetsSupplierNotLocked");
try {
- if (Thread.holdsLock(this)) {
- Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
+ if (DEBUG && Thread.holdsLock(this)) {
+ Slog.w(TAG, "Calling thread " + Thread.currentThread().getName()
+ " is holding mLock", new Throwable());
}
@@ -849,17 +976,36 @@
/**
* Creates a Resources object set with a ResourcesImpl object matching the given key.
*
- * @param activityToken The Activity this Resources object should be associated with.
* @param key The key describing the parameters of the ResourcesImpl object.
* @param classLoader The classloader to use for the Resources object.
* If null, {@link ClassLoader#getSystemClassLoader()} is used.
- * @param apkSupplier The apk assets supplier to use when creating a new ResourcesImpl object.
* @return A Resources object that gets updated when
* {@link #applyConfigurationToResourcesLocked(Configuration, CompatibilityInfo)}
* is called.
*/
- private @Nullable Resources createResources(@Nullable IBinder activityToken,
- @NonNull ResourcesKey key, @NonNull ClassLoader classLoader,
+ @Nullable
+ private Resources createResources(@NonNull ResourcesKey key, @NonNull ClassLoader classLoader,
+ @Nullable ApkAssetsSupplier apkSupplier) {
+ synchronized (this) {
+ if (DEBUG) {
+ Throwable here = new Throwable();
+ here.fillInStackTrace();
+ Slog.w(TAG, "!! Create resources for key=" + key, here);
+ }
+
+ ResourcesImpl resourcesImpl = findOrCreateResourcesImplForKeyLocked(key, apkSupplier);
+ if (resourcesImpl == null) {
+ return null;
+ }
+
+ return createResourcesLocked(classLoader, resourcesImpl, key.mCompatInfo);
+ }
+ }
+
+ @Nullable
+ private Resources createResourcesForActivity(@NonNull IBinder activityToken,
+ @NonNull ResourcesKey key, @NonNull Configuration initialOverrideConfig,
+ @Nullable Integer overrideDisplayId, @NonNull ClassLoader classLoader,
@Nullable ApkAssetsSupplier apkSupplier) {
synchronized (this) {
if (DEBUG) {
@@ -873,12 +1019,8 @@
return null;
}
- if (activityToken != null) {
- return createResourcesForActivityLocked(activityToken, classLoader,
- resourcesImpl, key.mCompatInfo);
- } else {
- return createResourcesLocked(classLoader, resourcesImpl, key.mCompatInfo);
- }
+ return createResourcesForActivityLocked(activityToken, initialOverrideConfig,
+ overrideDisplayId, classLoader, resourcesImpl, key.mCompatInfo);
}
}
@@ -899,7 +1041,10 @@
* @param splitResDirs An array of split resource paths. Can be null.
* @param overlayDirs An array of overlay paths. Can be null.
* @param libDirs An array of resource library paths. Can be null.
- * @param displayId The ID of the display for which to create the resources.
+ * @param overrideDisplayId The ID of the display for which the returned Resources should be
+ * based. This will cause display-based configuration properties to override those of the base
+ * Resources for the {@code activityToken}, or the global configuration if {@code activityToken}
+ * is null.
* @param overrideConfig The configuration to apply on top of the base configuration. Can be
* null. Mostly used with Activities that are in multi-window which may override width and
* height properties from the base config.
@@ -909,13 +1054,14 @@
* {@link ClassLoader#getSystemClassLoader()} is used.
* @return a Resources object from which to access resources.
*/
- public @Nullable Resources getResources(
+ @Nullable
+ public Resources getResources(
@Nullable IBinder activityToken,
@Nullable String resDir,
@Nullable String[] splitResDirs,
@Nullable String[] overlayDirs,
@Nullable String[] libDirs,
- int displayId,
+ @Nullable Integer overrideDisplayId,
@Nullable Configuration overrideConfig,
@NonNull CompatibilityInfo compatInfo,
@Nullable ClassLoader classLoader,
@@ -927,20 +1073,30 @@
splitResDirs,
overlayDirs,
libDirs,
- displayId,
- overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
+ overrideDisplayId != null ? overrideDisplayId : INVALID_DISPLAY,
+ overrideConfig,
compatInfo,
loaders == null ? null : loaders.toArray(new ResourcesLoader[0]));
classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
- if (activityToken != null) {
- rebaseKeyForActivity(activityToken, key);
- }
-
// Preload the ApkAssets required by the key to prevent performing heavy I/O while the
// ResourcesManager lock is held.
final ApkAssetsSupplier assetsSupplier = createApkAssetsSupplierNotLocked(key);
- return createResources(activityToken, key, classLoader, assetsSupplier);
+
+ if (overrideDisplayId != null) {
+ rebaseKeyForDisplay(key, overrideDisplayId);
+ }
+
+ Resources resources;
+ if (activityToken != null) {
+ Configuration initialOverrideConfig = new Configuration(key.mOverrideConfiguration);
+ rebaseKeyForActivity(activityToken, key, overrideDisplayId != null);
+ resources = createResourcesForActivity(activityToken, key, initialOverrideConfig,
+ overrideDisplayId, classLoader, assetsSupplier);
+ } else {
+ resources = createResources(key, classLoader, assetsSupplier);
+ }
+ return resources;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
@@ -949,24 +1105,26 @@
/**
* Updates an Activity's Resources object with overrideConfig. The Resources object
* that was previously returned by {@link #getResources(IBinder, String, String[], String[],
- * String[], int, Configuration, CompatibilityInfo, ClassLoader, List)} is still valid and will
- * have the updated configuration.
+ * String[], Integer, Configuration, CompatibilityInfo, ClassLoader, List)} is still valid and
+ * will have the updated configuration.
*
* @param activityToken The Activity token.
* @param overrideConfig The configuration override to update.
* @param displayId Id of the display where activity currently resides.
- * @param movedToDifferentDisplay Indicates if the activity was moved to different display.
*/
public void updateResourcesForActivity(@NonNull IBinder activityToken,
- @Nullable Configuration overrideConfig, int displayId,
- boolean movedToDifferentDisplay) {
+ @Nullable Configuration overrideConfig, int displayId) {
try {
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
"ResourcesManager#updateResourcesForActivity");
+ if (displayId == INVALID_DISPLAY) {
+ throw new IllegalArgumentException("displayId can not be INVALID_DISPLAY");
+ }
synchronized (this) {
final ActivityResources activityResources =
getOrCreateActivityResourcesStructLocked(activityToken);
+ boolean movedToDifferentDisplay = activityResources.overrideDisplayId != displayId;
if (Objects.equals(activityResources.overrideConfig, overrideConfig)
&& !movedToDifferentDisplay) {
// They are the same and no change of display id, no work to do.
@@ -983,6 +1141,8 @@
} else {
activityResources.overrideConfig.unset();
}
+ // Update the Activity's override display id.
+ activityResources.overrideDisplayId = displayId;
if (DEBUG) {
Throwable here = new Throwable();
@@ -1000,24 +1160,26 @@
// Rebase each Resources associated with this Activity.
final int refCount = activityResources.activityResources.size();
for (int i = 0; i < refCount; i++) {
- final WeakReference<Resources> weakResRef =
+ final ActivityResource activityResource =
activityResources.activityResources.get(i);
- final Resources resources = weakResRef.get();
+ final Resources resources = activityResource.resources.get();
if (resources == null) {
continue;
}
- final ResourcesKey newKey = rebaseActivityOverrideConfig(resources, oldConfig,
+ final ResourcesKey newKey = rebaseActivityOverrideConfig(activityResource,
overrideConfig, displayId);
- if (newKey != null) {
- final ResourcesImpl resourcesImpl =
- findOrCreateResourcesImplForKeyLocked(newKey);
- if (resourcesImpl != null && resourcesImpl != resources.getImpl()) {
- // Set the ResourcesImpl, updating it for all users of this Resources
- // object.
- resources.setImpl(resourcesImpl);
- }
+ if (newKey == null) {
+ continue;
+ }
+
+ final ResourcesImpl resourcesImpl =
+ findOrCreateResourcesImplForKeyLocked(newKey);
+ if (resourcesImpl != null && resourcesImpl != resources.getImpl()) {
+ // Set the ResourcesImpl, updating it for all users of this Resources
+ // object.
+ resources.setImpl(resourcesImpl);
}
}
}
@@ -1031,9 +1193,13 @@
* that an Activity's Resources should be set to.
*/
@Nullable
- private ResourcesKey rebaseActivityOverrideConfig(@NonNull Resources resources,
- @NonNull Configuration oldOverrideConfig, @Nullable Configuration newOverrideConfig,
- int displayId) {
+ private ResourcesKey rebaseActivityOverrideConfig(@NonNull ActivityResource activityResource,
+ @Nullable Configuration newOverrideConfig, int displayId) {
+ final Resources resources = activityResource.resources.get();
+ if (resources == null) {
+ return null;
+ }
+
// Extract the ResourcesKey that was last used to create the Resources for this
// activity.
final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl());
@@ -1049,16 +1215,33 @@
rebasedOverrideConfig.setTo(newOverrideConfig);
}
- final boolean hadOverrideConfig = !oldOverrideConfig.equals(Configuration.EMPTY);
- if (hadOverrideConfig && oldKey.hasOverrideConfiguration()) {
- // Generate a delta between the old base Activity override configuration and
- // the actual final override configuration that was used to figure out the
- // real delta this Resources object wanted.
- Configuration overrideOverrideConfig = Configuration.generateDelta(
- oldOverrideConfig, oldKey.mOverrideConfiguration);
- rebasedOverrideConfig.updateFrom(overrideOverrideConfig);
+ final Integer overrideDisplayId = activityResource.overrideDisplayId;
+ if (overrideDisplayId != null) {
+ DisplayAdjustments displayAdjustments = new DisplayAdjustments(rebasedOverrideConfig);
+ displayAdjustments.getConfiguration().setTo(activityResource.overrideConfig);
+ displayAdjustments.setCompatibilityInfo(oldKey.mCompatInfo);
+
+ DisplayMetrics dm = getDisplayMetrics(overrideDisplayId, displayAdjustments);
+ applyDisplayMetricsToConfiguration(dm, rebasedOverrideConfig);
}
+ final boolean hasOverrideConfig =
+ !activityResource.overrideConfig.equals(Configuration.EMPTY);
+ if (hasOverrideConfig) {
+ rebasedOverrideConfig.updateFrom(activityResource.overrideConfig);
+ }
+
+ if (activityResource.overrideDisplayId != null
+ && activityResource.overrideConfig.windowConfiguration.getAppBounds() == null) {
+ // If this activity resource is overriding the display from the token and the key's
+ // window config app bounds is null we need to explicitly override this to
+ // ensure the display adjustments are as expected.
+ rebasedOverrideConfig.windowConfiguration.setAppBounds(null);
+ }
+
+ // Ensure the new key keeps the expected override display instead of the new token display.
+ displayId = overrideDisplayId != null ? overrideDisplayId : displayId;
+
// Create the new ResourcesKey with the rebased override config.
final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir,
oldKey.mSplitResDirs, oldKey.mOverlayDirs, oldKey.mLibDirs,
@@ -1090,12 +1273,11 @@
+ mResConfiguration.seq + ", newSeq=" + config.seq);
return false;
}
- int changes = mResConfiguration.updateFrom(config);
+
// Things might have changed in display manager, so clear the cached displays.
mAdjustedDisplays.clear();
- DisplayMetrics defaultDisplayMetrics = getDisplayMetrics();
-
+ int changes = mResConfiguration.updateFrom(config);
if (compat != null && (mResCompatibilityInfo == null ||
!mResCompatibilityInfo.equals(compat))) {
mResCompatibilityInfo = compat;
@@ -1104,10 +1286,10 @@
| ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
}
- Resources.updateSystemConfiguration(config, defaultDisplayMetrics, compat);
+ DisplayMetrics displayMetrics = getDisplayMetrics();
+ Resources.updateSystemConfiguration(config, displayMetrics, compat);
ApplicationPackageManager.configurationChanged();
- //Slog.i(TAG, "Configuration changed in " + currentPackageName());
Configuration tmpConfig = new Configuration();
@@ -1137,11 +1319,7 @@
}
tmpConfig.setTo(config);
-
- // Apply the override configuration before setting the display adjustments to ensure that
- // the process config does not override activity display adjustments.
- final boolean hasOverrideConfiguration = key.hasOverrideConfiguration();
- if (hasOverrideConfiguration) {
+ if (key.hasOverrideConfiguration()) {
tmpConfig.updateFrom(key.mOverrideConfiguration);
}
@@ -1153,22 +1331,8 @@
daj = new DisplayAdjustments(daj);
daj.setCompatibilityInfo(compat);
}
-
- final int displayId = key.mDisplayId;
- if (displayId == Display.DEFAULT_DISPLAY) {
- daj.setConfiguration(tmpConfig);
- }
- DisplayMetrics dm = getDisplayMetrics(displayId, daj);
- if (displayId != Display.DEFAULT_DISPLAY) {
- applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
-
- // Re-apply the override configuration to ensure that configuration contexts based on
- // a display context (ex: createDisplayContext().createConfigurationContext()) have the
- // correct override.
- if (hasOverrideConfiguration) {
- tmpConfig.updateFrom(key.mOverrideConfiguration);
- }
- }
+ daj.setConfiguration(tmpConfig);
+ DisplayMetrics dm = getDisplayMetrics(generateDisplayId(key), daj);
resourcesImpl.updateConfiguration(tmpConfig, dm, compat);
}
@@ -1305,8 +1469,10 @@
for (ActivityResources activityResources : mActivityResourceReferences.values()) {
final int resCount = activityResources.activityResources.size();
for (int i = 0; i < resCount; i++) {
- final WeakReference<Resources> ref = activityResources.activityResources.get(i);
- final Resources r = ref != null ? ref.get() : null;
+ final ActivityResource activityResource =
+ activityResources.activityResources.get(i);
+ final Resources r = activityResource != null
+ ? activityResource.resources.get() : null;
if (r != null) {
final ResourcesKey key = updatedResourceKeys.get(r.getImpl());
if (key != null) {
@@ -1338,10 +1504,16 @@
if (tokenResources == null) {
return false;
}
- final ArrayList<WeakReference<Resources>> resourcesRefs =
- tokenResources.activityResources;
+ final ArrayList<ActivityResource> resourcesRefs = tokenResources.activityResources;
for (int i = resourcesRefs.size() - 1; i >= 0; i--) {
- final Resources res = resourcesRefs.get(i).get();
+ final ActivityResource activityResource = resourcesRefs.get(i);
+ if (activityResource.overrideDisplayId != null) {
+ // This resource overrides the display of the token so we should not be
+ // modifying its display adjustments here.
+ continue;
+ }
+
+ final Resources res = activityResource.resources.get();
if (res != null) {
res.overrideDisplayAdjustments(override);
handled = true;
diff --git a/core/java/android/app/WindowTokenClient.java b/core/java/android/app/WindowTokenClient.java
index b5d1039..9092ef36 100644
--- a/core/java/android/app/WindowTokenClient.java
+++ b/core/java/android/app/WindowTokenClient.java
@@ -71,8 +71,7 @@
final boolean configChanged = config.diff(newConfig) != 0;
if (displayChanged || configChanged) {
// TODO(ag/9789103): update resource manager logic to track non-activity tokens
- mResourcesManager.updateResourcesForActivity(this, newConfig, newDisplayId,
- displayChanged);
+ mResourcesManager.updateResourcesForActivity(this, newConfig, newDisplayId);
}
if (displayChanged) {
context.updateDisplay(newDisplayId);
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index d2a774b..c7b20b2 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -2674,52 +2674,6 @@
}
/**
- * Construct an encrypted, RFCOMM server socket.
- * Call #accept to retrieve connections to this socket.
- *
- * @return An RFCOMM BluetoothServerSocket
- * @throws IOException On error, for example Bluetooth not available, or insufficient
- * permissions.
- * @hide
- */
- public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port) throws IOException {
- BluetoothServerSocket socket =
- new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, false, true, port);
- int errno = socket.mSocket.bindListen();
- if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
- socket.setChannel(socket.mSocket.getPort());
- }
- if (errno < 0) {
- //TODO(BT): Throw the same exception error code
- // that the previous code was using.
- //socket.mSocket.throwErrnoNative(errno);
- throw new IOException("Error: " + errno);
- }
- return socket;
- }
-
- /**
- * Construct a SCO server socket.
- * Call #accept to retrieve connections to this socket.
- *
- * @return A SCO BluetoothServerSocket
- * @throws IOException On error, for example Bluetooth not available, or insufficient
- * permissions.
- * @hide
- */
- public static BluetoothServerSocket listenUsingScoOn() throws IOException {
- BluetoothServerSocket socket =
- new BluetoothServerSocket(BluetoothSocket.TYPE_SCO, false, false, -1);
- int errno = socket.mSocket.bindListen();
- if (errno < 0) {
- //TODO(BT): Throw the same exception error code
- // that the previous code was using.
- //socket.mSocket.throwErrnoNative(errno);
- }
- return socket;
- }
-
- /**
* Construct an encrypted, authenticated, L2CAP server socket.
* Call #accept to retrieve connections to this socket.
* <p>To auto assign a port without creating a SDP record use
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index bed7b26..b7c3289 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2076,7 +2076,7 @@
STAGED_SESSION_VERIFICATION_FAILED,
STAGED_SESSION_ACTIVATION_FAILED,
STAGED_SESSION_UNKNOWN,
- STAGED_SESSION_OTHER_ERROR})
+ STAGED_SESSION_CONFLICT})
@Retention(RetentionPolicy.SOURCE)
public @interface StagedSessionErrorCode{}
/**
@@ -2103,10 +2103,10 @@
public static final int STAGED_SESSION_UNKNOWN = 3;
/**
- * Constant indicating that a known error occurred while processing this staged session, but
- * the error could not be matched to other categories.
+ * Constant indicating that the session was in conflict with another staged session and had
+ * to be sacrificed for resolution.
*/
- public static final int STAGED_SESSION_OTHER_ERROR = 4;
+ public static final int STAGED_SESSION_CONFLICT = 4;
/** {@hide} */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 2006048..0f1f276 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -88,7 +88,6 @@
import android.util.SparseArray;
import android.util.TypedValue;
import android.util.apk.ApkSignatureVerifier;
-import android.view.Display;
import android.view.Gravity;
import com.android.internal.R;
@@ -8536,7 +8535,7 @@
null,
androidAppInfo.resourceDirs,
androidAppInfo.sharedLibraryFiles,
- Display.DEFAULT_DISPLAY,
+ null,
null,
systemResources.getCompatibilityInfo(),
systemResources.getClassLoader(),
diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java
index bc41806..b0437ac 100644
--- a/core/java/android/content/res/ApkAssets.java
+++ b/core/java/android/content/res/ApkAssets.java
@@ -101,14 +101,11 @@
public @interface FormatType {}
@GuardedBy("this")
- private final long mNativePtr;
+ private long mNativePtr; // final, except cleared in finalizer.
@Nullable
@GuardedBy("this")
- private final StringBlock mStringBlock;
-
- @GuardedBy("this")
- private boolean mOpen = true;
+ private final StringBlock mStringBlock; // null or closed if mNativePtr = 0.
@PropertyFlags
private final int mFlags;
@@ -380,12 +377,16 @@
/** @hide */
@Nullable
public OverlayableInfo getOverlayableInfo(String overlayableName) throws IOException {
- return nativeGetOverlayableInfo(mNativePtr, overlayableName);
+ synchronized (this) {
+ return nativeGetOverlayableInfo(mNativePtr, overlayableName);
+ }
}
/** @hide */
public boolean definesOverlayable() throws IOException {
- return nativeDefinesOverlayable(mNativePtr);
+ synchronized (this) {
+ return nativeDefinesOverlayable(mNativePtr);
+ }
}
/**
@@ -412,12 +413,12 @@
*/
public void close() {
synchronized (this) {
- if (mOpen) {
- mOpen = false;
+ if (mNativePtr != 0) {
if (mStringBlock != null) {
mStringBlock.close();
}
nativeDestroy(mNativePtr);
+ mNativePtr = 0;
}
}
}
diff --git a/core/java/android/content/res/ResourcesKey.java b/core/java/android/content/res/ResourcesKey.java
index 9da0f20..fcb80aa 100644
--- a/core/java/android/content/res/ResourcesKey.java
+++ b/core/java/android/content/res/ResourcesKey.java
@@ -16,6 +16,8 @@
package android.content.res;
+import static android.os.Build.VERSION_CODES.O;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
@@ -41,8 +43,17 @@
@Nullable
public final String[] mLibDirs;
- public final int mDisplayId;
+ /**
+ * The display ID that overrides the global resources display to produce the Resources display.
+ * If set to something other than {@link android.view.Display#INVALID_DISPLAY} this will
+ * override the global resources display for this key.
+ */
+ @UnsupportedAppUsage(maxTargetSdk = O)
+ public int mDisplayId;
+ /**
+ * The configuration applied to the global configuration to produce the Resources configuration.
+ */
@NonNull
public final Configuration mOverrideConfiguration;
@@ -58,7 +69,7 @@
@Nullable String[] splitResDirs,
@Nullable String[] overlayDirs,
@Nullable String[] libDirs,
- int displayId,
+ int overrideDisplayId,
@Nullable Configuration overrideConfig,
@Nullable CompatibilityInfo compatInfo,
@Nullable ResourcesLoader[] loader) {
@@ -67,7 +78,7 @@
mOverlayDirs = overlayDirs;
mLibDirs = libDirs;
mLoaders = (loader != null && loader.length == 0) ? null : loader;
- mDisplayId = displayId;
+ mDisplayId = overrideDisplayId;
mOverrideConfiguration = new Configuration(overrideConfig != null
? overrideConfig : Configuration.EMPTY);
mCompatInfo = compatInfo != null ? compatInfo : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
@@ -77,7 +88,7 @@
hash = 31 * hash + Arrays.hashCode(mSplitResDirs);
hash = 31 * hash + Arrays.hashCode(mOverlayDirs);
hash = 31 * hash + Arrays.hashCode(mLibDirs);
- hash = 31 * hash + mDisplayId;
+ hash = 31 * hash + Objects.hashCode(mDisplayId);
hash = 31 * hash + Objects.hashCode(mOverrideConfiguration);
hash = 31 * hash + Objects.hashCode(mCompatInfo);
hash = 31 * hash + Arrays.hashCode(mLoaders);
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index c1ba209..392f562 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -310,6 +310,7 @@
* @hide
*/
// TODO (b/114338689): Remove the flag and use IWindowManager#setShouldShowSystemDecors
+ @TestApi
public static final int VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS = 1 << 9;
/**
@@ -320,6 +321,7 @@
* @see #VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
* @hide
*/
+ @TestApi
public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1 << 10;
/** @hide */
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index b0d4497..fecfd3c 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2954,7 +2954,7 @@
* enough current data to make a decision, or the battery is currently
* charging.
*
- * @param curTime The current elepsed realtime in microseconds.
+ * @param curTime The current elapsed realtime in microseconds.
*/
@UnsupportedAppUsage
public abstract long computeBatteryTimeRemaining(long curTime);
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 1eb3fc1..df1f1b2 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -68,7 +68,7 @@
private static final String PROPERTY_GFX_DRIVER_PRERELEASE = "ro.gfx.driver.1";
private static final String PROPERTY_GFX_DRIVER_BUILD_TIME = "ro.gfx.driver_build_time";
private static final String METADATA_DRIVER_BUILD_TIME =
- "com.android.graphics.updatabledriver.build_time";
+ "com.android.graphics.driver.build_time";
private static final String METADATA_DEVELOPER_DRIVER_ENABLE =
"com.android.graphics.developerdriver.enable";
private static final String METADATA_INJECT_LAYERS_ENABLE =
@@ -878,9 +878,10 @@
throw new NullPointerException("apk's meta-data cannot be null");
}
- final String driverBuildTime = driverAppInfo.metaData.getString(METADATA_DRIVER_BUILD_TIME);
- if (driverBuildTime == null || driverBuildTime.isEmpty()) {
- Log.v(TAG, "com.android.graphics.updatabledriver.build_time is not set");
+ String driverBuildTime = driverAppInfo.metaData.getString(METADATA_DRIVER_BUILD_TIME);
+ if (driverBuildTime == null || driverBuildTime.length() <= 1) {
+ Log.v(TAG, "com.android.graphics.driver.build_time is not set");
+ driverBuildTime = "L0";
}
// driver_build_time in the meta-data is in "L<Unix epoch timestamp>" format. e.g. L123456.
// Long.parseLong will throw if the meta-data "driver_build_time" is not set properly.
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index ce6c0ff..a92d91b 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -18,6 +18,7 @@
package android.os;
import android.os.BatterySaverPolicyConfig;
+import android.os.ParcelDuration;
import android.os.PowerSaveState;
import android.os.WorkSource;
@@ -58,6 +59,9 @@
boolean setAdaptivePowerSavePolicy(in BatterySaverPolicyConfig config);
boolean setAdaptivePowerSaveEnabled(boolean enabled);
int getPowerSaveModeTrigger();
+ void setBatteryDischargePrediction(in ParcelDuration timeRemaining, boolean isCustomized);
+ ParcelDuration getBatteryDischargePrediction();
+ boolean isBatteryDischargePredictionPersonalized();
boolean isDeviceIdleMode();
boolean isLightDeviceIdleMode();
diff --git a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/WindowManagerShellTest.java b/core/java/android/os/ParcelDuration.aidl
similarity index 60%
rename from libs/WindowManager/Shell/tests/src/com/android/wm/shell/WindowManagerShellTest.java
rename to core/java/android/os/ParcelDuration.aidl
index f1ead3c..e1aa109 100644
--- a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/WindowManagerShellTest.java
+++ b/core/java/android/os/ParcelDuration.aidl
@@ -14,25 +14,6 @@
* limitations under the License.
*/
-package com.android.wm.shell;
+package android.os;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for the shell.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class WindowManagerShellTest {
-
- WindowManagerShell mShell;
-
- @Test
- public void testNothing() {
- // Do nothing
- }
-}
+parcelable ParcelDuration cpp_header "android/ParcelDuration.h";
\ No newline at end of file
diff --git a/core/java/android/os/ParcelDuration.java b/core/java/android/os/ParcelDuration.java
new file mode 100644
index 0000000..37cde31
--- /dev/null
+++ b/core/java/android/os/ParcelDuration.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.annotation.NonNull;
+
+import java.time.Duration;
+
+/**
+ * Parcelable version of {@link Duration} that can be used in binder calls.
+ *
+ * @hide
+ */
+public final class ParcelDuration implements Parcelable {
+
+ private final long mSeconds;
+ private final int mNanos;
+
+ /**
+ * Construct a Duration object using the given millisecond value.
+ *
+ * @hide
+ */
+ public ParcelDuration(long ms) {
+ this(Duration.ofMillis(ms));
+ }
+
+ /**
+ * Wrap a {@link Duration} instance.
+ *
+ * @param duration The {@link Duration} instance to wrap.
+ */
+ public ParcelDuration(@NonNull Duration duration) {
+ mSeconds = duration.getSeconds();
+ mNanos = duration.getNano();
+ }
+
+ private ParcelDuration(@NonNull Parcel parcel) {
+ mSeconds = parcel.readLong();
+ mNanos = parcel.readInt();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int parcelableFlags) {
+ parcel.writeLong(mSeconds);
+ parcel.writeInt(mNanos);
+ }
+
+ /**
+ * Returns a {@link Duration} instance that's equivalent to this Duration's length.
+ *
+ * @return a {@link Duration} instance of identical length.
+ */
+ @NonNull
+ public Duration getDuration() {
+ return Duration.ofSeconds(mSeconds, mNanos);
+ }
+
+ @Override
+ @NonNull
+ public String toString() {
+ return getDuration().toString();
+ }
+
+ /**
+ * Creator for Duration.
+ */
+ @NonNull
+ public static final Parcelable.Creator<ParcelDuration> CREATOR =
+ new Parcelable.Creator<ParcelDuration>() {
+
+ @Override
+ @NonNull
+ public ParcelDuration createFromParcel(@NonNull Parcel source) {
+ return new ParcelDuration(source);
+ }
+
+ @Override
+ @NonNull
+ public ParcelDuration[] newArray(int size) {
+ return new ParcelDuration[size];
+ }
+ };
+}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 309805f..ed38b3f 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -41,6 +41,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.time.Duration;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicLong;
@@ -1719,6 +1720,70 @@
}
/**
+ * Allows an app to tell the system how long it believes the battery will last and whether
+ * this estimate is customized based on historical device usage or on a generic configuration.
+ * These estimates will be displayed on system UI surfaces in place of the system computed
+ * value.
+ *
+ * Calling this requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
+ *
+ * @param timeRemaining The time remaining as a {@link Duration}.
+ * @param isPersonalized true if personalized based on device usage history, false otherwise.
+ * @throws IllegalStateException if the device is powered or currently charging
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
+ public void setBatteryDischargePrediction(@NonNull Duration timeRemaining,
+ boolean isPersonalized) {
+ if (timeRemaining == null) {
+ throw new IllegalArgumentException("time remaining must not be null");
+ }
+ try {
+ mService.setBatteryDischargePrediction(new ParcelDuration(timeRemaining),
+ isPersonalized);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the current battery life remaining estimate.
+ *
+ * @return The estimated battery life remaining as a {@link Duration}. Will be {@code null} if
+ * the device is powered, charging, or an error was encountered.
+ */
+ @Nullable
+ public Duration getBatteryDischargePrediction() {
+ try {
+ final ParcelDuration parcelDuration = mService.getBatteryDischargePrediction();
+ if (parcelDuration == null) {
+ return null;
+ }
+ return parcelDuration.getDuration();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns whether the current battery life remaining estimate is personalized based on device
+ * usage history or not. This value does not take a device's powered or charging state into
+ * account.
+ *
+ * @return A boolean indicating if the current discharge estimate is personalized based on
+ * historical device usage or not.
+ */
+ public boolean isBatteryDischargePredictionPersonalized() {
+ try {
+ return mService.isBatteryDischargePredictionPersonalized();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Get data about the battery saver mode for a specific service
* @param serviceType unique key for the service, one of {@link ServiceType}
* @return Battery saver state data.
@@ -2185,6 +2250,18 @@
}
/**
+ * Intent that is broadcast when the enhanced battery discharge prediction changes. The new
+ * value can be retrieved via {@link #getBatteryDischargePrediction()}.
+ * This broadcast is only sent to registered receivers.
+ *
+ * @hide
+ */
+ @TestApi
+ @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_ENHANCED_DISCHARGE_PREDICTION_CHANGED =
+ "android.os.action.ENHANCED_DISCHARGE_PREDICTION_CHANGED";
+
+ /**
* Intent that is broadcast when the state of {@link #isPowerSaveMode()} changes.
* This broadcast is only sent to registered receivers.
*/
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 50cc764..58c8efa 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -102,6 +102,8 @@
/** @hide */
public static final long TRACE_TAG_RRO = 1L << 26;
/** @hide */
+ public static final long TRACE_TAG_SYSPROP = 1L << 27;
+ /** @hide */
public static final long TRACE_TAG_APEX_MANAGER = 1L << 18;
private static final long TRACE_TAG_NOT_READY = 1L << 63;
diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl
index 61e6a05..be8b929 100644
--- a/core/java/android/os/incremental/IIncrementalService.aidl
+++ b/core/java/android/os/incremental/IIncrementalService.aidl
@@ -90,9 +90,10 @@
int unlink(int storageId, in @utf8InCpp String path);
/**
- * Checks if a file's certain range is loaded. File is specified by its path.
+ * Returns overall loading progress of all the files on a storage, progress value between [0,1].
+ * Returns a negative value on error.
*/
- boolean isFileRangeLoaded(int storageId, in @utf8InCpp String path, long start, long end);
+ float getLoadingProgress(int storageId);
/**
* Reads the metadata of a file. File is specified by either its path or 16 byte id.
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index ca6114f..b8dbfbb 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -304,29 +304,21 @@
}
/**
- * Checks whether a file under the current storage directory is fully loaded.
+ * Returns the loading progress of a storage
*
- * @param path The relative path of the file.
- * @return True if the file is fully loaded.
+ * @return progress value between [0, 1].
*/
- public boolean isFileFullyLoaded(@NonNull String path) {
- return isFileRangeLoaded(path, 0, -1);
- }
-
- /**
- * Checks whether a range in a file if loaded.
- *
- * @param path The relative path of the file.
- * @param start The starting offset of the range.
- * @param end The ending offset of the range.
- * @return True if the file is fully loaded.
- */
- public boolean isFileRangeLoaded(@NonNull String path, long start, long end) {
+ public float getLoadingProgress() throws IOException {
try {
- return mService.isFileRangeLoaded(mId, path, start, end);
+ final float res = mService.getLoadingProgress(mId);
+ if (res < 0) {
+ throw new IOException(
+ "getLoadingProgress() failed at querying loading progress, errno " + -res);
+ }
+ return res;
} catch (RemoteException e) {
e.rethrowFromSystemServer();
- return false;
+ return 0;
}
}
diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java
index dfdb57c4..fb7b232 100644
--- a/core/java/android/preference/DialogPreference.java
+++ b/core/java/android/preference/DialogPreference.java
@@ -36,8 +36,6 @@
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
import android.widget.TextView;
/**
@@ -337,9 +335,6 @@
if (state != null) {
dialog.onRestoreInstanceState(state);
}
- if (needInputMethod()) {
- requestInputMethod(dialog);
- }
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
@@ -380,24 +375,6 @@
}
/**
- * Returns whether the preference needs to display a soft input method when the dialog
- * is displayed. Default is false. Subclasses should override this method if they need
- * the soft input method brought up automatically.
- * @hide
- */
- protected boolean needInputMethod() {
- return false;
- }
-
- /**
- * Sets the required flags on the dialog window to enable input method window to show up.
- */
- private void requestInputMethod(Dialog dialog) {
- Window window = dialog.getWindow();
- window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
- }
-
- /**
* Creates the content view for the dialog (if a custom content view is
* required). By default, it inflates the dialog layout resource if it is
* set.
diff --git a/core/java/android/preference/EditTextPreference.java b/core/java/android/preference/EditTextPreference.java
index af6f184..75c5102 100644
--- a/core/java/android/preference/EditTextPreference.java
+++ b/core/java/android/preference/EditTextPreference.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -28,6 +29,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
+import android.view.WindowInsets;
import android.widget.EditText;
/**
@@ -123,7 +125,7 @@
EditText editText = mEditText;
editText.setText(getText());
-
+
ViewParent oldParent = editText.getParent();
if (oldParent != view) {
if (oldParent != null) {
@@ -133,6 +135,13 @@
}
}
+ @Override
+ protected void showDialog(Bundle state) {
+ super.showDialog(state);
+ mEditText.requestFocus();
+ mEditText.getWindowInsetsController().show(WindowInsets.Type.ime());
+ }
+
/**
* Adds the EditText widget of this preference to the dialog's view.
*
@@ -183,13 +192,6 @@
return mEditText;
}
- /** @hide */
- @Override
- protected boolean needInputMethod() {
- // We want the input method to show, if possible, when dialog is displayed
- return true;
- }
-
@Override
protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
diff --git a/core/java/android/preference/OWNERS b/core/java/android/preference/OWNERS
index d20511f..827134e 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/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index b45a1eb..859b703 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -197,6 +197,13 @@
"intelligence_content_suggestions";
/**
+ * Namespace for JobScheduler configurations.
+ * @hide
+ */
+ @TestApi
+ public static final String NAMESPACE_JOB_SCHEDULER = "jobscheduler";
+
+ /**
* Namespace for all media native related features.
*
* @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 73b33c2..c302def 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -65,6 +65,7 @@
import android.os.DropBoxManager;
import android.os.IBinder;
import android.os.LocaleList;
+import android.os.PowerManager;
import android.os.PowerManager.AutoPowerSaveModeTriggers;
import android.os.Process;
import android.os.RemoteCallback;
@@ -9037,6 +9038,13 @@
"accessibility_magnification_capability";
/**
+ * Whether the Adaptive connectivity option is enabled.
+ *
+ * @hide
+ */
+ public static final String ADAPTIVE_CONNECTIVITY_ENABLED = "adaptive_connectivity_enabled";
+
+ /**
* Keys we no longer back up under the current schema, but want to continue to
* process when restoring historical backup datasets.
*
@@ -11837,36 +11845,6 @@
public static final String ALARM_MANAGER_CONSTANTS = "alarm_manager_constants";
/**
- * Job scheduler specific settings.
- * This is encoded as a key=value list, separated by commas. Ex:
- *
- * "min_ready_jobs_count=2,moderate_use_factor=.5"
- *
- * The following keys are supported:
- *
- * <pre>
- * min_idle_count (int)
- * min_charging_count (int)
- * min_connectivity_count (int)
- * min_content_count (int)
- * min_ready_jobs_count (int)
- * heavy_use_factor (float)
- * moderate_use_factor (float)
- * fg_job_count (int)
- * bg_normal_job_count (int)
- * bg_moderate_job_count (int)
- * bg_low_job_count (int)
- * bg_critical_job_count (int)
- * </pre>
- *
- * <p>
- * Type: string
- * @hide
- * @see com.android.server.job.JobSchedulerService.Constants
- */
- public static final String JOB_SCHEDULER_CONSTANTS = "job_scheduler_constants";
-
- /**
* Job scheduler QuotaController specific settings.
* This is encoded as a key=value list, separated by commas. Ex:
*
@@ -12538,18 +12516,23 @@
* millis. See {@link #BATTERY_ESTIMATES_LAST_UPDATE_TIME} for the last time this value
* was updated.
*
+ * @deprecated Use {@link PowerManager#getBatteryDischargePrediction()} instead.
* @hide
*/
+ @Deprecated
public static final String TIME_REMAINING_ESTIMATE_MILLIS =
"time_remaining_estimate_millis";
/**
- * A boolean indicating whether {@link #TIME_REMAINING_ESTIMATE_MILLIS} is based customized
- * to the devices usage or using global models. See
+ * A boolean indicating whether {@link #TIME_REMAINING_ESTIMATE_MILLIS} is customized
+ * to the device's usage or using global models. See
* {@link #BATTERY_ESTIMATES_LAST_UPDATE_TIME} for the last time this value was updated.
*
+ * @deprecated Use {@link PowerManager#isBatteryDischargePredictionPersonalized()} instead.
+ *
* @hide
*/
+ @Deprecated
public static final String TIME_REMAINING_ESTIMATE_BASED_ON_USAGE =
"time_remaining_estimate_based_on_usage";
@@ -12558,8 +12541,10 @@
* average based on historical drain rates. See {@link #BATTERY_ESTIMATES_LAST_UPDATE_TIME}
* for the last time this value was updated.
*
+ * @deprecated Use {@link PowerManager#getHistoricalDischargeTime()} instead.
* @hide
*/
+ @Deprecated
public static final String AVERAGE_TIME_TO_DISCHARGE = "average_time_to_discharge";
/**
@@ -12568,7 +12553,9 @@
* and {@link #AVERAGE_TIME_TO_DISCHARGE} were last updated.
*
* @hide
+ * @deprecated No longer needed due to {@link PowerManager#getBatteryDischargePrediction}.
*/
+ @Deprecated
public static final String BATTERY_ESTIMATES_LAST_UPDATE_TIME =
"battery_estimates_last_update_time";
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 678f43d..04a4ca4 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -137,7 +137,7 @@
* <p>The service can provide an extra degree of security by requiring the user to authenticate
* before an app can be autofilled. The authentication is typically required in 2 scenarios:
* <ul>
- * <li>To unlock the user data (for example, using a master password or fingerprint
+ * <li>To unlock the user data (for example, using a main password or fingerprint
* authentication) - see
* {@link FillResponse.Builder#setAuthentication(AutofillId[], android.content.IntentSender, android.widget.RemoteViews)}.
* <li>To unlock a specific dataset (for example, by providing a CVC for a credit card) - see
@@ -363,9 +363,9 @@
* {@code login.some_bank.com} credentials to the {@code my_financial_app}; if the user agrees,
* then the service returns an unlocked dataset with the {@code some_bank.com} credentials.
*
- * <p><b>Note:</b> The autofill service could also whitelist well-known browser apps and skip the
- * verifications above, as long as the service can verify the authenticity of the browser app by
- * checking its signing certificate.
+ * <p><b>Note:</b> The autofill service could also add well-known browser apps into an allowlist and
+ * skip the verifications above, as long as the service can verify the authenticity of the browser
+ * app by checking its signing certificate.
*
* <a name="MultipleStepsSave"></a>
* <h3>Saving when data is split in multiple screens</h3>
@@ -507,9 +507,9 @@
* services and fill data. This mode needs to be explicitly requested for a given package up
* to a specified max version code allowing clean migration path when the target app begins to
* support autofill natively. Note that enabling compatibility may degrade performance for the
- * target package and should be used with caution. The platform supports whitelisting which packages
- * can be targeted in compatibility mode to ensure this mode is used only when needed and as long
- * as needed.
+ * target package and should be used with caution. The platform supports creating an allowlist for
+ * including which packages can be targeted in compatibility mode to ensure this mode is used only
+ * when needed and as long as needed.
*
* <p>You can request compatibility mode for packages of interest in the meta-data resource
* associated with your service. Below is a sample service declaration:
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 3fcb361..3ed7f6c 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -62,17 +62,17 @@
* to release the native resources used by the TextToSpeech engine.
*
* Apps targeting Android 11 that use text-to-speech should declare {@link
- * TextToSpeech.Engine#INTENT_ACTION_TTS_SERVICE} in the <code><queries></code> elements of their
+ * TextToSpeech.Engine#INTENT_ACTION_TTS_SERVICE} in the {@code queries} elements of their
* manifest:
*
- * <code>
- * <queries>
+ * <pre>
+ * <queries>
* ...
- * <intent>
- * <action android:name="android.intent.action.TTS_SERVICE" />
- * </intent>
- * </queries>
- * </code>
+ * <intent>
+ * <action android:name="android.intent.action.TTS_SERVICE" />
+ * </intent>
+ * </queries>
+ * </pre>
*/
public class TextToSpeech {
@@ -254,18 +254,17 @@
* </ul>
*
* Apps targeting Android 11 that use text-to-speech should declare {@link
- * #INTENT_ACTION_TTS_SERVICE} in the <code><queries></code> elements of their
+ * TextToSpeech.Engine#INTENT_ACTION_TTS_SERVICE} in the {@code queries} elements of their
* manifest:
*
- * <code>
- * <queries>
+ * <pre>
+ * <queries>
* ...
- * <intent>
- * <action android:name="android.intent.action.TTS_SERVICE" />
- * </intent>
- * </queries>
- * </code>
-
+ * <intent>
+ * <action android:name="android.intent.action.TTS_SERVICE" />
+ * </intent>
+ * </queries>
+ * </pre>
*/
public class Engine {
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index a6e6d05..b807180 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -938,7 +938,6 @@
* {@link SubscriptionManager#getDefaultSubscriptionId})
* and the value as the list of {@link EmergencyNumber};
* null if this information is not available.
- * @hide
*/
public void onEmergencyNumberListChanged(
@NonNull Map<Integer, List<EmergencyNumber>> emergencyNumberList) {
@@ -948,17 +947,50 @@
/**
* Callback invoked when an outgoing call is placed to an emergency number.
*
- * @param placedEmergencyNumber the emergency number {@link EmergencyNumber} the call is placed
- * to.
+ * This method will be called when an emergency call is placed on any subscription (including
+ * the no-SIM case), regardless of which subscription this listener was registered on.
+ *
+ * This method is deprecated. Both this method and the new
+ * {@link #onOutgoingEmergencyCall(EmergencyNumber, int)} will be called when an outgoing
+ * emergency call is placed.
+ *
+ * @param placedEmergencyNumber The {@link EmergencyNumber} the emergency call was placed to.
+ *
+ * @deprecated Use {@link #onOutgoingEmergencyCall(EmergencyNumber, int)}.
* @hide
*/
@SystemApi
@TestApi
+ @Deprecated
public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber) {
// default implementation empty
}
/**
+ * Callback invoked when an outgoing call is placed to an emergency number.
+ *
+ * This method will be called when an emergency call is placed on any subscription (including
+ * the no-SIM case), regardless of which subscription this listener was registered on.
+ *
+ * Both this method and the deprecated {@link #onOutgoingEmergencyCall(EmergencyNumber)} will be
+ * called when an outgoing emergency call is placed. You should only implement one of these
+ * methods.
+ *
+ * @param placedEmergencyNumber The {@link EmergencyNumber} the emergency call was placed to.
+ * @param subscriptionId The subscription ID used to place the emergency call. If the
+ * emergency call was placed without a valid subscription (e.g. when there
+ * are no SIM cards in the device), this will be equal to
+ * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber,
+ int subscriptionId) {
+ }
+
+ /**
* Callback invoked when an outgoing SMS is placed to an emergency number.
*
* @param sentEmergencyNumber the emergency number {@link EmergencyNumber} the SMS is sent to.
@@ -1336,13 +1368,19 @@
() -> psl.onEmergencyNumberListChanged(emergencyNumberList)));
}
- public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber) {
+ public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber,
+ int subscriptionId) {
PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
if (psl == null) return;
Binder.withCleanCallingIdentity(
() -> mExecutor.execute(
() -> psl.onOutgoingEmergencyCall(placedEmergencyNumber)));
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(
+ () -> psl.onOutgoingEmergencyCall(placedEmergencyNumber,
+ subscriptionId)));
}
public void onOutgoingEmergencySms(@NonNull EmergencyNumber sentEmergencyNumber) {
diff --git a/core/java/android/text/OWNERS b/core/java/android/text/OWNERS
index e561371..0b51b2d 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/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java
index 25a4108..a06a0c6 100644
--- a/core/java/android/view/InputEventReceiver.java
+++ b/core/java/android/view/InputEventReceiver.java
@@ -25,6 +25,7 @@
import dalvik.system.CloseGuard;
+import java.io.PrintWriter;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
@@ -53,6 +54,7 @@
private static native void nativeFinishInputEvent(long receiverPtr, int seq, boolean handled);
private static native boolean nativeConsumeBatchedInputEvents(long receiverPtr,
long frameTimeNanos);
+ private static native String nativeDump(long receiverPtr, String prefix);
/**
* Creates an input event receiver bound to the specified input channel.
@@ -221,6 +223,18 @@
}
/**
+ * Dump the state of this InputEventReceiver to the writer.
+ * @param prefix the prefix (typically whitespace padding) to append in front of each line
+ * @param writer the writer where the dump should be written
+ */
+ public void dump(String prefix, PrintWriter writer) {
+ writer.println(prefix + getClass().getName());
+ writer.println(prefix + " mInputChannel: " + mInputChannel);
+ writer.println(prefix + " mSeqMap: " + mSeqMap);
+ writer.println(prefix + " mReceiverPtr:\n" + nativeDump(mReceiverPtr, prefix + " "));
+ }
+
+ /**
* Factory for InputEventReceiver
*/
public interface Factory {
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index e341845..1ef701f 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -70,11 +70,8 @@
// Window is visible.
public boolean visible;
- // Window can receive keys.
- public boolean canReceiveKeys;
-
- // Window has focus.
- public boolean hasFocus;
+ // Window can be focused.
+ public boolean focusable;
// Window has wallpaper. (window is the current wallpaper target)
public boolean hasWallpaper;
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 7f45c04..403ac3a 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -629,7 +629,7 @@
if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged");
mHost.notifyInsetsChanged();
}
- if (!mState.equals(state, true /* excludingCaptionInsets */,
+ if (!mState.equals(mLastDispatchedState, true /* excludingCaptionInsets */,
true /* excludeInvisibleIme */)) {
if (DEBUG) Log.d(TAG, "onStateChanged, send state to WM: " + mState);
updateRequestedState();
@@ -1138,15 +1138,14 @@
if (invokeCallback) {
control.cancel();
}
+ boolean stateChanged = false;
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
RunningAnimation runningAnimation = mRunningAnimations.get(i);
if (runningAnimation.runner == control) {
mRunningAnimations.remove(i);
ArraySet<Integer> types = toInternalType(control.getTypes());
for (int j = types.size() - 1; j >= 0; j--) {
- if (getSourceConsumer(types.valueAt(j)).notifyAnimationFinished()) {
- mHost.notifyInsetsChanged();
- }
+ stateChanged |= getSourceConsumer(types.valueAt(j)).notifyAnimationFinished();
}
if (invokeCallback && runningAnimation.startDispatched) {
dispatchAnimationEnd(runningAnimation.runner.getAnimation());
@@ -1154,6 +1153,10 @@
break;
}
}
+ if (stateChanged) {
+ mHost.notifyInsetsChanged();
+ updateRequestedState();
+ }
}
private void applyLocalVisibilityOverride() {
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 6b0b509..593b37a 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -60,6 +60,8 @@
*/
public class InsetsState implements Parcelable {
+ public static final InsetsState EMPTY = new InsetsState();
+
/**
* Internal representation of inset source types. This is different from the public API in
* {@link WindowInsets.Type} as one type from the public API might indicate multiple windows
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 859e9a4..65cc2f8 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
+import android.annotation.FloatRange;
import android.graphics.RenderNode;
import java.util.ArrayList;
@@ -725,7 +726,7 @@
* @see View#setAlpha(float)
* @return This object, allowing calls to methods in this class to be chained.
*/
- public ViewPropertyAnimator alpha(float value) {
+ public ViewPropertyAnimator alpha(@FloatRange(from = 0.0f, to = 1.0f) float value) {
animateProperty(ALPHA, value);
return this;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3f02d70..6e17ac9 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -7532,36 +7532,36 @@
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
String innerPrefix = prefix + " ";
- writer.print(prefix); writer.println("ViewRoot:");
- writer.print(innerPrefix); writer.print("mAdded="); writer.print(mAdded);
- writer.print(" mRemoved="); writer.println(mRemoved);
- writer.print(innerPrefix); writer.print("mConsumeBatchedInputScheduled=");
- writer.println(mConsumeBatchedInputScheduled);
- writer.print(innerPrefix); writer.print("mConsumeBatchedInputImmediatelyScheduled=");
- writer.println(mConsumeBatchedInputImmediatelyScheduled);
- writer.print(innerPrefix); writer.print("mPendingInputEventCount=");
- writer.println(mPendingInputEventCount);
- writer.print(innerPrefix); writer.print("mProcessInputEventsScheduled=");
- writer.println(mProcessInputEventsScheduled);
- writer.print(innerPrefix); writer.print("mTraversalScheduled=");
- writer.print(mTraversalScheduled);
- writer.print(innerPrefix); writer.print("mIsAmbientMode=");
- writer.print(mIsAmbientMode);
- writer.print(innerPrefix); writer.print("mUnbufferedInputSource=");
- writer.print(Integer.toHexString(mUnbufferedInputSource));
-
+ writer.println(prefix + "ViewRoot:");
+ writer.println(innerPrefix + "mAdded=" + mAdded);
+ writer.println(innerPrefix + "mRemoved=" + mRemoved);
+ writer.println(innerPrefix + "mStopped=" + mStopped);
+ writer.println(innerPrefix + "mConsumeBatchedInputScheduled="
+ + mConsumeBatchedInputScheduled);
+ writer.println(innerPrefix + "mConsumeBatchedInputImmediatelyScheduled="
+ + mConsumeBatchedInputImmediatelyScheduled);
+ writer.println(innerPrefix + "mPendingInputEventCount=" + mPendingInputEventCount);
+ writer.println(innerPrefix + "mProcessInputEventsScheduled="
+ + mProcessInputEventsScheduled);
+ writer.println(innerPrefix + "mTraversalScheduled=" + mTraversalScheduled);
if (mTraversalScheduled) {
- writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
- } else {
- writer.println();
+ writer.println(innerPrefix + " (barrier=" + mTraversalBarrier + ")");
}
+ writer.println(innerPrefix + "mIsAmbientMode=" + mIsAmbientMode);
+ writer.println(innerPrefix + "mUnbufferedInputSource="
+ + Integer.toHexString(mUnbufferedInputSource));
+
mFirstInputStage.dump(innerPrefix, writer);
+ if (mInputEventReceiver != null) {
+ mInputEventReceiver.dump(innerPrefix, writer);
+ }
+
mChoreographer.dump(prefix, writer);
mInsetsController.dump(prefix, writer);
- writer.print(prefix); writer.println("View Hierarchy:");
+ writer.println(prefix + "View Hierarchy:");
dumpViewHierarchy(innerPrefix, writer, mView);
}
@@ -8890,6 +8890,9 @@
* @param targets the search queue for targets
*/
private void collectRootScrollCaptureTargets(Queue<ScrollCaptureTarget> targets) {
+ if (mRootScrollCaptureCallbacks == null) {
+ return;
+ }
for (ScrollCaptureCallback cb : mRootScrollCaptureCallbacks) {
// Add to the list for consideration
Point offset = new Point(mView.getLeft(), mView.getTop());
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 2864485..7cc347d 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -294,7 +294,7 @@
*/
public InputMethodInfo(String packageName, String className,
CharSequence label, String settingsActivity) {
- this(buildDummyResolveInfo(packageName, className, label), false /* isAuxIme */,
+ this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */,
settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
false /* inlineSuggestionsEnabled */, false /* isVrOnly */);
@@ -344,7 +344,7 @@
mIsVrOnly = isVrOnly;
}
- private static ResolveInfo buildDummyResolveInfo(String packageName, String className,
+ private static ResolveInfo buildFakeResolveInfo(String packageName, String className,
CharSequence label) {
ResolveInfo ri = new ResolveInfo();
ServiceInfo si = new ServiceInfo();
diff --git a/core/java/android/webkit/PacProcessor.java b/core/java/android/webkit/PacProcessor.java
index 7e7b987..b04105a 100644
--- a/core/java/android/webkit/PacProcessor.java
+++ b/core/java/android/webkit/PacProcessor.java
@@ -32,6 +32,10 @@
/**
* Returns the default PacProcessor instance.
*
+ * <p> There can only be one default {@link PacProcessor} instance.
+ * This method will create a new instance if one did not already exist, or
+ * if the previous instance was released with {@link #releasePacProcessor}.
+ *
* @return the default PacProcessor instance.
*/
@NonNull
@@ -43,14 +47,21 @@
* Returns PacProcessor instance associated with the {@link Network}.
* The host resolution is done on this {@link Network}.
*
- * @param networkHandle a handle representing {@link Network} handle.
- * @return PacProcessor instance for the specified network.
- * @see Network#getNetworkHandle
- * @see Network#fromNetworkHandle
+ * <p> There can only be one {@link PacProcessor} instance at a time for each {@link Network}.
+ * This method will create a new instance if one did not already exist, or
+ * if the previous instance was released with {@link #releasePacProcessor}.
+ *
+ * <p> The {@link PacProcessor} instance needs to be released manually with
+ * {@link #releasePacProcessor} when the associated {@link Network} goes away.
+ *
+ * @param network a {@link Network} which this {@link PacProcessor}
+ * will use for host/address resolution.
+ * If {@code null} this method is equivalent to {@link #getInstance}.
+ * @return {@link PacProcessor} instance for the specified network.
*/
@NonNull
- static PacProcessor getInstanceForNetwork(long networkHandle) {
- return WebViewFactory.getProvider().getPacProcessorForNetwork(networkHandle);
+ static PacProcessor getInstanceForNetwork(@Nullable Network network) {
+ return WebViewFactory.getProvider().getPacProcessorForNetwork(network);
}
/**
@@ -73,19 +84,22 @@
/**
* Stops support for this {@link PacProcessor} and release its resources.
* No methods of this class must be called after calling this method.
+ *
+ * <p> Released instances will not be reused; a subsequent call to
+ * {@link #getInstance} and {@link #getInstanceForNetwork}
+ * for the same network will create a new instance.
*/
default void releasePacProcessor() {
throw new UnsupportedOperationException("Not implemented");
}
/**
- * Returns a network handle associated with this {@link PacProcessor}.
+ * Returns a {@link Network} associated with this {@link PacProcessor}.
*
- * @return a network handle or 0 if a network is unspecified.
- * @see Network#getNetworkHandle
- * @see Network#fromNetworkHandle
+ * @return an associated {@link Network} or {@code null} if a network is unspecified.
*/
- default long getNetworkHandle() {
+ @Nullable
+ default Network getNetwork() {
throw new UnsupportedOperationException("Not implemented");
}
}
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index f1863e3..ce999cd 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -17,6 +17,7 @@
package android.webkit;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Context;
import android.content.Intent;
@@ -188,13 +189,13 @@
* Returns PacProcessor instance associated with the {@link Network}.
* The host resolution is done on this {@link Network}.
*
- * @param networkHandle a network handle representing the {@link Network}.
+ * @param network a {@link Network} which needs to be associated
+ * with the returned {@link PacProcessor}.
+ * If {@code null} the method returns default {@link PacProcessor}.
* @return the {@link PacProcessor} instance associated with {@link Network}.
- * @see Network#getNetworkHandle
- * @see Network#fromNetworkHandle
*/
@NonNull
- default PacProcessor getPacProcessorForNetwork(long networkHandle) {
+ default PacProcessor getPacProcessorForNetwork(@Nullable Network network) {
throw new UnsupportedOperationException("Not implemented");
}
diff --git a/core/java/android/window/ITaskOrganizerController.aidl b/core/java/android/window/ITaskOrganizerController.aidl
index 1c03b2f..92fa80e 100644
--- a/core/java/android/window/ITaskOrganizerController.aidl
+++ b/core/java/android/window/ITaskOrganizerController.aidl
@@ -25,11 +25,9 @@
interface ITaskOrganizerController {
/**
- * Register a TaskOrganizer to manage tasks as they enter the given windowing mode.
- * If there was already a TaskOrganizer for this windowing mode it will be evicted
- * and receive taskVanished callbacks in the process.
+ * Register a TaskOrganizer to manage all the tasks with supported windowing modes.
*/
- void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode);
+ void registerTaskOrganizer(ITaskOrganizer organizer);
/**
* Unregisters a previously registered task organizer.
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index 502680d..7ec4f99 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -36,14 +36,12 @@
public class TaskOrganizer extends WindowOrganizer {
/**
- * Register a TaskOrganizer to manage tasks as they enter the given windowing mode.
- * If there was already a TaskOrganizer for this windowing mode it will be evicted
- * and receive taskVanished callbacks in the process.
+ * Register a TaskOrganizer to manage tasks as they enter a supported windowing mode.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
- public final void registerOrganizer(int windowingMode) {
+ public final void registerOrganizer() {
try {
- getController().registerTaskOrganizer(mInterface, windowingMode);
+ getController().registerTaskOrganizer(mInterface);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/window/TaskOrganizerTaskEmbedder.java b/core/java/android/window/TaskOrganizerTaskEmbedder.java
index 1b87521..46c72f8 100644
--- a/core/java/android/window/TaskOrganizerTaskEmbedder.java
+++ b/core/java/android/window/TaskOrganizerTaskEmbedder.java
@@ -73,7 +73,7 @@
// TODO(wm-shell): This currently prevents other organizers from controlling MULT_WINDOW
// windowing mode tasks. Plan is to migrate this to a wm-shell front-end when that
// infrastructure is ready.
- mTaskOrganizer.registerOrganizer(WINDOWING_MODE_MULTI_WINDOW);
+ // mTaskOrganizer.registerOrganizer();
mTaskOrganizer.setInterceptBackPressedOnTaskRoot(true);
return super.onInitialize();
diff --git a/core/java/android/window/VirtualDisplayTaskEmbedder.java b/core/java/android/window/VirtualDisplayTaskEmbedder.java
index 9ccb4c1..9013da3 100644
--- a/core/java/android/window/VirtualDisplayTaskEmbedder.java
+++ b/core/java/android/window/VirtualDisplayTaskEmbedder.java
@@ -19,6 +19,7 @@
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
import static android.view.Display.INVALID_DISPLAY;
import android.app.ActivityManager;
@@ -63,6 +64,7 @@
private int mDisplayDensityDpi;
private final boolean mSingleTaskInstance;
private final boolean mUsePublicVirtualDisplay;
+ private final boolean mUseTrustedDisplay;
private VirtualDisplay mVirtualDisplay;
private Insets mForwardedInsets;
private DisplayMetrics mTmpDisplayMetrics;
@@ -77,10 +79,12 @@
* only applicable if virtual displays are used
*/
public VirtualDisplayTaskEmbedder(Context context, VirtualDisplayTaskEmbedder.Host host,
- boolean singleTaskInstance, boolean usePublicVirtualDisplay) {
+ boolean singleTaskInstance, boolean usePublicVirtualDisplay,
+ boolean useTrustedDisplay) {
super(context, host);
mSingleTaskInstance = singleTaskInstance;
mUsePublicVirtualDisplay = usePublicVirtualDisplay;
+ mUseTrustedDisplay = useTrustedDisplay;
}
/**
@@ -103,6 +107,9 @@
if (mUsePublicVirtualDisplay) {
virtualDisplayFlags |= VIRTUAL_DISPLAY_FLAG_PUBLIC;
}
+ if (mUseTrustedDisplay) {
+ virtualDisplayFlags |= VIRTUAL_DISPLAY_FLAG_TRUSTED;
+ }
mVirtualDisplay = displayManager.createVirtualDisplay(
DISPLAY_NAME + "@" + System.identityHashCode(this), mHost.getWidth(),
diff --git a/core/java/com/android/internal/os/TEST_MAPPING b/core/java/com/android/internal/os/TEST_MAPPING
index f44b9fb..9698f19 100644
--- a/core/java/com/android/internal/os/TEST_MAPPING
+++ b/core/java/com/android/internal/os/TEST_MAPPING
@@ -26,5 +26,20 @@
"KernelSingleUidTimeReader\\.java"
]
}
+ ],
+ "postsubmit": [
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-filter": "com.android.internal.os.BstatsCpuTimesValidationTest"
+ }
+ ],
+ "file_patterns": [
+ "BatteryStatsImpl\\.java",
+ "KernelCpuUidFreqTimeReader\\.java",
+ "KernelSingleUidTimeReader\\.java"
+ ]
+ }
]
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 053b06f..2f8c457 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -347,7 +347,7 @@
super(context);
mLayoutInflater = LayoutInflater.from(context);
mRenderShadowsInCompositor = Settings.Global.getInt(context.getContentResolver(),
- DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 0) != 0;
+ DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 1) != 0;
}
/**
diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
index b2c5a99..d41d307 100644
--- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -61,7 +61,7 @@
void onRadioPowerStateChanged(in int state);
void onCallAttributesChanged(in CallAttributes callAttributes);
void onEmergencyNumberListChanged(in Map emergencyNumberList);
- void onOutgoingEmergencyCall(in EmergencyNumber placedEmergencyNumber);
+ void onOutgoingEmergencyCall(in EmergencyNumber placedEmergencyNumber, int subscriptionId);
void onOutgoingEmergencySms(in EmergencyNumber sentEmergencyNumber);
void onCallDisconnectCauseChanged(in int disconnectCause, in int preciseDisconnectCause);
void onImsCallDisconnectCauseChanged(in ImsReasonInfo imsReasonInfo);
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index c82a656..937b942 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -200,6 +200,20 @@
}
/**
+ * Ensures the truth of an expression involving whether the calling identity is authorized to
+ * call the calling method.
+ *
+ * @param expression a boolean expression
+ * @param message the message of the security exception to be thrown
+ * @throws SecurityException if {@code expression} is false
+ */
+ public static void checkSecurity(final boolean expression, final String message) {
+ if (!expression) {
+ throw new SecurityException(message);
+ }
+ }
+
+ /**
* Ensures the truth of an expression involving whether the calling user is authorized to
* call the calling method.
*
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index d5d635d..654b461 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -49,7 +49,8 @@
in ICheckCredentialProgressCallback progressCallback);
VerifyCredentialResponse verifyCredential(in LockscreenCredential credential, int userId, int flags);
VerifyCredentialResponse verifyTiedProfileChallenge(in LockscreenCredential credential, int userId, int flags);
- VerifyCredentialResponse verifyGatekeeperPassword(in byte[] gatekeeperPassword, long challenge, int userId);
+ VerifyCredentialResponse verifyGatekeeperPasswordHandle(long gatekeeperPasswordHandle, long challenge, int userId);
+ void removeGatekeeperPasswordHandle(long gatekeeperPasswordHandle);
boolean checkVoldPassword(int userId);
int getCredentialType(int userId);
byte[] getHashFactor(in LockscreenCredential currentCredential, int userId);
diff --git a/core/java/com/android/internal/widget/LocalImageResolver.java b/core/java/com/android/internal/widget/LocalImageResolver.java
index 2302de2..b4e108f 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.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 @@
* 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 @@
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/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index f7370d6..08a9f48 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -130,14 +130,15 @@
public @interface CredentialType {}
/**
- * Flag provided to {@link #verifyCredential(LockscreenCredential, long, int, int)} . If set,
- * the method will return the Gatekeeper Password in the {@link VerifyCredentialResponse}.
+ * Flag provided to {@link #verifyCredential(LockscreenCredential, int, int)} . If set, the
+ * method will return a handle to the Gatekeeper Password in the
+ * {@link VerifyCredentialResponse}.
*/
- public static final int VERIFY_FLAG_RETURN_GK_PW = 1 << 0;
+ public static final int VERIFY_FLAG_REQUEST_GK_PW_HANDLE = 1 << 0;
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, value = {
- VERIFY_FLAG_RETURN_GK_PW
+ VERIFY_FLAG_REQUEST_GK_PW_HANDLE
})
public @interface VerifyFlag {}
@@ -409,16 +410,16 @@
}
/**
- * With the Gatekeeper Password returned via {@link #verifyCredential(LockscreenCredential,
- * int, int)}, request Gatekeeper to create a HardwareAuthToken wrapping the given
- * challenge.
+ * With the Gatekeeper Password Handle returned via {@link #verifyCredential(
+ * LockscreenCredential, int, int)}, request Gatekeeper to create a HardwareAuthToken wrapping
+ * the given challenge.
*/
@NonNull
- public VerifyCredentialResponse verifyGatekeeperPassword(@NonNull byte[] gatekeeperPassword,
+ public VerifyCredentialResponse verifyGatekeeperPasswordHandle(long gatekeeperPasswordHandle,
long challenge, int userId) {
try {
- final VerifyCredentialResponse response = getLockSettings().verifyGatekeeperPassword(
- gatekeeperPassword, challenge, userId);
+ final VerifyCredentialResponse response = getLockSettings()
+ .verifyGatekeeperPasswordHandle(gatekeeperPasswordHandle, challenge, userId);
if (response == null) {
return VerifyCredentialResponse.ERROR;
}
@@ -429,6 +430,14 @@
}
}
+ public void removeGatekeeperPasswordHandle(long gatekeeperPasswordHandle) {
+ try {
+ getLockSettings().removeGatekeeperPasswordHandle(gatekeeperPasswordHandle);
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to remove gatekeeper password handle", e);
+ }
+ }
+
/**
* Check to see if a credential matches the saved one.
*
@@ -671,7 +680,7 @@
*/
public boolean setLockCredential(@NonNull LockscreenCredential newCredential,
@NonNull LockscreenCredential savedCredential, int userHandle) {
- if (!hasSecureLockScreen()) {
+ if (!hasSecureLockScreen() && newCredential.getType() != CREDENTIAL_TYPE_NONE) {
throw new UnsupportedOperationException(
"This operation requires the lock screen feature.");
}
@@ -766,7 +775,7 @@
/** Update the encryption password if it is enabled **/
private void updateEncryptionPassword(final int type, final byte[] password) {
- if (!hasSecureLockScreen()) {
+ if (!hasSecureLockScreen() && password != null && password.length != 0) {
throw new UnsupportedOperationException(
"This operation requires the lock screen feature.");
}
@@ -1566,7 +1575,7 @@
*/
public boolean setLockCredentialWithToken(@NonNull LockscreenCredential credential,
long tokenHandle, byte[] token, int userHandle) {
- if (!hasSecureLockScreen()) {
+ if (!hasSecureLockScreen() && credential.getType() != CREDENTIAL_TYPE_NONE) {
throw new UnsupportedOperationException(
"This operation requires the lock screen feature.");
}
diff --git a/core/java/com/android/internal/widget/VerifyCredentialResponse.java b/core/java/com/android/internal/widget/VerifyCredentialResponse.java
index e09eb42..ab14634 100644
--- a/core/java/com/android/internal/widget/VerifyCredentialResponse.java
+++ b/core/java/com/android/internal/widget/VerifyCredentialResponse.java
@@ -49,7 +49,7 @@
private final @ResponseCode int mResponseCode;
private final int mTimeout;
@Nullable private final byte[] mGatekeeperHAT;
- @Nullable private final byte[] mGatekeeperPw;
+ private final long mGatekeeperPasswordHandle;
public static final Parcelable.Creator<VerifyCredentialResponse> CREATOR
= new Parcelable.Creator<VerifyCredentialResponse>() {
@@ -58,10 +58,10 @@
final @ResponseCode int responseCode = source.readInt();
final int timeout = source.readInt();
final byte[] gatekeeperHAT = source.createByteArray();
- final byte[] gatekeeperPassword = source.createByteArray();
+ long gatekeeperPasswordHandle = source.readLong();
return new VerifyCredentialResponse(responseCode, timeout, gatekeeperHAT,
- gatekeeperPassword);
+ gatekeeperPasswordHandle);
}
@Override
@@ -72,7 +72,7 @@
public static class Builder {
@Nullable private byte[] mGatekeeperHAT;
- @Nullable private byte[] mGatekeeperPassword;
+ private long mGatekeeperPasswordHandle;
/**
* @param gatekeeperHAT Gatekeeper HardwareAuthToken, minted upon successful authentication.
@@ -82,8 +82,8 @@
return this;
}
- public Builder setGatekeeperPassword(byte[] gatekeeperPassword) {
- mGatekeeperPassword = gatekeeperPassword;
+ public Builder setGatekeeperPasswordHandle(long gatekeeperPasswordHandle) {
+ mGatekeeperPasswordHandle = gatekeeperPasswordHandle;
return this;
}
@@ -96,7 +96,7 @@
return new VerifyCredentialResponse(RESPONSE_OK,
0 /* timeout */,
mGatekeeperHAT,
- mGatekeeperPassword);
+ mGatekeeperPasswordHandle);
}
}
@@ -110,7 +110,7 @@
return new VerifyCredentialResponse(RESPONSE_RETRY,
timeout,
null /* gatekeeperHAT */,
- null /* gatekeeperPassword */);
+ 0L /* gatekeeperPasswordHandle */);
}
/**
@@ -121,20 +121,20 @@
return new VerifyCredentialResponse(RESPONSE_ERROR,
0 /* timeout */,
null /* gatekeeperHAT */,
- null /* gatekeeperPassword */);
+ 0L /* gatekeeperPasswordHandle */);
}
private VerifyCredentialResponse(@ResponseCode int responseCode, int timeout,
- @Nullable byte[] gatekeeperHAT, @Nullable byte[] gatekeeperPassword) {
+ @Nullable byte[] gatekeeperHAT, long gatekeeperPasswordHandle) {
mResponseCode = responseCode;
mTimeout = timeout;
mGatekeeperHAT = gatekeeperHAT;
- mGatekeeperPw = gatekeeperPassword;
+ mGatekeeperPasswordHandle = gatekeeperPasswordHandle;
}
public VerifyCredentialResponse stripPayload() {
return new VerifyCredentialResponse(mResponseCode, mTimeout,
- null /* gatekeeperHAT */, null /* gatekeeperPassword */);
+ null /* gatekeeperHAT */, 0L /* gatekeeperPasswordHandle */);
}
@Override
@@ -142,7 +142,7 @@
dest.writeInt(mResponseCode);
dest.writeInt(mTimeout);
dest.writeByteArray(mGatekeeperHAT);
- dest.writeByteArray(mGatekeeperPw);
+ dest.writeLong(mGatekeeperPasswordHandle);
}
@Override
@@ -155,9 +155,12 @@
return mGatekeeperHAT;
}
- @Nullable
- public byte[] getGatekeeperPw() {
- return mGatekeeperPw;
+ public long getGatekeeperPasswordHandle() {
+ return mGatekeeperPasswordHandle;
+ }
+
+ public boolean containsGatekeeperPasswordHandle() {
+ return mGatekeeperPasswordHandle != 0L;
}
public int getTimeout() {
@@ -176,7 +179,7 @@
public String toString() {
return "Response: " + mResponseCode
+ ", GK HAT: " + (mGatekeeperHAT != null)
- + ", GK PW: " + (mGatekeeperPw != null);
+ + ", GK PW: " + (mGatekeeperPasswordHandle != 0L);
}
public static VerifyCredentialResponse fromGateKeeperResponse(
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index ecdba3f..a063820 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -56,8 +56,7 @@
jfieldID scaleFactor;
jfieldID touchableRegion;
jfieldID visible;
- jfieldID canReceiveKeys;
- jfieldID hasFocus;
+ jfieldID focusable;
jfieldID hasWallpaper;
jfieldID paused;
jfieldID trustedOverlay;
@@ -145,10 +144,7 @@
mInfo.visible = env->GetBooleanField(obj,
gInputWindowHandleClassInfo.visible);
- mInfo.canReceiveKeys = env->GetBooleanField(obj,
- gInputWindowHandleClassInfo.canReceiveKeys);
- mInfo.hasFocus = env->GetBooleanField(obj,
- gInputWindowHandleClassInfo.hasFocus);
+ mInfo.focusable = env->GetBooleanField(obj, gInputWindowHandleClassInfo.focusable);
mInfo.hasWallpaper = env->GetBooleanField(obj,
gInputWindowHandleClassInfo.hasWallpaper);
mInfo.paused = env->GetBooleanField(obj,
@@ -320,11 +316,7 @@
GET_FIELD_ID(gInputWindowHandleClassInfo.visible, clazz,
"visible", "Z");
- GET_FIELD_ID(gInputWindowHandleClassInfo.canReceiveKeys, clazz,
- "canReceiveKeys", "Z");
-
- GET_FIELD_ID(gInputWindowHandleClassInfo.hasFocus, clazz,
- "hasFocus", "Z");
+ GET_FIELD_ID(gInputWindowHandleClassInfo.focusable, clazz, "focusable", "Z");
GET_FIELD_ID(gInputWindowHandleClassInfo.hasWallpaper, clazz,
"hasWallpaper", "Z");
diff --git a/core/jni/android_os_HwRemoteBinder.cpp b/core/jni/android_os_HwRemoteBinder.cpp
index f8f841c..3af55fe 100644
--- a/core/jni/android_os_HwRemoteBinder.cpp
+++ b/core/jni/android_os_HwRemoteBinder.cpp
@@ -269,22 +269,9 @@
return obj;
}
-JHwRemoteBinder::JHwRemoteBinder(
- JNIEnv *env, jobject thiz, const sp<hardware::IBinder> &binder)
- : mBinder(binder) {
- mDeathRecipientList = new HwBinderDeathRecipientList();
- jclass clazz = env->GetObjectClass(thiz);
- CHECK(clazz != NULL);
-
- mObject = env->NewWeakGlobalRef(thiz);
-}
-
-JHwRemoteBinder::~JHwRemoteBinder() {
- JNIEnv *env = AndroidRuntime::getJNIEnv();
-
- env->DeleteWeakGlobalRef(mObject);
- mObject = NULL;
-}
+JHwRemoteBinder::JHwRemoteBinder(JNIEnv* env, jobject /* thiz */,
+ const sp<hardware::IBinder>& binder)
+ : mBinder(binder), mDeathRecipientList(new HwBinderDeathRecipientList()) {}
sp<hardware::IBinder> JHwRemoteBinder::getBinder() const {
return mBinder;
diff --git a/core/jni/android_os_HwRemoteBinder.h b/core/jni/android_os_HwRemoteBinder.h
index 4b5a4c8..7eb81f3 100644
--- a/core/jni/android_os_HwRemoteBinder.h
+++ b/core/jni/android_os_HwRemoteBinder.h
@@ -36,9 +36,13 @@
std::vector<sp<HwBinderDeathRecipient>> mList;
Mutex mLock;
+protected:
+ ~HwBinderDeathRecipientList() override;
+
public:
- HwBinderDeathRecipientList();
- ~HwBinderDeathRecipientList();
+ explicit HwBinderDeathRecipientList();
+
+ DISALLOW_COPY_AND_ASSIGN(HwBinderDeathRecipientList);
void add(const sp<HwBinderDeathRecipient>& recipient);
void remove(const sp<HwBinderDeathRecipient>& recipient);
@@ -66,12 +70,7 @@
void setBinder(const sp<hardware::IBinder> &binder);
sp<HwBinderDeathRecipientList> getDeathRecipientList() const;
-protected:
- virtual ~JHwRemoteBinder();
-
private:
- jobject mObject;
-
sp<hardware::IBinder> mBinder;
sp<HwBinderDeathRecipientList> mDeathRecipientList;
DISALLOW_COPY_AND_ASSIGN(JHwRemoteBinder);
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index 979a69a..9ed71ac0 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -22,11 +22,12 @@
#include <nativehelper/JNIHelp.h>
+#include <android-base/stringprintf.h>
#include <android_runtime/AndroidRuntime.h>
+#include <input/InputTransport.h>
#include <log/log.h>
#include <utils/Looper.h>
-#include <utils/Vector.h>
-#include <input/InputTransport.h>
+#include <vector>
#include "android_os_MessageQueue.h"
#include "android_view_InputChannel.h"
#include "android_view_KeyEvent.h"
@@ -52,6 +53,21 @@
jmethodID onBatchedInputEventPending;
} gInputEventReceiverClassInfo;
+// Add prefix to the beginning of each line in 'str'
+static std::string addPrefix(std::string str, std::string_view prefix) {
+ str.insert(0, prefix); // insert at the beginning of the first line
+ const size_t prefixLength = prefix.length();
+ size_t pos = prefixLength; // just inserted prefix. start at the end of it
+ while (true) { // process all newline characters in 'str'
+ pos = str.find('\n', pos);
+ if (pos == std::string::npos) {
+ break;
+ }
+ str.insert(pos + 1, prefix); // insert prefix just after the '\n' character
+ pos += prefixLength + 1; // advance the position past the newly inserted prefix
+ }
+ return str;
+}
class NativeInputEventReceiver : public LooperCallback {
public:
@@ -64,6 +80,7 @@
status_t finishInputEvent(uint32_t seq, bool handled);
status_t consumeEvents(JNIEnv* env, bool consumeBatches, nsecs_t frameTime,
bool* outConsumedBatch);
+ std::string dump(const char* prefix);
protected:
virtual ~NativeInputEventReceiver();
@@ -80,7 +97,7 @@
PreallocatedInputEventFactory mInputEventFactory;
bool mBatchedInputEventPending;
int mFdEvents;
- Vector<Finish> mFinishQueue;
+ std::vector<Finish> mFinishQueue;
void setFdEvents(int events);
@@ -128,7 +145,7 @@
}
status_t status = mInputConsumer.sendFinishedSignal(seq, handled);
- if (status) {
+ if (status != OK) {
if (status == WOULD_BLOCK) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Could not send finished signal immediately. "
@@ -137,7 +154,7 @@
Finish finish;
finish.seq = seq;
finish.handled = handled;
- mFinishQueue.add(finish);
+ mFinishQueue.push_back(finish);
if (mFinishQueue.size() == 1) {
setFdEvents(ALOOPER_EVENT_INPUT | ALOOPER_EVENT_OUTPUT);
}
@@ -162,6 +179,9 @@
}
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
+ // Allowed return values of this function as documented in LooperCallback::handleEvent
+ constexpr int REMOVE_CALLBACK = 0;
+ constexpr int KEEP_CALLBACK = 1;
if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
// This error typically occurs when the publisher has closed the input channel
// as part of removing a window or finishing an IME session, in which case
@@ -170,41 +190,42 @@
ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred. "
"events=0x%x", getInputChannelName().c_str(), events);
}
- return 0; // remove the callback
+ return REMOVE_CALLBACK;
}
if (events & ALOOPER_EVENT_INPUT) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
status_t status = consumeEvents(env, false /*consumeBatches*/, -1, nullptr);
mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
- return status == OK || status == NO_MEMORY ? 1 : 0;
+ return status == OK || status == NO_MEMORY ? KEEP_CALLBACK : REMOVE_CALLBACK;
}
if (events & ALOOPER_EVENT_OUTPUT) {
for (size_t i = 0; i < mFinishQueue.size(); i++) {
- const Finish& finish = mFinishQueue.itemAt(i);
+ const Finish& finish = mFinishQueue[i];
status_t status = mInputConsumer.sendFinishedSignal(finish.seq, finish.handled);
- if (status) {
- mFinishQueue.removeItemsAt(0, i);
+ if (status != OK) {
+ mFinishQueue.erase(mFinishQueue.begin(), mFinishQueue.begin() + i);
if (status == WOULD_BLOCK) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Sent %zu queued finish events; %zu left.",
- getInputChannelName().c_str(), i, mFinishQueue.size());
+ getInputChannelName().c_str(), i, mFinishQueue.size());
}
- return 1; // keep the callback, try again later
+ return KEEP_CALLBACK; // try again later
}
ALOGW("Failed to send finished signal on channel '%s'. status=%d",
getInputChannelName().c_str(), status);
if (status != DEAD_OBJECT) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
- String8 message;
- message.appendFormat("Failed to finish input event. status=%d", status);
- jniThrowRuntimeException(env, message.string());
+ std::string message =
+ android::base::StringPrintf("Failed to finish input event. status=%d",
+ status);
+ jniThrowRuntimeException(env, message.c_str());
mMessageQueue->raiseAndClearException(env, "finishInputEvent");
}
- return 0; // remove the callback
+ return REMOVE_CALLBACK;
}
}
if (kDebugDispatchCycle) {
@@ -213,12 +234,12 @@
}
mFinishQueue.clear();
setFdEvents(ALOOPER_EVENT_INPUT);
- return 1;
+ return KEEP_CALLBACK;
}
ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
"events=0x%x", getInputChannelName().c_str(), events);
- return 1;
+ return KEEP_CALLBACK;
}
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
@@ -354,6 +375,23 @@
}
}
+std::string NativeInputEventReceiver::dump(const char* prefix) {
+ std::string out;
+ std::string consumerDump = addPrefix(mInputConsumer.dump(), " ");
+ out = out + "mInputConsumer:\n" + consumerDump + "\n";
+
+ out += android::base::StringPrintf("mBatchedInputEventPending: %s\n",
+ toString(mBatchedInputEventPending));
+ out = out + "mFinishQueue:\n";
+ for (const Finish& finish : mFinishQueue) {
+ out += android::base::StringPrintf(" seq=%" PRIu32 " handled=%s\n", finish.seq,
+ toString(finish.handled));
+ }
+ if (mFinishQueue.empty()) {
+ out = out + " <empty>\n";
+ }
+ return addPrefix(out, prefix);
+}
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject inputChannelObj, jobject messageQueueObj) {
@@ -374,9 +412,10 @@
receiverWeak, inputChannel, messageQueue);
status_t status = receiver->initialize();
if (status) {
- String8 message;
- message.appendFormat("Failed to initialize input event receiver. status=%d", status);
- jniThrowRuntimeException(env, message.string());
+ std::string message =
+ android::base::StringPrintf("Failed to initialize input event receiver. status=%d",
+ status);
+ jniThrowRuntimeException(env, message.c_str());
return 0;
}
@@ -397,9 +436,9 @@
reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
status_t status = receiver->finishInputEvent(seq, handled);
if (status && status != DEAD_OBJECT) {
- String8 message;
- message.appendFormat("Failed to finish input event. status=%d", status);
- jniThrowRuntimeException(env, message.string());
+ std::string message =
+ android::base::StringPrintf("Failed to finish input event. status=%d", status);
+ jniThrowRuntimeException(env, message.c_str());
}
}
@@ -411,26 +450,31 @@
status_t status = receiver->consumeEvents(env, true /*consumeBatches*/, frameTimeNanos,
&consumedBatch);
if (status && status != DEAD_OBJECT && !env->ExceptionCheck()) {
- String8 message;
- message.appendFormat("Failed to consume batched input event. status=%d", status);
- jniThrowRuntimeException(env, message.string());
+ std::string message =
+ android::base::StringPrintf("Failed to consume batched input event. status=%d",
+ status);
+ jniThrowRuntimeException(env, message.c_str());
return JNI_FALSE;
}
return consumedBatch ? JNI_TRUE : JNI_FALSE;
}
+static jstring nativeDump(JNIEnv* env, jclass clazz, jlong receiverPtr, jstring prefix) {
+ sp<NativeInputEventReceiver> receiver =
+ reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
+ ScopedUtfChars prefixChars(env, prefix);
+ return env->NewStringUTF(receiver->dump(prefixChars.c_str()).c_str());
+}
static const JNINativeMethod gMethods[] = {
- /* name, signature, funcPtr */
- { "nativeInit",
- "(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)J",
- (void*)nativeInit },
- { "nativeDispose", "(J)V",
- (void*)nativeDispose },
- { "nativeFinishInputEvent", "(JIZ)V",
- (void*)nativeFinishInputEvent },
- { "nativeConsumeBatchedInputEvents", "(JJ)Z",
- (void*)nativeConsumeBatchedInputEvents },
+ /* name, signature, funcPtr */
+ {"nativeInit",
+ "(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)J",
+ (void*)nativeInit},
+ {"nativeDispose", "(J)V", (void*)nativeDispose},
+ {"nativeFinishInputEvent", "(JIZ)V", (void*)nativeFinishInputEvent},
+ {"nativeConsumeBatchedInputEvents", "(JJ)Z", (void*)nativeConsumeBatchedInputEvents},
+ {"nativeDump", "(JLjava/lang/String;)Ljava/lang/String;", (void*)nativeDump},
};
int register_android_view_InputEventReceiver(JNIEnv* env) {
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 6eb8904..6212bcb 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2738,4 +2738,14 @@
// 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/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index d5619ca..9fccdaf 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -507,7 +507,7 @@
}
optional IntentFirewall intent_firewall = 65;
- optional SettingProto job_scheduler_constants = 66 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ reserved 66; // job_scheduler_constants
optional SettingProto job_scheduler_quota_controller_constants = 149 [ (android.privacy).dest = DEST_AUTOMATIC ];
reserved 150; // job_scheduler_time_controller_constants
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 541e018..3d12d07 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -181,6 +181,7 @@
optional SettingProto cmas_additional_broadcast_pkg = 14 [ (android.privacy).dest = DEST_AUTOMATIC ];
repeated SettingProto completed_categories = 15;
optional SettingProto connectivity_release_pending_intent_delay_ms = 16 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto adaptive_connectivity_enabled = 84 [ (android.privacy).dest = DEST_AUTOMATIC ];
message Controls {
option (android.msg_privacy).dest = DEST_EXPLICIT;
@@ -614,5 +615,5 @@
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 84;
+ // Next tag = 85;
}
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index 0455d58..a2f2c46 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -174,6 +174,16 @@
optional BatterySaverStateMachineProto battery_saver_state_machine = 50;
// Attentive timeout in ms. The timeout is disabled if it is set to -1.
optional sint32 attentive_timeout_ms = 51;
+ // The time (in the elapsed realtime timebase) at which the battery level will reach 0%. This
+ // is provided as an enhanced estimate and only valid if
+ // last_enhanced_discharge_time_updated_elapsed is greater than 0.
+ optional int64 enhanced_discharge_time_elapsed = 52;
+ // Timestamp (in the elapsed realtime timebase) of last update to enhanced battery estimate
+ // data.
+ optional int64 last_enhanced_discharge_time_updated_elapsed = 53;
+ // Whether or not the current enhanced discharge prediction is personalized based on device
+ // usage or not.
+ optional bool is_enhanced_discharge_prediction_personalized = 54;
}
// A com.android.server.power.PowerManagerService.SuspendBlockerImpl object.
diff --git a/core/res/Android.bp b/core/res/Android.bp
index b365de4..f94a2b0 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -46,6 +46,13 @@
},
}
+java_genrule {
+ name: "framework-res-package-jar",
+ srcs: [":framework-res{.export-package.apk}"],
+ out: ["framework-res-package.jar"],
+ cmd: "cp $(in) $(out)",
+}
+
// This logic can be removed once robolectric's transition to binary resources is complete
filegroup {
name: "robolectric_framework_raw_res_files",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 32c1e4a..57c1fcf 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -102,6 +102,7 @@
<protected-broadcast android:name="android.os.action.POWER_SAVE_WHITELIST_CHANGED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED_INTERNAL" />
+ <protected-broadcast android:name="android.os.action.ENHANCED_DISCHARGE_PREDICTION_CHANGED" />
<!-- @deprecated This is rarely used and will be phased out soon. -->
<protected-broadcast android:name="android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED" />
@@ -5040,6 +5041,10 @@
<permission android:name="android.permission.RESET_APP_ERRORS"
android:protectionLevel="signature" />
+ <!-- @hide Allows an application to create/destroy input consumer. -->
+ <permission android:name="android.permission.INPUT_CONSUMER"
+ android:protectionLevel="signature" />
+
<!-- Attribution for Geofencing service. -->
<attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
<!-- Attribution for Country Detector. -->
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 26dac61..b6f6627 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -515,9 +515,9 @@
<string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"للسماح للتطبيق بتلقّي الحِزم التي يتم إرسالها إلى جميع الأجهزة على شبكة Wi-Fi باستخدام عناوين بث متعدد، وليس باستخدام جهاز Android TV فقط. ويؤدي ذلك إلى استخدام قدر أكبر من الطاقة يفوق ما يتم استهلاكه في وضع البث غير المتعدد."</string>
<string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"للسماح للتطبيق بتلقي الحزم التي يتم إرسالها إلى جميع الأجهزة على شبكة Wi-Fi باستخدام عناوين بث متعدد، وليس باستخدام هاتفك فقط. ويؤدي ذلك إلى استخدام قدر أكبر من الطاقة يفوق وضع البث غير المتعدد."</string>
<string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"الدخول إلى إعدادات بلوتوث"</string>
- <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"للسماح للتطبيق بتهيئة لوحة البلوتوث المحلي، واكتشاف أجهزة التحكم عن بعد والاقتران بها."</string>
+ <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"للسماح للتطبيق بإعداد لوحة البلوتوث المحلي، واكتشاف أجهزة التحكم عن بعد والاقتران بها."</string>
<string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"للسماح للتطبيق بضبط البلوتوث على جهاز Android TV واكتشاف الأجهزة البعيدة والاقتران بها."</string>
- <string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"للسماح للتطبيق بتهيئة هاتف البلوتوث المحلي، واكتشاف أجهزة التحكم عن بعد والاقتران بها."</string>
+ <string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"للسماح للتطبيق بإعداد هاتف البلوتوث المحلي، واكتشاف أجهزة التحكم عن بعد والاقتران بها."</string>
<string name="permlab_accessWimaxState" msgid="7029563339012437434">"الاتصال بـشبكة WiMAX وقطع الاتصال بها"</string>
<string name="permdesc_accessWimaxState" msgid="5372734776802067708">"للسماح للتطبيق بتحديد ما إذا تم تفعيل WiMAX وتحديد معلومات حول أي شبكات WiMAX متصلة."</string>
<string name="permlab_changeWimaxState" msgid="6223305780806267462">"تغيير حالة WiMAX"</string>
@@ -1412,7 +1412,7 @@
<string name="select_input_method" msgid="3971267998568587025">"اختيار أسلوب الإدخال"</string>
<string name="show_ime" msgid="6406112007347443383">"استمرار عرضها على الشاشة أثناء نشاط لوحة المفاتيح الفعلية"</string>
<string name="hardware" msgid="1800597768237606953">"إظهار لوحة المفاتيح الافتراضية"</string>
- <string name="select_keyboard_layout_notification_title" msgid="4427643867639774118">"تهيئة لوحة المفاتيح الفعلية"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="4427643867639774118">"إعداد لوحة المفاتيح الفعلية"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"انقر لاختيار لغة وتنسيق"</string>
<string name="fast_scroll_alphabet" msgid="8854435958703888376">" أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
<string name="fast_scroll_numeric_alphabet" msgid="2529539945421557329">" 0123456789 أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 085df65..f9e3e2f 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -945,7 +945,7 @@
<string name="autofill_postal_code" msgid="7034789388968295591">"Kode pos"</string>
<string name="autofill_state" msgid="3341725337190434069">"Negara Bagian"</string>
<string name="autofill_zip_code" msgid="1315503730274962450">"Kode pos"</string>
- <string name="autofill_county" msgid="7781382735643492173">"Wilayah"</string>
+ <string name="autofill_county" msgid="7781382735643492173">"County"</string>
<string name="autofill_island" msgid="5367139008536593734">"Pulau"</string>
<string name="autofill_district" msgid="6428712062213557327">"Distrik"</string>
<string name="autofill_department" msgid="9047276226873531529">"Departemen"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 8871293..df7781e 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1773,7 +1773,7 @@
<string name="restr_pin_try_later" msgid="5897719962541636727">"Обиди се повторно подоцна"</string>
<string name="immersive_cling_title" msgid="2307034298721541791">"Се прикажува на цел екран"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"За да излезете, повлечете одозгора надолу."</string>
- <string name="immersive_cling_positive" msgid="7047498036346489883">"Разбрав"</string>
+ <string name="immersive_cling_positive" msgid="7047498036346489883">"Сфатив"</string>
<string name="done_label" msgid="7283767013231718521">"Готово"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Приказ на часови во кружно движење"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Приказ на минути во кружно движење"</string>
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 3c5d951..e17c312 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -129,6 +129,7 @@
<!-- virtual display test permissions -->
<uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" />
<uses-permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT" />
+ <uses-permission android:name="android.permission.ADD_TRUSTED_DISPLAY" />
<!-- color extraction test permissions -->
<uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 000e870..0a751dd 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -408,6 +408,9 @@
int originalVirtualDisplayOrientation = virtualDisplayContext.getResources()
.getConfiguration().orientation;
+
+ // Perform global config change and verify there is no config change in derived display
+ // context.
Configuration newAppConfig = new Configuration(originalAppConfig);
newAppConfig.seq++;
newAppConfig.orientation = newAppConfig.orientation == ORIENTATION_PORTRAIT
@@ -417,7 +420,7 @@
activityThread.handleConfigurationChanged(newAppConfig);
try {
- assertEquals("Virtual display orientation should not change when process"
+ assertEquals("Virtual display orientation must not change when process"
+ " configuration orientation changes.",
originalVirtualDisplayOrientation,
virtualDisplayContext.getResources().getConfiguration().orientation);
@@ -438,6 +441,50 @@
}
@Test
+ public void testActivityOrientationChanged_DoesntOverrideVirtualDisplayOrientation() {
+ final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+ final ActivityThread activityThread = activity.getActivityThread();
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ Configuration originalActivityConfig =
+ new Configuration(activity.getResources().getConfiguration());
+ DisplayManager dm = activity.getSystemService(DisplayManager.class);
+
+ int virtualDisplayWidth;
+ int virtualDisplayHeight;
+ if (originalActivityConfig.orientation == ORIENTATION_PORTRAIT) {
+ virtualDisplayWidth = 100;
+ virtualDisplayHeight = 200;
+ } else {
+ virtualDisplayWidth = 200;
+ virtualDisplayHeight = 100;
+ }
+ Display virtualDisplay = dm.createVirtualDisplay("virtual-display",
+ virtualDisplayWidth, virtualDisplayHeight, 200, null, 0).getDisplay();
+ Context virtualDisplayContext = activity.createDisplayContext(virtualDisplay);
+ int originalVirtualDisplayOrientation = virtualDisplayContext.getResources()
+ .getConfiguration().orientation;
+
+ // Perform activity config change and verify there is no config change in derived
+ // display context.
+ Configuration newActivityConfig = new Configuration(originalActivityConfig);
+ newActivityConfig.seq++;
+ newActivityConfig.orientation = newActivityConfig.orientation == ORIENTATION_PORTRAIT
+ ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
+
+ activityThread.updatePendingActivityConfiguration(activity.getActivityToken(),
+ newActivityConfig);
+ activityThread.handleActivityConfigurationChanged(activity.getActivityToken(),
+ newActivityConfig, INVALID_DISPLAY);
+
+ assertEquals("Virtual display orientation must not change when activity"
+ + " configuration orientation changes.",
+ originalVirtualDisplayOrientation,
+ virtualDisplayContext.getResources().getConfiguration().orientation);
+ });
+ }
+
+ @Test
public void testHandleConfigurationChanged_DoesntOverrideActivityConfig() {
final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
diff --git a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
index efcd458..45adf83 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
@@ -29,31 +29,50 @@
import junit.framework.TestCase;
+import java.util.HashMap;
+import java.util.Map;
+
public class ResourcesManagerTest extends TestCase {
+ private static final int SECONDARY_DISPLAY_ID = 1;
private static final String APP_ONE_RES_DIR = "app_one.apk";
private static final String APP_ONE_RES_SPLIT_DIR = "app_one_split.apk";
private static final String APP_TWO_RES_DIR = "app_two.apk";
private static final String LIB_RES_DIR = "lib.apk";
private ResourcesManager mResourcesManager;
- private DisplayMetrics mDisplayMetrics;
+ private Map<Integer, DisplayMetrics> mDisplayMetricsMap;
@Override
protected void setUp() throws Exception {
super.setUp();
- mDisplayMetrics = new DisplayMetrics();
- mDisplayMetrics.setToDefaults();
+ mDisplayMetricsMap = new HashMap<>();
+
+ DisplayMetrics defaultDisplayMetrics = new DisplayMetrics();
+ defaultDisplayMetrics.setToDefaults();
// Override defaults (which take device specific properties).
- mDisplayMetrics.density = 1.0f;
- mDisplayMetrics.densityDpi = DisplayMetrics.DENSITY_DEFAULT;
- mDisplayMetrics.xdpi = DisplayMetrics.DENSITY_DEFAULT;
- mDisplayMetrics.ydpi = DisplayMetrics.DENSITY_DEFAULT;
- mDisplayMetrics.noncompatDensity = mDisplayMetrics.density;
- mDisplayMetrics.noncompatDensityDpi = mDisplayMetrics.densityDpi;
- mDisplayMetrics.noncompatXdpi = DisplayMetrics.DENSITY_DEFAULT;
- mDisplayMetrics.noncompatYdpi = DisplayMetrics.DENSITY_DEFAULT;
+ defaultDisplayMetrics.density = 1.0f;
+ defaultDisplayMetrics.densityDpi = DisplayMetrics.DENSITY_DEFAULT;
+ defaultDisplayMetrics.xdpi = DisplayMetrics.DENSITY_DEFAULT;
+ defaultDisplayMetrics.ydpi = DisplayMetrics.DENSITY_DEFAULT;
+ defaultDisplayMetrics.widthPixels = 1440;
+ defaultDisplayMetrics.heightPixels = 2960;
+ defaultDisplayMetrics.noncompatDensity = defaultDisplayMetrics.density;
+ defaultDisplayMetrics.noncompatDensityDpi = defaultDisplayMetrics.densityDpi;
+ defaultDisplayMetrics.noncompatXdpi = DisplayMetrics.DENSITY_DEFAULT;
+ defaultDisplayMetrics.noncompatYdpi = DisplayMetrics.DENSITY_DEFAULT;
+ defaultDisplayMetrics.noncompatWidthPixels = defaultDisplayMetrics.widthPixels;
+ defaultDisplayMetrics.noncompatHeightPixels = defaultDisplayMetrics.heightPixels;
+ mDisplayMetricsMap.put(Display.DEFAULT_DISPLAY, defaultDisplayMetrics);
+
+ DisplayMetrics secondaryDisplayMetrics = new DisplayMetrics();
+ secondaryDisplayMetrics.setTo(defaultDisplayMetrics);
+ secondaryDisplayMetrics.widthPixels = 50;
+ secondaryDisplayMetrics.heightPixels = 100;
+ secondaryDisplayMetrics.noncompatWidthPixels = secondaryDisplayMetrics.widthPixels;
+ secondaryDisplayMetrics.noncompatHeightPixels = secondaryDisplayMetrics.heightPixels;
+ mDisplayMetricsMap.put(SECONDARY_DISPLAY_ID, secondaryDisplayMetrics);
mResourcesManager = new ResourcesManager() {
@Override
@@ -63,7 +82,7 @@
@Override
protected DisplayMetrics getDisplayMetrics(int displayId, DisplayAdjustments daj) {
- return mDisplayMetrics;
+ return mDisplayMetricsMap.get(displayId);
}
};
}
@@ -71,12 +90,12 @@
@SmallTest
public void testMultipleCallsWithIdenticalParametersCacheReference() {
Resources resources = mResourcesManager.getResources(
- null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+ null, APP_ONE_RES_DIR, null, null, null, null, null,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources);
Resources newResources = mResourcesManager.getResources(
- null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+ null, APP_ONE_RES_DIR, null, null, null, null, null,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(newResources);
assertSame(resources, newResources);
@@ -85,14 +104,14 @@
@SmallTest
public void testMultipleCallsWithDifferentParametersReturnDifferentReferences() {
Resources resources = mResourcesManager.getResources(
- null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+ null, APP_ONE_RES_DIR, null, null, null, null, null,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources);
Configuration overrideConfig = new Configuration();
overrideConfig.smallestScreenWidthDp = 200;
Resources newResources = mResourcesManager.getResources(
- null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, overrideConfig,
+ null, APP_ONE_RES_DIR, null, null, null, null, overrideConfig,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(newResources);
assertNotSame(resources, newResources);
@@ -101,13 +120,13 @@
@SmallTest
public void testAddingASplitCreatesANewImpl() {
Resources resources1 = mResourcesManager.getResources(
- null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+ null, APP_ONE_RES_DIR, null, null, null, null, null,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources1);
Resources resources2 = mResourcesManager.getResources(
null, APP_ONE_RES_DIR, new String[] { APP_ONE_RES_SPLIT_DIR }, null, null,
- Display.DEFAULT_DISPLAY, null, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO,null,
+ null, null, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null,
null);
assertNotNull(resources2);
@@ -118,12 +137,12 @@
@SmallTest
public void testUpdateConfigurationUpdatesAllAssetManagers() {
Resources resources1 = mResourcesManager.getResources(
- null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+ null, APP_ONE_RES_DIR, null, null, null, null, null,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources1);
Resources resources2 = mResourcesManager.getResources(
- null, APP_TWO_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+ null, APP_TWO_RES_DIR, null, null, null, null, null,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources2);
@@ -131,7 +150,7 @@
final Configuration overrideConfig = new Configuration();
overrideConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
Resources resources3 = mResourcesManager.getResources(
- activity, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY,
+ activity, APP_ONE_RES_DIR, null, null, null, null,
overrideConfig, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources3);
@@ -152,7 +171,7 @@
final Configuration expectedConfig = new Configuration();
expectedConfig.setToDefaults();
expectedConfig.setLocales(LocaleList.getAdjustedDefault());
- expectedConfig.densityDpi = mDisplayMetrics.densityDpi;
+ expectedConfig.densityDpi = mDisplayMetricsMap.get(Display.DEFAULT_DISPLAY).densityDpi;
expectedConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
assertEquals(expectedConfig, resources1.getConfiguration());
@@ -164,13 +183,13 @@
public void testTwoActivitiesWithIdenticalParametersShareImpl() {
Binder activity1 = new Binder();
Resources resources1 = mResourcesManager.getResources(
- activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+ activity1, APP_ONE_RES_DIR, null, null, null, null, null,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources1);
Binder activity2 = new Binder();
Resources resources2 = mResourcesManager.getResources(
- activity2, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+ activity2, APP_ONE_RES_DIR, null, null, null, null, null,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources1);
@@ -201,7 +220,7 @@
final Configuration overrideConfig = new Configuration();
overrideConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
mResourcesManager.updateResourcesForActivity(activity1, overrideConfig,
- Display.DEFAULT_DISPLAY, false /* movedToDifferentDisplay */);
+ Display.DEFAULT_DISPLAY);
assertSame(resources1, theme.getResources());
// Make sure we can still access the data.
@@ -226,7 +245,7 @@
Configuration config2 = new Configuration();
config2.screenLayout |= Configuration.SCREENLAYOUT_ROUND_YES;
Resources resources2 = mResourcesManager.getResources(
- activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, config2,
+ activity1, APP_ONE_RES_DIR, null, null, null, null, config2,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources2);
@@ -250,8 +269,7 @@
// Now update the Activity base override, and both resources should update.
config1.orientation = Configuration.ORIENTATION_LANDSCAPE;
- mResourcesManager.updateResourcesForActivity(activity1, config1, Display.DEFAULT_DISPLAY,
- false /* movedToDifferentDisplay */);
+ mResourcesManager.updateResourcesForActivity(activity1, config1, Display.DEFAULT_DISPLAY);
expectedConfig1.orientation = Configuration.ORIENTATION_LANDSCAPE;
assertEquals(expectedConfig1, resources1.getConfiguration());
@@ -290,4 +308,41 @@
assertEquals(originalOverrideDensity,
resources.getDisplayAdjustments().getConfiguration().densityDpi);
}
+
+ @SmallTest
+ public void testChangingActivityDisplayDoesntOverrideDisplayRequestedByResources() {
+ Binder activity = new Binder();
+
+ // Create a base token resources that are based on the default display.
+ Resources activityResources = mResourcesManager.createBaseTokenResources(
+ activity, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+ CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
+ // Create another resources that explicitly override the display of the base token above
+ // and set it to DEFAULT_DISPLAY.
+ Resources defaultDisplayResources = mResourcesManager.getResources(
+ activity, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+ CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
+
+ assertEquals(mDisplayMetricsMap.get(Display.DEFAULT_DISPLAY).widthPixels,
+ activityResources.getDisplayMetrics().widthPixels);
+ assertEquals(mDisplayMetricsMap.get(Display.DEFAULT_DISPLAY).heightPixels,
+ activityResources.getDisplayMetrics().heightPixels);
+ assertEquals(mDisplayMetricsMap.get(Display.DEFAULT_DISPLAY).widthPixels,
+ defaultDisplayResources.getDisplayMetrics().widthPixels);
+ assertEquals(mDisplayMetricsMap.get(Display.DEFAULT_DISPLAY).widthPixels,
+ defaultDisplayResources.getDisplayMetrics().widthPixels);
+
+ // Now change the display of the activity and ensure the activity's display metrics match
+ // the new display, but the other resources remain based on the default display.
+ mResourcesManager.updateResourcesForActivity(activity, null, SECONDARY_DISPLAY_ID);
+
+ assertEquals(mDisplayMetricsMap.get(SECONDARY_DISPLAY_ID).widthPixels,
+ activityResources.getDisplayMetrics().widthPixels);
+ assertEquals(mDisplayMetricsMap.get(SECONDARY_DISPLAY_ID).heightPixels,
+ activityResources.getDisplayMetrics().heightPixels);
+ assertEquals(mDisplayMetricsMap.get(Display.DEFAULT_DISPLAY).widthPixels,
+ defaultDisplayResources.getDisplayMetrics().widthPixels);
+ assertEquals(mDisplayMetricsMap.get(Display.DEFAULT_DISPLAY).widthPixels,
+ defaultDisplayResources.getDisplayMetrics().widthPixels);
+ }
}
diff --git a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
index daf6139..0f6284d 100644
--- a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
+++ b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
@@ -247,6 +247,25 @@
assertDisplayUnregistered(display);
}
+ /**
+ * Ensures that an application can create a trusted virtual display with the permission
+ * {@code ADD_TRUSTED_DISPLAY}.
+ */
+ public void testTrustedVirtualDisplay() throws Exception {
+ VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(NAME,
+ WIDTH, HEIGHT, DENSITY, mSurface,
+ DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED);
+ assertNotNull("virtual display must not be null", virtualDisplay);
+
+ Display display = virtualDisplay.getDisplay();
+ try {
+ assertDisplayRegistered(display, Display.FLAG_PRIVATE | Display.FLAG_TRUSTED);
+ } finally {
+ virtualDisplay.release();
+ }
+ assertDisplayUnregistered(display);
+ }
+
private void assertDisplayRegistered(Display display, int flags) {
assertNotNull("display object must not be null", display);
assertTrue("display must be valid", display.isValid());
diff --git a/core/tests/coretests/src/android/text/OWNERS b/core/tests/coretests/src/android/text/OWNERS
index a35c604..0b51b2d 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/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index af02b7b..de128ad 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -746,6 +746,20 @@
mController.onControlsChanged(createSingletonControl(ITYPE_IME));
assertEquals(newState.getSource(ITYPE_IME),
mTestHost.getModifiedState().peekSource(ITYPE_IME));
+
+ // The modified frames cannot be updated if there is an animation.
+ mController.onControlsChanged(createSingletonControl(ITYPE_NAVIGATION_BAR));
+ mController.hide(navigationBars());
+ newState = new InsetsState(mController.getState(), true /* copySource */);
+ newState.getSource(ITYPE_NAVIGATION_BAR).getFrame().top--;
+ mController.onStateChanged(newState);
+ assertNotEquals(newState.getSource(ITYPE_NAVIGATION_BAR),
+ mTestHost.getModifiedState().peekSource(ITYPE_NAVIGATION_BAR));
+
+ // The modified frames can be updated while the animation is done.
+ mController.cancelExistingAnimations();
+ assertEquals(newState.getSource(ITYPE_NAVIGATION_BAR),
+ mTestHost.getModifiedState().peekSource(ITYPE_NAVIGATION_BAR));
});
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index 7807f01..bef27e2 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -39,6 +39,7 @@
BatteryStatsTimerTest.class,
BatteryStatsUidTest.class,
BatteryStatsUserLifecycleTests.class,
+ BstatsCpuTimesValidationTest.class,
KernelCpuProcStringReaderTest.class,
KernelCpuUidActiveTimeReaderTest.class,
KernelCpuUidBpfMapReaderTest.class,
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
index c577eef..fe7c944 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
@@ -29,6 +29,8 @@
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_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 da40940..3636c73 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
@@ -33,6 +33,8 @@
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 665e22d..67f1fa5 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_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 c827fa8..33871e5 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_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 3d6ad7d..1b267ee 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 @@
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/car/Android.bp b/data/etc/car/Android.bp
index d0e688d..e122e00 100644
--- a/data/etc/car/Android.bp
+++ b/data/etc/car/Android.bp
@@ -144,13 +144,6 @@
}
prebuilt_etc {
- name: "allowed_privapp_com.android.car.floatingcardslauncher",
- sub_dir: "permissions",
- src: "com.android.car.floatingcardslauncher.xml",
- filename_from_src: true,
-}
-
-prebuilt_etc {
name: "allowed_privapp_com.android.car.ui.paintbooth",
sub_dir: "permissions",
src: "com.android.car.ui.paintbooth.xml",
diff --git a/data/etc/car/com.android.car.floatingcardslauncher.xml b/data/etc/car/com.android.car.floatingcardslauncher.xml
deleted file mode 100644
index 2755fee..0000000
--- a/data/etc/car/com.android.car.floatingcardslauncher.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<permissions>
- <privapp-permissions package="com.android.car.floatingcardslauncher">
- <permission name="android.permission.ACTIVITY_EMBEDDING"/>
- <permission name="android.permission.INTERACT_ACROSS_USERS"/>
- <permission name="android.permission.MANAGE_USERS"/>
- <permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
- <permission name="android.permission.MODIFY_PHONE_STATE"/>
- </privapp-permissions>
-</permissions>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index f410490..4f95a53 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -684,15 +684,13 @@
return b;
}
- // FIXME: The maxTargetSdk should be R, once R is no longer set to
- // CUR_DEVELOPMENT.
/**
* Creates a new immutable bitmap backed by ashmem which can efficiently
* be passed between processes.
*
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q,
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R,
publicAlternatives = "Use {@link #asShared()} instead")
public Bitmap createAshmemBitmap() {
checkRecycled("Can't copy a recycled bitmap");
diff --git a/graphics/java/android/graphics/BlurShader.java b/graphics/java/android/graphics/BlurShader.java
new file mode 100644
index 0000000..779a890
--- /dev/null
+++ b/graphics/java/android/graphics/BlurShader.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import android.annotation.Nullable;
+
+/**
+ * A subclass of shader that blurs input from another {@link android.graphics.Shader} instance
+ * or all the drawing commands with the {@link android.graphics.Paint} that this shader is
+ * attached to.
+ */
+public final class BlurShader extends Shader {
+
+ private final float mRadiusX;
+ private final float mRadiusY;
+ private final Shader mInputShader;
+
+ private long mNativeInputShader = 0;
+
+ /**
+ * Create a {@link BlurShader} that blurs the contents of the optional input shader
+ * with the specified radius along the x and y axis. If no input shader is provided
+ * then all drawing commands issued with a {@link android.graphics.Paint} that this
+ * shader is installed in will be blurred
+ * @param radiusX Radius of blur along the X axis
+ * @param radiusY Radius of blur along the Y axis
+ * @param inputShader Input shader that provides the content to be blurred
+ */
+ public BlurShader(float radiusX, float radiusY, @Nullable Shader inputShader) {
+ mRadiusX = radiusX;
+ mRadiusY = radiusY;
+ mInputShader = inputShader;
+ }
+
+ /** @hide **/
+ @Override
+ protected long createNativeInstance(long nativeMatrix) {
+ mNativeInputShader = mInputShader != null ? mInputShader.getNativeInstance() : 0;
+ return nativeCreate(nativeMatrix, mRadiusX, mRadiusY, mNativeInputShader);
+ }
+
+ /** @hide **/
+ @Override
+ protected boolean shouldDiscardNativeInstance() {
+ long currentNativeInstance = mInputShader != null ? mInputShader.getNativeInstance() : 0;
+ return mNativeInputShader != currentNativeInstance;
+ }
+
+ private static native long nativeCreate(long nativeMatrix, float radiusX, float radiusY,
+ long inputShader);
+}
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 28d7911..964640b 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -3111,7 +3111,7 @@
@CriticalNative
private static native boolean nGetFillPath(long paintPtr, long src, long dst);
@CriticalNative
- private static native long nSetShader(long paintPtr, long shader);
+ private static native void nSetShader(long paintPtr, long shader);
@CriticalNative
private static native long nSetColorFilter(long paintPtr, long filter);
@CriticalNative
diff --git a/keystore/TEST_MAPPING b/keystore/TEST_MAPPING
new file mode 100644
index 0000000..0511967
--- /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/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
new file mode 100644
index 0000000..1263748
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell;
+
+import android.app.ActivityManager.RunningTaskInfo;
+import android.util.Log;
+import android.util.Pair;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.window.TaskOrganizer;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Unified task organizer for all components in the shell.
+ */
+public class ShellTaskOrganizer extends TaskOrganizer {
+
+ private static final String TAG = "ShellTaskOrganizer";
+
+ /**
+ * Callbacks for when the tasks change in the system.
+ */
+ public interface TaskListener {
+ default void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {}
+ default void onTaskInfoChanged(RunningTaskInfo taskInfo) {}
+ default void onTaskVanished(RunningTaskInfo taskInfo) {}
+ default void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {}
+ }
+
+ private final SparseArray<ArrayList<TaskListener>> mListenersByWindowingMode =
+ new SparseArray<>();
+
+ // Keeps track of all the tasks reported to this organizer (changes in windowing mode will
+ // require us to report to both old and new listeners)
+ private final SparseArray<Pair<RunningTaskInfo, SurfaceControl>> mTasks = new SparseArray<>();
+
+ /**
+ * Adds a listener for tasks in a specific windowing mode.
+ */
+ public void addListener(TaskListener listener, int... windowingModes) {
+ for (int winMode : windowingModes) {
+ ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(winMode);
+ if (listeners == null) {
+ listeners = new ArrayList<>();
+ mListenersByWindowingMode.put(winMode, listeners);
+ }
+ if (listeners.contains(listener)) {
+ Log.w(TAG, "Listener already exists");
+ return;
+ }
+ listeners.add(listener);
+
+ // Notify the listener of all existing tasks in that windowing mode
+ for (int i = mTasks.size() - 1; i >= 0; i--) {
+ Pair<RunningTaskInfo, SurfaceControl> data = mTasks.valueAt(i);
+ int taskWinMode = data.first.configuration.windowConfiguration.getWindowingMode();
+ if (taskWinMode == winMode) {
+ listener.onTaskAppeared(data.first, data.second);
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes a registered listener.
+ */
+ public void removeListener(TaskListener listener) {
+ for (int i = 0; i < mListenersByWindowingMode.size(); i++) {
+ mListenersByWindowingMode.valueAt(i).remove(listener);
+ }
+ }
+
+ @Override
+ public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
+ mTasks.put(taskInfo.taskId, new Pair<>(taskInfo, leash));
+ ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(
+ getWindowingMode(taskInfo));
+ if (listeners != null) {
+ for (int i = listeners.size() - 1; i >= 0; i--) {
+ listeners.get(i).onTaskAppeared(taskInfo, leash);
+ }
+ }
+ }
+
+ @Override
+ public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
+ Pair<RunningTaskInfo, SurfaceControl> data = mTasks.get(taskInfo.taskId);
+ int winMode = getWindowingMode(taskInfo);
+ int prevWinMode = getWindowingMode(data.first);
+ if (prevWinMode != -1 && prevWinMode != winMode) {
+ // TODO: We currently send vanished/appeared as the task moves between win modes, but
+ // we should consider adding a different mode-changed callback
+ ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(prevWinMode);
+ if (listeners != null) {
+ for (int i = listeners.size() - 1; i >= 0; i--) {
+ listeners.get(i).onTaskVanished(taskInfo);
+ }
+ }
+ listeners = mListenersByWindowingMode.get(winMode);
+ if (listeners != null) {
+ SurfaceControl leash = data.second;
+ for (int i = listeners.size() - 1; i >= 0; i--) {
+ listeners.get(i).onTaskAppeared(taskInfo, leash);
+ }
+ }
+ } else {
+ ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(winMode);
+ if (listeners != null) {
+ for (int i = listeners.size() - 1; i >= 0; i--) {
+ listeners.get(i).onTaskInfoChanged(taskInfo);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
+ ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(
+ getWindowingMode(taskInfo));
+ if (listeners != null) {
+ for (int i = listeners.size() - 1; i >= 0; i--) {
+ listeners.get(i).onBackPressedOnTaskRoot(taskInfo);
+ }
+ }
+ }
+
+ @Override
+ public void onTaskVanished(RunningTaskInfo taskInfo) {
+ int prevWinMode = getWindowingMode(mTasks.get(taskInfo.taskId).first);
+ mTasks.remove(taskInfo.taskId);
+ ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(prevWinMode);
+ if (listeners != null) {
+ for (int i = listeners.size() - 1; i >= 0; i--) {
+ listeners.get(i).onTaskVanished(taskInfo);
+ }
+ }
+ }
+
+ private int getWindowingMode(RunningTaskInfo taskInfo) {
+ return taskInfo.configuration.windowConfiguration.getWindowingMode();
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index aeda2d9..283fd8d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -68,7 +68,7 @@
private final SparseArray<PerDisplay> mImePerDisplay = new SparseArray<>();
private final ArrayList<ImePositionProcessor> mPositionProcessors = new ArrayList<>();
- protected DisplayImeController(IWindowManager wmService, DisplayController displayController,
+ public DisplayImeController(IWindowManager wmService, DisplayController displayController,
Handler mainHandler, TransactionPool transactionPool) {
mHandler = mainHandler;
mWmService = wmService;
@@ -76,7 +76,8 @@
mDisplayController = displayController;
}
- protected void startMonitorDisplays() {
+ /** Starts monitor displays changes and set insets controller for each displays. */
+ public void startMonitorDisplays() {
mDisplayController.addDisplayWindowListener(this);
}
@@ -493,29 +494,4 @@
return IInputMethodManager.Stub.asInterface(
ServiceManager.getService(Context.INPUT_METHOD_SERVICE));
}
-
- /** Builds {@link DisplayImeController} instance. */
- public static class Builder {
- private IWindowManager mWmService;
- private DisplayController mDisplayController;
- private Handler mHandler;
- private TransactionPool mTransactionPool;
-
- public Builder(IWindowManager wmService, DisplayController displayController,
- Handler handler, TransactionPool transactionPool) {
- mWmService = wmService;
- mDisplayController = displayController;
- mHandler = handler;
- mTransactionPool = transactionPool;
- }
-
- /** Builds and initializes {@link DisplayImeController} instance. */
- public DisplayImeController build() {
- DisplayImeController displayImeController = new DisplayImeController(mWmService,
- mDisplayController, mHandler, mTransactionPool);
- // Separates startMonitorDisplays from constructor to prevent circular init issue.
- displayImeController.startMonitorDisplays();
- return displayImeController;
- }
- }
}
diff --git a/libs/WindowManager/Shell/tests/README.md b/libs/WindowManager/Shell/tests/README.md
new file mode 100644
index 0000000..c19db76
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/README.md
@@ -0,0 +1,15 @@
+# WM Shell Test
+
+This contains all tests written for WM (WindowManager) Shell and it's currently
+divided into 3 categories
+
+- unittest, tests against individual functions, usually @SmallTest and do not
+ require UI automation nor real device to run
+- integration, this maybe a mix of functional and integration tests. Contains
+ tests verify the WM Shell as a whole, like talking to WM core. This usually
+ involves mocking the window manager service or even talking to the real one.
+ Due to this nature, test cases in this package is normally annotated as
+ @LargeTest and runs with UI automation on real device
+- flicker, similar to functional tests with its sole focus on flickerness. See
+ [WM Shell Flicker Test Package](http://cs/android/framework/base/libs/WindowManager/Shell/tests/flicker/)
+ for more details
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp
new file mode 100644
index 0000000..5879022
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+android_test {
+ name: "WMShellFlickerTests",
+ srcs: ["src/**/*.java", "src/**/*.kt"],
+ manifest: "AndroidManifest.xml",
+ test_config: "AndroidTest.xml",
+ platform_apis: true,
+ certificate: "platform",
+ test_suites: ["device-tests"],
+ libs: ["android.test.runner"],
+ static_libs: [
+ "androidx.test.ext.junit",
+ "flickerlib",
+ "truth-prebuilt",
+ "app-helpers-core",
+ "launcher-helper-lib",
+ "launcher-aosp-tapl"
+ ],
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
new file mode 100644
index 0000000..8b2f668
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wm.shell.flicker">
+
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
+ <!-- Read and write traces from external storage -->
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <!-- Write secure settings -->
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <!-- Capture screen contents -->
+ <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
+ <!-- Enable / Disable tracing !-->
+ <uses-permission android:name="android.permission.DUMP" />
+ <!-- Run layers trace -->
+ <uses-permission android:name="android.permission.HARDWARE_TEST"/>
+ <!-- Workaround grant runtime permission exception from b/152733071 -->
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
+ <uses-permission android:name="android.permission.READ_LOGS"/>
+ <application>
+ <uses-library android:name="android.test.runner"/>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.wm.shell.flicker"
+ android:label="WindowManager Shell Flicker Tests">
+ </instrumentation>
+</manifest>
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
new file mode 100644
index 0000000..526fc50
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright 2020 Google Inc. All Rights Reserved.
+ -->
+<configuration description="Runs WindowManager Shell Flicker Tests">
+ <option name="test-tag" value="FlickerTests" />
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- keeps the screen on during tests -->
+ <option name="screen-always-on" value="on" />
+ <!-- prevents the phone from restarting -->
+ <option name="force-skip-system-props" value="true" />
+ <!-- set WM tracing verbose level to all -->
+ <option name="run-command" value="cmd window tracing level all" />
+ <!-- inform WM to log all transactions -->
+ <option name="run-command" value="cmd window tracing transaction" />
+ <!-- restart launcher to activate TAPL -->
+ <option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.DeviceCleaner">
+ <!-- reboot the device to teardown any crashed tests -->
+ <option name="cleanup-action" value="REBOOT" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true"/>
+ <option name="test-file-name" value="WMShellFlickerTests.apk"/>
+ <option name="test-file-name" value="WMShellFlickerTestApp.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.wm.shell.flicker"/>
+ <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
+ <option name="shell-timeout" value="6600s" />
+ <option name="test-timeout" value="6000s" />
+ <option name="hidden-api-checks" value="false" />
+ </test>
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/storage/emulated/0/Android/data/com.android.wm.shell.flicker/files" />
+ <option name="collect-on-run-ended-only" value="true" />
+ <option name="clean-up" value="true" />
+ </metrics_collector>
+</configuration>
diff --git a/libs/WindowManager/Shell/tests/flicker/README.md b/libs/WindowManager/Shell/tests/flicker/README.md
new file mode 100644
index 0000000..4502d49
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/README.md
@@ -0,0 +1,10 @@
+# WM Shell Flicker Test Package
+
+Please reference the following links
+
+- [Introduction to Flicker Test Library](http://cs/android/platform_testing/libraries/flicker/)
+- [Flicker Test in frameworks/base](http://cs/android/frameworks/base/tests/FlickerTests/)
+
+on what is Flicker Test and how to write a Flicker Test
+
+To run the Flicker Tests for WM Shell, simply run `atest WMShellFlickerTests`
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
new file mode 100644
index 0000000..4ff2bfc
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker
+
+import com.android.server.wm.flicker.dsl.EventLogAssertion
+import com.android.server.wm.flicker.dsl.LayersAssertion
+import com.android.server.wm.flicker.dsl.WmAssertion
+import com.android.server.wm.flicker.helpers.WindowUtils
+
+@JvmOverloads
+fun WmAssertion.statusBarWindowIsAlwaysVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("statusBarWindowIsAlwaysVisible", enabled, bugId) {
+ this.showsAboveAppWindow(FlickerTestBase.STATUS_BAR_WINDOW_TITLE)
+ }
+}
+
+@JvmOverloads
+fun WmAssertion.navBarWindowIsAlwaysVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("navBarWindowIsAlwaysVisible", enabled, bugId) {
+ this.showsAboveAppWindow(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.noUncoveredRegions(
+ beginRotation: Int,
+ endRotation: Int = beginRotation,
+ allStates: Boolean = true,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ val startingBounds = WindowUtils.getDisplayBounds(beginRotation)
+ val endingBounds = WindowUtils.getDisplayBounds(endRotation)
+ if (allStates) {
+ all("noUncoveredRegions", enabled, bugId) {
+ if (startingBounds == endingBounds) {
+ this.coversAtLeastRegion(startingBounds)
+ } else {
+ this.coversAtLeastRegion(startingBounds)
+ .then()
+ .coversAtLeastRegion(endingBounds)
+ }
+ }
+ } else {
+ start("noUncoveredRegions_StartingPos") {
+ this.coversAtLeastRegion(startingBounds)
+ }
+ end("noUncoveredRegions_EndingPos") {
+ this.coversAtLeastRegion(endingBounds)
+ }
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.navBarLayerIsAlwaysVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("navBarLayerIsAlwaysVisible", enabled, bugId) {
+ this.showsLayer(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.statusBarLayerIsAlwaysVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("statusBarLayerIsAlwaysVisible", enabled, bugId) {
+ this.showsLayer(FlickerTestBase.STATUS_BAR_WINDOW_TITLE)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.navBarLayerRotatesAndScales(
+ beginRotation: Int,
+ endRotation: Int = beginRotation,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ val startingPos = WindowUtils.getNavigationBarPosition(beginRotation)
+ val endingPos = WindowUtils.getNavigationBarPosition(endRotation)
+
+ start("navBarLayerRotatesAndScales_StartingPos", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, startingPos)
+ }
+ end("navBarLayerRotatesAndScales_EndingPost", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, endingPos)
+ }
+
+ if (startingPos == endingPos) {
+ all("navBarLayerRotatesAndScales", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, startingPos)
+ }
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.statusBarLayerRotatesScales(
+ beginRotation: Int,
+ endRotation: Int = beginRotation,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ val startingPos = WindowUtils.getStatusBarPosition(beginRotation)
+ val endingPos = WindowUtils.getStatusBarPosition(endRotation)
+
+ start("statusBarLayerRotatesScales_StartingPos", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.STATUS_BAR_WINDOW_TITLE, startingPos)
+ }
+ end("statusBarLayerRotatesScales_EndingPos", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.STATUS_BAR_WINDOW_TITLE, endingPos)
+ }
+}
+
+fun EventLogAssertion.focusChanges(
+ vararg windows: String,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all(enabled = enabled, bugId = bugId) {
+ this.focusChanges(windows)
+ }
+}
+
+fun EventLogAssertion.focusDoesNotChange(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all(enabled = enabled, bugId = bugId) {
+ this.focusDoesNotChange()
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt
new file mode 100644
index 0000000..99f824b
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker
+
+import android.os.RemoteException
+import android.os.SystemClock
+import android.platform.helpers.IAppHelper
+import android.view.Surface
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.server.wm.flicker.Flicker
+
+/**
+ * Base class of all Flicker test that performs common functions for all flicker tests:
+ *
+ *
+ * - Caches transitions so that a transition is run once and the transition results are used by
+ * tests multiple times. This is needed for parameterized tests which call the BeforeClass methods
+ * multiple times.
+ * - Keeps track of all test artifacts and deletes ones which do not need to be reviewed.
+ * - Fails tests if results are not available for any test due to jank.
+ */
+abstract class FlickerTestBase {
+ val instrumentation by lazy {
+ InstrumentationRegistry.getInstrumentation()
+ }
+ val uiDevice by lazy {
+ UiDevice.getInstance(instrumentation)
+ }
+
+ /**
+ * Build a test tag for the test
+ * @param testName Name of the transition(s) being tested
+ * @param app App being launcher
+ * @param rotation Initial screen rotation
+ *
+ * @return test tag with pattern <NAME>__<APP>__<ROTATION>
+ </ROTATION></APP></NAME> */
+ protected fun buildTestTag(testName: String, app: IAppHelper, rotation: Int): String {
+ return buildTestTag(
+ testName, app, rotation, rotation, app2 = null, extraInfo = "")
+ }
+
+ /**
+ * Build a test tag for the test
+ * @param testName Name of the transition(s) being tested
+ * @param app App being launcher
+ * @param beginRotation Initial screen rotation
+ * @param endRotation End screen rotation (if any, otherwise use same as initial)
+ *
+ * @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION>
+ </END_ROTATION></BEGIN_ROTATION></APP></NAME> */
+ protected fun buildTestTag(
+ testName: String,
+ app: IAppHelper,
+ beginRotation: Int,
+ endRotation: Int
+ ): String {
+ return buildTestTag(
+ testName, app, beginRotation, endRotation, app2 = null, extraInfo = "")
+ }
+
+ /**
+ * Build a test tag for the test
+ * @param testName Name of the transition(s) being tested
+ * @param app App being launcher
+ * @param app2 Second app being launched (if any)
+ * @param beginRotation Initial screen rotation
+ * @param endRotation End screen rotation (if any, otherwise use same as initial)
+ * @param extraInfo Additional information to append to the tag
+ *
+ * @return test tag with pattern <NAME>__<APP></APP>(S)>__<ROTATION></ROTATION>(S)>[__<EXTRA>]
+ </EXTRA></NAME> */
+ protected fun buildTestTag(
+ testName: String,
+ app: IAppHelper,
+ beginRotation: Int,
+ endRotation: Int,
+ app2: IAppHelper?,
+ extraInfo: String
+ ): String {
+ var testTag = "${testName}__${app.launcherName}"
+ if (app2 != null) {
+ testTag += "-${app2.launcherName}"
+ }
+ testTag += "__${Surface.rotationToString(beginRotation)}"
+ if (endRotation != beginRotation) {
+ testTag += "-${Surface.rotationToString(endRotation)}"
+ }
+ if (extraInfo.isNotEmpty()) {
+ testTag += "__$extraInfo"
+ }
+ return testTag
+ }
+
+ protected fun Flicker.setRotation(rotation: Int) {
+ try {
+ when (rotation) {
+ Surface.ROTATION_270 -> device.setOrientationLeft()
+ Surface.ROTATION_90 -> device.setOrientationRight()
+ Surface.ROTATION_0 -> device.setOrientationNatural()
+ else -> device.setOrientationNatural()
+ }
+ // Wait for animation to complete
+ SystemClock.sleep(1000)
+ } catch (e: RemoteException) {
+ throw RuntimeException(e)
+ }
+ }
+
+ companion object {
+ const val NAVIGATION_BAR_WINDOW_TITLE = "NavigationBar"
+ const val STATUS_BAR_WINDOW_TITLE = "StatusBar"
+ const val DOCKED_STACK_DIVIDER = "DockedStackDivider"
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NonRotationTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NonRotationTestBase.kt
new file mode 100644
index 0000000..90334ae
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NonRotationTestBase.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker
+
+import android.view.Surface
+import org.junit.runners.Parameterized
+
+abstract class NonRotationTestBase(
+ protected val rotationName: String,
+ protected val rotation: Int
+) : FlickerTestBase() {
+ companion object {
+ const val SCREENSHOT_LAYER = "RotationLayer"
+
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> {
+ val supportedRotations = intArrayOf(Surface.ROTATION_0, Surface.ROTATION_90)
+ return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt
new file mode 100644
index 0000000..308a36e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.wm.shell.flicker.helpers
+
+import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import com.android.server.wm.flicker.StandardAppHelper
+
+abstract class FlickerAppHelper(
+ instr: Instrumentation,
+ launcherName: String,
+ launcherStrategy: ILauncherStrategy
+) : StandardAppHelper(instr, sFlickerPackage, launcherName, launcherStrategy) {
+ companion object {
+ var sFlickerPackage = "com.android.wm.shell.flicker.testapp"
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
new file mode 100644
index 0000000..5391702
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.helpers
+
+import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import com.android.server.wm.flicker.helpers.hasPipWindow
+import com.android.server.wm.flicker.helpers.closePipWindow
+import org.junit.Assert
+
+class PipAppHelper(
+ instr: Instrumentation,
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : FlickerAppHelper(instr, "PipApp", launcherStrategy) {
+ fun clickEnterPipButton(device: UiDevice) {
+ val enterPipButton = device.findObject(By.res(getPackage(), "enter_pip"))
+ Assert.assertNotNull("Pip button not found, this usually happens when the device " +
+ "was left in an unknown state (e.g. in split screen)", enterPipButton)
+ enterPipButton.click()
+ device.hasPipWindow()
+ }
+
+ fun closePipWindow(device: UiDevice) {
+ device.closePipWindow()
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
new file mode 100644
index 0000000..4b04449
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+import android.view.Surface
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.LargeTest
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.helpers.closePipWindow
+import com.android.server.wm.flicker.helpers.expandPipWindow
+import com.android.server.wm.flicker.helpers.hasPipWindow
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible
+import com.android.wm.shell.flicker.navBarLayerRotatesAndScales
+import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
+import com.android.wm.shell.flicker.noUncoveredRegions
+import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
+import com.android.wm.shell.flicker.statusBarLayerRotatesScales
+import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip launch.
+ * To run this test: `atest FlickerTests:PipToAppTest`
+ */
+@LargeTest
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 152738416)
+class EnterPipTest(
+ rotationName: String,
+ rotation: Int
+) : PipTestBase(rotationName, rotation) {
+ @Test
+ fun test() {
+ flicker(instrumentation) {
+ withTag { buildTestTag("enterPip", testApp, rotation) }
+ repeat { 1 }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ }
+ eachRun {
+ device.pressHome()
+ testApp.open()
+ this.setRotation(rotation)
+ }
+ }
+ teardown {
+ eachRun {
+ if (device.hasPipWindow()) {
+ device.closePipWindow()
+ }
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ test {
+ if (device.hasPipWindow()) {
+ device.closePipWindow()
+ }
+ }
+ }
+ transitions {
+ testApp.clickEnterPipButton(device)
+ device.expandPipWindow()
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ all("pipWindowBecomesVisible") {
+ this.showsAppWindow(testApp.`package`)
+ .then()
+ .showsAppWindow(sPipWindowTitle)
+ }
+ }
+
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false)
+ navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0)
+ statusBarLayerRotatesScales(rotation, Surface.ROTATION_0)
+
+ all("pipLayerBecomesVisible") {
+ this.showsLayer(testApp.launcherName)
+ .then()
+ .showsLayer(sPipWindowTitle)
+ }
+ }
+ }
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> {
+ val supportedRotations = intArrayOf(Surface.ROTATION_0)
+ return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/WindowManagerShellTest.java b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt
similarity index 60%
copy from libs/WindowManager/Shell/tests/src/com/android/wm/shell/WindowManagerShellTest.java
copy to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt
index f1ead3c..3822d69 100644
--- a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/WindowManagerShellTest.java
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt
@@ -14,25 +14,18 @@
* limitations under the License.
*/
-package com.android.wm.shell;
+package com.android.wm.shell.flicker.pip
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
+import com.android.wm.shell.flicker.NonRotationTestBase
+import com.android.wm.shell.flicker.helpers.PipAppHelper
-import org.junit.Test;
-import org.junit.runner.RunWith;
+abstract class PipTestBase(
+ rotationName: String,
+ rotation: Int
+) : NonRotationTestBase(rotationName, rotation) {
+ protected val testApp = PipAppHelper(instrumentation)
-/**
- * Tests for the shell.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class WindowManagerShellTest {
-
- WindowManagerShell mShell;
-
- @Test
- public void testNothing() {
- // Do nothing
+ companion object {
+ const val sPipWindowTitle = "PipMenuActivity"
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/Android.bp b/libs/WindowManager/Shell/tests/flicker/test-apps/Android.bp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/Android.bp
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp
new file mode 100644
index 0000000..d12b492
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp
@@ -0,0 +1,20 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "WMShellFlickerTestApp",
+ srcs: ["**/*.java"],
+ sdk_version: "current",
+ test_suites: ["device-tests"],
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml
new file mode 100644
index 0000000..95dc1d4
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wm.shell.flicker.testapp">
+
+ <uses-sdk android:minSdkVersion="29"
+ android:targetSdkVersion="29"/>
+ <application android:allowBackup="false"
+ android:supportsRtl="true">
+ <activity android:name=".PipActivity"
+ android:resizeableActivity="true"
+ android:supportsPictureInPicture="true"
+ android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
+ android:taskAffinity="com.android.wm.shell.flicker.testapp.PipActivity"
+ android:label="PipApp"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml
new file mode 100644
index 0000000..e1870d9
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/holo_blue_bright">
+ <Button android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/enter_pip"
+ android:text="Enter PIP"/>
+</LinearLayout>
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java
new file mode 100644
index 0000000..3052816
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.testapp;
+
+import android.app.Activity;
+import android.app.PictureInPictureParams;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.util.Rational;
+import android.view.WindowManager;
+import android.widget.Button;
+
+public class PipActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ WindowManager.LayoutParams p = getWindow().getAttributes();
+ p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
+ .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+ getWindow().setAttributes(p);
+ setContentView(R.layout.activity_pip);
+ Button enterPip = (Button) findViewById(R.id.enter_pip);
+
+ PictureInPictureParams params = new PictureInPictureParams.Builder()
+ .setAspectRatio(new Rational(1, 1))
+ .setSourceRectHint(new Rect(0, 0, 100, 100))
+ .build();
+
+ enterPip.setOnClickListener((v) -> enterPictureInPictureMode(params));
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/Android.bp b/libs/WindowManager/Shell/tests/unittest/Android.bp
similarity index 96%
rename from libs/WindowManager/Shell/tests/Android.bp
rename to libs/WindowManager/Shell/tests/unittest/Android.bp
index 9868879..692e2fa 100644
--- a/libs/WindowManager/Shell/tests/Android.bp
+++ b/libs/WindowManager/Shell/tests/unittest/Android.bp
@@ -13,7 +13,7 @@
// limitations under the License.
android_test {
- name: "WindowManagerShellTests",
+ name: "WMShellUnitTests",
srcs: ["**/*.java"],
diff --git a/libs/WindowManager/Shell/tests/AndroidManifest.xml b/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml
similarity index 100%
rename from libs/WindowManager/Shell/tests/AndroidManifest.xml
rename to libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml
diff --git a/libs/WindowManager/Shell/tests/AndroidTest.xml b/libs/WindowManager/Shell/tests/unittest/AndroidTest.xml
similarity index 90%
rename from libs/WindowManager/Shell/tests/AndroidTest.xml
rename to libs/WindowManager/Shell/tests/unittest/AndroidTest.xml
index 4dce4db..21ed2c0 100644
--- a/libs/WindowManager/Shell/tests/AndroidTest.xml
+++ b/libs/WindowManager/Shell/tests/unittest/AndroidTest.xml
@@ -17,12 +17,12 @@
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="install-arg" value="-t" />
- <option name="test-file-name" value="WindowManagerShellTests.apk" />
+ <option name="test-file-name" value="WMShellUnitTests.apk" />
</target_preparer>
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="framework-base-presubmit" />
- <option name="test-tag" value="WindowManagerShellTests" />
+ <option name="test-tag" value="WMShellUnitTests" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.wm.shell.tests" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
diff --git a/libs/WindowManager/Shell/tests/res/values/config.xml b/libs/WindowManager/Shell/tests/unittest/res/values/config.xml
similarity index 100%
rename from libs/WindowManager/Shell/tests/res/values/config.xml
rename to libs/WindowManager/Shell/tests/unittest/res/values/config.xml
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
new file mode 100644
index 0000000..10672c8
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+
+import static org.junit.Assert.assertTrue;
+
+import android.app.ActivityManager.RunningTaskInfo;
+import android.content.res.Configuration;
+import android.view.SurfaceControl;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+/**
+ * Tests for the shell task organizer.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ShellTaskOrganizerTests {
+
+ ShellTaskOrganizer mOrganizer;
+
+ private class TrackingTaskListener implements ShellTaskOrganizer.TaskListener {
+ final ArrayList<RunningTaskInfo> appeared = new ArrayList<>();
+ final ArrayList<RunningTaskInfo> vanished = new ArrayList<>();
+ final ArrayList<RunningTaskInfo> infoChanged = new ArrayList<>();
+
+ @Override
+ public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
+ appeared.add(taskInfo);
+ }
+
+ @Override
+ public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
+ infoChanged.add(taskInfo);
+ }
+
+ @Override
+ public void onTaskVanished(RunningTaskInfo taskInfo) {
+ vanished.add(taskInfo);
+ }
+
+ @Override
+ public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
+ // Not currently used
+ }
+ }
+
+ @Before
+ public void setUp() {
+ mOrganizer = new ShellTaskOrganizer();
+ }
+
+ @Test
+ public void testAppearedVanished() {
+ RunningTaskInfo taskInfo = createTaskInfo(WINDOWING_MODE_MULTI_WINDOW);
+ TrackingTaskListener listener = new TrackingTaskListener();
+ mOrganizer.addListener(listener, WINDOWING_MODE_MULTI_WINDOW);
+ mOrganizer.onTaskAppeared(taskInfo, null);
+ assertTrue(listener.appeared.contains(taskInfo));
+
+ mOrganizer.onTaskVanished(taskInfo);
+ assertTrue(listener.vanished.contains(taskInfo));
+ }
+
+ @Test
+ public void testAddListenerExistingTasks() {
+ RunningTaskInfo taskInfo = createTaskInfo(WINDOWING_MODE_MULTI_WINDOW);
+ mOrganizer.onTaskAppeared(taskInfo, null);
+
+ TrackingTaskListener listener = new TrackingTaskListener();
+ mOrganizer.addListener(listener, WINDOWING_MODE_MULTI_WINDOW);
+ assertTrue(listener.appeared.contains(taskInfo));
+ }
+
+ @Test
+ public void testWindowingModeChange() {
+ RunningTaskInfo taskInfo = createTaskInfo(WINDOWING_MODE_MULTI_WINDOW);
+ TrackingTaskListener mwListener = new TrackingTaskListener();
+ TrackingTaskListener pipListener = new TrackingTaskListener();
+ mOrganizer.addListener(mwListener, WINDOWING_MODE_MULTI_WINDOW);
+ mOrganizer.addListener(pipListener, WINDOWING_MODE_PINNED);
+ mOrganizer.onTaskAppeared(taskInfo, null);
+ assertTrue(mwListener.appeared.contains(taskInfo));
+ assertTrue(pipListener.appeared.isEmpty());
+
+ taskInfo = createTaskInfo(WINDOWING_MODE_PINNED);
+ mOrganizer.onTaskInfoChanged(taskInfo);
+ assertTrue(mwListener.vanished.contains(taskInfo));
+ assertTrue(pipListener.appeared.contains(taskInfo));
+ }
+
+ private RunningTaskInfo createTaskInfo(int windowingMode) {
+ RunningTaskInfo taskInfo = new RunningTaskInfo();
+ taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
+ return taskInfo;
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/common/DisplayLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java
similarity index 100%
rename from libs/WindowManager/Shell/tests/src/com/android/wm/shell/common/DisplayLayoutTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 4d7e5df..dfb4009 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -37,7 +37,6 @@
#include <androidfw/TypeWrappers.h>
#include <cutils/atomic.h>
#include <utils/ByteOrder.h>
-#include <utils/Debug.h>
#include <utils/Log.h>
#include <utils/String16.h>
#include <utils/String8.h>
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 9ae5ad9..90d2537 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -462,6 +462,14 @@
"RenderNode.cpp",
"RenderProperties.cpp",
"RootRenderNode.cpp",
+ "shader/Shader.cpp",
+ "shader/BitmapShader.cpp",
+ "shader/BlurShader.cpp",
+ "shader/ComposeShader.cpp",
+ "shader/LinearGradientShader.cpp",
+ "shader/RadialGradientShader.cpp",
+ "shader/RuntimeShader.cpp",
+ "shader/SweepGradientShader.cpp",
"SkiaCanvas.cpp",
"VectorDrawable.cpp",
],
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index 8724442..ab9b8b5 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -56,12 +56,6 @@
public:
virtual ~AHBUploader() {}
- // Called to start creation of the Vulkan and EGL contexts on another thread before we actually
- // need to do an upload.
- void initialize() {
- onInitialize();
- }
-
void destroy() {
std::lock_guard _lock{mLock};
LOG_ALWAYS_FATAL_IF(mPendingUploads, "terminate called while uploads in progress");
@@ -91,7 +85,6 @@
sp<ThreadBase> mUploadThread = nullptr;
private:
- virtual void onInitialize() = 0;
virtual void onIdle() = 0;
virtual void onDestroy() = 0;
@@ -141,7 +134,6 @@
class EGLUploader : public AHBUploader {
private:
- void onInitialize() override {}
void onDestroy() override {
mEglManager.destroy();
}
@@ -231,62 +223,67 @@
class VkUploader : public AHBUploader {
private:
- void onInitialize() override {
- std::lock_guard _lock{mLock};
- if (!mUploadThread) {
- mUploadThread = new ThreadBase{};
- }
- if (!mUploadThread->isRunning()) {
- mUploadThread->start("GrallocUploadThread");
- }
-
- mUploadThread->queue().post([this]() {
- std::lock_guard _lock{mVkLock};
- if (!mVulkanManager.hasVkContext()) {
- mVulkanManager.initialize();
- }
- });
- }
void onDestroy() override {
+ std::lock_guard _lock{mVkLock};
mGrContext.reset();
- mVulkanManager.destroy();
+ mVulkanManagerStrong.clear();
}
void onIdle() override {
- mGrContext.reset();
+ onDestroy();
}
- void onBeginUpload() override {
- {
- std::lock_guard _lock{mVkLock};
- if (!mVulkanManager.hasVkContext()) {
- LOG_ALWAYS_FATAL_IF(mGrContext,
- "GrContext exists with no VulkanManager for vulkan uploads");
- mUploadThread->queue().runSync([this]() {
- mVulkanManager.initialize();
- });
- }
- }
- if (!mGrContext) {
- GrContextOptions options;
- mGrContext = mVulkanManager.createContext(options);
- LOG_ALWAYS_FATAL_IF(!mGrContext, "failed to create GrContext for vulkan uploads");
- this->postIdleTimeoutCheck();
- }
- }
+ void onBeginUpload() override {}
bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
AHardwareBuffer* ahb) override {
- ATRACE_CALL();
+ bool uploadSucceeded = false;
+ mUploadThread->queue().runSync([this, &uploadSucceeded, bitmap, ahb]() {
+ ATRACE_CALL();
+ std::lock_guard _lock{mVkLock};
- std::lock_guard _lock{mLock};
+ renderthread::VulkanManager* vkManager = getVulkanManager();
+ if (!vkManager->hasVkContext()) {
+ LOG_ALWAYS_FATAL_IF(mGrContext,
+ "GrContext exists with no VulkanManager for vulkan uploads");
+ vkManager->initialize();
+ }
- sk_sp<SkImage> image =
- SkImage::MakeFromAHardwareBufferWithData(mGrContext.get(), bitmap.pixmap(), ahb);
- return (image.get() != nullptr);
+ if (!mGrContext) {
+ GrContextOptions options;
+ mGrContext = vkManager->createContext(options,
+ renderthread::VulkanManager::ContextType::kUploadThread);
+ LOG_ALWAYS_FATAL_IF(!mGrContext, "failed to create GrContext for vulkan uploads");
+ this->postIdleTimeoutCheck();
+ }
+
+ sk_sp<SkImage> image =
+ SkImage::MakeFromAHardwareBufferWithData(mGrContext.get(), bitmap.pixmap(), ahb);
+ mGrContext->submit(true);
+
+ uploadSucceeded = (image.get() != nullptr);
+ });
+ return uploadSucceeded;
+ }
+
+ /* must be called on the upload thread after the vkLock has been acquired */
+ renderthread::VulkanManager* getVulkanManager() {
+ if (!mVulkanManagerStrong) {
+ mVulkanManagerStrong = mVulkanManagerWeak.promote();
+
+ // create a new manager if we couldn't promote the weak ref
+ if (!mVulkanManagerStrong) {
+ mVulkanManagerStrong = renderthread::VulkanManager::getInstance();
+ mGrContext.reset();
+ mVulkanManagerWeak = mVulkanManagerStrong;
+ }
+ }
+
+ return mVulkanManagerStrong.get();
}
sk_sp<GrDirectContext> mGrContext;
- renderthread::VulkanManager mVulkanManager;
+ sp<renderthread::VulkanManager> mVulkanManagerStrong;
+ wp<renderthread::VulkanManager> mVulkanManagerWeak;
std::mutex mVkLock;
};
@@ -428,7 +425,6 @@
bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
uirenderer::RenderPipelineType::SkiaGL;
createUploader(usingGL);
- sUploader->initialize();
}
void HardwareBitmapUploader::terminate() {
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 892d43a..473dc53d 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -524,6 +524,7 @@
// Next greater multiple of SKLITEDL_PAGE.
fReserved = (fUsed + skip + SKLITEDL_PAGE) & ~(SKLITEDL_PAGE - 1);
fBytes.realloc(fReserved);
+ LOG_ALWAYS_FATAL_IF(fBytes.get() == nullptr, "realloc(%zd) failed", fReserved);
}
SkASSERT(fUsed + skip <= fReserved);
auto op = (T*)(fBytes.get() + fUsed);
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 242b8b0..cfba5d4 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -42,6 +42,8 @@
#include <SkTextBlob.h>
#include <SkVertices.h>
+#include <shader/BitmapShader.h>
+
#include <memory>
#include <optional>
#include <utility>
@@ -49,6 +51,7 @@
namespace android {
using uirenderer::PaintUtils;
+using uirenderer::BitmapShader;
Canvas* Canvas::create_canvas(const SkBitmap& bitmap) {
return new SkiaCanvas(bitmap);
@@ -681,7 +684,9 @@
if (paint) {
pnt = *paint;
}
- pnt.setShader(bitmap.makeImage()->makeShader());
+
+ pnt.setShader(sk_ref_sp(new BitmapShader(
+ bitmap.makeImage(), SkTileMode::kClamp, SkTileMode::kClamp, nullptr)));
auto v = builder.detach();
apply_looper(&pnt, [&](const SkPaint& p) {
mCanvas->drawVertices(v, SkBlendMode::kModulate, p);
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index cd908354..0f566e4 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -23,7 +23,6 @@
#include "PathParser.h"
#include "SkColorFilter.h"
#include "SkImageInfo.h"
-#include "SkShader.h"
#include "hwui/Paint.h"
#ifdef __ANDROID__
@@ -159,10 +158,10 @@
// Draw path's fill, if fill color or gradient is valid
bool needsFill = false;
- SkPaint paint;
+ Paint paint;
if (properties.getFillGradient() != nullptr) {
paint.setColor(applyAlpha(SK_ColorBLACK, properties.getFillAlpha()));
- paint.setShader(sk_sp<SkShader>(SkSafeRef(properties.getFillGradient())));
+ paint.setShader(sk_sp<Shader>(SkSafeRef(properties.getFillGradient())));
needsFill = true;
} else if (properties.getFillColor() != SK_ColorTRANSPARENT) {
paint.setColor(applyAlpha(properties.getFillColor(), properties.getFillAlpha()));
@@ -179,7 +178,7 @@
bool needsStroke = false;
if (properties.getStrokeGradient() != nullptr) {
paint.setColor(applyAlpha(SK_ColorBLACK, properties.getStrokeAlpha()));
- paint.setShader(sk_sp<SkShader>(SkSafeRef(properties.getStrokeGradient())));
+ paint.setShader(sk_sp<Shader>(SkSafeRef(properties.getStrokeGradient())));
needsStroke = true;
} else if (properties.getStrokeColor() != SK_ColorTRANSPARENT) {
paint.setColor(applyAlpha(properties.getStrokeColor(), properties.getStrokeAlpha()));
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index ac7d41e..d4086f1 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -31,8 +31,8 @@
#include <SkPath.h>
#include <SkPathMeasure.h>
#include <SkRect.h>
-#include <SkShader.h>
#include <SkSurface.h>
+#include <shader/Shader.h>
#include <cutils/compiler.h>
#include <stddef.h>
@@ -227,20 +227,20 @@
strokeGradient = prop.strokeGradient;
onPropertyChanged();
}
- void setFillGradient(SkShader* gradient) {
+ void setFillGradient(Shader* gradient) {
if (fillGradient.get() != gradient) {
fillGradient = sk_ref_sp(gradient);
onPropertyChanged();
}
}
- void setStrokeGradient(SkShader* gradient) {
+ void setStrokeGradient(Shader* gradient) {
if (strokeGradient.get() != gradient) {
strokeGradient = sk_ref_sp(gradient);
onPropertyChanged();
}
}
- SkShader* getFillGradient() const { return fillGradient.get(); }
- SkShader* getStrokeGradient() const { return strokeGradient.get(); }
+ Shader* getFillGradient() const { return fillGradient.get(); }
+ Shader* getStrokeGradient() const { return strokeGradient.get(); }
float getStrokeWidth() const { return mPrimitiveFields.strokeWidth; }
void setStrokeWidth(float strokeWidth) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeWidth, strokeWidth);
@@ -320,8 +320,8 @@
count,
};
PrimitiveFields mPrimitiveFields;
- sk_sp<SkShader> fillGradient;
- sk_sp<SkShader> strokeGradient;
+ sk_sp<Shader> fillGradient;
+ sk_sp<Shader> strokeGradient;
};
// Called from UI thread
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index c138a32..2a377bb 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -73,7 +73,7 @@
static void simplifyPaint(int color, Paint* paint) {
paint->setColor(color);
- paint->setShader(nullptr);
+ paint->setShader((sk_sp<uirenderer::Shader>)nullptr);
paint->setColorFilter(nullptr);
paint->setLooper(nullptr);
paint->setStrokeWidth(4 + 0.04 * paint->getSkFont().getSize());
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index e75e9e7..0bb689c 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -30,6 +30,8 @@
#include <minikin/FamilyVariant.h>
#include <minikin/Hyphenator.h>
+#include <shader/Shader.h>
+
namespace android {
class Paint : public SkPaint {
@@ -149,8 +151,14 @@
// The only respected flags are : [ antialias, dither, filterBitmap ]
static uint32_t GetSkPaintJavaFlags(const SkPaint&);
static void SetSkPaintJavaFlags(SkPaint*, uint32_t flags);
+
+ void setShader(sk_sp<uirenderer::Shader> shader);
private:
+
+ using SkPaint::setShader;
+ using SkPaint::setImageFilter;
+
SkFont mFont;
sk_sp<SkDrawLooper> mLooper;
@@ -169,6 +177,7 @@
bool mStrikeThru = false;
bool mUnderline = false;
bool mDevKern = false;
+ sk_sp<uirenderer::Shader> mShader;
};
} // namespace android
diff --git a/libs/hwui/hwui/PaintImpl.cpp b/libs/hwui/hwui/PaintImpl.cpp
index fa2674f..21f60fd 100644
--- a/libs/hwui/hwui/PaintImpl.cpp
+++ b/libs/hwui/hwui/PaintImpl.cpp
@@ -24,7 +24,8 @@
, mWordSpacing(0)
, mFontFeatureSettings()
, mMinikinLocaleListId(0)
- , mFamilyVariant(minikin::FamilyVariant::DEFAULT) {
+ , mFamilyVariant(minikin::FamilyVariant::DEFAULT)
+ , mShader(nullptr) {
// SkPaint::antialiasing defaults to false, but
// SkFont::edging defaults to kAntiAlias. To keep them
// insync, we manually set the font to kAilas.
@@ -45,7 +46,8 @@
, mAlign(paint.mAlign)
, mStrikeThru(paint.mStrikeThru)
, mUnderline(paint.mUnderline)
- , mDevKern(paint.mDevKern) {}
+ , mDevKern(paint.mDevKern)
+ , mShader(paint.mShader){}
Paint::~Paint() {}
@@ -65,9 +67,30 @@
mStrikeThru = other.mStrikeThru;
mUnderline = other.mUnderline;
mDevKern = other.mDevKern;
+ mShader = other.mShader;
return *this;
}
+void Paint::setShader(sk_sp<uirenderer::Shader> shader) {
+ if (shader) {
+ // If there is an SkShader compatible shader, apply it
+ sk_sp<SkShader> skShader = shader->asSkShader();
+ if (skShader.get()) {
+ SkPaint::setShader(skShader);
+ SkPaint::setImageFilter(nullptr);
+ } else {
+ // ... otherwise the specified shader can only be represented as an ImageFilter
+ SkPaint::setShader(nullptr);
+ SkPaint::setImageFilter(shader->asSkImageFilter());
+ }
+ } else {
+ // No shader is provided at all, clear out both the SkShader and SkImageFilter slots
+ SkPaint::setShader(nullptr);
+ SkPaint::setImageFilter(nullptr);
+ }
+ mShader = shader;
+}
+
bool operator==(const Paint& a, const Paint& b) {
return static_cast<const SkPaint&>(a) == static_cast<const SkPaint&>(b) &&
a.mFont == b.mFont &&
diff --git a/libs/hwui/jni/Paint.cpp b/libs/hwui/jni/Paint.cpp
index df8635a..554674a 100644
--- a/libs/hwui/jni/Paint.cpp
+++ b/libs/hwui/jni/Paint.cpp
@@ -47,6 +47,7 @@
#include <minikin/LocaleList.h>
#include <minikin/Measurement.h>
#include <minikin/MinikinPaint.h>
+#include <shader/Shader.h>
#include <unicode/utf16.h>
#include <cassert>
@@ -54,6 +55,8 @@
#include <memory>
#include <vector>
+using namespace android::uirenderer;
+
namespace android {
struct JMetricsID {
@@ -782,11 +785,10 @@
return obj->getFillPath(*src, dst) ? JNI_TRUE : JNI_FALSE;
}
- static jlong setShader(CRITICAL_JNI_PARAMS_COMMA jlong objHandle, jlong shaderHandle) {
- Paint* obj = reinterpret_cast<Paint*>(objHandle);
- SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
- obj->setShader(sk_ref_sp(shader));
- return reinterpret_cast<jlong>(obj->getShader());
+ static void setShader(CRITICAL_JNI_PARAMS_COMMA jlong objHandle, jlong shaderHandle) {
+ auto* paint = reinterpret_cast<Paint*>(objHandle);
+ auto* shader = reinterpret_cast<Shader*>(shaderHandle);
+ paint->setShader(sk_ref_sp(shader));
}
static jlong setColorFilter(CRITICAL_JNI_PARAMS_COMMA jlong objHandle, jlong filterHandle) {
@@ -1097,7 +1099,7 @@
{"nGetStrokeJoin","(J)I", (void*) PaintGlue::getStrokeJoin},
{"nSetStrokeJoin","(JI)V", (void*) PaintGlue::setStrokeJoin},
{"nGetFillPath","(JJJ)Z", (void*) PaintGlue::getFillPath},
- {"nSetShader","(JJ)J", (void*) PaintGlue::setShader},
+ {"nSetShader","(JJ)V", (void*) PaintGlue::setShader},
{"nSetColorFilter","(JJ)J", (void*) PaintGlue::setColorFilter},
{"nSetXfermode","(JI)V", (void*) PaintGlue::setXfermode},
{"nSetPathEffect","(JJ)J", (void*) PaintGlue::setPathEffect},
diff --git a/libs/hwui/jni/Picture.cpp b/libs/hwui/jni/Picture.cpp
index d1b9521..8e4203c 100644
--- a/libs/hwui/jni/Picture.cpp
+++ b/libs/hwui/jni/Picture.cpp
@@ -111,7 +111,7 @@
SkPictureRecorder reRecorder;
- SkCanvas* canvas = reRecorder.beginRecording(mWidth, mHeight, NULL, 0);
+ SkCanvas* canvas = reRecorder.beginRecording(mWidth, mHeight);
mRecorder->partialReplay(canvas);
return reRecorder.finishRecordingAsPicture();
}
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index e76aace..7cb7723 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -5,6 +5,14 @@
#include "SkShader.h"
#include "SkBlendMode.h"
#include "include/effects/SkRuntimeEffect.h"
+#include "shader/Shader.h"
+#include "shader/BitmapShader.h"
+#include "shader/BlurShader.h"
+#include "shader/ComposeShader.h"
+#include "shader/LinearGradientShader.h"
+#include "shader/RadialGradientShader.h"
+#include "shader/RuntimeShader.h"
+#include "shader/SweepGradientShader.h"
#include <vector>
@@ -50,7 +58,7 @@
///////////////////////////////////////////////////////////////////////////////////////////////
-static void Shader_safeUnref(SkShader* shader) {
+static void Shader_safeUnref(Shader* shader) {
SkSafeUnref(shader);
}
@@ -74,15 +82,15 @@
SkBitmap bitmap;
image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
}
- sk_sp<SkShader> shader = image->makeShader(
- (SkTileMode)tileModeX, (SkTileMode)tileModeY);
- ThrowIAE_IfNull(env, shader.get());
- if (matrix) {
- shader = shader->makeWithLocalMatrix(*matrix);
- }
+ auto* shader = new BitmapShader(
+ image,
+ static_cast<SkTileMode>(tileModeX),
+ static_cast<SkTileMode>(tileModeY),
+ matrix
+ );
- return reinterpret_cast<jlong>(shader.release());
+ return reinterpret_cast<jlong>(shader);
}
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -118,17 +126,18 @@
#error Need to convert float array to SkScalar array before calling the following function.
#endif
- sk_sp<SkShader> shader(SkGradientShader::MakeLinear(pts, &colors[0],
- GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
- static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr));
- ThrowIAE_IfNull(env, shader);
+ auto* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
+ auto* shader = new LinearGradientShader(
+ pts,
+ colors,
+ GraphicsJNI::getNativeColorSpace(colorSpaceHandle),
+ pos,
+ static_cast<SkTileMode>(tileMode),
+ sGradientShaderFlags,
+ matrix
+ );
- const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- if (matrix) {
- shader = shader->makeWithLocalMatrix(*matrix);
- }
-
- return reinterpret_cast<jlong>(shader.release());
+ return reinterpret_cast<jlong>(shader);
}
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -148,17 +157,20 @@
#error Need to convert float array to SkScalar array before calling the following function.
#endif
- sk_sp<SkShader> shader = SkGradientShader::MakeRadial(center, radius, &colors[0],
- GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
- static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr);
- ThrowIAE_IfNull(env, shader);
+ auto* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- if (matrix) {
- shader = shader->makeWithLocalMatrix(*matrix);
- }
+ auto* shader = new RadialGradientShader(
+ center,
+ radius,
+ colors,
+ GraphicsJNI::getNativeColorSpace(colorSpaceHandle),
+ pos,
+ static_cast<SkTileMode>(tileMode),
+ sGradientShaderFlags,
+ matrix
+ );
- return reinterpret_cast<jlong>(shader.release());
+ return reinterpret_cast<jlong>(shader);
}
///////////////////////////////////////////////////////////////////////////////
@@ -174,54 +186,74 @@
#error Need to convert float array to SkScalar array before calling the following function.
#endif
- sk_sp<SkShader> shader = SkGradientShader::MakeSweep(x, y, &colors[0],
- GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
- sGradientShaderFlags, nullptr);
- ThrowIAE_IfNull(env, shader);
+ auto* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- if (matrix) {
- shader = shader->makeWithLocalMatrix(*matrix);
- }
+ auto* shader = new SweepGradientShader(
+ x,
+ y,
+ colors,
+ GraphicsJNI::getNativeColorSpace(colorSpaceHandle),
+ pos,
+ sGradientShaderFlags,
+ matrix
+ );
- return reinterpret_cast<jlong>(shader.release());
+ return reinterpret_cast<jlong>(shader);
}
///////////////////////////////////////////////////////////////////////////////////////////////
static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) {
- const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
- SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
- SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
- sk_sp<SkShader> baseShader(SkShaders::Blend(mode,
- sk_ref_sp(shaderA), sk_ref_sp(shaderB)));
+ auto* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
+ auto* shaderA = reinterpret_cast<Shader*>(shaderAHandle);
+ auto* shaderB = reinterpret_cast<Shader*>(shaderBHandle);
- SkShader* shader;
+ auto mode = static_cast<SkBlendMode>(xfermodeHandle);
- if (matrix) {
- shader = baseShader->makeWithLocalMatrix(*matrix).release();
- } else {
- shader = baseShader.release();
- }
- return reinterpret_cast<jlong>(shader);
+ auto* composeShader = new ComposeShader(
+ *shaderA,
+ *shaderB,
+ mode,
+ matrix
+ );
+
+ return reinterpret_cast<jlong>(composeShader);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+static jlong BlurShader_create(JNIEnv* env , jobject o, jlong matrixPtr, jfloat sigmaX,
+ jfloat sigmaY, jlong shaderHandle) {
+ auto* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
+ auto* inputShader = reinterpret_cast<Shader*>(shaderHandle);
+
+ auto* blurShader = new BlurShader(
+ sigmaX,
+ sigmaY,
+ inputShader,
+ matrix
+ );
+ return reinterpret_cast<jlong>(blurShader);
}
///////////////////////////////////////////////////////////////////////////////////////////////
static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderFactory, jlong matrixPtr,
jbyteArray inputs, jlong colorSpaceHandle, jboolean isOpaque) {
- SkRuntimeEffect* effect = reinterpret_cast<SkRuntimeEffect*>(shaderFactory);
+ auto* effect = reinterpret_cast<SkRuntimeEffect*>(shaderFactory);
AutoJavaByteArray arInputs(env, inputs);
- sk_sp<SkData> fData;
- fData = SkData::MakeWithCopy(arInputs.ptr(), arInputs.length());
- const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- sk_sp<SkShader> shader = effect->makeShader(fData, nullptr, 0, matrix, isOpaque == JNI_TRUE);
- ThrowIAE_IfNull(env, shader);
+ auto data = SkData::MakeWithCopy(arInputs.ptr(), arInputs.length());
+ auto* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- return reinterpret_cast<jlong>(shader.release());
+ auto* shader = new RuntimeShader(
+ *effect,
+ std::move(data),
+ isOpaque == JNI_TRUE,
+ matrix
+ );
+ return reinterpret_cast<jlong>(shader);
}
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -239,12 +271,8 @@
///////////////////////////////////////////////////////////////////////////////////////////////
-static void Effect_safeUnref(SkRuntimeEffect* effect) {
- SkSafeUnref(effect);
-}
-
static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) {
- return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Effect_safeUnref));
+ return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref));
}
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -262,6 +290,10 @@
{ "nativeCreate", "(JJII)J", (void*)BitmapShader_constructor },
};
+static const JNINativeMethod gBlurShaderMethods[] = {
+ { "nativeCreate", "(JFFJ)J", (void*)BlurShader_create }
+};
+
static const JNINativeMethod gLinearGradientMethods[] = {
{ "nativeCreate", "(JFFFF[J[FIJ)J", (void*)LinearGradient_create },
};
@@ -293,6 +325,8 @@
NELEM(gShaderMethods));
android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
NELEM(gBitmapShaderMethods));
+ android::RegisterMethodsOrDie(env, "android/graphics/BlurShader", gBlurShaderMethods,
+ NELEM(gBlurShaderMethods));
android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
NELEM(gLinearGradientMethods));
android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index fc594da..e817ca7 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -184,7 +184,9 @@
proxy->setSwapBehavior(SwapBehavior::kSwap_discardBuffer);
}
proxy->setSurface(window, enableTimeout);
- ANativeWindow_release(window);
+ if (window) {
+ ANativeWindow_release(window);
+ }
}
static jboolean android_view_ThreadedRenderer_pause(JNIEnv* env, jobject clazz,
diff --git a/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp b/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp
index 9cffceb..a1adcb3 100644
--- a/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -143,13 +143,13 @@
static void updateFullPathFillGradient(JNIEnv*, jobject, jlong pathPtr, jlong fillGradientPtr) {
VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
- SkShader* fillShader = reinterpret_cast<SkShader*>(fillGradientPtr);
+ auto* fillShader = reinterpret_cast<Shader*>(fillGradientPtr);
path->mutateStagingProperties()->setFillGradient(fillShader);
}
static void updateFullPathStrokeGradient(JNIEnv*, jobject, jlong pathPtr, jlong strokeGradientPtr) {
VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
- SkShader* strokeShader = reinterpret_cast<SkShader*>(strokeGradientPtr);
+ auto* strokeShader = reinterpret_cast<Shader*>(strokeGradientPtr);
path->mutateStagingProperties()->setStrokeGradient(strokeShader);
}
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index aad0cca..b51f6dc 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -77,10 +77,10 @@
}
void RenderProxy::setSurface(ANativeWindow* window, bool enableTimeout) {
- ANativeWindow_acquire(window);
+ if (window) { ANativeWindow_acquire(window); }
mRenderThread.queue().post([this, win = window, enableTimeout]() mutable {
mContext->setSurface(win, enableTimeout);
- ANativeWindow_release(win);
+ if (win) { ANativeWindow_release(win); }
});
}
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 565fb61..4dcbc44 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -131,8 +131,7 @@
, mFrameCallbackTaskPending(false)
, mRenderState(nullptr)
, mEglManager(nullptr)
- , mFunctorManager(WebViewFunctorManager::instance())
- , mVkManager(nullptr) {
+ , mFunctorManager(WebViewFunctorManager::instance()) {
Properties::load();
start("RenderThread");
}
@@ -166,7 +165,7 @@
initializeChoreographer();
mEglManager = new EglManager();
mRenderState = new RenderState(*this);
- mVkManager = new VulkanManager();
+ mVkManager = VulkanManager::getInstance();
mCacheManager = new CacheManager();
}
@@ -196,7 +195,8 @@
}
void RenderThread::requireVkContext() {
- if (mVkManager->hasVkContext()) {
+ // the getter creates the context in the event it had been destroyed by destroyRenderingContext
+ if (vulkanManager().hasVkContext()) {
return;
}
mVkManager->initialize();
@@ -222,13 +222,18 @@
mEglManager->destroy();
}
} else {
- if (vulkanManager().hasVkContext()) {
- setGrContext(nullptr);
- vulkanManager().destroy();
- }
+ setGrContext(nullptr);
+ mVkManager.clear();
}
}
+VulkanManager& RenderThread::vulkanManager() {
+ if (!mVkManager.get()) {
+ mVkManager = VulkanManager::getInstance();
+ }
+ return *mVkManager.get();
+}
+
void RenderThread::dumpGraphicsMemory(int fd) {
globalProfileData()->dump(fd);
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index b8ce556..d7dc00b 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -110,7 +110,7 @@
void setGrContext(sk_sp<GrDirectContext> cxt);
CacheManager& cacheManager() { return *mCacheManager; }
- VulkanManager& vulkanManager() { return *mVkManager; }
+ VulkanManager& vulkanManager();
sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& skBitmap);
void dumpGraphicsMemory(int fd);
@@ -188,7 +188,7 @@
sk_sp<GrDirectContext> mGrContext;
CacheManager* mCacheManager;
- VulkanManager* mVkManager;
+ sp<VulkanManager> mVkManager;
};
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 249936e..76ec078 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -57,12 +57,22 @@
#define GET_INST_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(mInstance, "vk" #F)
#define GET_DEV_PROC(F) m##F = (PFN_vk##F)vkGetDeviceProcAddr(mDevice, "vk" #F)
-void VulkanManager::destroy() {
- if (VK_NULL_HANDLE != mCommandPool) {
- mDestroyCommandPool(mDevice, mCommandPool, nullptr);
- mCommandPool = VK_NULL_HANDLE;
+sp<VulkanManager> VulkanManager::getInstance() {
+ // cache a weakptr to the context to enable a second thread to share the same vulkan state
+ static wp<VulkanManager> sWeakInstance = nullptr;
+ static std::mutex sLock;
+
+ std::lock_guard _lock{sLock};
+ sp<VulkanManager> vulkanManager = sWeakInstance.promote();
+ if (!vulkanManager.get()) {
+ vulkanManager = new VulkanManager();
+ sWeakInstance = vulkanManager;
}
+ return vulkanManager;
+}
+
+VulkanManager::~VulkanManager() {
if (mDevice != VK_NULL_HANDLE) {
mDeviceWaitIdle(mDevice);
mDestroyDevice(mDevice, nullptr);
@@ -73,6 +83,7 @@
}
mGraphicsQueue = VK_NULL_HANDLE;
+ mAHBUploadQueue = VK_NULL_HANDLE;
mPresentQueue = VK_NULL_HANDLE;
mDevice = VK_NULL_HANDLE;
mPhysicalDevice = VK_NULL_HANDLE;
@@ -175,6 +186,7 @@
for (uint32_t i = 0; i < queueCount; i++) {
if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
mGraphicsQueueIndex = i;
+ LOG_ALWAYS_FATAL_IF(queueProps[i].queueCount < 2);
break;
}
}
@@ -283,7 +295,7 @@
queueNextPtr, // pNext
0, // VkDeviceQueueCreateFlags
mGraphicsQueueIndex, // queueFamilyIndex
- 1, // queueCount
+ 2, // queueCount
queuePriorities, // pQueuePriorities
},
{
@@ -347,20 +359,7 @@
this->setupDevice(mExtensions, mPhysicalDeviceFeatures2);
mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 0, &mGraphicsQueue);
-
- // create the command pool for the command buffers
- if (VK_NULL_HANDLE == mCommandPool) {
- VkCommandPoolCreateInfo commandPoolInfo;
- memset(&commandPoolInfo, 0, sizeof(VkCommandPoolCreateInfo));
- commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
- // this needs to be on the render queue
- commandPoolInfo.queueFamilyIndex = mGraphicsQueueIndex;
- commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
- SkDEBUGCODE(VkResult res =)
- mCreateCommandPool(mDevice, &commandPoolInfo, nullptr, &mCommandPool);
- SkASSERT(VK_SUCCESS == res);
- }
- LOG_ALWAYS_FATAL_IF(mCommandPool == VK_NULL_HANDLE);
+ mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 1, &mAHBUploadQueue);
mGetDeviceQueue(mDevice, mPresentQueueIndex, 0, &mPresentQueue);
@@ -369,7 +368,8 @@
}
}
-sk_sp<GrDirectContext> VulkanManager::createContext(const GrContextOptions& options) {
+sk_sp<GrDirectContext> VulkanManager::createContext(const GrContextOptions& options,
+ ContextType contextType) {
auto getProc = [](const char* proc_name, VkInstance instance, VkDevice device) {
if (device != VK_NULL_HANDLE) {
return vkGetDeviceProcAddr(device, proc_name);
@@ -381,7 +381,8 @@
backendContext.fInstance = mInstance;
backendContext.fPhysicalDevice = mPhysicalDevice;
backendContext.fDevice = mDevice;
- backendContext.fQueue = mGraphicsQueue;
+ backendContext.fQueue = (contextType == ContextType::kRenderThread) ? mGraphicsQueue
+ : mAHBUploadQueue;
backendContext.fGraphicsQueueIndex = mGraphicsQueueIndex;
backendContext.fMaxAPIVersion = mAPIVersion;
backendContext.fVkExtensions = &mExtensions;
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 3f2df8d..75c05b8 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -43,10 +43,9 @@
// This class contains the shared global Vulkan objects, such as VkInstance, VkDevice and VkQueue,
// which are re-used by CanvasContext. This class is created once and should be used by all vulkan
// windowing contexts. The VulkanManager must be initialized before use.
-class VulkanManager {
+class VulkanManager final : public RefBase {
public:
- explicit VulkanManager() {}
- ~VulkanManager() { destroy(); }
+ static sp<VulkanManager> getInstance();
// Sets up the vulkan context that is shared amonst all clients of the VulkanManager. This must
// be call once before use of the VulkanManager. Multiple calls after the first will simiply
@@ -68,9 +67,6 @@
Frame dequeueNextBuffer(VulkanSurface* surface);
void swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect);
- // Cleans up all the global state in the VulkanManger.
- void destroy();
-
// Inserts a wait on fence command into the Vulkan command buffer.
status_t fenceWait(int fence, GrDirectContext* grContext);
@@ -83,12 +79,24 @@
// the internal state of VulkanManager: VulkanManager must be alive to use the returned value.
VkFunctorInitParams getVkFunctorInitParams() const;
- sk_sp<GrDirectContext> createContext(const GrContextOptions& options);
+
+ enum class ContextType {
+ kRenderThread,
+ kUploadThread
+ };
+
+ // returns a Skia graphic context used to draw content on the specified thread
+ sk_sp<GrDirectContext> createContext(const GrContextOptions& options,
+ ContextType contextType = ContextType::kRenderThread);
uint32_t getDriverVersion() const { return mDriverVersion; }
private:
friend class VulkanSurface;
+
+ explicit VulkanManager() {}
+ ~VulkanManager();
+
// Sets up the VkInstance and VkDevice objects. Also fills out the passed in
// VkPhysicalDeviceFeatures struct.
void setupDevice(GrVkExtensions&, VkPhysicalDeviceFeatures2&);
@@ -154,9 +162,9 @@
uint32_t mGraphicsQueueIndex;
VkQueue mGraphicsQueue = VK_NULL_HANDLE;
+ VkQueue mAHBUploadQueue = VK_NULL_HANDLE;
uint32_t mPresentQueueIndex;
VkQueue mPresentQueue = VK_NULL_HANDLE;
- VkCommandPool mCommandPool = VK_NULL_HANDLE;
// Variables saved to populate VkFunctorInitParams.
static const uint32_t mAPIVersion = VK_MAKE_VERSION(1, 1, 0);
diff --git a/libs/hwui/shader/BitmapShader.cpp b/libs/hwui/shader/BitmapShader.cpp
new file mode 100644
index 0000000..fe653e8
--- /dev/null
+++ b/libs/hwui/shader/BitmapShader.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BitmapShader.h"
+
+#include "SkImagePriv.h"
+
+namespace android::uirenderer {
+BitmapShader::BitmapShader(const sk_sp<SkImage>& image, const SkTileMode tileModeX,
+ const SkTileMode tileModeY, const SkMatrix* matrix)
+ : Shader(matrix), skShader(image->makeShader(tileModeX, tileModeY)) {}
+
+sk_sp<SkShader> BitmapShader::makeSkShader() {
+ return skShader;
+}
+
+BitmapShader::~BitmapShader() {}
+} // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/shader/BitmapShader.h b/libs/hwui/shader/BitmapShader.h
new file mode 100644
index 0000000..ed6a6e6
--- /dev/null
+++ b/libs/hwui/shader/BitmapShader.h
@@ -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.
+ */
+
+#pragma once
+
+#include "Shader.h"
+#include "SkShader.h"
+
+namespace android::uirenderer {
+
+/**
+ * Shader implementation that renders a Bitmap as either a SkShader or SkImageFilter
+ */
+class BitmapShader : public Shader {
+public:
+ BitmapShader(const sk_sp<SkImage>& image, const SkTileMode tileModeX,
+ const SkTileMode tileModeY, const SkMatrix* matrix);
+ ~BitmapShader() override;
+
+protected:
+ sk_sp<SkShader> makeSkShader() override;
+
+private:
+ sk_sp<SkShader> skShader;
+};
+} // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/shader/BlurShader.cpp b/libs/hwui/shader/BlurShader.cpp
new file mode 100644
index 0000000..4d18cdd
--- /dev/null
+++ b/libs/hwui/shader/BlurShader.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BlurShader.h"
+#include "SkImageFilters.h"
+#include "SkRefCnt.h"
+#include "utils/Blur.h"
+
+namespace android::uirenderer {
+BlurShader::BlurShader(float radiusX, float radiusY, Shader* inputShader, const SkMatrix* matrix)
+ : Shader(matrix)
+ , skImageFilter(
+ SkImageFilters::Blur(
+ Blur::convertRadiusToSigma(radiusX),
+ Blur::convertRadiusToSigma(radiusY),
+ inputShader ? inputShader->asSkImageFilter() : nullptr)
+ ) { }
+
+sk_sp<SkImageFilter> BlurShader::makeSkImageFilter() {
+ return skImageFilter;
+}
+
+BlurShader::~BlurShader() {}
+
+} // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/shader/BlurShader.h b/libs/hwui/shader/BlurShader.h
new file mode 100644
index 0000000..9eb22bd
--- /dev/null
+++ b/libs/hwui/shader/BlurShader.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include "Shader.h"
+
+namespace android::uirenderer {
+
+/**
+ * Shader implementation that blurs another Shader instance or the source bitmap
+ */
+class BlurShader : public Shader {
+public:
+ /**
+ * Creates a BlurShader instance with the provided radius values to blur along the x and y
+ * axis accordingly.
+ *
+ * This will blur the contents of the provided input shader if it is non-null, otherwise
+ * the source bitmap will be blurred instead.
+ */
+ BlurShader(float radiusX, float radiusY, Shader* inputShader, const SkMatrix* matrix);
+ ~BlurShader() override;
+protected:
+ sk_sp<SkImageFilter> makeSkImageFilter() override;
+private:
+ sk_sp<SkImageFilter> skImageFilter;
+};
+
+} // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/shader/ComposeShader.cpp b/libs/hwui/shader/ComposeShader.cpp
new file mode 100644
index 0000000..3765489
--- /dev/null
+++ b/libs/hwui/shader/ComposeShader.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ComposeShader.h"
+
+#include "SkImageFilters.h"
+#include "SkShader.h"
+
+namespace android::uirenderer {
+
+ComposeShader::ComposeShader(Shader& shaderA, Shader& shaderB, const SkBlendMode blendMode,
+ const SkMatrix* matrix)
+ : Shader(matrix) {
+ // If both Shaders can be represented as SkShaders then use those, if not
+ // create an SkImageFilter from both Shaders and create the equivalent SkImageFilter
+ sk_sp<SkShader> skShaderA = shaderA.asSkShader();
+ sk_sp<SkShader> skShaderB = shaderB.asSkShader();
+ if (skShaderA.get() && skShaderB.get()) {
+ skShader = SkShaders::Blend(blendMode, skShaderA, skShaderB);
+ skImageFilter = nullptr;
+ } else {
+ sk_sp<SkImageFilter> skImageFilterA = shaderA.asSkImageFilter();
+ sk_sp<SkImageFilter> skImageFilterB = shaderB.asSkImageFilter();
+ skShader = nullptr;
+ skImageFilter = SkImageFilters::Xfermode(blendMode, skImageFilterA, skImageFilterB);
+ }
+}
+
+sk_sp<SkShader> ComposeShader::makeSkShader() {
+ return skShader;
+}
+
+sk_sp<SkImageFilter> ComposeShader::makeSkImageFilter() {
+ return skImageFilter;
+}
+
+ComposeShader::~ComposeShader() {}
+} // namespace android::uirenderer
diff --git a/libs/hwui/shader/ComposeShader.h b/libs/hwui/shader/ComposeShader.h
new file mode 100644
index 0000000..a246b52
--- /dev/null
+++ b/libs/hwui/shader/ComposeShader.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "Shader.h"
+#include "SkShader.h"
+
+namespace android::uirenderer {
+
+/**
+ * Shader implementation that can composite 2 Shaders together with the specified blend mode.
+ * This implementation can appropriately convert the composed result to either an SkShader or
+ * SkImageFilter depending on the inputs
+ */
+class ComposeShader : public Shader {
+public:
+ ComposeShader(Shader& shaderA, Shader& shaderB, const SkBlendMode blendMode,
+ const SkMatrix* matrix);
+ ~ComposeShader() override;
+
+protected:
+ sk_sp<SkShader> makeSkShader() override;
+ sk_sp<SkImageFilter> makeSkImageFilter() override;
+
+private:
+ sk_sp<SkShader> skShader;
+ sk_sp<SkImageFilter> skImageFilter;
+};
+} // namespace android::uirenderer
diff --git a/libs/hwui/shader/LinearGradientShader.cpp b/libs/hwui/shader/LinearGradientShader.cpp
new file mode 100644
index 0000000..868fa44
--- /dev/null
+++ b/libs/hwui/shader/LinearGradientShader.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LinearGradientShader.h"
+
+#include <vector>
+
+#include "SkGradientShader.h"
+
+namespace android::uirenderer {
+
+LinearGradientShader::LinearGradientShader(const SkPoint pts[2],
+ const std::vector<SkColor4f>& colors,
+ sk_sp<SkColorSpace> colorspace, const SkScalar pos[],
+ const SkTileMode tileMode, const uint32_t shaderFlags,
+ const SkMatrix* matrix)
+ : Shader(matrix)
+ , skShader(SkGradientShader::MakeLinear(pts, colors.data(), colorspace, pos, colors.size(),
+ tileMode, shaderFlags, nullptr)) {}
+
+sk_sp<SkShader> LinearGradientShader::makeSkShader() {
+ return skShader;
+}
+
+LinearGradientShader::~LinearGradientShader() {}
+} // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/shader/LinearGradientShader.h b/libs/hwui/shader/LinearGradientShader.h
new file mode 100644
index 0000000..596f4e0
--- /dev/null
+++ b/libs/hwui/shader/LinearGradientShader.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "Shader.h"
+#include "SkShader.h"
+
+namespace android::uirenderer {
+
+/**
+ * Shader implementation that renders a color ramp of colors to either as either SkShader or
+ * SkImageFilter
+ */
+class LinearGradientShader : public Shader {
+public:
+ LinearGradientShader(const SkPoint pts[2], const std::vector<SkColor4f>& colors,
+ sk_sp<SkColorSpace> colorspace, const SkScalar pos[],
+ const SkTileMode tileMode, const uint32_t shaderFlags,
+ const SkMatrix* matrix);
+ ~LinearGradientShader() override;
+
+protected:
+ sk_sp<SkShader> makeSkShader() override;
+
+private:
+ sk_sp<SkShader> skShader;
+};
+} // namespace android::uirenderer
diff --git a/libs/hwui/shader/RadialGradientShader.cpp b/libs/hwui/shader/RadialGradientShader.cpp
new file mode 100644
index 0000000..21ff56f
--- /dev/null
+++ b/libs/hwui/shader/RadialGradientShader.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "RadialGradientShader.h"
+
+#include <vector>
+
+#include "SkGradientShader.h"
+
+namespace android::uirenderer {
+
+RadialGradientShader::RadialGradientShader(const SkPoint& center, const float radius,
+ const std::vector<SkColor4f>& colors,
+ sk_sp<SkColorSpace> colorspace, const SkScalar pos[],
+ const SkTileMode tileMode, const uint32_t shaderFlags,
+ const SkMatrix* matrix)
+ : Shader(matrix)
+ , skShader(SkGradientShader::MakeRadial(center, radius, colors.data(), colorspace, pos,
+ colors.size(), tileMode, shaderFlags, nullptr)) {}
+
+sk_sp<SkShader> RadialGradientShader::makeSkShader() {
+ return skShader;
+}
+
+RadialGradientShader::~RadialGradientShader() {}
+} // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/shader/RadialGradientShader.h b/libs/hwui/shader/RadialGradientShader.h
new file mode 100644
index 0000000..9a2ff13
--- /dev/null
+++ b/libs/hwui/shader/RadialGradientShader.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "Shader.h"
+#include "SkShader.h"
+
+namespace android::uirenderer {
+
+/**
+ * Shader implementation that renders a color ramp from the center outward to either as either
+ * a SkShader or SkImageFilter
+ */
+class RadialGradientShader : public Shader {
+public:
+ RadialGradientShader(const SkPoint& center, const float radius,
+ const std::vector<SkColor4f>& colors, sk_sp<SkColorSpace> colorSpace,
+ const SkScalar pos[], const SkTileMode tileMode, const uint32_t shaderFlags,
+ const SkMatrix* matrix);
+ ~RadialGradientShader() override;
+
+protected:
+ sk_sp<SkShader> makeSkShader() override;
+
+private:
+ sk_sp<SkShader> skShader;
+};
+} // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/shader/RuntimeShader.cpp b/libs/hwui/shader/RuntimeShader.cpp
new file mode 100644
index 0000000..dd0b698
--- /dev/null
+++ b/libs/hwui/shader/RuntimeShader.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RuntimeShader.h"
+
+#include "SkShader.h"
+#include "include/effects/SkRuntimeEffect.h"
+
+namespace android::uirenderer {
+
+RuntimeShader::RuntimeShader(SkRuntimeEffect& effect, sk_sp<SkData> data, bool isOpaque,
+ const SkMatrix* matrix)
+ : Shader(nullptr)
+ , // Explicitly passing null as RuntimeShader is created with the
+ // matrix directly
+ skShader(effect.makeShader(std::move(data), nullptr, 0, matrix, isOpaque)) {}
+
+sk_sp<SkShader> RuntimeShader::makeSkShader() {
+ return skShader;
+}
+
+RuntimeShader::~RuntimeShader() {}
+} // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/shader/RuntimeShader.h b/libs/hwui/shader/RuntimeShader.h
new file mode 100644
index 0000000..7fe0b02
--- /dev/null
+++ b/libs/hwui/shader/RuntimeShader.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "Shader.h"
+#include "SkShader.h"
+#include "include/effects/SkRuntimeEffect.h"
+
+namespace android::uirenderer {
+
+/**
+ * RuntimeShader implementation that can map to either a SkShader or SkImageFilter
+ */
+class RuntimeShader : public Shader {
+public:
+ RuntimeShader(SkRuntimeEffect& effect, sk_sp<SkData> data, bool isOpaque,
+ const SkMatrix* matrix);
+ ~RuntimeShader() override;
+
+protected:
+ sk_sp<SkShader> makeSkShader() override;
+
+private:
+ sk_sp<SkShader> skShader;
+};
+} // namespace android::uirenderer
diff --git a/libs/hwui/shader/Shader.cpp b/libs/hwui/shader/Shader.cpp
new file mode 100644
index 0000000..45123dd
--- /dev/null
+++ b/libs/hwui/shader/Shader.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Shader.h"
+
+#include "SkImageFilters.h"
+#include "SkPaint.h"
+#include "SkRefCnt.h"
+
+namespace android::uirenderer {
+
+Shader::Shader(const SkMatrix* matrix)
+ : localMatrix(matrix ? *matrix : SkMatrix::I())
+ , skShader(nullptr)
+ , skImageFilter(nullptr) {}
+
+Shader::~Shader() {}
+
+sk_sp<SkShader> Shader::asSkShader() {
+ // If we already have created a shader with these parameters just return the existing
+ // shader we have already created
+ if (!this->skShader.get()) {
+ this->skShader = makeSkShader();
+ if (this->skShader.get()) {
+ if (!localMatrix.isIdentity()) {
+ this->skShader = this->skShader->makeWithLocalMatrix(localMatrix);
+ }
+ }
+ }
+ return this->skShader;
+}
+
+/**
+ * By default return null as we cannot convert all visual effects to SkShader instances
+ */
+sk_sp<SkShader> Shader::makeSkShader() {
+ return nullptr;
+}
+
+sk_sp<SkImageFilter> Shader::asSkImageFilter() {
+ // If we already have created an ImageFilter with these parameters just return the existing
+ // ImageFilter we have already created
+ if (!this->skImageFilter.get()) {
+ // Attempt to create an SkImageFilter from the current Shader implementation
+ this->skImageFilter = makeSkImageFilter();
+ if (this->skImageFilter) {
+ if (!localMatrix.isIdentity()) {
+ // If we have created an SkImageFilter and we have a transformation, wrap
+ // the created SkImageFilter to apply the given matrix
+ this->skImageFilter = SkImageFilters::MatrixTransform(
+ localMatrix, kMedium_SkFilterQuality, this->skImageFilter);
+ }
+ } else {
+ // Otherwise if no SkImageFilter implementation is provided, create one from
+ // the result of asSkShader. Note the matrix is already applied to the shader in
+ // this case so just convert it to an SkImageFilter using SkImageFilters::Paint
+ SkPaint paint;
+ paint.setShader(asSkShader());
+ sk_sp<SkImageFilter> paintFilter = SkImageFilters::Paint(paint);
+ this->skImageFilter = SkImageFilters::Xfermode(SkBlendMode::kDstIn,
+ std::move(paintFilter));
+ }
+ }
+ return this->skImageFilter;
+}
+
+/**
+ * By default return null for subclasses to implement. If there is not a direct SkImageFilter
+ * conversion
+ */
+sk_sp<SkImageFilter> Shader::makeSkImageFilter() {
+ return nullptr;
+}
+} // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/shader/Shader.h b/libs/hwui/shader/Shader.h
new file mode 100644
index 0000000..6403e11
--- /dev/null
+++ b/libs/hwui/shader/Shader.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "SkImageFilter.h"
+#include "SkShader.h"
+#include "SkPaint.h"
+#include "SkRefCnt.h"
+
+class SkMatrix;
+
+namespace android::uirenderer {
+
+/**
+ * Shader class that can optionally wrap an SkShader or SkImageFilter depending
+ * on the implementation
+ */
+class Shader: public SkRefCnt {
+public:
+ /**
+ * Creates a Shader instance with an optional transformation matrix. The transformation matrix
+ * is copied internally and ownership is unchanged. It is the responsibility of the caller to
+ * deallocate it appropriately.
+ * @param matrix Optional matrix to transform the underlying SkShader or SkImageFilter
+ */
+ Shader(const SkMatrix* matrix);
+ virtual ~Shader();
+
+ /**
+ * Create an SkShader from the current Shader instance or return a previously
+ * created instance. This can be null if no SkShader could be created from this
+ * Shader instance.
+ */
+ sk_sp<SkShader> asSkShader();
+
+ /**
+ * Create an SkImageFilter from the current Shader instance or return a previously
+ * created instance. Unlike asSkShader, this method cannot return null.
+ */
+ sk_sp<SkImageFilter> asSkImageFilter();
+
+protected:
+ /**
+ * Create a new SkShader instance based on this Shader instance
+ */
+ virtual sk_sp<SkShader> makeSkShader();
+
+ /**
+ * Create a new SkImageFilter instance based on this Shader instance. If no SkImageFilter
+ * can be created then return nullptr
+ */
+ virtual sk_sp<SkImageFilter> makeSkImageFilter();
+
+private:
+ /**
+ * Optional matrix transform
+ */
+ const SkMatrix localMatrix;
+
+ /**
+ * Cached SkShader instance to be returned on subsequent queries
+ */
+ sk_sp<SkShader> skShader;
+
+ /**
+ * Cached SkImageFilter instance to be returned on subsequent queries
+ */
+ sk_sp<SkImageFilter> skImageFilter;
+};
+} // namespace android::uirenderer
diff --git a/libs/hwui/shader/SweepGradientShader.cpp b/libs/hwui/shader/SweepGradientShader.cpp
new file mode 100644
index 0000000..3b1f37f
--- /dev/null
+++ b/libs/hwui/shader/SweepGradientShader.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SweepGradientShader.h"
+
+#include <vector>
+
+#include "SkGradientShader.h"
+#include "SkImageFilters.h"
+
+namespace android::uirenderer {
+
+SweepGradientShader::SweepGradientShader(float x, float y, const std::vector<SkColor4f>& colors,
+ const sk_sp<SkColorSpace>& colorspace, const SkScalar pos[],
+ const uint32_t shaderFlags, const SkMatrix* matrix)
+ : Shader(matrix)
+ , skShader(SkGradientShader::MakeSweep(x, y, colors.data(), colorspace, pos, colors.size(),
+ shaderFlags, nullptr)) {}
+
+sk_sp<SkShader> SweepGradientShader::makeSkShader() {
+ return skShader;
+}
+
+SweepGradientShader::~SweepGradientShader() {}
+} // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/shader/SweepGradientShader.h b/libs/hwui/shader/SweepGradientShader.h
new file mode 100644
index 0000000..dad3ef0
--- /dev/null
+++ b/libs/hwui/shader/SweepGradientShader.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "Shader.h"
+#include "SkShader.h"
+
+namespace android::uirenderer {
+
+/**
+ * Shader implementation that renders a color ramp clockwise such that the start and end colors
+ * are visible at 3 o'clock. This handles converting to either an SkShader or SkImageFilter
+ */
+class SweepGradientShader : public Shader {
+public:
+ SweepGradientShader(float x, float y, const std::vector<SkColor4f>& colors,
+ const sk_sp<SkColorSpace>& colorspace, const SkScalar pos[],
+ const uint32_t shaderFlags, const SkMatrix* matrix);
+ virtual ~SweepGradientShader() override;
+
+protected:
+ virtual sk_sp<SkShader> makeSkShader() override;
+
+private:
+ sk_sp<SkShader> skShader;
+};
+} // namespace android::uirenderer
diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
index c4067af..e2c1651 100644
--- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
@@ -18,6 +18,7 @@
#include "hwui/Paint.h"
#include "TestSceneBase.h"
#include "tests/common/BitmapAllocationTestUtils.h"
+#include <shader/BitmapShader.h>
#include "utils/Color.h"
class BitmapShaders;
@@ -45,15 +46,24 @@
});
Paint paint;
+ sk_sp<BitmapShader> bitmapShader = sk_make_sp<BitmapShader>(
+ hwuiBitmap->makeImage(),
+ SkTileMode::kRepeat,
+ SkTileMode::kRepeat,
+ nullptr
+ );
+
sk_sp<SkImage> image = hwuiBitmap->makeImage();
- sk_sp<SkShader> repeatShader =
- image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat);
- paint.setShader(std::move(repeatShader));
+ paint.setShader(std::move(bitmapShader));
canvas.drawRoundRect(0, 0, 500, 500, 50.0f, 50.0f, paint);
- sk_sp<SkShader> mirrorShader =
- image->makeShader(SkTileMode::kMirror, SkTileMode::kMirror);
- paint.setShader(std::move(mirrorShader));
+ sk_sp<BitmapShader> mirrorBitmapShader = sk_make_sp<BitmapShader>(
+ image,
+ SkTileMode::kMirror,
+ SkTileMode::kMirror,
+ nullptr
+ );
+ paint.setShader(std::move(mirrorBitmapShader));
canvas.drawRoundRect(0, 600, 500, 1100, 50.0f, 50.0f, paint);
}
diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
index 5886ea3..d37bc3c 100644
--- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
+++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
@@ -20,6 +20,10 @@
#include <SkGradientShader.h>
#include <SkImagePriv.h>
#include <ui/PixelFormat.h>
+#include <shader/BitmapShader.h>
+#include <shader/LinearGradientShader.h>
+#include <shader/RadialGradientShader.h>
+#include <shader/ComposeShader.h>
class HwBitmapInCompositeShader;
@@ -50,20 +54,41 @@
pixels[4000 + 4 * i + 3] = 255;
}
buffer->unlock();
- sk_sp<Bitmap> hardwareBitmap(Bitmap::createFrom(buffer->toAHardwareBuffer(),
- SkColorSpace::MakeSRGB()));
- sk_sp<SkShader> hardwareShader(createBitmapShader(*hardwareBitmap));
+
+ sk_sp<BitmapShader> bitmapShader = sk_make_sp<BitmapShader>(
+ Bitmap::createFrom(
+ buffer->toAHardwareBuffer(),
+ SkColorSpace::MakeSRGB()
+ )->makeImage(),
+ SkTileMode::kClamp,
+ SkTileMode::kClamp,
+ nullptr
+ );
SkPoint center;
center.set(50, 50);
- SkColor colors[2];
- colors[0] = Color::Black;
- colors[1] = Color::White;
- sk_sp<SkShader> gradientShader = SkGradientShader::MakeRadial(
- center, 50, colors, nullptr, 2, SkTileMode::kRepeat);
- sk_sp<SkShader> compositeShader(
- SkShaders::Blend(SkBlendMode::kDstATop, hardwareShader, gradientShader));
+ std::vector<SkColor4f> vColors(2);
+ vColors[0] = SkColors::kBlack;
+ vColors[1] = SkColors::kWhite;
+
+ sk_sp<RadialGradientShader> radialShader = sk_make_sp<RadialGradientShader>(
+ center,
+ 50,
+ vColors,
+ SkColorSpace::MakeSRGB(),
+ nullptr,
+ SkTileMode::kRepeat,
+ 0,
+ nullptr
+ );
+
+ sk_sp<ComposeShader> compositeShader = sk_make_sp<ComposeShader>(
+ *bitmapShader.get(),
+ *radialShader.get(),
+ SkBlendMode::kDstATop,
+ nullptr
+ );
Paint paint;
paint.setShader(std::move(compositeShader));
diff --git a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
index a9449b6..76e39de 100644
--- a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
@@ -17,7 +17,8 @@
#include "TestSceneBase.h"
#include "tests/common/TestListViewSceneBase.h"
#include "hwui/Paint.h"
-#include <SkGradientShader.h>
+#include "SkColor.h"
+#include <shader/LinearGradientShader.h>
class ListOfFadedTextAnimation;
@@ -42,15 +43,26 @@
pts[0].set(0, 0);
pts[1].set(0, 1);
- SkColor colors[2] = {Color::Black, Color::Transparent};
- sk_sp<SkShader> s(
- SkGradientShader::MakeLinear(pts, colors, NULL, 2, SkTileMode::kClamp));
-
SkMatrix matrix;
matrix.setScale(1, length);
matrix.postRotate(-90);
+
+ std::vector<SkColor4f> vColors(2);
+ vColors[0] = SkColors::kBlack;
+ vColors[1] = SkColors::kTransparent;
+
+ sk_sp<LinearGradientShader> linearGradientShader = sk_make_sp<LinearGradientShader>(
+ pts,
+ vColors,
+ SkColorSpace::MakeSRGB(),
+ nullptr,
+ SkTileMode::kClamp,
+ 0,
+ &matrix
+ );
+
Paint fadingPaint;
- fadingPaint.setShader(s->makeWithLocalMatrix(matrix));
+ fadingPaint.setShader(linearGradientShader);
fadingPaint.setBlendMode(SkBlendMode::kDstOut);
canvas.drawRect(0, 0, length, itemHeight, fadingPaint);
canvas.restore();
diff --git a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
index a0bc5aa..bdc157f 100644
--- a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
@@ -17,7 +17,7 @@
#include "TestSceneBase.h"
#include <SkColorMatrixFilter.h>
-#include <SkGradientShader.h>
+#include <shader/LinearGradientShader.h>
class SimpleColorMatrixAnimation;
@@ -65,9 +65,12 @@
// enough renderer might apply it directly to the paint color)
float pos[] = {0, 1};
SkPoint pts[] = {SkPoint::Make(0, 0), SkPoint::Make(width, height)};
- SkColor colors[2] = {Color::DeepPurple_500, Color::DeepOrange_500};
- paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 2,
- SkTileMode::kClamp));
+ std::vector<SkColor4f> colors(2);
+ colors[0] = SkColor4f::FromColor(Color::DeepPurple_500);
+ colors[1] = SkColor4f::FromColor(Color::DeepOrange_500);
+ paint.setShader(sk_make_sp<LinearGradientShader>(
+ pts, colors, SkColorSpace::MakeSRGB(), pos, SkTileMode::kClamp,
+ 0, nullptr));
// overdraw several times to emphasize shader cost
for (int i = 0; i < 10; i++) {
diff --git a/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
index 57a260c..9a15c9d 100644
--- a/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
@@ -17,6 +17,7 @@
#include "TestSceneBase.h"
#include <SkGradientShader.h>
+#include <shader/LinearGradientShader.h>
class SimpleGradientAnimation;
@@ -55,9 +56,24 @@
// overdraw several times to emphasize shader cost
for (int i = 0; i < 10; i++) {
// use i%2 start position to pick 2 color combo with black in it
- SkColor colors[3] = {Color::Transparent, Color::Black, Color::Cyan_500};
- paint.setShader(SkGradientShader::MakeLinear(pts, colors + (i % 2), pos, 2,
- SkTileMode::kClamp));
+ std::vector<SkColor4f> vColors(2);
+ vColors[0] = ((i % 2) == 0) ?
+ SkColor4f::FromColor(Color::Transparent) :
+ SkColor4f::FromColor(Color::Black);
+ vColors[1] = (((i + 1) % 2) == 0) ?
+ SkColor4f::FromColor(Color::Black) :
+ SkColor4f::FromColor(Color::Cyan_500);
+
+ sk_sp<LinearGradientShader> gradient = sk_make_sp<LinearGradientShader>(
+ pts,
+ vColors,
+ SkColorSpace::MakeSRGB(),
+ pos,
+ SkTileMode::kClamp,
+ 0,
+ nullptr
+ );
+ paint.setShader(gradient);
canvas.drawRect(i, i, width, height, paint);
}
});
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
index fcc64fd..f77ca2a 100644
--- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -73,7 +73,7 @@
// Test picture recording.
SkPictureRecorder recorder;
- SkCanvas* skPicCanvas = recorder.beginRecording(1, 1, NULL, 0);
+ SkCanvas* skPicCanvas = recorder.beginRecording(1, 1);
SkiaCanvas picCanvas(skPicCanvas);
picCanvas.drawBitmap(*adobeBitmap, 0, 0, nullptr);
sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture();
@@ -104,7 +104,7 @@
// Create a picture canvas.
SkPictureRecorder recorder;
- SkCanvas* skPicCanvas = recorder.beginRecording(1, 1, NULL, 0);
+ SkCanvas* skPicCanvas = recorder.beginRecording(1, 1);
SkiaCanvas picCanvas(skPicCanvas);
state = picCanvas.captureCanvasState();
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index 6d4c574..5e56b26 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -17,9 +17,14 @@
#include <gtest/gtest.h>
#include "PathParser.h"
+#include "GraphicsJNI.h"
+#include "SkGradientShader.h"
+#include "SkShader.h"
#include "VectorDrawable.h"
#include "utils/MathUtils.h"
#include "utils/VectorDrawableUtils.h"
+#include <shader/Shader.h>
+#include <shader/LinearGradientShader.h>
#include <functional>
@@ -395,7 +400,21 @@
bitmap.allocN32Pixels(5, 5, false);
SkCanvas canvas(bitmap);
- sk_sp<SkShader> shader = SkShaders::Color(SK_ColorBLACK);
+ SkPoint pts[2];
+ pts[0].set(0, 0);
+ pts[1].set(0, 0);
+
+ std::vector<SkColor4f> colors(2);
+ colors[0] = SkColors::kBlack;
+ colors[1] = SkColors::kBlack;
+
+ sk_sp<LinearGradientShader> shader = sk_sp(new LinearGradientShader(pts,
+ colors,
+ SkColorSpace::MakeSRGB(),
+ nullptr,
+ SkTileMode::kClamp,
+ SkGradientShader::kInterpolateColorsInPremul_Flag,
+ nullptr));
// Initial ref count is 1
EXPECT_TRUE(shader->unique());
diff --git a/libs/input/MouseCursorController.cpp b/libs/input/MouseCursorController.cpp
index 80b555b..45da008 100644
--- a/libs/input/MouseCursorController.cpp
+++ b/libs/input/MouseCursorController.cpp
@@ -168,7 +168,7 @@
updatePointerLocked();
} else {
mLocked.pointerFadeDirection = -1;
- mContext.startAnimation();
+ startAnimationLocked();
}
}
@@ -185,7 +185,7 @@
updatePointerLocked();
} else {
mLocked.pointerFadeDirection = 1;
- mContext.startAnimation();
+ startAnimationLocked();
}
}
@@ -312,10 +312,9 @@
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 @@
}
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 @@
spriteController->closeTransaction();
}
-
// Keep animating.
return true;
}
@@ -399,7 +394,7 @@
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 @@
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 448165b..e6dfc4c 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 @@
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 @@
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 @@
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 14c96ce..8f04cfb 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -57,7 +57,6 @@
controller->mContext.setHandlerController(controller);
controller->mContext.setCallbackController(controller);
- controller->mContext.initializeDisplayEventReceiver();
return controller;
}
@@ -189,24 +188,6 @@
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 @@
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 1f561da..827fcf1 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -70,7 +70,6 @@
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 2d7e22b..f30e8d8 100644
--- a/libs/input/PointerControllerContext.cpp
+++ b/libs/input/PointerControllerContext.cpp
@@ -38,10 +38,10 @@
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::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 @@
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 @@
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 @@
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 92e1bda..98073fe 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 @@
void startAnimation();
void setInactivityTimeout(InactivityTimeout inactivityTimeout);
- void setAnimationPending(bool animationPending);
nsecs_t getAnimationTime();
void clearSpotsByDisplay(int32_t displayId);
@@ -107,9 +109,11 @@
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 @@
};
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 c7430ce..f7c685f 100644
--- a/libs/input/TouchSpotController.cpp
+++ b/libs/input/TouchSpotController.cpp
@@ -142,7 +142,8 @@
}
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 @@
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 @@
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 @@
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 f3b3550..703de36 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 @@
void clearSpots();
void reloadSpotResources();
- bool doFadingAnimation(nsecs_t timestamp, bool keepAnimating);
+ bool doAnimations(nsecs_t timestamp);
private:
struct Spot {
@@ -76,6 +78,8 @@
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 @@
void releaseSpotLocked(Spot* spot);
void fadeOutAndReleaseSpotLocked(Spot* spot);
void fadeOutAndReleaseAllSpotsLocked();
+ bool doFadingAnimationLocked(nsecs_t timestamp);
+ void startAnimationLocked();
};
} // namespace android
diff --git a/location/java/android/location/timezone/LocationTimeZoneEvent.java b/location/java/android/location/timezone/LocationTimeZoneEvent.java
index ea3353c..540bdff 100644
--- a/location/java/android/location/timezone/LocationTimeZoneEvent.java
+++ b/location/java/android/location/timezone/LocationTimeZoneEvent.java
@@ -21,6 +21,7 @@
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.UserHandle;
import java.util.ArrayList;
import java.util.Collections;
@@ -37,7 +38,7 @@
@IntDef({ EVENT_TYPE_UNKNOWN, EVENT_TYPE_SUCCESS, EVENT_TYPE_SUCCESS })
@interface EventType {}
- /** Uninitialized value for {@link #mEventType} */
+ /** Uninitialized value for {@link #mEventType} - must not be used for real events. */
private static final int EVENT_TYPE_UNKNOWN = 0;
/**
@@ -60,6 +61,9 @@
private static final int EVENT_TYPE_MAX = EVENT_TYPE_UNCERTAIN;
+ @NonNull
+ private final UserHandle mUserHandle;
+
@EventType
private final int mEventType;
@@ -68,8 +72,9 @@
private final long mElapsedRealtimeNanos;
- private LocationTimeZoneEvent(@EventType int eventType, @NonNull List<String> timeZoneIds,
- long elapsedRealtimeNanos) {
+ private LocationTimeZoneEvent(@NonNull UserHandle userHandle, @EventType int eventType,
+ @NonNull List<String> timeZoneIds, long elapsedRealtimeNanos) {
+ mUserHandle = Objects.requireNonNull(userHandle);
mEventType = checkValidEventType(eventType);
mTimeZoneIds = immutableList(timeZoneIds);
@@ -83,6 +88,14 @@
}
/**
+ * Returns the current user when the event was generated.
+ */
+ @NonNull
+ public UserHandle getUserHandle() {
+ return mUserHandle;
+ }
+
+ /**
* Returns the time of this fix, in elapsed real-time since system boot.
*
* <p>This value can be reliably compared to {@link
@@ -117,7 +130,8 @@
@Override
public String toString() {
return "LocationTimeZoneEvent{"
- + "mEventType=" + mEventType
+ + "mUserHandle=" + mUserHandle
+ + ", mEventType=" + mEventType
+ ", mTimeZoneIds=" + mTimeZoneIds
+ ", mElapsedRealtimeNanos=" + mElapsedRealtimeNanos
+ '}';
@@ -127,12 +141,14 @@
new Parcelable.Creator<LocationTimeZoneEvent>() {
@Override
public LocationTimeZoneEvent createFromParcel(Parcel in) {
+ UserHandle userHandle = UserHandle.readFromParcel(in);
int eventType = in.readInt();
@SuppressWarnings("unchecked")
ArrayList<String> timeZoneIds =
(ArrayList<String>) in.readArrayList(null /* classLoader */);
long elapsedRealtimeNanos = in.readLong();
- return new LocationTimeZoneEvent(eventType, timeZoneIds, elapsedRealtimeNanos);
+ return new LocationTimeZoneEvent(
+ userHandle, eventType, timeZoneIds, elapsedRealtimeNanos);
}
@Override
@@ -148,6 +164,7 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
+ mUserHandle.writeToParcel(parcel, flags);
parcel.writeInt(mEventType);
parcel.writeList(mTimeZoneIds);
parcel.writeLong(mElapsedRealtimeNanos);
@@ -162,19 +179,21 @@
return false;
}
LocationTimeZoneEvent that = (LocationTimeZoneEvent) o;
- return mEventType == that.mEventType
+ return mUserHandle.equals(that.mUserHandle)
+ && mEventType == that.mEventType
&& mElapsedRealtimeNanos == that.mElapsedRealtimeNanos
&& mTimeZoneIds.equals(that.mTimeZoneIds);
}
@Override
public int hashCode() {
- return Objects.hash(mEventType, mTimeZoneIds, mElapsedRealtimeNanos);
+ return Objects.hash(mUserHandle, mEventType, mTimeZoneIds, mElapsedRealtimeNanos);
}
/** @hide */
public static final class Builder {
+ private UserHandle mUserHandle;
private @EventType int mEventType = EVENT_TYPE_UNKNOWN;
private @NonNull List<String> mTimeZoneIds = Collections.emptyList();
private long mElapsedRealtimeNanos;
@@ -186,13 +205,22 @@
* Sets the contents of this from the supplied instance.
*/
public Builder(@NonNull LocationTimeZoneEvent ltz) {
+ mUserHandle = ltz.mUserHandle;
mEventType = ltz.mEventType;
mTimeZoneIds = ltz.mTimeZoneIds;
mElapsedRealtimeNanos = ltz.mElapsedRealtimeNanos;
}
/**
- * Set the time zone ID of this fix.
+ * Set the current user when this event was generated.
+ */
+ public Builder setUserHandle(@NonNull UserHandle userHandle) {
+ mUserHandle = Objects.requireNonNull(userHandle);
+ return this;
+ }
+
+ /**
+ * Set the time zone ID of this event.
*/
public Builder setEventType(@EventType int eventType) {
checkValidEventType(eventType);
@@ -201,7 +229,7 @@
}
/**
- * Sets the time zone IDs of this fix.
+ * Sets the time zone IDs of this event.
*/
public Builder setTimeZoneIds(@NonNull List<String> timeZoneIds) {
mTimeZoneIds = Objects.requireNonNull(timeZoneIds);
@@ -209,9 +237,7 @@
}
/**
- * Sets the time of this fix, in elapsed real-time since system boot.
- *
- * @param time elapsed real-time of fix, in nanoseconds since system boot.
+ * Sets the time of this event, in elapsed real-time since system boot.
*/
public Builder setElapsedRealtimeNanos(long time) {
mElapsedRealtimeNanos = time;
@@ -222,8 +248,8 @@
* Builds a {@link LocationTimeZoneEvent} instance.
*/
public LocationTimeZoneEvent build() {
- return new LocationTimeZoneEvent(this.mEventType, this.mTimeZoneIds,
- this.mElapsedRealtimeNanos);
+ return new LocationTimeZoneEvent(
+ mUserHandle, mEventType, mTimeZoneIds, mElapsedRealtimeNanos);
}
}
diff --git a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderBase.java b/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderBase.java
index 0143c88..c533c20 100644
--- a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderBase.java
+++ b/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderBase.java
@@ -32,7 +32,7 @@
/**
* Base class for location time zone providers implemented as unbundled services.
*
- * TODO Provide details of the expected service actions.
+ * TODO(b/152744911): Provide details of the expected service actions and threading.
*
* <p>IMPORTANT: This class is effectively a public API for unbundled applications, and must remain
* API stable.
diff --git a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderRequestUnbundled.java b/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderRequestUnbundled.java
index dd80466..e898bbf 100644
--- a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderRequestUnbundled.java
+++ b/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderRequestUnbundled.java
@@ -44,6 +44,24 @@
}
@Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ LocationTimeZoneProviderRequestUnbundled that =
+ (LocationTimeZoneProviderRequestUnbundled) o;
+ return mRequest.equals(that.mRequest);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mRequest);
+ }
+
+ @Override
public String toString() {
return mRequest.toString();
}
diff --git a/media/java/android/media/MediaTranscodeManager.java b/media/java/android/media/MediaTranscodeManager.java
index e1bff03..4e2ae5c 100644
--- a/media/java/android/media/MediaTranscodeManager.java
+++ b/media/java/android/media/MediaTranscodeManager.java
@@ -36,7 +36,10 @@
import java.io.FileNotFoundException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
@@ -94,11 +97,17 @@
TODO(hkuang): Clarify whether supports framerate conversion.
@hide
*/
-public final class MediaTranscodeManager {
+public final class MediaTranscodeManager implements AutoCloseable {
private static final String TAG = "MediaTranscodeManager";
private static final String MEDIA_TRANSCODING_SERVICE = "media.transcoding";
+ /** Maximum number of retry to connect to the service. */
+ private static final int CONNECT_SERVICE_RETRY_COUNT = 100;
+
+ /** Interval between trying to reconnect to the service. */
+ private static final int INTERVAL_CONNECT_SERVICE_RETRY_MS = 40;
+
/**
* Default transcoding type.
* @hide
@@ -117,6 +126,25 @@
*/
public static final int TRANSCODING_TYPE_IMAGE = 2;
+ @Override
+ public void close() throws Exception {
+ release();
+ }
+
+ /**
+ * Releases the MediaTranscodeManager.
+ */
+ //TODO(hkuang): add test for it.
+ private void release() throws Exception {
+ synchronized (mLock) {
+ if (mTranscodingClient != null) {
+ mTranscodingClient.unregister();
+ } else {
+ throw new UnsupportedOperationException("Failed to release");
+ }
+ }
+ }
+
/** @hide */
@IntDef(prefix = {"TRANSCODING_TYPE_"}, value = {
TRANSCODING_TYPE_UNKNOWN,
@@ -181,10 +209,12 @@
private final String mPackageName;
private final int mPid;
private final int mUid;
- private final ExecutorService mCallbackExecutor = Executors.newSingleThreadExecutor();
- private static MediaTranscodeManager sMediaTranscodeManager;
+ private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
private final HashMap<Integer, TranscodingJob> mPendingTranscodingJobs = new HashMap();
- @NonNull private ITranscodingClient mTranscodingClient;
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ @NonNull private ITranscodingClient mTranscodingClient = null;
+ private static MediaTranscodeManager sMediaTranscodeManager;
private void handleTranscodingFinished(int jobId, TranscodingResultParcel result) {
synchronized (mPendingTranscodingJobs) {
@@ -209,7 +239,7 @@
}
}
- private void handleTranscodingFailed(int jobId, int errorCodec) {
+ private void handleTranscodingFailed(int jobId, int errorCode) {
synchronized (mPendingTranscodingJobs) {
// Gets the job associated with the jobId and removes it from
// mPendingTranscodingJobs.
@@ -254,6 +284,98 @@
}
}
+ private static IMediaTranscodingService getService(boolean retry) {
+ int retryCount = !retry ? 1 : CONNECT_SERVICE_RETRY_COUNT;
+ Log.i(TAG, "get service with rety " + retryCount);
+ for (int count = 1; count <= retryCount; count++) {
+ Log.d(TAG, "Trying to connect to service. Try count: " + count);
+ IMediaTranscodingService service = IMediaTranscodingService.Stub.asInterface(
+ ServiceManager.getService(MEDIA_TRANSCODING_SERVICE));
+ if (service != null) {
+ return service;
+ }
+ try {
+ // Sleep a bit before retry.
+ Thread.sleep(INTERVAL_CONNECT_SERVICE_RETRY_MS);
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+ }
+
+ throw new UnsupportedOperationException("Failed to connect to MediaTranscoding service");
+ }
+
+ /*
+ * Handle client binder died event.
+ * Upon receiving a binder died event of the client, we will do the following:
+ * 1) For the job that is running, notify the client that the job is failed with error code,
+ * so client could choose to retry the job or not.
+ * TODO(hkuang): Add a new error code to signal service died error.
+ * 2) For the jobs that is still pending or paused, we will resubmit the job internally once
+ * we successfully reconnect to the service and register a new client.
+ * 3) When trying to connect to the service and register a new client. The service may need time
+ * to reboot or never boot up again. So we will retry for a number of times. If we still
+ * could not connect, we will notify client job failure for the pending and paused jobs.
+ */
+ private void onClientDied() {
+ synchronized (mLock) {
+ mTranscodingClient = null;
+ }
+
+ // Delegates the job notification and retry to the executor as it may take some time.
+ mExecutor.execute(() -> {
+ // List to track the jobs that we want to retry.
+ List<TranscodingJob> retryJobs = new ArrayList<TranscodingJob>();
+
+ // First notify the client of job failure for all the running jobs.
+ synchronized (mPendingTranscodingJobs) {
+ for (Map.Entry<Integer, TranscodingJob> entry :
+ mPendingTranscodingJobs.entrySet()) {
+ TranscodingJob job = entry.getValue();
+
+ if (job.getStatus() == TranscodingJob.STATUS_RUNNING) {
+ job.updateStatusAndResult(TranscodingJob.STATUS_FINISHED,
+ TranscodingJob.RESULT_ERROR);
+
+ // Remove the job from pending jobs.
+ mPendingTranscodingJobs.remove(entry.getKey());
+
+ if (job.mListener != null && job.mListenerExecutor != null) {
+ Log.i(TAG, "Notify client job failed");
+ job.mListenerExecutor.execute(
+ () -> job.mListener.onTranscodingFinished(job));
+ }
+ } else if (job.getStatus() == TranscodingJob.STATUS_PENDING
+ || job.getStatus() == TranscodingJob.STATUS_PAUSED) {
+ // Add the job to retryJobs to handle them later.
+ retryJobs.add(job);
+ }
+ }
+ }
+
+ // Try to register with the service once it boots up.
+ IMediaTranscodingService service = getService(true /*retry*/);
+ boolean haveTranscodingClient = false;
+ if (service != null) {
+ synchronized (mLock) {
+ mTranscodingClient = registerClient(service);
+ if (mTranscodingClient != null) {
+ haveTranscodingClient = true;
+ }
+ }
+ }
+
+ for (TranscodingJob job : retryJobs) {
+ // Notify the job failure if we fails to connect to the service or fail
+ // to retry the job.
+ if (!haveTranscodingClient || !job.retry()) {
+ // TODO(hkuang): Return correct error code to the client.
+ handleTranscodingFailed(job.getJobId(), 0 /*unused */);
+ }
+ }
+ });
+ }
+
private void updateStatus(int jobId, int status) {
synchronized (mPendingTranscodingJobs) {
final TranscodingJob job = mPendingTranscodingJobs.get(jobId);
@@ -336,6 +458,30 @@
}
};
+ private ITranscodingClient registerClient(IMediaTranscodingService service)
+ throws UnsupportedOperationException {
+ synchronized (mLock) {
+ try {
+ // Registers the client with MediaTranscoding service.
+ mTranscodingClient = service.registerClient(
+ mTranscodingClientCallback,
+ mPackageName,
+ mPackageName,
+ IMediaTranscodingService.USE_CALLING_UID,
+ IMediaTranscodingService.USE_CALLING_PID);
+
+ if (mTranscodingClient != null) {
+ mTranscodingClient.asBinder().linkToDeath(() -> onClientDied(), /* flags */ 0);
+ }
+ return mTranscodingClient;
+ } catch (RemoteException re) {
+ Log.e(TAG, "Failed to register new client due to exception " + re);
+ mTranscodingClient = null;
+ }
+ }
+ throw new UnsupportedOperationException("Failed to register new client");
+ }
+
/* Private constructor. */
private MediaTranscodeManager(@NonNull Context context,
IMediaTranscodingService transcodingService) {
@@ -344,21 +490,17 @@
mPackageName = mContext.getPackageName();
mPid = Os.getuid();
mUid = Os.getpid();
-
- try {
- // Registers the client with MediaTranscoding service.
- mTranscodingClient = transcodingService.registerClient(
- mTranscodingClientCallback,
- mPackageName,
- mPackageName,
- IMediaTranscodingService.USE_CALLING_UID,
- IMediaTranscodingService.USE_CALLING_PID);
- } catch (RemoteException re) {
- Log.e(TAG, "Failed to register new client due to exception " + re);
- throw new UnsupportedOperationException("Failed to register new client");
- }
+ mTranscodingClient = registerClient(transcodingService);
}
+ @Override
+ protected void finalize() {
+ try {
+ release();
+ } catch (Exception ex) {
+ Log.e(TAG, "Failed to release");
+ }
+ }
public static final class TranscodingRequest {
/** Uri of the source media file. */
@@ -807,6 +949,16 @@
}
/**
+ * Resubmit the transcoding job to the service.
+ *
+ * @return true if successfully resubmit the job to the service. False otherwise.
+ */
+ public synchronized boolean retry() {
+ // TODO(hkuang): Implement this.
+ return true;
+ }
+
+ /**
* Cancels the transcoding job and notify the listener.
* If the job happened to finish before being canceled this call is effectively a no-op and
* will not update the result in that case.
@@ -879,9 +1031,15 @@
*/
public static MediaTranscodeManager getInstance(@NonNull Context context) {
// Acquires the MediaTranscoding service.
- IMediaTranscodingService service = IMediaTranscodingService.Stub.asInterface(
- ServiceManager.getService(MEDIA_TRANSCODING_SERVICE));
+ IMediaTranscodingService service = getService(false /*retry*/);
+ return getInstance(context, service);
+ }
+ /** Similar as above, but wait till the service is ready. */
+ @VisibleForTesting
+ public static MediaTranscodeManager getInstance(@NonNull Context context, boolean retry) {
+ // Acquires the MediaTranscoding service.
+ IMediaTranscodingService service = getService(retry);
return getInstance(context, service);
}
@@ -896,6 +1054,7 @@
sMediaTranscodeManager = new MediaTranscodeManager(context.getApplicationContext(),
transcodingService);
}
+
return sMediaTranscodeManager;
}
}
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index 21378c8..77f7b54 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -41,7 +41,8 @@
// These commands are for the TransportPerformer
void setMetadata(in MediaMetadata metadata, long duration, String metadataDescription);
void setPlaybackState(in PlaybackState state);
- void setQueue(in ParceledListSlice queue);
+ void resetQueue();
+ IBinder getBinderForSetQueue();
void setQueueTitle(CharSequence title);
void setExtras(in Bundle extras);
void setRatingType(int type);
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 70bd160..549e793 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -25,7 +25,6 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ParceledListSlice;
import android.media.AudioAttributes;
import android.media.MediaDescription;
import android.media.MediaMetadata;
@@ -36,6 +35,7 @@
import android.os.BadParcelableException;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
@@ -103,6 +103,8 @@
* System only flag for a session that needs to have priority over all other
* sessions. This flag ensures this session will receive media button events
* regardless of the current ordering in the system.
+ * If there are two or more sessions with this flag, the last session that sets this flag
+ * will be the global priority session.
*
* @hide
*/
@@ -491,7 +493,12 @@
*/
public void setQueue(@Nullable List<QueueItem> queue) {
try {
- mBinder.setQueue(queue == null ? null : new ParceledListSlice(queue));
+ if (queue == null) {
+ mBinder.resetQueue();
+ } else {
+ IBinder binder = mBinder.getBinderForSetQueue();
+ ParcelableListBinder.send(binder, queue);
+ }
} catch (RemoteException e) {
Log.wtf("Dead object in setQueue.", e);
}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 6976a35..2000693 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -523,7 +523,8 @@
* @param keyEvent The KeyEvent to send.
* @hide
*/
- public void dispatchMediaKeyEventAsSystemService(KeyEvent keyEvent) {
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public void dispatchMediaKeyEventAsSystemService(@NonNull KeyEvent keyEvent) {
dispatchMediaKeyEventInternal(true, keyEvent, false);
}
@@ -548,6 +549,7 @@
* @return {@code true} if the event was sent to the session, {@code false} otherwise
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public boolean dispatchMediaKeyEventAsSystemService(@NonNull MediaSession.Token sessionToken,
@NonNull KeyEvent keyEvent) {
if (sessionToken == null) {
@@ -586,10 +588,15 @@
* Should be only called by the {@link com.android.internal.policy.PhoneWindow} or
* {@link android.view.FallbackEventHandler} when the foreground activity didn't consume the key
* from the hardware devices.
+ * <p>
+ * Valid stream types include {@link AudioManager.PublicStreamTypes} and
+ * {@link AudioManager#USE_DEFAULT_STREAM_TYPE}.
*
- * @param keyEvent The KeyEvent to send.
+ * @param keyEvent volume key event
+ * @param streamType type of stream
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public void dispatchVolumeKeyEventAsSystemService(@NonNull KeyEvent keyEvent, int streamType) {
dispatchVolumeKeyEventInternal(true, keyEvent, streamType, false);
}
@@ -614,6 +621,7 @@
* @param keyEvent volume key event
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public void dispatchVolumeKeyEventAsSystemService(@NonNull MediaSession.Token sessionToken,
@NonNull KeyEvent keyEvent) {
if (sessionToken == null) {
diff --git a/media/java/android/media/session/ParcelableListBinder.java b/media/java/android/media/session/ParcelableListBinder.java
new file mode 100644
index 0000000..a7aacf2
--- /dev/null
+++ b/media/java/android/media/session/ParcelableListBinder.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.annotation.NonNull;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * Binder to receive a list that has a large number of {@link Parcelable} items.
+ *
+ * It's similar to {@link android.content.pm.ParceledListSlice}, but transactions are performed in
+ * the opposite direction.
+ *
+ * @param <T> the type of {@link Parcelable}
+ * @hide
+ */
+public class ParcelableListBinder<T extends Parcelable> extends Binder {
+
+ private static final int SUGGESTED_MAX_IPC_SIZE = IBinder.getSuggestedMaxIpcSizeBytes();
+
+ private static final int END_OF_PARCEL = 0;
+ private static final int ITEM_CONTINUED = 1;
+
+ private final Consumer<List<T>> mConsumer;
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private final List<T> mList = new ArrayList<>();
+
+ @GuardedBy("mLock")
+ private int mCount;
+
+ @GuardedBy("mLock")
+ private boolean mConsumed;
+
+ /**
+ * Creates an instance.
+ *
+ * @param consumer a consumer that consumes the list received
+ */
+ public ParcelableListBinder(@NonNull Consumer<List<T>> consumer) {
+ mConsumer = consumer;
+ }
+
+ @Override
+ protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ if (code != FIRST_CALL_TRANSACTION) {
+ return super.onTransact(code, data, reply, flags);
+ }
+ List<T> listToBeConsumed;
+ synchronized (mLock) {
+ if (mConsumed) {
+ return false;
+ }
+ int i = mList.size();
+ if (i == 0) {
+ mCount = data.readInt();
+ }
+ while (i < mCount && data.readInt() != END_OF_PARCEL) {
+ mList.add(data.readParcelable(null));
+ i++;
+ }
+ if (i >= mCount) {
+ listToBeConsumed = mList;
+ mConsumed = true;
+ } else {
+ listToBeConsumed = null;
+ }
+ }
+ if (listToBeConsumed != null) {
+ mConsumer.accept(listToBeConsumed);
+ }
+ return true;
+ }
+
+ /**
+ * Sends a list of {@link Parcelable} to a binder.
+ *
+ * @param binder a binder interface backed by {@link ParcelableListBinder}
+ * @param list a list to send
+ */
+ public static <T extends Parcelable> void send(@NonNull IBinder binder, @NonNull List<T> list)
+ throws RemoteException {
+ int count = list.size();
+ int i = 0;
+ while (i < count) {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ if (i == 0) {
+ data.writeInt(count);
+ }
+ while (i < count && data.dataSize() < SUGGESTED_MAX_IPC_SIZE) {
+ data.writeInt(ITEM_CONTINUED);
+ data.writeParcelable(list.get(i), 0);
+ i++;
+ }
+ if (i < count) {
+ data.writeInt(END_OF_PARCEL);
+ }
+ binder.transact(FIRST_CALL_TRANSACTION, data, reply, 0);
+ reply.recycle();
+ data.recycle();
+ }
+ }
+}
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 5770c67..5db6729 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -2060,7 +2060,7 @@
env->GetIntField(settings, env->GetFieldID(clazz, "mModulation", "I")));
FrontendInnerFec innerFec =
static_cast<FrontendInnerFec>(
- env->GetLongField(settings, env->GetFieldID(clazz, "mFec", "J")));
+ env->GetLongField(settings, env->GetFieldID(clazz, "mInnerFec", "J")));
uint32_t symbolRate =
static_cast<uint32_t>(
env->GetIntField(settings, env->GetFieldID(clazz, "mSymbolRate", "I")));
@@ -2069,7 +2069,7 @@
env->GetIntField(settings, env->GetFieldID(clazz, "mOuterFec", "I")));
FrontendDvbcAnnex annex =
static_cast<FrontendDvbcAnnex>(
- env->GetByteField(settings, env->GetFieldID(clazz, "mAnnex", "B")));
+ env->GetIntField(settings, env->GetFieldID(clazz, "mAnnex", "I")));
FrontendDvbcSpectralInversion spectralInversion =
static_cast<FrontendDvbcSpectralInversion>(
env->GetIntField(
diff --git a/media/tests/MediaTranscodingTest/Android.bp b/media/tests/MediaTranscodingTest/Android.bp
index fcf8f11..907c3c8 100644
--- a/media/tests/MediaTranscodingTest/Android.bp
+++ b/media/tests/MediaTranscodingTest/Android.bp
@@ -8,6 +8,7 @@
static_libs: [
"androidx.test.ext.junit",
"androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
"android-support-test",
"testng"
],
diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java
index 8fe1088..009a41e 100644
--- a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java
+++ b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java
@@ -23,15 +23,23 @@
import android.media.MediaTranscodeManager.TranscodingJob;
import android.media.MediaTranscodeManager.TranscodingRequest;
import android.net.Uri;
+import android.os.Bundle;
import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.uiautomator.UiDevice;
+
import org.junit.Test;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
@@ -127,8 +135,9 @@
super.setUp();
mContext = getInstrumentation().getContext();
- mMediaTranscodeManager = MediaTranscodeManager.getInstance(mContext);
+ mMediaTranscodeManager = MediaTranscodeManager.getInstance(mContext, true /*retry*/);
assertNotNull(mMediaTranscodeManager);
+ androidx.test.InstrumentationRegistry.registerInstance(getInstrumentation(), new Bundle());
// Setup source HEVC file uri.
mSourceHEVCVideoUri = resourceToUri(mContext, R.raw.VideoOnlyHEVC, "VideoOnlyHEVC.mp4");
@@ -148,8 +157,6 @@
@Test
public void testTranscodingFromHevcToAvc() throws Exception {
- Log.d(TAG, "Starting: testMediaTranscodeManager");
-
Semaphore transcodeCompleteSemaphore = new Semaphore(0);
// Create a file Uri: file:///data/user/0/com.android.mediatranscodingtest/cache/temp.mp4
@@ -194,6 +201,7 @@
stats.mAveragePSNR >= PSNR_THRESHOLD);
}
+
@Test
public void testCancelTranscoding() throws Exception {
Log.d(TAG, "Starting: testMediaTranscodeManager");
@@ -300,5 +308,94 @@
assertTrue("Failed to receive at least 10 progress updates",
progressUpdateCount.get() > 10);
}
+
+ // [[ $(adb shell whoami) == "root" ]]
+ private boolean checkIfRoot() throws IOException {
+ try (ParcelFileDescriptor result = getInstrumentation().getUiAutomation()
+ .executeShellCommand("whoami");
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
+ new FileInputStream(result.getFileDescriptor())))) {
+ String line;
+ while ((line = bufferedReader.readLine()) != null) {
+ if (line.contains("root")) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private String executeShellCommand(String cmd) throws Exception {
+ return UiDevice.getInstance(
+ InstrumentationRegistry.getInstrumentation()).executeShellCommand(cmd);
+ }
+
+ @Test
+ public void testHandleTranscoderServiceDied() throws Exception {
+ try {
+ if (!checkIfRoot()) {
+ throw new AssertionError("must be root to run this test; try adb root?");
+ } else {
+ Log.i(TAG, "Device is root");
+ }
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
+
+ Semaphore transcodeCompleteSemaphore = new Semaphore(0);
+ Semaphore jobStartedSemaphore = new Semaphore(0);
+
+ // Transcode a 15 seconds video, so that the transcoding is not finished when we kill the
+ // service.
+ Uri srcUri = Uri.parse(ContentResolver.SCHEME_FILE + "://"
+ + mContext.getCacheDir().getAbsolutePath() + "/longtest_15s.mp4");
+ Uri destinationUri = Uri.parse(ContentResolver.SCHEME_FILE + "://"
+ + mContext.getCacheDir().getAbsolutePath() + "/HevcTranscode.mp4");
+
+ TranscodingRequest request =
+ new TranscodingRequest.Builder()
+ .setSourceUri(mSourceHEVCVideoUri)
+ .setDestinationUri(destinationUri)
+ .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+ .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+ .setVideoTrackFormat(createMediaFormat())
+ .build();
+ Executor listenerExecutor = Executors.newSingleThreadExecutor();
+
+ Log.i(TAG, "transcoding to " + createMediaFormat());
+
+ TranscodingJob job = mMediaTranscodeManager.enqueueRequest(request, listenerExecutor,
+ transcodingJob -> {
+ Log.d(TAG, "Transcoding completed with result: " + transcodingJob.getResult());
+ assertEquals(transcodingJob.getResult(), TranscodingJob.RESULT_ERROR);
+ transcodeCompleteSemaphore.release();
+ });
+ assertNotNull(job);
+
+ AtomicInteger progressUpdateCount = new AtomicInteger(0);
+
+ // Set progress update executor and use the same executor as result listener.
+ job.setOnProgressUpdateListener(listenerExecutor,
+ new TranscodingJob.OnProgressUpdateListener() {
+ @Override
+ public void onProgressUpdate(int newProgress) {
+ if (newProgress > 0) {
+ jobStartedSemaphore.release();
+ }
+ }
+ });
+
+ // Wait for progress update so the job is in running state.
+ jobStartedSemaphore.tryAcquire(TRANSCODE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ assertTrue("Job is not running", job.getStatus() == TranscodingJob.STATUS_RUNNING);
+
+ // Kills the service and expects receiving failure of the job.
+ executeShellCommand("pkill -f media.transcoding");
+
+ Log.d(TAG, "testMediaTranscodeManager - Waiting for transcode result.");
+ boolean finishedOnTime = transcodeCompleteSemaphore.tryAcquire(
+ TRANSCODE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ assertTrue("Invalid job status", job.getStatus() == TranscodingJob.STATUS_FINISHED);
+ }
}
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index e90fbd4..e0ebec6 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -11901,8 +11901,8 @@
field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionInfo> CREATOR;
field public static final int INVALID_ID = -1; // 0xffffffff
field public static final int STAGED_SESSION_ACTIVATION_FAILED = 2; // 0x2
+ field public static final int STAGED_SESSION_CONFLICT = 4; // 0x4
field public static final int STAGED_SESSION_NO_ERROR = 0; // 0x0
- field public static final int STAGED_SESSION_OTHER_ERROR = 4; // 0x4
field public static final int STAGED_SESSION_UNKNOWN = 3; // 0x3
field public static final int STAGED_SESSION_VERIFICATION_FAILED = 1; // 0x1
}
@@ -14250,6 +14250,10 @@
enum_constant public static final android.graphics.BlurMaskFilter.Blur SOLID;
}
+ public final class BlurShader extends android.graphics.Shader {
+ ctor public BlurShader(float, float, @Nullable android.graphics.Shader);
+ }
+
public class Camera {
ctor public Camera();
method public void applyToCanvas(android.graphics.Canvas);
@@ -35282,9 +35286,11 @@
public final class PowerManager {
method public void addThermalStatusListener(@NonNull android.os.PowerManager.OnThermalStatusChangedListener);
method public void addThermalStatusListener(@NonNull java.util.concurrent.Executor, @NonNull android.os.PowerManager.OnThermalStatusChangedListener);
+ method @Nullable public java.time.Duration getBatteryDischargePrediction();
method public int getCurrentThermalStatus();
method public int getLocationPowerSaveMode();
method public float getThermalHeadroom(@IntRange(from=0, to=60) int);
+ method public boolean isBatteryDischargePredictionPersonalized();
method public boolean isDeviceIdleMode();
method public boolean isIgnoringBatteryOptimizations(String);
method public boolean isInteractive();
@@ -45986,6 +45992,7 @@
method public void onDataConnectionStateChanged(int);
method public void onDataConnectionStateChanged(int, int);
method @RequiresPermission("android.permission.READ_PHONE_STATE") public void onDisplayInfoChanged(@NonNull android.telephony.TelephonyDisplayInfo);
+ method public void onEmergencyNumberListChanged(@NonNull java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>);
method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
method public void onMessageWaitingIndicatorChanged(boolean);
method @RequiresPermission("android.permission.MODIFY_PHONE_STATE") public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
@@ -46502,7 +46509,9 @@
method @Deprecated public String iccTransmitApduBasicChannel(int, int, int, int, int, String);
method @Deprecated public String iccTransmitApduLogicalChannel(int, int, int, int, int, int, String);
method public boolean isConcurrentVoiceAndDataSupported();
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public boolean isDataConnectionAllowed();
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean isDataEnabled();
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabledForReason(int);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataRoamingEnabled();
method public boolean isEmergencyNumber(@NonNull String);
method public boolean isHearingAidCompatibilitySupported();
@@ -46524,6 +46533,7 @@
method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
method public void sendVisualVoicemailSms(String, int, String, android.app.PendingIntent);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(boolean);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabledForReason(int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setForbiddenPlmns(@NonNull java.util.List<java.lang.String>);
method public boolean setLine1NumberForDisplay(String, String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setNetworkSelectionModeAutomatic();
@@ -46571,6 +46581,10 @@
field public static final int DATA_CONNECTING = 1; // 0x1
field public static final int DATA_DISCONNECTED = 0; // 0x0
field public static final int DATA_DISCONNECTING = 4; // 0x4
+ field public static final int DATA_ENABLED_REASON_CARRIER = 2; // 0x2
+ field public static final int DATA_ENABLED_REASON_POLICY = 1; // 0x1
+ field public static final int DATA_ENABLED_REASON_THERMAL = 3; // 0x3
+ field public static final int DATA_ENABLED_REASON_USER = 0; // 0x0
field public static final int DATA_SUSPENDED = 3; // 0x3
field public static final int DATA_UNKNOWN = -1; // 0xffffffff
field public static final String EXTRA_ACTIVE_SIM_SUPPORTED_COUNT = "android.telephony.extra.ACTIVE_SIM_SUPPORTED_COUNT";
@@ -53328,7 +53342,7 @@
}
public class ViewPropertyAnimator {
- method public android.view.ViewPropertyAnimator alpha(float);
+ method public android.view.ViewPropertyAnimator alpha(@FloatRange(from=0.0f, to=1.0f) float);
method public android.view.ViewPropertyAnimator alphaBy(float);
method public void cancel();
method public long getDuration();
diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt
index 617a83f0..8892a29 100644
--- a/non-updatable-api/module-lib-current.txt
+++ b/non-updatable-api/module-lib-current.txt
@@ -46,6 +46,13 @@
field public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 65536; // 0x10000
}
+ public final class MediaSessionManager {
+ method public void dispatchMediaKeyEventAsSystemService(@NonNull android.view.KeyEvent);
+ method public boolean dispatchMediaKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
+ method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.view.KeyEvent, int);
+ method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
+ }
+
}
package android.os {
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index 3fd0ee1..d1264df 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -7298,6 +7298,7 @@
method @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE) public boolean isAmbientDisplaySuppressedForToken(@NonNull String);
method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setAdaptivePowerSaveEnabled(boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setAdaptivePowerSavePolicy(@NonNull android.os.BatterySaverPolicyConfig);
+ method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void setBatteryDischargePrediction(@NonNull java.time.Duration, boolean);
method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public boolean setDynamicPowerSaveHint(boolean, int);
method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setPowerSaveModeEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void suppressAmbientDisplay(@NonNull String, boolean);
@@ -9682,7 +9683,8 @@
public class PhoneStateListener {
method public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
- method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber);
+ method @Deprecated public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber);
+ method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
method public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber);
method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
method public void onRadioPowerStateChanged(int);
@@ -10099,10 +10101,8 @@
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAnyRadioPoweredOn();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApnMetered(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataConnectionAllowed();
method public boolean isDataConnectivityPossible();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataEnabledForApn(int);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabledWithReason(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean isIccLockEnabled();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
@@ -10134,7 +10134,6 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabledWithReason(int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunisticNetworkState(boolean);
@@ -10172,10 +10171,6 @@
field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
- field public static final int DATA_ENABLED_REASON_CARRIER = 2; // 0x2
- field public static final int DATA_ENABLED_REASON_POLICY = 1; // 0x1
- field public static final int DATA_ENABLED_REASON_THERMAL = 3; // 0x3
- field public static final int DATA_ENABLED_REASON_USER = 0; // 0x0
field public static final String EXTRA_ANOMALY_DESCRIPTION = "android.telephony.extra.ANOMALY_DESCRIPTION";
field public static final String EXTRA_ANOMALY_ID = "android.telephony.extra.ANOMALY_ID";
field public static final String EXTRA_PHONE_IN_ECM_STATE = "android.telephony.extra.PHONE_IN_ECM_STATE";
@@ -11585,8 +11580,8 @@
public interface PacProcessor {
method @Nullable public String findProxyForUrl(@NonNull String);
method @NonNull public static android.webkit.PacProcessor getInstance();
- method @NonNull public static android.webkit.PacProcessor getInstanceForNetwork(long);
- method public default long getNetworkHandle();
+ method @NonNull public static android.webkit.PacProcessor getInstanceForNetwork(@Nullable android.net.Network);
+ method @Nullable public default android.net.Network getNetwork();
method public default void releasePacProcessor();
method public boolean setProxyScript(@NonNull String);
}
@@ -11727,7 +11722,7 @@
method public android.webkit.CookieManager getCookieManager();
method public android.webkit.GeolocationPermissions getGeolocationPermissions();
method @NonNull public default android.webkit.PacProcessor getPacProcessor();
- method @NonNull public default android.webkit.PacProcessor getPacProcessorForNetwork(long);
+ method @NonNull public default android.webkit.PacProcessor getPacProcessorForNetwork(@Nullable android.net.Network);
method public android.webkit.ServiceWorkerController getServiceWorkerController();
method public android.webkit.WebViewFactoryProvider.Statics getStatics();
method @Deprecated public android.webkit.TokenBindingService getTokenBindingService();
diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml
index 039f2c0..d3277de 100644
--- a/packages/CarSystemUI/res/values/config.xml
+++ b/packages/CarSystemUI/res/values/config.xml
@@ -121,7 +121,6 @@
<string-array name="config_systemUIServiceComponentsExclude" translatable="false">
<item>com.android.systemui.recents.Recents</item>
<item>com.android.systemui.volume.VolumeUI</item>
- <item>com.android.systemui.stackdivider.Divider</item>
<item>com.android.systemui.statusbar.phone.StatusBar</item>
<item>com.android.systemui.keyboard.KeyboardUI</item>
<item>com.android.systemui.pip.PipUI</item>
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml b/packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml
index b8e1edc..20aa5f7 100644
--- a/packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml
+++ b/packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml
@@ -22,7 +22,8 @@
<item target="attr/icon" value="@attr/icon"/>
<item target="attr/selectedIcon" value="@attr/selectedIcon"/>
- <item target="attr/intent" value="@attr/longIntent"/>
+ <item target="attr/intent" value="@attr/intent"/>
+ <item target="attr/longIntent" value="@attr/longIntent"/>
<item target="attr/componentNames" value="@attr/componentNames"/>
<item target="attr/highlightWhenSelected" value="@attr/highlightWhenSelected"/>
<item target="attr/categories" value="@attr/categories"/>
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
index b2f98ec..24d9d09 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
@@ -22,7 +22,6 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.SystemServicesModule;
import com.android.systemui.dagger.SystemUIModule;
-import com.android.systemui.onehanded.dagger.OneHandedModule;
import com.android.systemui.pip.phone.dagger.PipModule;
import dagger.Subcomponent;
@@ -36,7 +35,6 @@
DependencyProvider.class,
DependencyBinder.class,
PipModule.class,
- OneHandedModule.class,
SystemServicesModule.class,
SystemUIModule.class,
CarSystemUIModule.class,
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
index 797a178..3971e18 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
@@ -34,7 +34,6 @@
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsModule;
import com.android.systemui.shortcut.ShortcutKeyDispatcher;
-import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.dagger.StatusBarModule;
import com.android.systemui.statusbar.notification.InstantAppNotifier;
import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
@@ -42,6 +41,7 @@
import com.android.systemui.theme.ThemeOverlayController;
import com.android.systemui.toast.ToastUI;
import com.android.systemui.util.leak.GarbageMonitor;
+import com.android.systemui.wmshell.WMShell;
import dagger.Binds;
import dagger.Module;
@@ -59,12 +59,6 @@
@ClassKey(AuthController.class)
public abstract SystemUI bindAuthController(AuthController sysui);
- /** Inject into Divider. */
- @Binds
- @IntoMap
- @ClassKey(Divider.class)
- public abstract SystemUI bindDivider(Divider sysui);
-
/** Inject Car Navigation Bar. */
@Binds
@IntoMap
@@ -192,4 +186,10 @@
@IntoMap
@ClassKey(SideLoadedAppController.class)
public abstract SystemUI bindSideLoadedAppController(SideLoadedAppController sysui);
+
+ /** Inject into WMShell. */
+ @Binds
+ @IntoMap
+ @ClassKey(WMShell.class)
+ public abstract SystemUI bindWMShell(WMShell sysui);
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index 290700f..3eea513 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -47,7 +47,6 @@
import com.android.systemui.qs.tileimpl.QSFactoryImpl;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsImplementation;
-import com.android.systemui.stackdivider.DividerModule;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
@@ -75,7 +74,6 @@
@Module(
includes = {
- DividerModule.class,
QSModule.class,
CarWMShellModule.class
})
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
index 143c444f..b8bf825 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
@@ -29,6 +29,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
+import com.android.systemui.car.notification.BottomNotificationPanelViewMediator;
+import com.android.systemui.car.notification.TopNotificationPanelViewMediator;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
@@ -95,6 +97,7 @@
populateMaps();
readConfigs();
checkEnabledBarsHaveUniqueBarTypes();
+ checkSystemBarEnabledForNotificationPanel();
setInsetPaddingsForOverlappingCorners();
sortSystemBarSidesByZOrder();
}
@@ -221,6 +224,34 @@
}
}
+ private void checkSystemBarEnabledForNotificationPanel() throws RuntimeException {
+
+ String notificationPanelMediatorName =
+ mResources.getString(R.string.config_notificationPanelViewMediator);
+ if (notificationPanelMediatorName == null) {
+ return;
+ }
+
+ Class<?> notificationPanelMediatorUsed = null;
+ try {
+ notificationPanelMediatorUsed = Class.forName(notificationPanelMediatorName);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+
+ if (!mTopNavBarEnabled && notificationPanelMediatorUsed.isAssignableFrom(
+ TopNotificationPanelViewMediator.class)) {
+ throw new RuntimeException(
+ "Top System Bar must be enabled to use " + notificationPanelMediatorName);
+ }
+
+ if (!mBottomNavBarEnabled && notificationPanelMediatorUsed.isAssignableFrom(
+ BottomNotificationPanelViewMediator.class)) {
+ throw new RuntimeException("Bottom System Bar must be enabled to use "
+ + notificationPanelMediatorName);
+ }
+ }
+
private void setInsetPaddingsForOverlappingCorners() {
setInsetPaddingForOverlappingCorner(TOP, LEFT);
setInsetPaddingForOverlappingCorner(TOP, RIGHT);
@@ -277,7 +308,7 @@
}
private static boolean isHorizontalBar(@SystemBarSide int side) {
- return side == TOP || side == BOTTOM;
+ return side == TOP || side == BOTTOM;
}
private static boolean isVerticalBar(@SystemBarSide int side) {
diff --git a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
index e493c97..c7354ed 100644
--- a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
@@ -49,7 +49,7 @@
private final Context mContext;
private SparseArray<PerDisplay> mPerDisplaySparseArray;
- private DisplaySystemBarsController(
+ public DisplaySystemBarsController(
Context context,
IWindowManager wmService,
DisplayController displayController,
@@ -167,33 +167,4 @@
}
}
}
-
- /** Builds {@link DisplaySystemBarsController} instance. */
- public static class Builder {
- private Context mContext;
- private IWindowManager mWmService;
- private DisplayController mDisplayController;
- private Handler mHandler;
- private TransactionPool mTransactionPool;
-
- public Builder(Context context, IWindowManager wmService,
- DisplayController displayController, Handler handler,
- TransactionPool transactionPool) {
- mContext = context;
- mWmService = wmService;
- mDisplayController = displayController;
- mHandler = handler;
- mTransactionPool = transactionPool;
- }
-
- /** Builds and initializes {@link DisplaySystemBarsController} instance. */
- public DisplaySystemBarsController build() {
- DisplaySystemBarsController displaySystemBarsController =
- new DisplaySystemBarsController(
- mContext, mWmService, mDisplayController, mHandler, mTransactionPool);
- // Separates startMonitorDisplays from constructor to prevent circular init issue.
- displaySystemBarsController.startMonitorDisplays();
- return displaySystemBarsController;
- }
- }
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java b/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java
index 2324c3d..fd6685f 100644
--- a/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java
@@ -40,8 +40,8 @@
DisplayImeController provideDisplayImeController(Context context,
IWindowManager wmService, DisplayController displayController,
@Main Handler mainHandler, TransactionPool transactionPool) {
- return new DisplaySystemBarsController.Builder(context, wmService, displayController,
- mainHandler, transactionPool).build();
+ return new DisplaySystemBarsController(context, wmService, displayController,
+ mainHandler, transactionPool);
}
/** TODO(b/150319024): PipMenuActivity will move to a Window */
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java
index b65578d..391f75e 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java
@@ -64,13 +64,13 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
- mController = new DisplaySystemBarsController.Builder(
+ mController = new DisplaySystemBarsController(
mContext,
mIWindowManager,
mDisplayController,
mHandler,
mTransactionPool
- ).build();
+ );
}
@Test
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index f80e934..9ff8684 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -352,16 +352,18 @@
if (powerManager != null) {
powerManager.reboot("dynsystem");
}
- } else {
- Log.e(TAG, "Failed to enable DynamicSystem because of native runtime error.");
- mNM.cancel(NOTIFICATION_ID);
-
- Toast.makeText(this,
- getString(R.string.toast_failed_to_reboot_to_dynsystem),
- Toast.LENGTH_LONG).show();
-
- mDynSystem.remove();
+ return;
}
+
+ Log.e(TAG, "Failed to enable DynamicSystem because of native runtime error.");
+
+ Toast.makeText(this,
+ getString(R.string.toast_failed_to_reboot_to_dynsystem),
+ Toast.LENGTH_LONG).show();
+
+ postStatus(STATUS_NOT_STARTED, CAUSE_ERROR_EXCEPTION, null);
+ resetTaskAndStop();
+ mDynSystem.remove();
}
private void executeRebootToNormalCommand() {
diff --git a/packages/PrintSpooler/res/values-fa/strings.xml b/packages/PrintSpooler/res/values-fa/strings.xml
index 596947d..719fc92 100644
--- a/packages/PrintSpooler/res/values-fa/strings.xml
+++ b/packages/PrintSpooler/res/values-fa/strings.xml
@@ -31,7 +31,7 @@
<string name="template_all_pages" msgid="3322235982020148762">"همه <xliff:g id="PAGE_COUNT">%1$s</xliff:g> صفحه"</string>
<string name="template_page_range" msgid="428638530038286328">"محدوده <xliff:g id="PAGE_COUNT">%1$s</xliff:g> صفحه"</string>
<string name="pages_range_example" msgid="8558694453556945172">"مثلاً ۱—۵،۹،۷—۱۰"</string>
- <string name="print_preview" msgid="8010217796057763343">"پیشنمایش چاپ"</string>
+ <string name="print_preview" msgid="8010217796057763343">"پیشنمای چاپ"</string>
<string name="install_for_print_preview" msgid="6366303997385509332">"نصب نمایشگر PDF برای پیشنمایش"</string>
<string name="printing_app_crashed" msgid="854477616686566398">"برنامه چاپ خراب شد"</string>
<string name="generating_print_job" msgid="3119608742651698916">"در حال ایجاد کار چاپ"</string>
diff --git a/packages/PrintSpooler/res/values-uz/strings.xml b/packages/PrintSpooler/res/values-uz/strings.xml
index d17bce7..ea0a6ea 100644
--- a/packages/PrintSpooler/res/values-uz/strings.xml
+++ b/packages/PrintSpooler/res/values-uz/strings.xml
@@ -100,7 +100,7 @@
</string-array>
<string-array name="orientation_labels">
<item msgid="4061931020926489228">"Tik holat"</item>
- <item msgid="3199660090246166812">"Eniga"</item>
+ <item msgid="3199660090246166812">"Yotiq"</item>
</string-array>
<string name="print_write_error_message" msgid="5787642615179572543">"Faylga yozib bo‘lmadi"</string>
<string name="print_error_default_message" msgid="8602678405502922346">"Xatolik yuz berdi. Qaytadan urining."</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index f3b22d3..5fc311a 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -139,7 +139,7 @@
<string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"قدرت سیگنال Wi‑Fi کامل است."</string>
<string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"شبکه باز"</string>
<string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"شبکه ایمن"</string>
- <string name="process_kernel_label" msgid="950292573930336765">"سیستم عامل Android"</string>
+ <string name="process_kernel_label" msgid="950292573930336765">"سیستمعامل Android"</string>
<string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"برنامههای حذف شده"</string>
<string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"برنامهها و کاربران حذف شده"</string>
<string name="data_usage_ota" msgid="7984667793701597001">"بهروزرسانیهای سیستم"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index f219d24..8b92640 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -37,7 +37,7 @@
<string name="wifi_no_internet" msgid="1774198889176926299">"Ինտերնետ կապ չկա"</string>
<string name="saved_network" msgid="7143698034077223645">"Ով է պահել՝ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Ավտոմատ կերպով կապակցվել է %1$s-ի միջոցով"</string>
- <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Ավտոմատ կերպով միացել է ցանցի վարկանիշի ծառայության մատակարարի միջոցով"</string>
+ <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Ավտոմատ միացել է ցանցերի վարկանիշի մատակարարի միջոցով"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Միացված է %1$s-ի միջոցով"</string>
<string name="connected_via_app" msgid="3532267661404276584">"Միացված է <xliff:g id="NAME">%1$s</xliff:g>-ի միջոցով"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Հասանելի է %1$s-ի միջոցով"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 83b72e9..27f5dc9 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -93,8 +93,8 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Sim-toegang"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-audio"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Gehoorapparaten"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Verbonden met gehoorapparaten"</string>
+ <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Hoortoestellen"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Verbonden met hoortoestellen"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Verbonden met audio van medium"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Verbonden met audio van telefoon"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Verbonden met server voor bestandsoverdracht"</string>
@@ -111,7 +111,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Gebruiken voor audio van telefoon"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Gebruiken voor bestandsoverdracht"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Gebruiken voor invoer"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Gebruiken voor gehoorapparaten"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Gebruiken voor hoortoestellen"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Koppelen"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"KOPPELEN"</string>
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Annuleren"</string>
@@ -127,8 +127,8 @@
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Hoofdtelefoon"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Randapparaat voor invoer"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
- <string name="bluetooth_hearingaid_left_pairing_message" msgid="8561855779703533591">"Linker gehoorapparaat koppelen…"</string>
- <string name="bluetooth_hearingaid_right_pairing_message" msgid="2655347721696331048">"Rechter gehoorapparaat koppelen…"</string>
+ <string name="bluetooth_hearingaid_left_pairing_message" msgid="8561855779703533591">"Linker hoortoestel koppelen…"</string>
+ <string name="bluetooth_hearingaid_right_pairing_message" msgid="2655347721696331048">"Rechter hoortoestel koppelen…"</string>
<string name="bluetooth_hearingaid_left_battery_level" msgid="7375621694748104876">"Links: batterijniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_hearingaid_right_battery_level" msgid="1850094448499089312">"Rechts: batterijniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wifi: uitgeschakeld."</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 9d06c84..72a6074 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -465,7 +465,16 @@
synchronized (mMediaDevicesLock) {
mMediaDevices.clear();
mMediaDevices.addAll(devices);
- mMediaDevices.addAll(buildDisconnectedBluetoothDevice());
+ // Add disconnected bluetooth devices only when phone output device is available.
+ for (MediaDevice device : devices) {
+ final int type = device.getDeviceType();
+ if (type == MediaDevice.MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE
+ || type == MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE
+ || type == MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE) {
+ mMediaDevices.addAll(buildDisconnectedBluetoothDevice());
+ break;
+ }
+ }
}
final MediaDevice infoMediaDevice = mInfoMediaManager.getCurrentConnectedDevice();
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
index a654fd4..8e850b2 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
@@ -585,6 +585,7 @@
when(device1.getId()).thenReturn(TEST_DEVICE_ID_1);
when(device2.getId()).thenReturn(TEST_DEVICE_ID_2);
when(device3.getId()).thenReturn(TEST_DEVICE_ID_3);
+ when(device1.getDeviceType()).thenReturn(MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE);
when(mLocalMediaManager.mPhoneDevice.getId()).thenReturn("test_phone_id");
assertThat(mLocalMediaManager.mMediaDevices).hasSize(2);
@@ -683,6 +684,7 @@
when(device1.getId()).thenReturn(TEST_DEVICE_ID_1);
when(device2.getId()).thenReturn(TEST_DEVICE_ID_2);
when(device3.getId()).thenReturn(TEST_DEVICE_ID_3);
+ when(device1.getDeviceType()).thenReturn(MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE);
when(mLocalMediaManager.mPhoneDevice.getId()).thenReturn("test_phone_id");
assertThat(mLocalMediaManager.mMediaDevices).hasSize(2);
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index bdf00e3..bcd2ff7 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -175,5 +175,6 @@
Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED,
Settings.Secure.PANIC_GESTURE_ENABLED,
Settings.Secure.PANIC_SOUND_ENABLED,
+ Settings.Secure.ADAPTIVE_CONNECTIVITY_ENABLED
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 4ea7f3a..3630f25 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -263,5 +263,6 @@
VALIDATORS.put(Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.PANIC_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.PANIC_SOUND_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.ADAPTIVE_CONNECTIVITY_ENABLED, BOOLEAN_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 47cc6d0..a293148 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -860,9 +860,6 @@
p.end(intentFirewallToken);
dumpSetting(s, p,
- Settings.Global.JOB_SCHEDULER_CONSTANTS,
- GlobalSettingsProto.JOB_SCHEDULER_CONSTANTS);
- dumpSetting(s, p,
Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS,
GlobalSettingsProto.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS);
dumpSetting(s, p,
@@ -1976,6 +1973,9 @@
dumpSetting(s, p,
Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS,
SecureSettingsProto.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS);
+ dumpSetting(s, p,
+ Settings.Secure.ADAPTIVE_CONNECTIVITY_ENABLED,
+ SecureSettingsProto.ADAPTIVE_CONNECTIVITY_ENABLED);
final long controlsToken = p.start(SecureSettingsProto.CONTROLS);
dumpSetting(s, p,
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 0ac3355..f219aec 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -309,7 +309,6 @@
Settings.Global.INSTANT_APP_DEXOPT_ENABLED,
Settings.Global.INTENT_FIREWALL_UPDATE_CONTENT_URL,
Settings.Global.INTENT_FIREWALL_UPDATE_METADATA_URL,
- Settings.Global.JOB_SCHEDULER_CONSTANTS,
Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS,
Settings.Global.KEEP_PROFILE_IN_BACKGROUND,
Settings.Global.KERNEL_CPU_THREAD_READER,
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 4ce9f5a..af008b9 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -113,6 +113,7 @@
<uses-permission android:name="android.permission.SET_ORIENTATION" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.MONITOR_INPUT" />
+ <uses-permission android:name="android.permission.INPUT_CONSUMER" />
<!-- DreamManager -->
<uses-permission android:name="android.permission.READ_DREAM_STATE" />
diff --git a/packages/SystemUI/README.md b/packages/SystemUI/README.md
index 68b9553..148fabb 100644
--- a/packages/SystemUI/README.md
+++ b/packages/SystemUI/README.md
@@ -88,11 +88,6 @@
Registers all the callbacks/listeners required to show the Volume dialog when
it should be shown.
-### [com.android.systemui.stackdivider.Divider](/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java)
-
-Shows the drag handle for the divider between two apps when in split screen
-mode.
-
### [com.android.systemui.status.phone.StatusBar](/packages/SystemUI/src/com/android/systemui/status/phone/StatusBar.java)
This shows the UI for the status bar and the notification shade it contains.
@@ -153,6 +148,10 @@
Biometric UI.
+### [com.android.systemui.wmshell.WMShell](/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java)
+
+Delegates SysUI events to WM Shell controllers.
+
---
* [Plugins](/packages/SystemUI/docs/plugins.md)
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index b42d71a..df66bf5 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -45,4 +45,5 @@
-keep class com.android.systemui.dagger.GlobalRootComponent { *; }
-keep class com.android.systemui.dagger.GlobalRootComponent$SysUIComponentImpl { *; }
--keep class com.android.systemui.dagger.Dagger** { *; }
\ No newline at end of file
+-keep class com.android.systemui.dagger.Dagger** { *; }
+-keep class com.android.systemui.tv.Dagger** { *; }
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/drawable/face_auth_wallpaper.png b/packages/SystemUI/res-keyguard/drawable/face_auth_wallpaper.png
new file mode 100644
index 0000000..b907f4e
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/face_auth_wallpaper.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/bubble_stack_user_education.xml b/packages/SystemUI/res/layout/bubble_stack_user_education.xml
index 6164032..fe1ed4b 100644
--- a/packages/SystemUI/res/layout/bubble_stack_user_education.xml
+++ b/packages/SystemUI/res/layout/bubble_stack_user_education.xml
@@ -15,8 +15,8 @@
~ limitations under the License.
-->
<LinearLayout
+ android:id="@+id/stack_education_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/user_education_view"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingTop="48dp"
@@ -25,26 +25,29 @@
android:paddingEnd="16dp"
android:layout_marginEnd="24dp"
android:orientation="vertical"
- android:background="@drawable/bubble_stack_user_education_bg">
-
+ android:background="@drawable/bubble_stack_user_education_bg"
+ >
<TextView
- android:id="@+id/user_education_title"
+ android:id="@+id/stack_education_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="16dp"
android:fontFamily="@*android:string/config_bodyFontFamilyMedium"
android:maxLines="2"
android:ellipsize="end"
+ android:gravity="start"
+ android:textAlignment="viewStart"
android:text="@string/bubbles_user_education_title"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Headline"/>
<TextView
- android:id="@+id/user_education_description"
+ android:id="@+id/stack_education_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
+ android:gravity="start"
+ android:textAlignment="viewStart"
android:text="@string/bubbles_user_education_description"
android:fontFamily="@*android:string/config_bodyFontFamily"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/>
-
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/bubbles_manage_button_education.xml b/packages/SystemUI/res/layout/bubbles_manage_button_education.xml
index 213bb92..b51dc93 100644
--- a/packages/SystemUI/res/layout/bubbles_manage_button_education.xml
+++ b/packages/SystemUI/res/layout/bubbles_manage_button_education.xml
@@ -14,77 +14,77 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.systemui.bubbles.ManageEducationView
+
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:id="@+id/manage_education_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clickable="true"
+ android:paddingTop="28dp"
+ android:paddingBottom="16dp"
+ android:paddingStart="@dimen/bubble_expanded_view_padding"
+ android:paddingEnd="48dp"
+ android:layout_marginEnd="24dp"
+ android:orientation="vertical"
+ android:background="@drawable/bubble_stack_user_education_bg"
>
- <LinearLayout
+
+ <TextView
+ android:id="@+id/user_education_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:id="@+id/manage_education_view"
- android:clickable="true"
- android:paddingTop="28dp"
+ android:paddingStart="16dp"
android:paddingBottom="16dp"
- android:paddingStart="@dimen/bubble_expanded_view_padding"
- android:paddingEnd="48dp"
- android:layout_marginEnd="24dp"
- android:orientation="vertical"
- android:background="@drawable/bubble_stack_user_education_bg"
- >
+ android:fontFamily="@*android:string/config_bodyFontFamilyMedium"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:gravity="start"
+ android:textAlignment="viewStart"
+ android:text="@string/bubbles_user_education_manage_title"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Headline"/>
- <TextView
- android:id="@+id/user_education_title"
+ <TextView
+ android:id="@+id/user_education_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingStart="16dp"
+ android:paddingBottom="24dp"
+ android:text="@string/bubbles_user_education_manage"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:gravity="start"
+ android:textAlignment="viewStart"
+ android:fontFamily="@*android:string/config_bodyFontFamily"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/>
+
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:id="@+id/button_layout"
+ android:orientation="horizontal" >
+
+ <com.android.systemui.statusbar.AlphaOptimizedButton
+ style="@android:style/Widget.Material.Button.Borderless"
+ android:id="@+id/manage"
+ android:layout_gravity="start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingStart="16dp"
- android:paddingBottom="16dp"
- android:fontFamily="@*android:string/config_bodyFontFamilyMedium"
- android:maxLines="2"
- android:ellipsize="end"
- android:text="@string/bubbles_user_education_manage_title"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Headline"/>
+ android:focusable="true"
+ android:clickable="false"
+ android:text="@string/manage_bubbles_text"
+ android:textColor="?attr/wallpaperTextColor"
+ />
- <TextView
- android:id="@+id/user_education_description"
+ <com.android.systemui.statusbar.AlphaOptimizedButton
+ style="@android:style/Widget.Material.Button.Borderless"
+ android:id="@+id/got_it"
+ android:layout_gravity="start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingStart="16dp"
- android:paddingBottom="24dp"
- android:text="@string/bubbles_user_education_manage"
- android:maxLines="2"
- android:ellipsize="end"
- android:fontFamily="@*android:string/config_bodyFontFamily"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/>
-
- <LinearLayout
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:id="@+id/button_layout"
- android:orientation="horizontal" >
-
- <com.android.systemui.statusbar.AlphaOptimizedButton
- style="@android:style/Widget.Material.Button.Borderless"
- android:id="@+id/manage"
- android:layout_gravity="start"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="true"
- android:clickable="false"
- android:text="@string/manage_bubbles_text"
- android:textColor="?attr/wallpaperTextColor"
- />
-
- <com.android.systemui.statusbar.AlphaOptimizedButton
- style="@android:style/Widget.Material.Button.Borderless"
- android:id="@+id/got_it"
- android:layout_gravity="start"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="true"
- android:text="@string/bubbles_user_education_got_it"
- android:textColor="?attr/wallpaperTextColor"
- />
- </LinearLayout>
+ android:focusable="true"
+ android:text="@string/bubbles_user_education_got_it"
+ android:textColor="?attr/wallpaperTextColor"
+ />
</LinearLayout>
-</com.android.systemui.bubbles.ManageEducationView>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml
index 2c4b937..fd89c0b 100644
--- a/packages/SystemUI/res/layout/notification_conversation_info.xml
+++ b/packages/SystemUI/res/layout/notification_conversation_info.xml
@@ -210,7 +210,7 @@
android:clickable="false"
android:focusable="false"
android:ellipsize="end"
- android:maxLines="3"
+ android:maxLines="4"
android:textAppearance="@style/TextAppearance.NotificationImportanceDetail"/>
</com.android.systemui.statusbar.notification.row.ButtonLinearLayout>
diff --git a/packages/SystemUI/res/layout/partial_conversation_info.xml b/packages/SystemUI/res/layout/partial_conversation_info.xml
index 0795170..c353d08 100644
--- a/packages/SystemUI/res/layout/partial_conversation_info.xml
+++ b/packages/SystemUI/res/layout/partial_conversation_info.xml
@@ -128,6 +128,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
+ android:textDirection="locale"
style="@style/TextAppearance.NotificationImportanceChannelGroup" />
</LinearLayout>
</com.android.systemui.statusbar.notification.row.ButtonLinearLayout>
diff --git a/packages/SystemUI/res/layout/udfps_view.xml b/packages/SystemUI/res/layout/udfps_view.xml
index 732758a..31a33fb 100644
--- a/packages/SystemUI/res/layout/udfps_view.xml
+++ b/packages/SystemUI/res/layout/udfps_view.xml
@@ -5,6 +5,6 @@
android:id="@+id/udfps_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- systemui:sensorRadius="140px"
- systemui:sensorMarginBottom="630px"
+ systemui:sensorRadius="130px"
+ systemui:sensorCenterY="1636px"
systemui:sensorTouchAreaCoefficient="0.5"/>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index bac915d..316fa8a 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Hervat"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Kanselleer"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Deel"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Vee uit"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Skermopname is gekanselleer"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Skermopname is gestoor, tik om te sien"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Skermopname is uitgevee"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Kon nie skermopname uitvee nie"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Kon nie toestemmings kry nie"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Kon nie skermopname begin nie"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 43ab1d2..e2a4dc6 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ከቆመበት ቀጥል"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ይቅር"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"አጋራ"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ሰርዝ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"የማያ ገጽ ቀረጻ ተሰርዟል"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"የማያ ገጽ ቀረጻ ተቀምጧል፣ ለመመልከት መታ ያድርጉ"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"የማያ ገጽ ቀረጻ ተሰርዟል"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"የማያ ገጽ ቀረጻን መሰረዝ ላይ ስህተት"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ፈቃዶችን ማግኘት አልተቻለም"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"የማያ ገጽ ቀረጻን መጀመር ላይ ስህተት"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index c68d088..b33c6c5 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"استئناف"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"إلغاء"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"مشاركة"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"حذف"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"تمّ إلغاء تسجيل الشاشة."</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"تمّ حفظ تسجيل الشاشة، انقر لعرضه."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"تمّ حذف تسجيل الشاشة."</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"حدث خطأ أثناء حذف تسجيل الشاشة."</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"تعذّر الحصول على أذونات."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"حدث خطأ في بدء تسجيل الشاشة"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index d604fd4..5a3c659 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ৰখোৱাৰ পৰা পুনৰ আৰম্ভ কৰক"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"বাতিল কৰক"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"শ্বেয়াৰ কৰক"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"মচক"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"স্ক্রীণ ৰেকৰ্ড কৰাটো বাতিল কৰা হ’ল"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"স্ক্রীণ ৰেকৰ্ডিং ছেভ কৰা হ’ল, চাবলৈ টিপক"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"স্ক্রীণ ৰেকৰ্ডিং মচা হ’ল"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"স্ক্রীণ ৰেকৰ্ডিং মচি থাকোঁতে কিবা আসোঁৱাহ হ’ল"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"অনুমতি পাব পৰা নগ\'ল"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"স্ক্রীন ৰেকৰ্ড কৰা আৰম্ভ কৰোঁতে আসোঁৱাহ হৈছে"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index b1df252..4aa4bda 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Davam edin"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Ləğv edin"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Paylaşın"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Silin"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekranın video çəkimi ləğv edildi"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Ekranın video çəkimi yadda saxlanıldı. Baxmaq üçün klikləyin"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ekranın video çəkimi silindi"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Ekranın video çəkiminin silinməsi zamanı xəta baş verdi"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"İcazələr əldə edilmədi"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Ekranın yazılması ilə bağlı xəta"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index f3c4c6b..a9725f3 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Nastavi"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Otkaži"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Deli"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Izbriši"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Snimanje ekrana je otkazano"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Snimak ekrana je sačuvan, dodirnite da biste pregledali"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Snimak ekrana je izbrisan"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Došlo je do problema pri brisanju snimka ekrana"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Preuzimanje dozvola nije uspelo"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Greška pri pokretanju snimanja ekrana"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 9c0eeb2..b4c5eba 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Узнавіць"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Скасаваць"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Абагуліць"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Выдаліць"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Запіс экрана скасаваны"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Запіс экрана захаваны. Націсніце, каб прагледзець"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Запіс экрана выдалены"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Памылка выдалення запісу экрана"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Не ўдалося атрымаць дазволы"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Памылка пачатку запісу экрана"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 3bf12ad..52e8286 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Възобновяване"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Отказ"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Споделяне"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Изтриване"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Записването на екрана е анулирано"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Записът на екрана е запазен. Докоснете, за да го видите"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Записът на екрана е изтрит"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"При изтриването на записа на екрана възникна грешка"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Извличането на разрешенията не бе успешно."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"При стартирането на записа на екрана възникна грешка"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 5b7c953..d0de9cf 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"আবার চালু করুন"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"বাতিল করুন"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"শেয়ার করুন"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"মুছুন"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"স্ক্রিন রেকর্ডিং বাতিল করা হয়েছে"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"স্ক্রিন রেকর্ডিং সেভ করা হয়েছে, দেখতে ট্যাপ করুন"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"স্ক্রিন রেকর্ডিং মুছে ফেলা হয়েছে"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"স্ক্রিন রেকডিং মুছে ফেলার সময় সমস্যা হয়েছে"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"অনুমতি পাওয়া যায়নি"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"স্ক্রিন রেকর্ডিং শুরু করার সময় সমস্যা হয়েছে"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 31f88c8f..57b7945 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Nastavi"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Otkaži"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Dijeli"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Izbriši"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Snimanje ekrana je otkazano"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Snimak ekrana je sačuvan. Dodirnite za prikaz."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Snimak ekrana je izbrisan"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Greška prilikom brisanja snimka ekrana"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Dobijanje odobrenja nije uspjelo"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Greška pri pokretanju snimanja ekrana"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 753e25f..0489d18 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Reprèn"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel·la"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Comparteix"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Suprimeix"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"S\'ha cancel·lat la gravació de la pantalla"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"S\'ha desat la gravació de la pantalla; toca per mostrar"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"S\'ha suprimit la gravació de la pantalla"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"S\'ha produït un error en suprimir la gravació de la pantalla"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"No s\'han pogut obtenir els permisos"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"S\'ha produït un error en iniciar la gravació de pantalla"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 039500d..121a81d 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Obnovit"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Zrušit"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Sdílet"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Smazat"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Nahrávání obrazovky bylo zrušeno"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Záznam obrazovky byl uložen, zobrazíte jej klepnutím"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Záznam obrazovky byl smazán"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Při mazání záznamu obrazovky došlo k chybě"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nepodařilo se načíst oprávnění"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Při spouštění nahrávání obrazovky došlo k chybě"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 0c8a5b7..8863695 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Genoptag"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annuller"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Del"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Slet"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Skærmoptagelsen er annulleret"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Skærmoptagelsen er gemt. Tryk for at se den."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Skærmoptagelsen er slettet"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Der opstod en fejl ved sletning af skærmoptagelsen"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Det lykkedes ikke et hente tilladelserne"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Skærmoptagelsen kunne ikke startes"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 1c4c7ab..8d990c6 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Fortsetzen"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Abbrechen"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Teilen"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Löschen"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Bildschirmaufzeichnung abgebrochen"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Bildschirmaufzeichnung gespeichert, zum Ansehen tippen"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Bildschirmaufzeichnung gelöscht"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Fehler beim Löschen der Bildschirmaufzeichnung"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Berechtigungen nicht erhalten"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Fehler beim Start der Bildschirmaufzeichnung"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 07ff807..4384749 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Συνέχιση"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Ακύρωση"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Κοινοποίηση"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Διαγραφή"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Η εγγραφή οθόνης ακυρώθηκε"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Η εγγραφή οθόνης αποθηκεύτηκε. Πατήστε για προβολή."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Η εγγραφή οθόνης διαγράφηκε"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Παρουσιάστηκε σφάλμα κατά τη διαγραφή της εγγραφής οθόνης"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Η λήψη αδειών απέτυχε"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Σφάλμα κατά την έναρξη της εγγραφής οθόνης"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 0e22b58..8a7963a 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Resume"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Delete"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording cancelled"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Screen recording deleted"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index acf087d..7b2b25a 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Resume"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Delete"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording cancelled"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Screen recording deleted"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 0e22b58..8a7963a 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Resume"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Delete"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording cancelled"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Screen recording deleted"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 0e22b58..8a7963a 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Resume"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Delete"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording cancelled"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Screen recording deleted"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 4f4238a..15738f2 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Resume"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Delete"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording canceled"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Screen recording deleted"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 38fa528..aa81ab8 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Reanudar"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Compartir"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Borrar"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Se canceló la grabación de pantalla"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Se guardó la grabación de pantalla; presiona para verla"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Se borró la grabación de pantalla"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error al borrar la grabación de pantalla"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Error al obtener permisos"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error al iniciar la grabación de pantalla"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 10aa6ca..8638570 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Seguir"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Compartir"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Eliminar"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Se ha cancelado la grabación de la pantalla"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Se ha guardado la grabación de la pantalla; toca para verla"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Se ha eliminado la grabación de la pantalla"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"No se ha podido eliminar la grabación de la pantalla"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"No se han podido obtener los permisos"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"No se ha podido empezar a grabar la pantalla"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 9122ce5..f5ffad2 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Jätka"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Tühista"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Jaga"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Kustuta"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekraanikuva salvestamine on tühistatud"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Ekraanikuva salvestis on salvestatud, puudutage vaatamiseks"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ekraanikuva salvestis on kustutatud"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Viga ekraanikuva salvestise kustutamisel"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Lubade hankimine ebaõnnestus"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Viga ekraanikuva salvestamise alustamisel"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 38b2103d..1d5ac1a 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Berrekin"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Utzi"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Partekatu"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Ezabatu"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Utzi zaio pantaila grabatzeari"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Gorde da pantailaren grabaketa; sakatu ikusteko"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ezabatu da pantailaren grabaketa"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Errore bat gertatu da pantailaren grabaketa ezabatzean"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Ezin izan dira lortu baimenak"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Errore bat gertatu da pantaila grabatzen hastean"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index d39d0c3..55d8ab2 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ازسرگیری"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"لغو"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"همرسانی"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"حذف"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ضبط صفحهنمایش لغو شد"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"ضبط صفحهنمایش ذخیره شد، برای مشاهده ضربه بزنید"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"فایل ضبط صفحهنمایش حذف شد"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"خطا در حذف فایل ضبط صفحهنمایش"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"مجوزها دریافت نشدند"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"خطا هنگام شروع ضبط صفحهنمایش"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 52e5e8c..f30c44b 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Jatka"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Peruuta"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Jaa"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Poista"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Näytön tallennus peruutettu"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Näyttötallenne tallennettu, katso napauttamalla"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Näyttötallenne poistettu"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Virhe poistettaessa näyttötallennetta"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Käyttöoikeuksien hakeminen epäonnistui."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Virhe näytön tallennuksen aloituksessa"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 4797f32..f6196dd63 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Reprendre"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annuler"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Partager"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Supprimer"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"L\'enregistrement d\'écran a été annulé"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"L\'enregistrement d\'écran est terminé. Touchez ici pour l\'afficher."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"L\'enregistrement d\'écran a été supprimé"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Une erreur s\'est produite lors de la suppression de l\'enregistrement d\'écran"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Impossible d\'obtenir les autorisations"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Une erreur s\'est produite lors du démarrage de l\'enregistrement d\'écran"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index e5df728..0146ce4 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Reprendre"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annuler"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Partager"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Supprimer"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Enregistrement de l\'écran annulé"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Enregistrement de l\'écran enregistré. Appuyez pour afficher"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Enregistrement de l\'écran supprimé"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Erreur lors de la suppression de l\'enregistrement de l\'écran"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Échec d\'obtention des autorisations"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Erreur lors du démarrage de l\'enregistrement de l\'écran"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 246fefd..fd4d3c6 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Retomar"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Compartir"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Eliminar"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Cancelouse a gravación de pantalla"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Gardouse a gravación de pantalla; toca esta notificación para visualizala"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Eliminouse a gravación de pantalla"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Produciuse un erro ao eliminar a gravación de pantalla"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Produciuse un erro ao obter os permisos"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Produciuse un erro ao iniciar a gravación da pantalla"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index beaacaa..46f7a2b 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ફરી શરૂ કરો"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"રદ કરો"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"શેર કરો"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ડિલીટ કરો"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"સ્ક્રીન રેકોર્ડિંગ રદ કર્યું"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"સ્ક્રીન રેકોર્ડિંગ સાચવ્યું, જોવા માટે ટૅપ કરો"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"સ્ક્રીન રેકોર્ડિંગ ડિલીટ કર્યું"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"સ્ક્રીન રેકોર્ડિંગ ડિલીટ કરવામાં ભૂલ આવી"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"પરવાનગીઓ મેળવવામાં નિષ્ફળ રહ્યાં"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"સ્ક્રીનને રેકૉર્ડ કરવાનું શરૂ કરવામાં ભૂલ"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index de4fc48..e4a6ed7 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"फिर से शुरू करें"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"रद्द करें"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"शेयर करें"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"मिटाएं"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"स्क्रीन रिकॉर्डिंग रद्द कर दी गई"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"स्क्रीन रिकॉर्डिंग सेव की गई, देखने के लिए टैप करें"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"स्क्रीन रिकॉर्डिंग मिटा दी गई"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"स्क्रीन रिकॉर्डिंग मिटाने में गड़बड़ी हुई"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"मंज़ूरी नहीं मिल सकी"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"स्क्रीन को रिकॉर्ड करने में गड़बड़ी आ रही है"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 7bf0b93..a27b066 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Nastavi"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Odustani"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Dijeli"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Izbriši"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Snimanje zaslona otkazano"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Snimanje zaslona spremljeno je, dodirnite da biste ga pregledali"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Snimanje zaslona izbrisano"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Pogreška prilikom brisanja snimanja zaslona"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Dohvaćanje dopuštenja nije uspjelo"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Pogreška prilikom pokretanja snimanja zaslona"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 875a05f..0d1f50a 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Folytatás"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Mégse"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Megosztás"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Törlés"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"A képernyő rögzítése megszakítva"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Képernyőfelvétel mentve, koppintson a megtekintéshez"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"A képernyőről készült felvétel törölve"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Hiba történt a képernyőről készült felvétel törlésekor"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nincs engedély"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Hiba a képernyőrögzítés indításakor"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 4cc406b..f9a10fa 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Վերսկսել"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Չեղարկել"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Կիսվել"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Ջնջել"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Էկրանի տեսագրումը չեղարկվեց"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Էկրանի տեսագրությունը պահվեց։ Հպեք՝ դիտելու համար:"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Էկրանի տեսագրությունը ջնջվեց"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Չհաջողվեց ջնջել տեսագրությունը"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Չհաջողվեց ստանալ անհրաժեշտ թույլտվությունները"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Չհաջողվեց սկսել տեսագրումը"</string>
@@ -337,7 +335,7 @@
<string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"Էկրանը կողպված է ուղղաձիգ դիրքավորմամբ:"</string>
<string name="accessibility_rotation_lock_off_changed" msgid="5772498370935088261">"Էկրանն այժմ ավտոմատ կպտտվի:"</string>
<string name="accessibility_rotation_lock_on_landscape_changed" msgid="5785739044300729592">"Էկրանն այժմ կողպված է հորիզոնական դիրքում:"</string>
- <string name="accessibility_rotation_lock_on_portrait_changed" msgid="5580170829728987989">"Էկրանն այժմ կողպված է ուղղահայաց դիրքում:"</string>
+ <string name="accessibility_rotation_lock_on_portrait_changed" msgid="5580170829728987989">"Էկրանն այժմ կողպված է ուղղաձիգ դիրքում:"</string>
<string name="dessert_case" msgid="9104973640704357717">"Dessert Case"</string>
<string name="start_dreams" msgid="9131802557946276718">"Էկրանապահ"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 5f7dce4..f65be90 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Lanjutkan"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Batal"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Bagikan"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Hapus"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Rekaman layar dibatalkan"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Rekaman layar disimpan, ketuk untuk melihat"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Rekaman layar dihapus"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error saat menghapus rekaman layar"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Gagal mendapatkan izin"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Terjadi error saat memulai perekaman layar"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index b5f6e57..66c9147 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Halda áfram"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Hætta við"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Deila"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Eyða"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Hætt við skjáupptöku"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Skjáupptaka vistuð, ýttu til að skoða"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Skjáupptöku eytt"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Villa við að eyða skjáupptöku"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Ekki tókst að fá heimildir"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Villa við að hefja upptöku skjás"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index f4453b7..b0e64a2 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Riprendi"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annulla"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Condividi"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"CANC"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Registrazione dello schermo annullata"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Registrazione dello schermo salvata. Tocca per visualizzarla."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Registrazione dello schermo eliminata"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Errore durante l\'eliminazione della registrazione dello schermo"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Impossibile ottenere le autorizzazioni"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Errore durante l\'avvio della registrazione dello schermo"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 161fedc..92fa09b 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"המשך"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ביטול"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"שיתוף"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"מחיקה"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"הקלטת המסך בוטלה"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"הקלטת המסך נשמרה, יש להקיש כדי להציג"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"הקלטת המסך נמחקה"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"שגיאה במחיקת הקלטת המסך"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"קבלת ההרשאות נכשלה"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"שגיאה בהפעלה של הקלטת המסך"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index fa9c040..e427c8f 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"再開"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"キャンセル"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"共有"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"削除"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"画面の録画をキャンセルしました"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"画面の録画を保存しました。タップで表示できます"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"画面の録画を削除しました"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"画面の録画の削除中にエラーが発生しました"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"権限を取得できませんでした"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"画面の録画中にエラーが発生しました"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index a3ddf70..b86bf8c 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"გაგრძელება"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"გაუქმება"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"გაზიარება"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"წაშლა"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ეკრანის ჩაწერა გაუქმდა"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"ეკრანის ჩანაწერი შენახულია, შეეხეთ სანახავად"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"ეკრანის ჩანაწერი წაიშალა"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ეკრანის ჩანაწერის წაშლისას წარმოიშვა შეცდომა"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ნებართვების მიღება ვერ მოხერხდა"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ეკრანის ჩაწერის დაწყებისას წარმოიქმნა შეცდომა"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 0d3f7f9..1adaf2b 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Жалғастыру"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Бас тарту"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Бөлісу"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Жою"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Экранды бейнеге жазудан бас тартылды"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Экран бейне жазбасы сақталды, көру үшін түртіңіз"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Экран бейне жазбасы жойылды"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Экран бейне жазбасын жою кезінде қате кетті"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Рұқсаттар алынбады"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Экрандағы бейнені жазу кезінде қате шықты."</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 5abd740..961a37b 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"បន្ត"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"បោះបង់"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"ចែករំលែក"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"លុប"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"បានបោះបង់ការថតសកម្មភាពអេក្រង់"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"បានរក្សាទុកការថតសកម្មភាពអេក្រង់។ សូមចុចដើម្បីមើល"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"បានលុបការថតសកម្មភាពអេក្រង់"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"មានបញ្ហាក្នុងការលុបការថតសកម្មភាពអេក្រង់"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"មិនអាចទទួលបានការអនុញ្ញាតទេ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"មានបញ្ហាក្នុងការចាប់ផ្ដើមថតអេក្រង់"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 47f2385..7ec6a9f 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ಮುಂದುವರಿಸಿ"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ರದ್ದುಮಾಡಿ"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"ಹಂಚಿಕೊಳ್ಳಿ"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ಅಳಿಸಿ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಅನ್ನು ರದ್ದುಮಾಡಲಾಗಿದೆ"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಅನ್ನು ಉಳಿಸಲಾಗಿದೆ, ವೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಅಳಿಸಲಾಗಿದೆ"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಅಳಿಸುವಾಗ ದೋಷ ಕಂಡುಬಂದಿದೆ"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ಅನುಮತಿಗಳನ್ನು ಪಡೆಯುವಲ್ಲಿ ವಿಫಲವಾಗಿದೆ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಪ್ರಾರಂಭಿಸುವಾಗ ದೋಷ ಕಂಡುಬಂದಿದೆ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index beb7eda..840a98e 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"재개"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"취소"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"공유"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"삭제"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"화면 녹화가 취소되었습니다."</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"화면 녹화본이 저장되었습니다. 확인하려면 탭하세요."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"화면 녹화가 삭제되었습니다."</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"화면 녹화는 삭제하는 중에 오류가 발생했습니다."</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"권한을 확보하지 못했습니다."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"화면 녹화 시작 중 오류 발생"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 4fbb09e..14ee566 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Улантуу"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Жокко чыгаруу"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Бөлүшүү"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Ооба"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Экранды жаздыруу жокко чыгарылды"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Экранды жаздыруу сакталды, көрүү үчүн таптап коюңуз"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Экранды жаздыруу өчүрүлдү"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Экранды жаздырууну өчүрүүдө ката кетти"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Уруксаттар алынбай калды"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Экранды жаздырууну баштоодо ката кетти"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 6d7feab..553d0da 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ສືບຕໍ່"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ຍົກເລີກ"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"ແບ່ງປັນ"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ລຶບ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ຍົກເລີກການບັນທຶກໜ້າຈໍແລ້ວ"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"ຈັດເກັບການບັນທຶກໜ້າຈໍ, ແຕະເພື່ອເບິ່ງ"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"ລຶບການບັນທຶກໜ້າຈໍອອກແລ້ວ"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ເກີດຄວາມຜິດພາດໃນການລຶບການບັນທຶກໜ້າຈໍ"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ໂຫຼດສິດອະນຸຍາດບໍ່ສຳເລັດ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ເກີດຄວາມຜິດພາດໃນການບັນທຶກໜ້າຈໍ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 21217a0..28d6e6b 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Tęsti"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Atšaukti"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Bendrinti"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Ištrinti"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekrano įrašymas atšauktas"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Ekrano įrašas išsaugotas, palieskite ir peržiūrėkite"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ekrano įrašas ištrintas"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Ištrinant ekrano įrašą įvyko klaida"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nepavyko gauti leidimų"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Pradedant ekrano vaizdo įrašymą iškilo problema"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 4945dfa..223a57f 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Atsākt"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Atcelt"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Kopīgot"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Dzēst"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekrāna ierakstīšana ir atcelta."</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Ekrāna ieraksts ir saglabāts. Pieskarieties, lai to skatītu."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ekrāna ieraksts ir izdzēsts."</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Dzēšot ekrāna ierakstu, radās kļūda."</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Neizdevās iegūt atļaujas."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Sākot ierakstīt ekrāna saturu, radās kļūda."</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 40d4698..a591031 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Продолжи"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Откажи"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Сподели"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Избриши"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Снимањето екран е откажано"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Снимката од екранот е зачувана, допрете за да ја видите"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Снимката од екранот е избришана"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Грешка при бришењето на снимката од екранот"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Не успеаја да се добијат дозволи"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Грешка при почетокот на снимањето на екранот"</string>
@@ -667,7 +665,7 @@
<string name="tuner_warning_title" msgid="7721976098452135267">"Забава за некои, но не за сите"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Адаптерот на УИ на системот ви дава дополнителни начини за дотерување и приспособување на корисничкиот интерфејс на Android. Овие експериментални функции можеби ќе се изменат, расипат или ќе исчезнат во следните изданија. Продолжете со претпазливост."</string>
<string name="tuner_persistent_warning" msgid="230466285569307806">"Овие експериментални функции можеби ќе се изменат, расипат или ќе исчезнат во следните изданија. Продолжете со претпазливост."</string>
- <string name="got_it" msgid="477119182261892069">"Разбрав"</string>
+ <string name="got_it" msgid="477119182261892069">"Сфатив"</string>
<string name="tuner_toast" msgid="3812684836514766951">"Честито! Го додадовте Адаптерот на УИ на системот на Поставки"</string>
<string name="remove_from_settings" msgid="633775561782209994">"Отстрани од поставки"</string>
<string name="remove_from_settings_prompt" msgid="551565437265615426">"Да се отстрани Адаптерот на УИ на системот од Поставки и да престанат да се користат сите негови функции?"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index c3bd65e..47d220d 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"പുനരാരംഭിക്കുക"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"റദ്ദാക്കുക"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"പങ്കിടുക"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ഇല്ലാതാക്കുക"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"സ്ക്രീൻ റെക്കോർഡിംഗ് റദ്ദാക്കി"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"സ്ക്രീൻ റെക്കോർഡിംഗ് സംരക്ഷിച്ചു, കാണാൻ ടാപ്പ് ചെയ്യുക"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"സ്ക്രീൻ റെക്കോർഡിംഗ് ഇല്ലാതാക്കി"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"സ്ക്രീൻ റെക്കോർഡിംഗ് ഇല്ലാതാക്കുന്നതിൽ പിശക്"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"അനുമതികൾ ലഭിച്ചില്ല"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"സ്ക്രീൻ റെക്കോർഡിംഗ് ആരംഭിക്കുന്നതിൽ പിശക്"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 5f08f05..202f292 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Үргэлжлүүлэх"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Цуцлах"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Хуваалцах"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Устгах"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Дэлгэцийн бичлэгийг цуцалсан"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Дэлгэцийн бичлэгийг хадгалсан. Харахын тулд товшино уу"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Дэлгэцийн бичлэгийг устгасан"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Дэлгэцийн бичлэгийг устгахад алдаа гарлаа"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Зөвшөөрөл авч чадсангүй"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Дэлгэцийн бичлэгийг эхлүүлэхэд алдаа гарлаа"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 6d525df..e412072 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"पुन्हा सुरू करा"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"रद्द करा"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"शेअर करा"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"हटवा"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"स्क्रीन रेकॉर्डिंग रद्द केले"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"स्क्रीन रेकॉर्डिंग सेव्ह केली, पाहण्यासाठी टॅप करा"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"स्क्रीन रेकॉर्डिंग हटवले"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"स्क्रीन रेकॉर्डिंग हटवताना एरर आली"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"परवानग्या मिळवता आल्या नाहीत"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"स्क्रीन रेकॉर्डिंग सुरू करताना एरर आली"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 4f832e4..d01ab8c 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Sambung semula"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Batal"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Kongsi"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Padam"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Rakaman skrin dibatalkan"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Rakaman skrin disimpan, ketik untuk melihat"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Rakaman skrin dipadamkan"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Ralat semasa memadamkan rakaman skrin"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Gagal mendapatkan kebenaran"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Ralat semasa memulakan rakaman skrin"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 150ed94e..83272f2 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ဆက်လုပ်ရန်"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"မလုပ်တော့"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"မျှဝေရန်"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ဖျက်ရန်"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ဖန်သားပြင် ရိုက်ကူးမှု ပယ်ဖျက်လိုက်ပါပြီ"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"ဖန်သားပြင် ရိုက်ကူးမှု သိမ်းထားသည်၊ ကြည့်ရန် တို့ပါ"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"ဖန်သားပြင် ရိုက်ကူးမှု ဖျက်ပြီးပါပြီ"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ဖန်သားပြင် ရိုက်ကူးမှု ဖျက်ရာတွင် အမှားအယွင်းရှိနေသည်"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ခွင့်ပြုချက် မရယူနိုင်ပါ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ဖန်သားပြင် ရိုက်ကူးမှု စတင်ရာတွင် အမှားအယွင်းရှိနေသည်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 849c2e9..01859ef 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Gjenoppta"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Avbryt"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Del"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Slett"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Skjermopptak er avbrutt"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Skjermopptaket er lagret. Trykk for å se det"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Skjermopptaket er slettet"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Feil ved sletting av skjermopptaket"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Kunne ikke få tillatelser"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Feil ved start av skjermopptaket"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 2ac442e..e548a96 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"जारी राख्नुहोस्"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"रद्द गर्नुहोस्"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"सेयर गर्नुहोस्"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"मेट्नुहोस्"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"स्क्रिन रेकर्ड गर्ने कार्य रद्द गरियो"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"स्क्रिन रेकर्डिङ सुरक्षित गरियो, हेर्न ट्याप गर्नुहोस्"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"स्क्रिनको रेकर्डिङ मेटाइयो"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"स्क्रिनको रेकर्डिङ मेट्ने क्रममा त्रुटि"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"अनुमति प्राप्त गर्न सकिएन"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"स्क्रिन रेकर्ड गर्न थाल्ने क्रममा त्रुटि भयो"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index da0f427..fa028c3 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Hervatten"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annuleren"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Delen"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Verwijderen"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Schermopname geannuleerd"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Schermopname opgeslagen, tik om te bekijken"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Schermopname verwijderd"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Fout bij verwijderen van schermopname"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Kan rechten niet ophalen"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Fout bij starten van schermopname"</string>
@@ -354,7 +352,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Invoer"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Gehoorapparaten"</string>
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Hoortoestellen"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Inschakelen..."</string>
<string name="quick_settings_brightness_label" msgid="680259653088849563">"Helderheid"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatisch draaien"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 029aa69..4c6ef48 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ପୁଣି ଚାଲୁ କରନ୍ତୁ"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ବାତିଲ୍ କରନ୍ତୁ"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"ସେୟାର୍ କରନ୍ତୁ"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ଡିଲିଟ୍ କରନ୍ତୁ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ସ୍କ୍ରିନ୍ ରେକର୍ଡିଂ ବାତିଲ୍ କରିଦିଆଯାଇଛି"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"ସ୍କ୍ରିନ୍ ରେକର୍ଡିଂ ସେଭ୍ ହୋଇଛି, ଦେଖିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"ସ୍କ୍ରିନ୍ ରେକର୍ଡିଂ ଡିଲିଟ୍ କରିଦିଆଯାଇଛି"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ସ୍କ୍ରିନ୍ ରେକର୍ଡିଂ ଡିଲିଟ୍ କରିବାରେ ତ୍ରୁଟି"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ଅନୁମତି ପାଇବାରେ ଅସଫଳ ହେଲା।"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ସ୍କ୍ରିନ୍ ରେକର୍ଡିଂ ଆରମ୍ଭ କରିବାରେ ତ୍ରୁଟି"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index ed5f40c..98583c0 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ਮੁੜ-ਚਾਲੂ ਕਰੋ"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ਰੱਦ ਕਰੋ"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"ਸਾਂਝਾ ਕਰੋ"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ਮਿਟਾਓ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ਸਕ੍ਰੀਨ ਦੀ ਰਿਕਾਰਡਿੰਗ ਰੱਦ ਕੀਤੀ ਗਈ"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਰੱਖਿਅਤ ਕੀਤੀ ਗਈ, ਦੇਖਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਨੂੰ ਮਿਟਾਇਆ ਗਿਆ"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਨੂੰ ਮਿਟਾਉਣ ਦੌਰਾਨ ਗੜਬੜ ਹੋਈ"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ਇਜਾਜ਼ਤਾਂ ਪ੍ਰਾਪਤ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਵੇਲੇ ਗੜਬੜ ਹੋਈ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index ba30ced..4d5a2ae 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Wznów"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Anuluj"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Udostępnij"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Usuń"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Anulowano nagrywanie zawartości ekranu"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Zapisano nagranie zawartości ekranu – kliknij, by je obejrzeć"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Usunięto nagranie zawartości ekranu"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Błąd podczas usuwania nagrania zawartości ekranu"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nie udało się uzyskać uprawnień"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Błąd podczas rozpoczynania rejestracji zawartości ekranu"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 715b0e4..ef5c9ce 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Retomar"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Compartilhar"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Excluir"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Gravação de tela cancelada"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Gravação de tela salva, toque para ver"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Gravação de tela excluída"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Erro ao excluir a gravação de tela"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Não foi possível acessar as permissões"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Erro ao iniciar a gravação de tela"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 1a59de4..541f12c 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Retomar"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Partilhar"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Eliminar"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Gravação de ecrã cancelada."</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Gravação de ecrã guardada. Toque para ver."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Gravação de ecrã eliminada."</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Erro ao eliminar a gravação de ecrã."</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Falha ao obter as autorizações."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Ocorreu um erro ao iniciar a gravação do ecrã."</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 715b0e4..ef5c9ce 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Retomar"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Compartilhar"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Excluir"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Gravação de tela cancelada"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Gravação de tela salva, toque para ver"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Gravação de tela excluída"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Erro ao excluir a gravação de tela"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Não foi possível acessar as permissões"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Erro ao iniciar a gravação de tela"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index cf428a3..3e2373d 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Reluați"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Anulați"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Trimiteți"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Ștergeți"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Înregistrarea ecranului a fost anulată"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Înregistrarea ecranului a fost salvată. Atingeți pentru vizualizare"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Înregistrarea ecranului a fost ștearsă."</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Eroare la ștergerea înregistrării ecranului"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nu s-au obținut permisiunile"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Eroare la începerea înregistrării ecranului"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index ba86e95..7747724 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Возобновить"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Отмена"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Поделиться"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Удалить"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Запись видео с экрана отменена"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Запись видео с экрана сохранена. Чтобы открыть ее, нажмите на уведомление."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Запись видео с экрана удалена"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Не удалось удалить запись видео с экрана"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Не удалось получить необходимые разрешения"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Не удалось начать запись видео с экрана."</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 1cd1ceb..b8813f2 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"නැවත අරඹන්න"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"අවලංගු කරන්න"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"බෙදා ගන්න"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"මකන්න"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"තිර පටිගත කිරීම අවලංගු කරන ලදී"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"තිර පටිගත කිරීම සුරකින ලදී, බැලීමට තට්ටු කරන්න"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"තිර පටිගත කිරීම මකන ලදී"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"තිර පටිගත කිරීම මැකීමේ දෝෂයකි"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"අවසර ලබා ගැනීමට අසමත් විය"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"තිර පටිගත කිරීම ආරම්භ කිරීමේ දෝෂයකි"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 7548607..0f9cb5f 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Obnoviť"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Zrušiť"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Zdieľať"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Odstrániť"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Záznam obrazovky bol zrušený"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Záznam obrazovky bol uložený, zobrazíte ho klepnutím"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Záznam obrazovky bol odstránený"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Pri odstraňovaní záznamu obrazovky sa vyskytla chyba"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nepodarilo sa získať povolenia"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Pri spustení nahrávania obrazovky sa vyskytla chyba"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 07ad8c1..18db332 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Nadaljuj"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Prekliči"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Deli"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Izbriši"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Snemanje zaslona je preklicano"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Videoposnetek zaslona je shranjen, dotaknite se za ogled"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Videoposnetek zaslona je izbrisan"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Napaka pri brisanju videoposnetka zaslona"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Dovoljenj ni bilo mogoče pridobiti"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Napaka pri začenjanju snemanja zaslona"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index b92744d..57ab1c3 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -108,15 +108,13 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Vazhdo"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Anulo"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Ndaj"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Fshi"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Regjistrimi i ekranit u anulua"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Regjistrimi i ekranit u ruajt, trokit për ta parë"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Regjistrimi i ekranit u fshi"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Gabim gjatë fshirjes së regjistrimit të ekranit"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Marrja e lejeve dështoi"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Gabim gjatë nisjes së regjistrimit të ekranit"</string>
<string name="usb_preference_title" msgid="1439924437558480718">"Opsionet e transferimit të dosjeve të USB-së"</string>
- <string name="use_mtp_button_title" msgid="5036082897886518086">"Lidh si një lexues \"media\" (MTP)"</string>
+ <string name="use_mtp_button_title" msgid="5036082897886518086">"Lidh si një luajtës të medias (MTP)"</string>
<string name="use_ptp_button_title" msgid="7676427598943446826">"Montoje si kamerë (PTP)"</string>
<string name="installer_cd_button_title" msgid="5499998592841984743">"Instalo \"Transferimi i skedarëve të Android\" për Mac"</string>
<string name="accessibility_back" msgid="6530104400086152611">"Prapa"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index f57d92b..ec763f6 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Настави"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Откажи"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Дели"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Избриши"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Снимање екрана је отказано"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Снимак екрана је сачуван, додирните да бисте прегледали"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Снимак екрана је избрисан"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Дошло је до проблема при брисању снимка екрана"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Преузимање дозвола није успело"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Грешка при покретању снимања екрана"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 876e337..a0a563d 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Återuppta"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Avbryt"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Dela"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Radera"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Skärminspelningen har avbrutits"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Skärminspelningen har sparats, tryck här om du vill titta på den"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Skärminspelningen har raderats"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Det gick inte att radera skärminspelningen"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Behörighet saknas"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Det gick inte att starta skärminspelningen"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 25e3493..7e264a4 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Endelea"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Ghairi"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Shiriki"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Futa"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Imeghairi mchakato wa kurekodi skrini"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Imehifadhi rekodi ya skrini, gusa ili uangalie"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Imefuta rekodi ya skrini"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Hitilafu imetokea wakati wa kufuta rekodi ya skrini"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Imeshindwa kupata ruhusa"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Hitilafu imetokea wakati wa kuanza kurekodi skrini"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 19e67db..e0f20ce 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"மீண்டும் தொடங்கு"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ரத்துசெய்"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"பகிர்"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"நீக்கு"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"திரை ரெக்கார்டிங் ரத்துசெய்யப்பட்டது"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"திரை ரெக்கார்டிங் சேமிக்கப்பட்டது, பார்க்கத் தட்டவும்"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"திரை ரெக்கார்டிங் நீக்கப்பட்டது"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"திரை ரெக்கார்டிங்கை நீக்குவதில் பிழை"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"அனுமதிகளைப் பெற இயலவில்லை"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ஸ்கிரீன் ரெக்கார்டிங்கைத் தொடங்குவதில் பிழை"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 34ff9b1..3e94b72 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"కొనసాగించు"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"రద్దు చేయి"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"షేర్ చేయి"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"తొలగించు"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"స్క్రీన్ రికార్డ్ రద్దు చేయబడింది"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"స్క్రీన్ రికార్డింగ్ సేవ్ చేయబడింది, చూడటం కోసం నొక్కండి"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"స్క్రీన్ రికార్డింగ్ తొలగించబడింది"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"స్క్రీన్ రికార్డింగ్ని తొలగిస్తున్నప్పుడు ఎర్రర్ ఏర్పడింది"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"అనుమతులను పొందడం విఫలమైంది"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"స్క్రీన్ రికార్డింగ్ ప్రారంభించడంలో ఎర్రర్ ఏర్పడింది"</string>
diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml
index 7b1479a..b2d057b 100644
--- a/packages/SystemUI/res/values-television/config.xml
+++ b/packages/SystemUI/res/values-television/config.xml
@@ -28,7 +28,6 @@
<string-array name="config_systemUIServiceComponents" translatable="false">
<item>com.android.systemui.util.NotificationChannels</item>
<item>com.android.systemui.volume.VolumeUI</item>
- <item>com.android.systemui.stackdivider.Divider</item>
<item>com.android.systemui.statusbar.tv.TvStatusBar</item>
<item>com.android.systemui.usb.StorageNotification</item>
<item>com.android.systemui.power.PowerUI</item>
@@ -42,6 +41,7 @@
<item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
<item>com.android.systemui.toast.ToastUI</item>
<item>com.android.systemui.onehanded.OneHandedUI</item>
+ <item>com.android.systemui.wmshell.WMShell</item>
</string-array>
<!-- Show a separate icon for low and high volume on the volume dialog -->
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index d37be57..088b624 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ทำต่อ"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ยกเลิก"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"แชร์"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ลบ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ยกเลิกการบันทึกหน้าจอแล้ว"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"บันทึกการบันทึกหน้าจอแล้ว แตะเพื่อดู"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"ลบการบันทึกหน้าจอแล้ว"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"เกิดข้อผิดพลาดในการลบการบันทึกหน้าจอ"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ขอสิทธิ์ไม่สำเร็จ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"เกิดข้อผิดพลาดขณะเริ่มบันทึกหน้าจอ"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index af474c7..e787b17 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Ituloy"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Kanselahin"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Ibahagi"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"I-delete"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Kinansela ang pag-record ng screen"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Na-save ang pag-record ng screen, i-tap para tingnan"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Na-delete ang pag-record ng screen"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error sa pag-delete sa pag-record ng screen"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Hindi nakuha ang mga pahintulot"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Nagkaroon ng error sa pagsisimula ng pag-record ng screen"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index ee494a2..e339445 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Devam ettir"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"İptal"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Paylaş"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Sil"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekran kaydı iptal edildi"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Ekran kaydı tamamlandı, görüntülemek için dokunun"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ekran kaydı silindi"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Ekran kaydı silinirken hata oluştu"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"İzinler alınamadı"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Ekran kaydı başlatılırken hata oluştu"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index c444c47..f5419f1 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Відновити"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Скасувати"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Поділитися"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Видалити"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Запис екрана скасовано"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Запис екрана збережено. Натисніть, щоб переглянути"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Запис екрана видалено"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Не вдалося видалити запис екрана"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Не вдалось отримати дозволи"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Не вдалося почати запис екрана"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 729ed5a..2abf350 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"دوبارہ شروع کریں"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"منسوخ کریں"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"اشتراک کریں"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"حذف کریں"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"اسکرین ریکارڈنگ منسوخ ہو گئی"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"اسکرین ریکارڈنگ محفوظ ہو گئی، دیکھنے کیلئے تھپتھپائیں"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"اسکرین ریکارڈنگ حذف ہو گئی"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"اسکرین ریکارڈنگ کو حذف کرنے میں خرابی"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"اجازتیں حاصل کرنے میں ناکامی"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"اسکرین ریکارڈنگ شروع کرنے میں خرابی"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index cf1da75..61b10a4 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Davom etish"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Bekor qilish"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Ulashish"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"O‘chirish"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekrandan yozib olish bekor qilindi"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Ekrandan yozib olingan video saqlandi. Uni ochish uchun bildirishnomani bosing."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ekrandan yozib olingan video o‘chirib tashlandi"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Ekrandan yozib olingan vi olib tashlanmadi"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Zarur ruxsatlar olinmadi"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Ekranni yozib olish boshlanmadi"</string>
@@ -362,7 +360,7 @@
<string name="accessibility_quick_settings_rotation_value" msgid="2916484894750819251">"<xliff:g id="ID_1">%s</xliff:g> rejimi"</string>
<string name="quick_settings_rotation_locked_label" msgid="4420863550666310319">"Aylanmaydigan qilingan"</string>
<string name="quick_settings_rotation_locked_portrait_label" msgid="1194988975270484482">"Tik holat"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="2000295772687238645">"Eniga"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="2000295772687238645">"Yotiq"</string>
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Kiritish usuli"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Joylashuv"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Joylashuvni aniqlash xizmati yoqilmagan"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 5794bdf..6107270 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Tiếp tục"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Hủy"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Chia sẻ"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Xóa"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Đã hủy bản ghi màn hình"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Đã lưu bản ghi màn hình, nhấn để xem"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Đã xóa bản ghi màn hình"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Lỗi khi xóa bản ghi màn hình"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Không được cấp đủ quyền"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Lỗi khi bắt đầu ghi màn hình"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 41c132c..ffd1995 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"继续"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"取消"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"分享"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"删除"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"已取消录制屏幕"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"屏幕录制内容已保存,点按即可查看"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"已删除屏幕录制内容"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"删除屏幕录制内容时出错"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"无法获取权限"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"启动屏幕录制时出错"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index b2e1b90..1575427 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"繼續"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"取消"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"分享"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"刪除"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"已取消錄影畫面"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"已儲存錄影畫面,輕按即可查看"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"已刪除錄影畫面"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"刪除錄影畫面時發生錯誤"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"無法獲得權限"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"開始錄影畫面時發生錯誤"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 346b1239..bbd8355 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"繼續"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"取消"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"分享"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"刪除"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"已取消錄製螢幕畫面"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"已儲存螢幕畫面錄製內容,輕觸即可查看"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"已刪除螢幕畫面錄製內容"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"刪除螢幕畫面錄製內容時發生錯誤"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"無法取得權限"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"開始錄製螢幕畫面時發生錯誤"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 5abce7f..63b4c61 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Qalisa kabusha"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Khansela"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Yabelana"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Susa"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ukurekhoda isikrini kukhanseliwe"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Ukurekhoda isikrini kulondoloziwe, thepha ukuze ubuke"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ukurekhoda isikrini kususiwe"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Iphutha lokususa ukurekhoda isikrini"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Yehlulekile ukuthola izimvume"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Iphutha lokuqala ukurekhoda isikrini"</string>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 84dbd60..a625029 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -159,7 +159,7 @@
<declare-styleable name="UdfpsView">
<attr name="sensorRadius" format="dimension"/>
- <attr name="sensorMarginBottom" format="dimension"/>
+ <attr name="sensorCenterY" format="dimension"/>
<attr name="sensorPressureCoefficient" format="float"/>
<attr name="sensorTouchAreaCoefficient" format="float"/>
</declare-styleable>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index ce1ca5a..130bb4f 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -301,7 +301,6 @@
<item>com.android.systemui.keyguard.KeyguardViewMediator</item>
<item>com.android.systemui.recents.Recents</item>
<item>com.android.systemui.volume.VolumeUI</item>
- <item>com.android.systemui.stackdivider.Divider</item>
<item>com.android.systemui.statusbar.phone.StatusBar</item>
<item>com.android.systemui.usb.StorageNotification</item>
<item>com.android.systemui.power.PowerUI</item>
@@ -323,6 +322,7 @@
<item>com.android.systemui.accessibility.SystemActions</item>
<item>com.android.systemui.toast.ToastUI</item>
<item>com.android.systemui.onehanded.OneHandedUI</item>
+ <item>com.android.systemui.wmshell.WMShell</item>
</string-array>
<!-- QS tile shape store width. negative implies fill configuration instead of stroke-->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 765a942..d12f010 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1342,7 +1342,7 @@
<dimen name="controls_app_divider_height">2dp</dimen>
<dimen name="controls_app_divider_side_margin">32dp</dimen>
- <dimen name="controls_card_margin">2dp</dimen>
+ <dimen name="controls_card_margin">@dimen/control_base_item_margin</dimen>
<item name="control_card_elevation" type="dimen" format="float">15</item>
<dimen name="controls_dialog_padding">32dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 823c1ff..bfa7532 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -278,14 +278,10 @@
<string name="screenrecord_cancel_label">Cancel</string>
<!-- Label for notification action to share screen recording [CHAR LIMIT=35] -->
<string name="screenrecord_share_label">Share</string>
- <!-- Label for notification action to delete a screen recording file [CHAR LIMIT=35] -->
- <string name="screenrecord_delete_label">Delete</string>
<!-- A toast message shown after successfully canceling a screen recording [CHAR LIMIT=NONE] -->
<string name="screenrecord_cancel_success">Screen recording canceled</string>
<!-- Notification text shown after saving a screen recording to prompt the user to view it [CHAR LIMIT=100] -->
<string name="screenrecord_save_message">Screen recording saved, tap to view</string>
- <!-- A toast message shown after successfully deleting a screen recording [CHAR LIMIT=NONE] -->
- <string name="screenrecord_delete_description">Screen recording deleted</string>
<!-- A toast message shown when there is an error deleting a screen recording [CHAR LIMIT=NONE] -->
<string name="screenrecord_delete_error">Error deleting screen recording</string>
<!-- A toast message shown when the screen recording cannot be started due to insufficient permissions [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 748a9c9..27809b5 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -65,7 +65,6 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
import com.android.systemui.shared.system.PackageManagerWrapper;
-import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -324,7 +323,6 @@
@Inject Lazy<DisplayImeController> mDisplayImeController;
@Inject Lazy<RecordingController> mRecordingController;
@Inject Lazy<ProtoTracer> mProtoTracer;
- @Inject Lazy<Divider> mDivider;
@Inject
public Dependency() {
@@ -521,7 +519,6 @@
mProviders.put(AutoHideController.class, mAutoHideController::get);
mProviders.put(RecordingController.class, mRecordingController::get);
- mProviders.put(Divider.class, mDivider::get);
Dependency.setInstance(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 59af458..17b840cc 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -162,8 +162,8 @@
*
* @param context application context
* @param callback the container that holds the items to be manipulated
- * @param small the smallest allowable size for the manuipulated items.
- * @param large the largest allowable size for the manuipulated items.
+ * @param small the smallest allowable size for the manipulated items.
+ * @param large the largest allowable size for the manipulated items.
*/
public ExpandHelper(Context context, Callback callback, int small, int large) {
mSmallSize = small;
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index d17ca404..47066a0 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -22,7 +22,6 @@
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.NonNull;
-import android.content.Context;
import android.content.res.Resources;
import android.graphics.RectF;
import android.os.Handler;
@@ -115,24 +114,24 @@
private final ArrayMap<View, Animator> mDismissPendingMap = new ArrayMap<>();
public SwipeHelper(
- int swipeDirection, Callback callback, Context context, FalsingManager falsingManager) {
+ int swipeDirection, Callback callback, Resources resources,
+ ViewConfiguration viewConfiguration, FalsingManager falsingManager) {
mCallback = callback;
mHandler = new Handler();
mSwipeDirection = swipeDirection;
mVelocityTracker = VelocityTracker.obtain();
- final ViewConfiguration configuration = ViewConfiguration.get(context);
- mPagingTouchSlop = configuration.getScaledPagingTouchSlop();
- mSlopMultiplier = configuration.getScaledAmbiguousGestureMultiplier();
+ mPagingTouchSlop = viewConfiguration.getScaledPagingTouchSlop();
+ mSlopMultiplier = viewConfiguration.getScaledAmbiguousGestureMultiplier();
// Extra long-press!
mLongPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f);
- Resources res = context.getResources();
- mDensityScale = res.getDisplayMetrics().density;
- mFalsingThreshold = res.getDimensionPixelSize(R.dimen.swipe_helper_falsing_threshold);
- mFadeDependingOnAmountSwiped = res.getBoolean(R.bool.config_fadeDependingOnAmountSwiped);
+ mDensityScale = resources.getDisplayMetrics().density;
+ mFalsingThreshold = resources.getDimensionPixelSize(R.dimen.swipe_helper_falsing_threshold);
+ mFadeDependingOnAmountSwiped = resources.getBoolean(
+ R.bool.config_fadeDependingOnAmountSwiped);
mFalsingManager = falsingManager;
- mFlingAnimationUtils = new FlingAnimationUtils(res.getDisplayMetrics(),
+ mFlingAnimationUtils = new FlingAnimationUtils(resources.getDisplayMetrics(),
getMaxEscapeAnimDuration() / 1000f);
}
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index eeb3b28..a3339f6 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -19,6 +19,7 @@
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.location.LocationManager;
import android.media.AudioManager;
import android.media.AudioRecordingConfiguration;
import android.os.Handler;
@@ -66,6 +67,13 @@
private final AppOpsManager mAppOps;
private final AudioManager mAudioManager;
+ private final LocationManager mLocationManager;
+
+ // mLocationProviderPackages are cached and updated only occasionally
+ private static final long LOCATION_PROVIDER_UPDATE_FREQUENCY_MS = 30000;
+ private long mLastLocationProviderPackageUpdate;
+ private List<String> mLocationProviderPackages;
+
private H mBGHandler;
private final List<AppOpsController.Callback> mCallbacks = new ArrayList<>();
private final SparseArray<Set<Callback>> mCallbacksByCode = new SparseArray<>();
@@ -83,8 +91,10 @@
protected static final int[] OPS = new int[] {
AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION,
AppOpsManager.OP_CAMERA,
+ AppOpsManager.OP_PHONE_CALL_CAMERA,
AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
AppOpsManager.OP_RECORD_AUDIO,
+ AppOpsManager.OP_PHONE_CALL_MICROPHONE,
AppOpsManager.OP_COARSE_LOCATION,
AppOpsManager.OP_FINE_LOCATION
};
@@ -105,6 +115,7 @@
mCallbacksByCode.put(OPS[i], new ArraySet<>());
}
mAudioManager = audioManager;
+ mLocationManager = context.getSystemService(LocationManager.class);
dumpManager.registerDumpable(TAG, this);
}
@@ -288,6 +299,26 @@
return isUserVisible(item.getCode(), item.getUid(), item.getPackageName());
}
+ /**
+ * Checks if a package is the current location provider.
+ *
+ * <p>Data is cached to avoid too many calls into system server
+ *
+ * @param packageName The package that might be the location provider
+ *
+ * @return {@code true} iff the package is the location provider.
+ */
+ private boolean isLocationProvider(String packageName) {
+ long now = System.currentTimeMillis();
+
+ if (mLastLocationProviderPackageUpdate + LOCATION_PROVIDER_UPDATE_FREQUENCY_MS < now) {
+ mLastLocationProviderPackageUpdate = now;
+ mLocationProviderPackages = mLocationManager.getProviderPackages(
+ LocationManager.FUSED_PROVIDER);
+ }
+
+ return mLocationProviderPackages.contains(packageName);
+ }
/**
* Does the app-op, uid and package name, refer to an operation that should be shown to the
@@ -303,7 +334,13 @@
// does not correspond to a platform permission
// which may be user sensitive, so for now always show it to the user.
if (appOpCode == AppOpsManager.OP_SYSTEM_ALERT_WINDOW
- || appOpCode == AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION) {
+ || appOpCode == AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION
+ || appOpCode == AppOpsManager.OP_PHONE_CALL_CAMERA
+ || appOpCode == AppOpsManager.OP_PHONE_CALL_MICROPHONE) {
+ return true;
+ }
+
+ if (appOpCode == AppOpsManager.OP_CAMERA && isLocationProvider(packageName)) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java
index d4e6506b..0892612 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java
@@ -111,7 +111,7 @@
// VerifyCredentialResponse so that we can request a Gatekeeper HAT with the
// Gatekeeper Password and operationId.
mPendingLockCheck = LockPatternChecker.verifyCredential(mLockPatternUtils,
- password, mEffectiveUserId, LockPatternUtils.VERIFY_FLAG_RETURN_GK_PW,
+ password, mEffectiveUserId, LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE,
this::onCredentialVerified);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java
index ad89ae8..ab8162f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java
@@ -75,7 +75,7 @@
mLockPatternUtils,
credential,
mEffectiveUserId,
- LockPatternUtils.VERIFY_FLAG_RETURN_GK_PW,
+ LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE,
this::onPatternVerified);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
index a8f6f85..b44ff29 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
@@ -292,10 +292,12 @@
// The response passed into this method contains the Gatekeeper Password. We still
// have to request Gatekeeper to create a Hardware Auth Token with the
// Gatekeeper Password and Challenge (keystore operationId in this case)
- final VerifyCredentialResponse gkResponse = mLockPatternUtils.verifyGatekeeperPassword(
- response.getGatekeeperPw(), mOperationId, mEffectiveUserId);
+ final long pwHandle = response.getGatekeeperPasswordHandle();
+ final VerifyCredentialResponse gkResponse = mLockPatternUtils
+ .verifyGatekeeperPasswordHandle(pwHandle, mOperationId, mEffectiveUserId);
mCallback.onCredentialMatched(gkResponse.getGatekeeperHAT());
+ mLockPatternUtils.removeGatekeeperPasswordHandle(pwHandle);
} else {
if (timeoutMs > 0) {
mHandler.removeCallbacks(mClearErrorRunnable);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
index 36353fa..d7e9138 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
@@ -53,12 +53,10 @@
private final Paint mScrimPaint;
private final Paint mDebugTextPaint;
- private float mSensorX;
- private float mSensorY;
private final RectF mSensorRect;
private final Paint mSensorPaint;
private final float mSensorRadius;
- private final float mSensorMarginBottom;
+ private final float mSensorCenterY;
private final float mSensorTouchAreaCoefficient;
private final int mMaxBurnInOffsetX;
private final int mMaxBurnInOffsetY;
@@ -66,6 +64,10 @@
private final Rect mTouchableRegion;
private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener;
+ // This is calculated from the screen's dimensions at runtime, as opposed to mSensorCenterY,
+ // which is defined in layout.xml
+ private float mSensorCenterX;
+
// AOD anti-burn-in offsets
private float mInterpolatedDarkAmount;
private float mBurnInOffsetX;
@@ -84,7 +86,7 @@
if (!a.hasValue(R.styleable.UdfpsView_sensorRadius)) {
throw new IllegalArgumentException("UdfpsView must contain sensorRadius");
}
- if (!a.hasValue(R.styleable.UdfpsView_sensorMarginBottom)) {
+ if (!a.hasValue(R.styleable.UdfpsView_sensorCenterY)) {
throw new IllegalArgumentException("UdfpsView must contain sensorMarginBottom");
}
if (!a.hasValue(R.styleable.UdfpsView_sensorTouchAreaCoefficient)) {
@@ -92,7 +94,7 @@
"UdfpsView must contain sensorTouchAreaCoefficient");
}
mSensorRadius = a.getDimension(R.styleable.UdfpsView_sensorRadius, 0f);
- mSensorMarginBottom = a.getDimension(R.styleable.UdfpsView_sensorMarginBottom, 0f);
+ mSensorCenterY = a.getDimension(R.styleable.UdfpsView_sensorCenterY, 0f);
mSensorTouchAreaCoefficient = a.getFloat(
R.styleable.UdfpsView_sensorTouchAreaCoefficient, 0f);
} finally {
@@ -163,10 +165,9 @@
final int h = getLayoutParams().height;
final int w = getLayoutParams().width;
mScrimRect.set(0 /* left */, 0 /* top */, w, h);
- mSensorX = w / 2f;
- mSensorY = h - mSensorMarginBottom - mSensorRadius;
- mSensorRect.set(mSensorX - mSensorRadius, mSensorY - mSensorRadius,
- mSensorX + mSensorRadius, mSensorY + mSensorRadius);
+ mSensorCenterX = w / 2f;
+ mSensorRect.set(mSensorCenterX - mSensorRadius, mSensorCenterY - mSensorRadius,
+ mSensorCenterX + mSensorRadius, mSensorCenterY + mSensorRadius);
// Sets mTouchableRegion with rounded up values from mSensorRect.
mSensorRect.roundOut(mTouchableRegion);
@@ -210,10 +211,10 @@
}
boolean isValidTouch(float x, float y, float pressure) {
- return x > (mSensorX - mSensorRadius * mSensorTouchAreaCoefficient)
- && x < (mSensorX + mSensorRadius * mSensorTouchAreaCoefficient)
- && y > (mSensorY - mSensorRadius * mSensorTouchAreaCoefficient)
- && y < (mSensorY + mSensorRadius * mSensorTouchAreaCoefficient);
+ return x > (mSensorCenterX - mSensorRadius * mSensorTouchAreaCoefficient)
+ && x < (mSensorCenterX + mSensorRadius * mSensorTouchAreaCoefficient)
+ && y > (mSensorCenterY - mSensorRadius * mSensorTouchAreaCoefficient)
+ && y < (mSensorCenterY + mSensorRadius * mSensorTouchAreaCoefficient);
}
void setScrimAlpha(int alpha) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index fa0d2ba..80150c9 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -305,7 +305,7 @@
mActivityView = new ActivityView(mContext, null /* attrs */, 0 /* defStyle */,
true /* singleTaskInstance */, false /* usePublicVirtualDisplay*/,
- true /* disableSurfaceViewBackgroundLayer */);
+ true /* disableSurfaceViewBackgroundLayer */, true /* useTrustedDisplay */);
// Set ActivityView's alpha value as zero, since there is no view content to be shown.
setContentVisibility(false);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index ec9644a..64df2b9 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -19,11 +19,7 @@
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN;
-import static com.android.systemui.Prefs.Key.HAS_SEEN_BUBBLES_EDUCATION;
-import static com.android.systemui.Prefs.Key.HAS_SEEN_BUBBLES_MANAGE_EDUCATION;
import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_STACK_VIEW;
-import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_USER_EDUCATION;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
@@ -38,7 +34,6 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Outline;
@@ -54,7 +49,6 @@
import android.util.Log;
import android.view.Choreographer;
import android.view.DisplayCutout;
-import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SurfaceControl;
@@ -70,10 +64,8 @@
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
-import android.widget.LinearLayout;
import android.widget.TextView;
-import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.dynamicanimation.animation.DynamicAnimation;
@@ -82,7 +74,6 @@
import androidx.dynamicanimation.animation.SpringForce;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.Interpolators;
import com.android.systemui.Prefs;
import com.android.systemui.R;
@@ -115,10 +106,6 @@
implements ViewTreeObserver.OnComputeInternalInsetsListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleStackView" : TAG_BUBBLES;
- /** Animation durations for bubble stack user education views. **/
- static final int ANIMATE_STACK_USER_EDUCATION_DURATION = 200;
- private static final int ANIMATE_STACK_USER_EDUCATION_DURATION_SHORT = 40;
-
/** How far the flyout needs to be dragged before it's dismissed regardless of velocity. */
static final float FLYOUT_DRAG_PERCENT_DISMISS = 0.25f;
@@ -556,7 +543,7 @@
// Otherwise, we either tapped the stack (which means we're collapsed
// and should expand) or the currently selected bubble (we're expanded
// and should collapse).
- if (!maybeShowStackUserEducation()) {
+ if (!maybeShowStackEdu()) {
mBubbleData.setExpanded(!mBubbleData.isExpanded());
}
}
@@ -582,7 +569,9 @@
}
if (mBubbleData.isExpanded()) {
- maybeShowManageEducation(false /* show */);
+ if (mManageEduView != null) {
+ mManageEduView.hide(false /* show */);
+ }
// If we're expanded, tell the animation controller to prepare to drag this bubble,
// dispatching to the individual bubble magnet listener.
@@ -637,7 +626,9 @@
mExpandedAnimationController.dragBubbleOut(
v, viewInitialX + dx, viewInitialY + dy);
} else {
- hideStackUserEducation(false /* fromExpansion */);
+ if (mStackEduView != null) {
+ mStackEduView.hide(false /* fromExpansion */);
+ }
mStackAnimationController.moveStackFromTouch(
viewInitialX + dx, viewInitialY + dy);
}
@@ -684,7 +675,7 @@
private OnClickListener mFlyoutClickListener = new OnClickListener() {
@Override
public void onClick(View view) {
- if (maybeShowStackUserEducation()) {
+ if (maybeShowStackEdu()) {
// If we're showing user education, don't open the bubble show the education first
mBubbleToExpandAfterFlyoutCollapse = null;
} else {
@@ -728,7 +719,7 @@
mFlyout.removeCallbacks(mHideFlyout);
animateFlyoutCollapsed(shouldDismiss, velX);
- maybeShowStackUserEducation();
+ maybeShowStackEdu();
}
};
@@ -737,14 +728,8 @@
@Nullable
private BubbleOverflow mBubbleOverflow;
-
- private boolean mShouldShowUserEducation;
- private boolean mAnimatingEducationAway;
- private View mUserEducationView;
-
- private boolean mShouldShowManageEducation;
- private ManageEducationView mManageEducationView;
- private boolean mAnimatingManageEducationAway;
+ private StackEducationView mStackEduView;
+ private ManageEducationView mManageEduView;
private ViewGroup mManageMenu;
private ImageView mManageSettingsIcon;
@@ -805,8 +790,6 @@
onBubbleAnimatedOut);
mSurfaceSynchronizer = synchronizer != null ? synchronizer : DEFAULT_SURFACE_SYNCHRONIZER;
- setUpUserEducation();
-
// Force LTR by default since most of the Bubbles UI is positioned manually by the user, or
// is centered. It greatly simplifies translation positioning/animations. Views that will
// actually lay out differently in RTL, such as the flyout and expanded view, will set their
@@ -819,6 +802,8 @@
mBubbleContainer.setClipChildren(false);
addView(mBubbleContainer, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ updateUserEdu();
+
mExpandedViewContainer = new FrameLayout(context);
mExpandedViewContainer.setElevation(elevation);
mExpandedViewContainer.setClipChildren(false);
@@ -1092,48 +1077,66 @@
addView(mManageMenu);
}
- private void setUpUserEducation() {
- if (mUserEducationView != null) {
- removeView(mUserEducationView);
+ /**
+ * Whether the educational view should show for the expanded view "manage" menu.
+ */
+ private boolean shouldShowManageEdu() {
+ final boolean seen = Prefs.getBoolean(mContext,
+ Prefs.Key.HAS_SEEN_BUBBLES_MANAGE_EDUCATION, false /* default */);
+ final boolean shouldShow = (!seen || BubbleDebugConfig.forceShowUserEducation(mContext))
+ && mExpandedBubble != null;
+ if (BubbleDebugConfig.DEBUG_USER_EDUCATION) {
+ Log.d(TAG, "Show manage edu: " + shouldShow);
}
- mShouldShowUserEducation = shouldShowBubblesEducation();
- if (DEBUG_USER_EDUCATION) {
- Log.d(TAG, "shouldShowUserEducation: " + mShouldShowUserEducation);
- }
- if (mShouldShowUserEducation) {
- mUserEducationView = mInflater.inflate(R.layout.bubble_stack_user_education, this,
- false /* attachToRoot */);
- mUserEducationView.setVisibility(GONE);
+ return shouldShow;
+ }
- final TypedArray ta = mContext.obtainStyledAttributes(
- new int[] {android.R.attr.colorAccent,
- android.R.attr.textColorPrimaryInverse});
- final int bgColor = ta.getColor(0, Color.BLACK);
- int textColor = ta.getColor(1, Color.WHITE);
- ta.recycle();
- textColor = ContrastColorUtil.ensureTextContrast(textColor, bgColor, true);
-
- TextView title = mUserEducationView.findViewById(R.id.user_education_title);
- TextView description = mUserEducationView.findViewById(R.id.user_education_description);
- title.setTextColor(textColor);
- description.setTextColor(textColor);
-
- updateUserEducationForLayoutDirection();
- addView(mUserEducationView);
+ private void maybeShowManageEdu() {
+ if (!shouldShowManageEdu()) {
+ return;
}
+ if (mManageEduView == null) {
+ mManageEduView = new ManageEducationView(mContext);
+ addView(mManageEduView);
+ }
+ mManageEduView.show(mExpandedBubble.getExpandedView(), mTempRect);
+ }
- if (mManageEducationView != null) {
- removeView(mManageEducationView);
+ /**
+ * Whether education view should show for the collapsed stack.
+ */
+ private boolean shouldShowStackEdu() {
+ final boolean seen = Prefs.getBoolean(getContext(),
+ Prefs.Key.HAS_SEEN_BUBBLES_EDUCATION, false /* default */);
+ final boolean shouldShow = !seen || BubbleDebugConfig.forceShowUserEducation(mContext);
+ if (BubbleDebugConfig.DEBUG_USER_EDUCATION) {
+ Log.d(TAG, "Show stack edu: " + shouldShow);
}
- mShouldShowManageEducation = shouldShowManageEducation();
- if (DEBUG_USER_EDUCATION) {
- Log.d(TAG, "shouldShowManageEducation: " + mShouldShowManageEducation);
+ return shouldShow;
+ }
+
+ /**
+ * @return true if education view for collapsed stack should show and was not showing before.
+ */
+ private boolean maybeShowStackEdu() {
+ if (!shouldShowStackEdu()) {
+ return false;
}
- if (mShouldShowManageEducation) {
- mManageEducationView = (ManageEducationView)
- mInflater.inflate(R.layout.bubbles_manage_button_education, this /* root */,
- false /* attachToRoot */);
- addView(mManageEducationView);
+ if (mStackEduView == null) {
+ mStackEduView = new StackEducationView(mContext);
+ addView(mStackEduView);
+ }
+ return mStackEduView.show(mStackAnimationController.getStartPosition());
+ }
+
+ private void updateUserEdu() {
+ maybeShowStackEdu();
+ if (mManageEduView != null) {
+ mManageEduView.invalidate();
+ }
+ maybeShowManageEdu();
+ if (mStackEduView != null) {
+ mStackEduView.invalidate();
}
}
@@ -1164,9 +1167,9 @@
*/
public void onThemeChanged() {
setUpFlyout();
- setUpUserEducation();
setUpManageMenu();
updateOverflow();
+ updateUserEdu();
updateExpandedViewTheme();
}
@@ -1197,12 +1200,11 @@
public void onLayoutDirectionChanged(int direction) {
mManageMenu.setLayoutDirection(direction);
mFlyout.setLayoutDirection(direction);
- if (mUserEducationView != null) {
- mUserEducationView.setLayoutDirection(direction);
- updateUserEducationForLayoutDirection();
+ if (mStackEduView != null) {
+ mStackEduView.setLayoutDirection(direction);
}
- if (mManageEducationView != null) {
- mManageEducationView.setLayoutDirection(direction);
+ if (mManageEduView != null) {
+ mManageEduView.setLayoutDirection(direction);
}
updateExpandedViewDirection(direction);
}
@@ -1446,7 +1448,7 @@
Log.d(TAG, "addBubble: " + bubble);
}
- if (getBubbleCount() == 0 && mShouldShowUserEducation) {
+ if (getBubbleCount() == 0 && shouldShowStackEdu()) {
// Override the default stack position if we're showing user education.
mStackAnimationController.setStackPosition(
mStackAnimationController.getStartPosition());
@@ -1649,115 +1651,6 @@
notifyExpansionChanged(mExpandedBubble, mIsExpanded);
}
- /**
- * If necessary, shows the user education view for the bubble stack. This appears the first
- * time a user taps on a bubble.
- *
- * @return true if user education was shown, false otherwise.
- */
- private boolean maybeShowStackUserEducation() {
- if (mShouldShowUserEducation && mUserEducationView.getVisibility() != VISIBLE) {
- mUserEducationView.setAlpha(0);
- mUserEducationView.setVisibility(VISIBLE);
- updateUserEducationForLayoutDirection();
-
- // Post so we have height of mUserEducationView
- mUserEducationView.post(() -> {
- final int viewHeight = mUserEducationView.getHeight();
- PointF stackPosition = mStackAnimationController.getStartPosition();
- final float translationY = stackPosition.y + (mBubbleSize / 2) - (viewHeight / 2);
- mUserEducationView.setTranslationY(translationY);
- mUserEducationView.animate()
- .setDuration(ANIMATE_STACK_USER_EDUCATION_DURATION)
- .setInterpolator(FAST_OUT_SLOW_IN)
- .alpha(1);
- });
- Prefs.putBoolean(getContext(), HAS_SEEN_BUBBLES_EDUCATION, true);
- return true;
- }
- return false;
- }
-
- private void updateUserEducationForLayoutDirection() {
- if (mUserEducationView == null) {
- return;
- }
- LinearLayout textLayout = mUserEducationView.findViewById(R.id.user_education_view);
- TextView title = mUserEducationView.findViewById(R.id.user_education_title);
- TextView description = mUserEducationView.findViewById(R.id.user_education_description);
- boolean isLtr =
- getResources().getConfiguration().getLayoutDirection() == LAYOUT_DIRECTION_LTR;
- if (isLtr) {
- mUserEducationView.setLayoutDirection(LAYOUT_DIRECTION_LTR);
- textLayout.setBackgroundResource(R.drawable.bubble_stack_user_education_bg);
- title.setGravity(Gravity.LEFT);
- description.setGravity(Gravity.LEFT);
- } else {
- mUserEducationView.setLayoutDirection(LAYOUT_DIRECTION_RTL);
- textLayout.setBackgroundResource(R.drawable.bubble_stack_user_education_bg_rtl);
- title.setGravity(Gravity.RIGHT);
- description.setGravity(Gravity.RIGHT);
- }
- }
-
- /**
- * If necessary, hides the user education view for the bubble stack.
- *
- * @param fromExpansion if true this indicates the hide is happening due to the bubble being
- * expanded, false if due to a touch outside of the bubble stack.
- */
- void hideStackUserEducation(boolean fromExpansion) {
- if (mShouldShowUserEducation
- && mUserEducationView.getVisibility() == VISIBLE
- && !mAnimatingEducationAway) {
- mAnimatingEducationAway = true;
- mUserEducationView.animate()
- .alpha(0)
- .setDuration(fromExpansion
- ? ANIMATE_STACK_USER_EDUCATION_DURATION_SHORT
- : ANIMATE_STACK_USER_EDUCATION_DURATION)
- .withEndAction(() -> {
- mAnimatingEducationAway = false;
- mShouldShowUserEducation = shouldShowBubblesEducation();
- mUserEducationView.setVisibility(GONE);
- });
- }
- }
-
- /**
- * If necessary, toggles the user education view for the manage button. This is shown when the
- * bubble stack is expanded for the first time.
- *
- * @param show whether the user education view should show or not.
- */
- void maybeShowManageEducation(boolean show) {
- if (mManageEducationView == null) {
- return;
- }
- if (show
- && mShouldShowManageEducation
- && mManageEducationView.getVisibility() != VISIBLE
- && mIsExpanded
- && mExpandedBubble.getExpandedView() != null) {
- mManageEducationView.show(mExpandedBubble.getExpandedView(), mTempRect,
- () -> maybeShowManageEducation(false) /* run on click */);
- Prefs.putBoolean(getContext(), HAS_SEEN_BUBBLES_MANAGE_EDUCATION, true);
- } else if (!show
- && mManageEducationView.getVisibility() == VISIBLE
- && !mAnimatingManageEducationAway) {
- mManageEducationView.animate()
- .alpha(0)
- .setDuration(mIsExpansionAnimating
- ? ANIMATE_STACK_USER_EDUCATION_DURATION_SHORT
- : ANIMATE_STACK_USER_EDUCATION_DURATION)
- .withEndAction(() -> {
- mAnimatingManageEducationAway = false;
- mShouldShowManageEducation = shouldShowManageEducation();
- mManageEducationView.setVisibility(GONE);
- });
- }
- }
-
void showExpandedViewContents(int displayId) {
if (mExpandedBubble != null
&& mExpandedBubble.getExpandedView() != null
@@ -1791,7 +1684,9 @@
cancelDelayedExpandCollapseSwitchAnimations();
mIsExpanded = true;
- hideStackUserEducation(true /* fromExpansion */);
+ if (mStackEduView != null) {
+ mStackEduView.hide(true /* fromExpansion */);
+ }
beforeExpandedViewAnimation();
mBubbleContainer.setActiveController(mExpandedAnimationController);
@@ -1799,7 +1694,9 @@
updatePointerPosition();
mExpandedAnimationController.expandFromStack(() -> {
afterExpandedViewAnimation();
- maybeShowManageEducation(true);
+ if (mIsExpanded && mExpandedBubble.getExpandedView() != null) {
+ maybeShowManageEdu();
+ }
} /* after */);
mExpandedViewContainer.setTranslationX(0);
@@ -1936,7 +1833,9 @@
.withEndActions(() -> {
final BubbleViewProvider previouslySelected = mExpandedBubble;
beforeExpandedViewAnimation();
- maybeShowManageEducation(false);
+ if (mManageEduView != null) {
+ mManageEduView.hide(false /* fromExpansion */);
+ }
if (DEBUG_BUBBLE_STACK_VIEW) {
Log.d(TAG, "animateCollapse");
@@ -2104,8 +2003,8 @@
// from any location.
if (!mIsExpanded
|| mShowingManage
- || (mManageEducationView != null
- && mManageEducationView.getVisibility() == VISIBLE)) {
+ || (mManageEduView != null
+ && mManageEduView.getVisibility() == VISIBLE)) {
touchableRegion.setEmpty();
}
}
@@ -2289,7 +2188,7 @@
if (flyoutMessage == null
|| flyoutMessage.message == null
|| !bubble.showFlyout()
- || (mUserEducationView != null && mUserEducationView.getVisibility() == VISIBLE)
+ || (mStackEduView != null && mStackEduView.getVisibility() == VISIBLE)
|| isExpanded()
|| mIsExpansionAnimating
|| mIsGestureInProgress
@@ -2398,7 +2297,7 @@
* them.
*/
public void getTouchableRegion(Rect outRect) {
- if (mUserEducationView != null && mUserEducationView.getVisibility() == VISIBLE) {
+ if (mStackEduView != null && mStackEduView.getVisibility() == VISIBLE) {
// When user education shows then capture all touches
outRect.set(0, 0, getWidth(), getHeight());
return;
@@ -2770,18 +2669,6 @@
return mExpandedBubble.getExpandedView().performBackPressIfNeeded();
}
- /** Whether the educational view should appear for bubbles. **/
- private boolean shouldShowBubblesEducation() {
- return BubbleDebugConfig.forceShowUserEducation(getContext())
- || !Prefs.getBoolean(getContext(), HAS_SEEN_BUBBLES_EDUCATION, false);
- }
-
- /** Whether the educational view should appear for the expanded view "manage" button. **/
- private boolean shouldShowManageEducation() {
- return BubbleDebugConfig.forceShowUserEducation(getContext())
- || !Prefs.getBoolean(getContext(), HAS_SEEN_BUBBLES_MANAGE_EDUCATION, false);
- }
-
/** For debugging only */
List<Bubble> getBubblesOnScreen() {
List<Bubble> bubbles = new ArrayList<>();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt b/packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt
index c58ab31..26a9773 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt
@@ -18,52 +18,56 @@
import android.content.Context
import android.graphics.Color
import android.graphics.Rect
-import android.util.AttributeSet
-import android.view.Gravity
+import android.view.LayoutInflater
import android.view.View
import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView
import com.android.internal.util.ContrastColorUtil
import com.android.systemui.Interpolators
+import com.android.systemui.Prefs
+import com.android.systemui.Prefs.Key.HAS_SEEN_BUBBLES_MANAGE_EDUCATION
import com.android.systemui.R
/**
- * Educational view to highlight the manage button that allows a user to configure the settings
+ * User education view to highlight the manage button that allows a user to configure the settings
* for the bubble. Shown only the first time a user expands a bubble.
*/
-class ManageEducationView @JvmOverloads constructor(
- context: Context?,
- attrs: AttributeSet? = null,
- defStyleAttr: Int = 0,
- defStyleRes: Int = 0
-) : LinearLayout(context, attrs, defStyleAttr, defStyleRes) {
+class ManageEducationView constructor(context: Context) : LinearLayout(context) {
+
+ private val TAG = if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "BubbleManageEducationView"
+ else BubbleDebugConfig.TAG_BUBBLES
+
+ private val ANIMATE_DURATION : Long = 200
+ private val ANIMATE_DURATION_SHORT : Long = 40
private val manageView by lazy { findViewById<View>(R.id.manage_education_view) }
private val manageButton by lazy { findViewById<Button>(R.id.manage) }
private val gotItButton by lazy { findViewById<Button>(R.id.got_it) }
private val titleTextView by lazy { findViewById<TextView>(R.id.user_education_title) }
private val descTextView by lazy { findViewById<TextView>(R.id.user_education_description) }
- private var isInflated = false
+
+ private var isHiding = false
init {
- this.visibility = View.GONE
- this.elevation = resources.getDimensionPixelSize(R.dimen.bubble_elevation).toFloat()
- this.layoutDirection = View.LAYOUT_DIRECTION_LOCALE
+ LayoutInflater.from(context).inflate(R.layout.bubbles_manage_button_education, this);
+ visibility = View.GONE
+ elevation = resources.getDimensionPixelSize(R.dimen.bubble_elevation).toFloat()
+
+ // BubbleStackView forces LTR by default
+ // since most of Bubble UI direction depends on positioning by the user.
+ // This view actually lays out differently in RTL, so we set layout LOCALE here.
+ layoutDirection = View.LAYOUT_DIRECTION_LOCALE
}
- override fun setLayoutDirection(direction: Int) {
- super.setLayoutDirection(direction)
- // setLayoutDirection runs before onFinishInflate
- // so skip if views haven't inflated; otherwise we'll get NPEs
- if (!isInflated) return
- setDirection()
+ override fun setLayoutDirection(layoutDirection: Int) {
+ super.setLayoutDirection(layoutDirection)
+ setDrawableDirection()
}
override fun onFinishInflate() {
super.onFinishInflate()
- isInflated = true
- setDirection()
+ layoutDirection = resources.configuration.layoutDirection
setTextColor()
}
@@ -78,29 +82,35 @@
descTextView.setTextColor(textColor)
}
- fun setDirection() {
+ private fun setDrawableDirection() {
manageView.setBackgroundResource(
if (resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL)
R.drawable.bubble_stack_user_education_bg_rtl
else R.drawable.bubble_stack_user_education_bg)
- titleTextView.gravity = Gravity.START
- descTextView.gravity = Gravity.START
}
- fun show(expandedView: BubbleExpandedView, rect : Rect, hideMenu: Runnable) {
+ /**
+ * If necessary, toggles the user education view for the manage button. This is shown when the
+ * bubble stack is expanded for the first time.
+ *
+ * @param show whether the user education view should show or not.
+ */
+ fun show(expandedView: BubbleExpandedView, rect : Rect) {
+ if (visibility == VISIBLE) return
+
alpha = 0f
visibility = View.VISIBLE
post {
expandedView.getManageButtonBoundsOnScreen(rect)
- with(hideMenu) {
- manageButton
- .setOnClickListener {
- expandedView.findViewById<View>(R.id.settings_button).performClick()
- this.run()
- }
- gotItButton.setOnClickListener { this.run() }
- setOnClickListener { this.run() }
- }
+
+ manageButton
+ .setOnClickListener {
+ expandedView.findViewById<View>(R.id.settings_button).performClick()
+ hide(true /* isStackExpanding */)
+ }
+ gotItButton.setOnClickListener { hide(true /* isStackExpanding */) }
+ setOnClickListener { hide(true /* isStackExpanding */) }
+
with(manageView) {
translationX = 0f
val inset = resources.getDimensionPixelSize(
@@ -109,9 +119,27 @@
}
bringToFront()
animate()
- .setDuration(BubbleStackView.ANIMATE_STACK_USER_EDUCATION_DURATION.toLong())
+ .setDuration(ANIMATE_DURATION)
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.alpha(1f)
}
+ setShouldShow(false)
+ }
+
+ fun hide(isStackExpanding: Boolean) {
+ if (visibility != VISIBLE || isHiding) return
+
+ animate()
+ .withStartAction { isHiding = true }
+ .alpha(0f)
+ .setDuration(if (isStackExpanding) ANIMATE_DURATION_SHORT else ANIMATE_DURATION)
+ .withEndAction {
+ isHiding = false
+ visibility = GONE
+ };
+ }
+
+ private fun setShouldShow(shouldShow: Boolean) {
+ Prefs.putBoolean(context, HAS_SEEN_BUBBLES_MANAGE_EDUCATION, !shouldShow)
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt b/packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt
new file mode 100644
index 0000000..3e4c729
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.bubbles
+
+import android.content.Context
+import android.graphics.Color
+import android.graphics.PointF
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.LinearLayout
+import android.widget.TextView
+import com.android.internal.util.ContrastColorUtil
+import com.android.systemui.Interpolators
+import com.android.systemui.Prefs
+import com.android.systemui.Prefs.Key.HAS_SEEN_BUBBLES_EDUCATION
+import com.android.systemui.R
+
+/**
+ * User education view to highlight the collapsed stack of bubbles.
+ * Shown only the first time a user taps the stack.
+ */
+class StackEducationView constructor(context: Context) : LinearLayout(context){
+
+ private val TAG = if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "BubbleStackEducationView"
+ else BubbleDebugConfig.TAG_BUBBLES
+
+ private val ANIMATE_DURATION : Long = 200
+ private val ANIMATE_DURATION_SHORT : Long = 40
+
+ private val view by lazy { findViewById<View>(R.id.stack_education_layout) }
+ private val titleTextView by lazy { findViewById<TextView>(R.id.stack_education_title) }
+ private val descTextView by lazy { findViewById<TextView>(R.id.stack_education_description) }
+
+ private var isHiding = false
+
+ init {
+ LayoutInflater.from(context).inflate(R.layout.bubble_stack_user_education, this);
+
+ visibility = View.GONE
+ elevation = resources.getDimensionPixelSize(R.dimen.bubble_elevation).toFloat()
+
+ // BubbleStackView forces LTR by default
+ // since most of Bubble UI direction depends on positioning by the user.
+ // This view actually lays out differently in RTL, so we set layout LOCALE here.
+ layoutDirection = View.LAYOUT_DIRECTION_LOCALE
+ }
+
+ override fun setLayoutDirection(layoutDirection: Int) {
+ super.setLayoutDirection(layoutDirection)
+ setDrawableDirection()
+ }
+
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+ layoutDirection = resources.configuration.layoutDirection
+ setTextColor()
+ }
+
+ private fun setTextColor() {
+ val ta = mContext.obtainStyledAttributes(intArrayOf(android.R.attr.colorAccent,
+ android.R.attr.textColorPrimaryInverse))
+ val bgColor = ta.getColor(0 /* index */, Color.BLACK)
+ var textColor = ta.getColor(1 /* index */, Color.WHITE)
+ ta.recycle()
+ textColor = ContrastColorUtil.ensureTextContrast(textColor, bgColor, true)
+ titleTextView.setTextColor(textColor)
+ descTextView.setTextColor(textColor)
+ }
+
+ private fun setDrawableDirection() {
+ view.setBackgroundResource(
+ if (resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_LTR)
+ R.drawable.bubble_stack_user_education_bg
+ else R.drawable.bubble_stack_user_education_bg_rtl)
+ }
+
+ /**
+ * If necessary, shows the user education view for the bubble stack. This appears the first
+ * time a user taps on a bubble.
+ *
+ * @return true if user education was shown, false otherwise.
+ */
+ fun show(stackPosition: PointF) : Boolean{
+ if (visibility == VISIBLE) return false
+
+ setAlpha(0f)
+ setVisibility(View.VISIBLE)
+ post {
+ with(view) {
+ val bubbleSize = context.resources.getDimensionPixelSize(
+ R.dimen.individual_bubble_size)
+ translationY = stackPosition.y + bubbleSize / 2 - getHeight() / 2
+ }
+ animate()
+ .setDuration(ANIMATE_DURATION)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .alpha(1f)
+ }
+ setShouldShow(false)
+ return true
+ }
+
+ /**
+ * If necessary, hides the stack education view.
+ *
+ * @param fromExpansion if true this indicates the hide is happening due to the bubble being
+ * expanded, false if due to a touch outside of the bubble stack.
+ */
+ fun hide(fromExpansion: Boolean) {
+ if (visibility != VISIBLE || isHiding) return
+
+ animate()
+ .alpha(0f)
+ .setDuration(if (fromExpansion) ANIMATE_DURATION_SHORT else ANIMATE_DURATION)
+ .withEndAction { visibility = GONE }
+ }
+
+ private fun setShouldShow(shouldShow: Boolean) {
+ Prefs.putBoolean(context, HAS_SEEN_BUBBLES_EDUCATION, !shouldShow)
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt
index 1bda841..d930c98 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt
@@ -87,6 +87,10 @@
* @param list a list of favorite controls. The list will be stored in the same order.
*/
fun storeFavorites(structures: List<StructureInfo>) {
+ if (structures.isEmpty() && !file.exists()) {
+ // Do not create a new file to store nothing
+ return
+ }
executor.execute {
Log.d(TAG, "Saving data to file: $file")
val atomicFile = AtomicFile(file)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
index c683a87..31830b9 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
@@ -72,8 +72,13 @@
TYPE_CONTROL -> {
ControlHolder(
layoutInflater.inflate(R.layout.controls_base_item, parent, false).apply {
- layoutParams.apply {
+ (layoutParams as ViewGroup.MarginLayoutParams).apply {
width = ViewGroup.LayoutParams.MATCH_PARENT
+ // Reset margins as they will be set through the decoration
+ topMargin = 0
+ bottomMargin = 0
+ leftMargin = 0
+ rightMargin = 0
}
elevation = this@ControlAdapter.elevation
background = parent.context.getDrawable(
@@ -386,7 +391,7 @@
val type = parent.adapter?.getItemViewType(position)
if (type == ControlAdapter.TYPE_CONTROL) {
outRect.apply {
- top = topMargin
+ top = topMargin * 2 // Use double margin, as we are not setting bottom
left = sideMargins
right = sideMargins
bottom = 0
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
index c95e81c..596e440 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
@@ -66,12 +66,6 @@
@ClassKey(SystemUIAuxiliaryDumpService.class)
public abstract Service bindSystemUIAuxiliaryDumpService(SystemUIAuxiliaryDumpService service);
- /** */
- @Binds
- @IntoMap
- @ClassKey(TakeScreenshotService.class)
- public abstract Service bindTakeScreenshotService(TakeScreenshotService service);
-
/** Inject into RecordingService */
@Binds
@IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 5a77723..8a67e96 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -61,7 +61,7 @@
import com.android.systemui.shared.plugins.PluginManagerImpl;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.phone.AutoHideController;
@@ -193,7 +193,7 @@
SysUiState sysUiFlagsContainer,
BroadcastDispatcher broadcastDispatcher,
CommandQueue commandQueue,
- Divider divider,
+ Optional<SplitScreen> splitScreenOptional,
Optional<Recents> recentsOptional,
Lazy<StatusBar> statusBarLazy,
ShadeController shadeController,
@@ -215,7 +215,7 @@
sysUiFlagsContainer,
broadcastDispatcher,
commandQueue,
- divider,
+ splitScreenOptional,
recentsOptional,
statusBarLazy,
shadeController,
@@ -321,5 +321,4 @@
public ModeSwitchesController providesModeSwitchesController(Context context) {
return new ModeSwitchesController(context);
}
-
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index 7281faf1..b606201 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -22,7 +22,6 @@
import com.android.systemui.SystemUIAppComponentFactory;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardSliceProvider;
-import com.android.systemui.onehanded.dagger.OneHandedModule;
import com.android.systemui.pip.phone.dagger.PipModule;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.InjectionInflationController;
@@ -37,7 +36,6 @@
DefaultComponentBinder.class,
DependencyProvider.class,
DependencyBinder.class,
- OneHandedModule.class,
PipModule.class,
SystemServicesModule.class,
SystemUIBinder.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
index 7fe9faf..ceb9aee 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
@@ -41,6 +41,7 @@
import android.hardware.SensorPrivacyManager;
import android.hardware.display.ColorDisplayManager;
import android.hardware.display.DisplayManager;
+import android.hardware.face.FaceManager;
import android.media.AudioManager;
import android.media.MediaRouter2Manager;
import android.media.session.MediaSessionManager;
@@ -59,6 +60,7 @@
import android.telecom.TelecomManager;
import android.telephony.TelephonyManager;
import android.view.IWindowManager;
+import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
@@ -168,6 +170,14 @@
@Provides
@SysUISingleton
+ @Nullable
+ static FaceManager provideFaceManager(Context context) {
+ return context.getSystemService(FaceManager.class);
+
+ }
+
+ @Provides
+ @SysUISingleton
static IPackageManager provideIPackageManager() {
return IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
}
@@ -312,6 +322,12 @@
@Provides
@SysUISingleton
+ static ViewConfiguration provideViewConfiguration(Context context) {
+ return ViewConfiguration.get(context);
+ }
+
+ @Provides
+ @SysUISingleton
static UserManager provideUserManager(Context context) {
return context.getSystemService(UserManager.class);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index 0aebb7e..9dfd9f8 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -34,7 +34,6 @@
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsModule;
import com.android.systemui.shortcut.ShortcutKeyDispatcher;
-import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.dagger.StatusBarModule;
import com.android.systemui.statusbar.notification.InstantAppNotifier;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -43,6 +42,7 @@
import com.android.systemui.toast.ToastUI;
import com.android.systemui.util.leak.GarbageMonitor;
import com.android.systemui.volume.VolumeUI;
+import com.android.systemui.wmshell.WMShell;
import dagger.Binds;
import dagger.Module;
@@ -61,12 +61,6 @@
@ClassKey(AuthController.class)
public abstract SystemUI bindAuthController(AuthController service);
- /** Inject into Divider. */
- @Binds
- @IntoMap
- @ClassKey(Divider.class)
- public abstract SystemUI bindDivider(Divider sysui);
-
/** Inject into GarbageMonitor.Service. */
@Binds
@IntoMap
@@ -187,4 +181,10 @@
@IntoMap
@ClassKey(WindowMagnification.class)
public abstract SystemUI bindWindowMagnification(WindowMagnification sysui);
+
+ /** Inject into WMShell. */
+ @Binds
+ @IntoMap
+ @ClassKey(WMShell.class)
+ public abstract SystemUI bindWMShell(WMShell sysui);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index 3b225d5..a021114 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -41,7 +41,6 @@
import com.android.systemui.qs.tileimpl.QSFactoryImpl;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsImplementation;
-import com.android.systemui.stackdivider.DividerModule;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
@@ -75,7 +74,6 @@
* overridden by the System UI implementation.
*/
@Module(includes = {
- DividerModule.class,
QSModule.class,
WMShellModule.class
})
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index abfc2ab..e985e3d 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -16,24 +16,17 @@
package com.android.systemui.dagger;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.pm.PackageManager;
-
-import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.BootCompleteCache;
import com.android.systemui.BootCompleteCacheImpl;
import com.android.systemui.assist.AssistModule;
import com.android.systemui.demomode.dagger.DemoModeModule;
import com.android.systemui.doze.dagger.DozeComponent;
-import com.android.systemui.dump.DumpManager;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.log.dagger.LogModule;
import com.android.systemui.model.SysUiState;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.Recents;
+import com.android.systemui.screenshot.dagger.ScreenshotModule;
import com.android.systemui.settings.dagger.SettingsModule;
-import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
@@ -41,12 +34,10 @@
import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
-import com.android.systemui.statusbar.phone.KeyguardLiftController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.concurrency.ConcurrencyModule;
-import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.util.sensors.SensorModule;
import com.android.systemui.util.settings.SettingsUtilModule;
import com.android.systemui.util.time.SystemClock;
@@ -67,6 +58,7 @@
DemoModeModule.class,
LogModule.class,
PeopleHubModule.class,
+ ScreenshotModule.class,
SensorModule.class,
SettingsModule.class,
SettingsUtilModule.class
@@ -87,22 +79,6 @@
public abstract ContextComponentHelper bindComponentHelper(
ContextComponentResolver componentHelper);
- @SysUISingleton
- @Provides
- @Nullable
- static KeyguardLiftController provideKeyguardLiftController(
- Context context,
- StatusBarStateController statusBarStateController,
- AsyncSensorManager asyncSensorManager,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- DumpManager dumpManager) {
- if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
- return null;
- }
- return new KeyguardLiftController(statusBarStateController, asyncSensorManager,
- keyguardUpdateMonitor, dumpManager);
- }
-
/** */
@Binds
public abstract NotificationRowBinder bindNotificationRowBinder(
@@ -118,9 +94,6 @@
abstract CommandQueue optionalCommandQueue();
@BindsOptionalOf
- abstract Divider optionalDivider();
-
- @BindsOptionalOf
abstract HeadsUpManager optionalHeadsUpManager();
@BindsOptionalOf
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 1a1cc07..19b0ea1 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -33,9 +33,6 @@
import javax.inject.Inject;
-import dagger.Reusable;
-
-@Reusable // Don't create multiple DozeServices.
public class DozeService extends DreamService
implements DozeMachine.Service, RequestDoze, PluginListener<DozeServicePlugin> {
private static final String TAG = "DozeService";
@@ -60,7 +57,7 @@
setWindowless(true);
mPluginManager.addPluginListener(this, DozeServicePlugin.class, false /* allowMultiple */);
- DozeComponent dozeComponent = mDozeComponentBuilder.build();
+ DozeComponent dozeComponent = mDozeComponentBuilder.build(this);
mDozeMachine = dozeComponent.getDozeMachine();
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java
index 2472854..05050f9 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java
@@ -19,6 +19,7 @@
import com.android.systemui.doze.DozeMachine;
import com.android.systemui.doze.DozeService;
+import dagger.BindsInstance;
import dagger.Subcomponent;
/**
@@ -30,7 +31,7 @@
/** Simple Builder for {@link DozeComponent}. */
@Subcomponent.Factory
interface Builder {
- DozeComponent build();
+ DozeComponent build(@BindsInstance DozeMachine.Service dozeMachineService);
}
/** Supply a {@link DozeMachine}. */
diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java
index a12e280..04f7c36 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java
@@ -33,7 +33,6 @@
import com.android.systemui.doze.DozeScreenState;
import com.android.systemui.doze.DozeScreenStatePreventingAdapter;
import com.android.systemui.doze.DozeSensors;
-import com.android.systemui.doze.DozeService;
import com.android.systemui.doze.DozeSuspendScreenStatePreventingAdapter;
import com.android.systemui.doze.DozeTriggers;
import com.android.systemui.doze.DozeUi;
@@ -52,9 +51,9 @@
@Provides
@DozeScope
@WrappedService
- static DozeMachine.Service providesWrappedService(DozeService dozeService, DozeHost dozeHost,
- DozeParameters dozeParameters) {
- DozeMachine.Service wrappedService = dozeService;
+ static DozeMachine.Service providesWrappedService(DozeMachine.Service dozeMachineService,
+ DozeHost dozeHost, DozeParameters dozeParameters) {
+ DozeMachine.Service wrappedService = dozeMachineService;
wrappedService = new DozeBrightnessHostForwarder(wrappedService, dozeHost);
wrappedService = DozeScreenStatePreventingAdapter.wrapIfNeeded(
wrappedService, dozeParameters);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt
new file mode 100644
index 0000000..9dcc3bb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
+import android.content.res.Resources
+import android.database.ContentObserver
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
+import android.hardware.biometrics.BiometricSourceType
+import android.os.Handler
+import android.provider.Settings.System.SCREEN_BRIGHTNESS_FLOAT
+import android.util.MathUtils
+import android.view.View
+import android.view.WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
+import android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+import com.android.internal.annotations.VisibleForTesting
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.Dumpable
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.NotificationShadeWindowController
+import com.android.systemui.util.settings.GlobalSettings
+import com.android.systemui.util.settings.SystemSettings
+import java.io.FileDescriptor
+import java.io.PrintWriter
+import java.lang.Float.max
+import java.util.concurrent.TimeUnit
+
+val DEFAULT_ANIMATION_DURATION = TimeUnit.SECONDS.toMillis(4)
+val MAX_SCREEN_BRIGHTNESS = 100 // 0..100
+val MAX_SCRIM_OPACTY = 50 // 0..100
+val DEFAULT_USE_FACE_WALLPAPER = false
+
+/**
+ * This class is responsible for ramping up the display brightness (and white overlay) in order
+ * to mitigate low light conditions when running face auth without an IR camera.
+ */
+@SysUISingleton
+open class FaceAuthScreenBrightnessController(
+ private val notificationShadeWindowController: NotificationShadeWindowController,
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ private val resources: Resources,
+ private val globalSettings: GlobalSettings,
+ private val systemSettings: SystemSettings,
+ private val mainHandler: Handler,
+ private val dumpManager: DumpManager
+) : Dumpable {
+
+ private var userDefinedBrightness: Float = 1f
+ @VisibleForTesting
+ var useFaceAuthWallpaper = globalSettings
+ .getInt("sysui.use_face_auth_wallpaper", if (DEFAULT_USE_FACE_WALLPAPER) 1 else 0) == 1
+ private val brightnessAnimationDuration = globalSettings
+ .getLong("sysui.face_brightness_anim_duration", DEFAULT_ANIMATION_DURATION)
+ private val maxScreenBrightness = globalSettings
+ .getInt("sysui.face_max_brightness", MAX_SCREEN_BRIGHTNESS) / 100f
+ private val maxScrimOpacity = globalSettings
+ .getInt("sysui.face_max_scrim_opacity", MAX_SCRIM_OPACTY) / 100f
+ private val keyguardUpdateCallback = object : KeyguardUpdateMonitorCallback() {
+ override fun onBiometricRunningStateChanged(
+ running: Boolean,
+ biometricSourceType: BiometricSourceType?
+ ) {
+ if (biometricSourceType != BiometricSourceType.FACE) {
+ return
+ }
+ // TODO enable only when receiving a low-light error
+ overridingBrightness = running
+ }
+ }
+ private lateinit var whiteOverlay: View
+ private var brightnessAnimator: ValueAnimator? = null
+ private var overridingBrightness = false
+ set(value) {
+ if (field == value) {
+ return
+ }
+ field = value
+ brightnessAnimator?.cancel()
+
+ if (!value) {
+ notificationShadeWindowController.setFaceAuthDisplayBrightness(BRIGHTNESS_OVERRIDE_NONE)
+ if (whiteOverlay.alpha > 0) {
+ brightnessAnimator = createAnimator(whiteOverlay.alpha, 0f).apply {
+ duration = 200
+ addUpdateListener {
+ whiteOverlay.alpha = it.animatedValue as Float
+ }
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ whiteOverlay.visibility = View.INVISIBLE
+ brightnessAnimator = null
+ }
+ })
+ start()
+ }
+ }
+ return
+ }
+
+ val targetBrightness = max(maxScreenBrightness, userDefinedBrightness)
+ whiteOverlay.visibility = View.VISIBLE
+ brightnessAnimator = createAnimator(0f, 1f).apply {
+ duration = brightnessAnimationDuration
+ addUpdateListener {
+ val progress = it.animatedValue as Float
+ val brightnessProgress = MathUtils.constrainedMap(
+ userDefinedBrightness, targetBrightness, 0f, 0.5f, progress)
+ val scrimProgress = MathUtils.constrainedMap(
+ 0f, maxScrimOpacity, 0.5f, 1f, progress)
+ notificationShadeWindowController.setFaceAuthDisplayBrightness(brightnessProgress)
+ whiteOverlay.alpha = scrimProgress
+ }
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ brightnessAnimator = null
+ }
+ })
+ start()
+ }
+ }
+
+ @VisibleForTesting
+ open fun createAnimator(start: Float, end: Float) = ValueAnimator.ofFloat(start, end)
+
+ /**
+ * Returns a bitmap that should be used by the lock screen as a wallpaper, if face auth requires
+ * a secure wallpaper.
+ */
+ var faceAuthWallpaper: Bitmap? = null
+ get() {
+ val user = KeyguardUpdateMonitor.getCurrentUser()
+ if (useFaceAuthWallpaper && keyguardUpdateMonitor.isFaceAuthEnabledForUser(user)) {
+ val options = BitmapFactory.Options().apply {
+ inScaled = false
+ }
+ return BitmapFactory.decodeResource(resources, R.drawable.face_auth_wallpaper, options)
+ }
+ return null
+ }
+ private set
+
+ fun attach(overlayView: View) {
+ whiteOverlay = overlayView
+ whiteOverlay.focusable = FLAG_NOT_FOCUSABLE
+ whiteOverlay.background = ColorDrawable(Color.WHITE)
+ whiteOverlay.isEnabled = false
+ whiteOverlay.alpha = 0f
+ whiteOverlay.visibility = View.INVISIBLE
+
+ dumpManager.registerDumpable(this.javaClass.name, this)
+ keyguardUpdateMonitor.registerCallback(keyguardUpdateCallback)
+ systemSettings.registerContentObserver(SCREEN_BRIGHTNESS_FLOAT,
+ object : ContentObserver(mainHandler) {
+ override fun onChange(selfChange: Boolean) {
+ userDefinedBrightness = systemSettings.getFloat(SCREEN_BRIGHTNESS_FLOAT)
+ }
+ })
+ userDefinedBrightness = systemSettings.getFloat(SCREEN_BRIGHTNESS_FLOAT)
+ }
+
+ override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
+ pw.apply {
+ println("overridingBrightness: $overridingBrightness")
+ println("useFaceAuthWallpaper: $useFaceAuthWallpaper")
+ println("brightnessAnimator: $brightnessAnimator")
+ println("brightnessAnimationDuration: $brightnessAnimationDuration")
+ println("maxScreenBrightness: $maxScreenBrightness")
+ println("userDefinedBrightness: $userDefinedBrightness")
+ }
+ }
+}
\ No newline at end of file
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 7c5dcd8..c9164f0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -16,8 +16,13 @@
package com.android.systemui.keyguard.dagger;
+import android.annotation.Nullable;
import android.app.trust.TrustManager;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.hardware.face.FaceManager;
+import android.os.Handler;
import android.os.PowerManager;
import com.android.internal.widget.LockPatternUtils;
@@ -25,16 +30,25 @@
import com.android.keyguard.KeyguardViewController;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.keyguard.FaceAuthScreenBrightnessController;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+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;
+import java.util.Optional;
import java.util.concurrent.Executor;
import dagger.Lazy;
@@ -82,4 +96,50 @@
navigationModeController,
injectionInflationController);
}
+
+ @SysUISingleton
+ @Provides
+ @Nullable
+ static KeyguardLiftController provideKeyguardLiftController(
+ Context context,
+ StatusBarStateController statusBarStateController,
+ AsyncSensorManager asyncSensorManager,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ DumpManager dumpManager) {
+ if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
+ return null;
+ }
+ return new KeyguardLiftController(statusBarStateController, asyncSensorManager,
+ keyguardUpdateMonitor, dumpManager);
+ }
+
+ @SysUISingleton
+ @Provides
+ static Optional<FaceAuthScreenBrightnessController> provideFaceAuthScreenBrightnessController(
+ Context context,
+ NotificationShadeWindowController notificationShadeWindowController,
+ @Main Resources resources,
+ Handler handler,
+ @Nullable FaceManager faceManager,
+ PackageManager packageManager,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ GlobalSettings globalSetting,
+ SystemSettings systemSettings,
+ DumpManager dumpManager) {
+ if (faceManager == null || !packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
+ return Optional.empty();
+ }
+
+ // Cameras that support "self illumination," via IR for example, don't need low light
+ // environment mitigation.
+ boolean needsLowLightMitigation = faceManager.getSensorProperties().stream()
+ .anyMatch((properties) -> !properties.supportsSelfIllumination);
+ if (!needsLowLightMitigation) {
+ return Optional.empty();
+ }
+
+ return Optional.of(new FaceAuthScreenBrightnessController(
+ notificationShadeWindowController, keyguardUpdateMonitor, resources,
+ globalSetting, systemSettings, handler, dumpManager));
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
index fdbff98..6bd5274 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
@@ -54,32 +54,35 @@
if (mediaListeners.containsKey(key)) {
return
}
- // Having an old key means that we're migrating from/to resumption. We should invalidate
- // the old listener and create a new one.
+ // Having an old key means that we're migrating from/to resumption. We should update
+ // the old listener to make sure that events will be dispatched to the new location.
val migrating = oldKey != null && key != oldKey
var wasPlaying = false
if (migrating) {
- if (mediaListeners.containsKey(oldKey)) {
- val oldListener = mediaListeners.remove(oldKey)
- wasPlaying = oldListener?.playing ?: false
- oldListener?.destroy()
+ val reusedListener = mediaListeners.remove(oldKey)
+ if (reusedListener != null) {
+ wasPlaying = reusedListener.playing ?: false
if (DEBUG) Log.d(TAG, "migrating key $oldKey to $key, for resumption")
+ reusedListener.mediaData = data
+ reusedListener.key = key
+ mediaListeners[key] = reusedListener
+ if (wasPlaying != reusedListener.playing) {
+ // If a player becomes active because of a migration, we'll need to broadcast
+ // its state. Doing it now would lead to reentrant callbacks, so let's wait
+ // until we're done.
+ mainExecutor.execute {
+ if (mediaListeners[key]?.playing == true) {
+ if (DEBUG) Log.d(TAG, "deliver delayed playback state for $key")
+ timeoutCallback.invoke(key, false /* timedOut */)
+ }
+ }
+ }
+ return
} else {
Log.w(TAG, "Old key $oldKey for player $key doesn't exist. Continuing...")
}
}
mediaListeners[key] = PlaybackStateListener(key, data)
-
- // If a player becomes active because of a migration, we'll need to broadcast its state.
- // Doing it now would lead to reentrant callbacks, so let's wait until we're done.
- if (migrating && mediaListeners[key]?.playing != wasPlaying) {
- mainExecutor.execute {
- if (mediaListeners[key]?.playing == true) {
- if (DEBUG) Log.d(TAG, "deliver delayed playback state for $key")
- timeoutCallback.invoke(key, false /* timedOut */)
- }
- }
- }
}
override fun onMediaDataRemoved(key: String) {
@@ -91,26 +94,34 @@
}
private inner class PlaybackStateListener(
- private val key: String,
+ var key: String,
data: MediaData
) : MediaController.Callback() {
var timedOut = false
var playing: Boolean? = null
+ var mediaData: MediaData = data
+ set(value) {
+ mediaController?.unregisterCallback(this)
+ field = value
+ mediaController = if (field.token != null) {
+ mediaControllerFactory.create(field.token)
+ } else {
+ null
+ }
+ mediaController?.registerCallback(this)
+ // Let's register the cancellations, but not dispatch events now.
+ // Timeouts didn't happen yet and reentrant events are troublesome.
+ processState(mediaController?.playbackState, dispatchEvents = false)
+ }
+
// Resume controls may have null token
- private val mediaController = if (data.token != null) {
- mediaControllerFactory.create(data.token)
- } else {
- null
- }
+ private var mediaController: MediaController? = null
private var cancellation: Runnable? = null
init {
- mediaController?.registerCallback(this)
- // Let's register the cancellations, but not dispatch events now.
- // Timeouts didn't happen yet and reentrant events are troublesome.
- processState(mediaController?.playbackState, dispatchEvents = false)
+ mediaData = data
}
fun destroy() {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 6c8a23b..aec3543 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -111,7 +111,6 @@
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
import com.android.systemui.navigationbar.buttons.KeyButtonView;
@@ -123,7 +122,7 @@
import com.android.systemui.recents.Recents;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.AutoHideUiElement;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
@@ -180,7 +179,7 @@
private final NavigationModeController mNavigationModeController;
private final BroadcastDispatcher mBroadcastDispatcher;
private final CommandQueue mCommandQueue;
- private final Divider mDivider;
+ private final Optional<SplitScreen> mSplitScreenOptional;
private final Optional<Recents> mRecentsOptional;
private final SystemActions mSystemActions;
private final Handler mHandler;
@@ -377,22 +376,22 @@
private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
new DeviceConfig.OnPropertiesChangedListener() {
- @Override
- public void onPropertiesChanged(DeviceConfig.Properties properties) {
- if (properties.getKeyset().contains(NAV_BAR_HANDLE_FORCE_OPAQUE)) {
- mForceNavBarHandleOpaque = properties.getBoolean(
- NAV_BAR_HANDLE_FORCE_OPAQUE, /* defaultValue = */ true);
- }
- }
- };
+ @Override
+ public void onPropertiesChanged(DeviceConfig.Properties properties) {
+ if (properties.getKeyset().contains(NAV_BAR_HANDLE_FORCE_OPAQUE)) {
+ mForceNavBarHandleOpaque = properties.getBoolean(
+ NAV_BAR_HANDLE_FORCE_OPAQUE, /* defaultValue = */ true);
+ }
+ }
+ };
private final DeviceProvisionedController.DeviceProvisionedListener mUserSetupListener =
new DeviceProvisionedController.DeviceProvisionedListener() {
- @Override
- public void onUserSetupChanged() {
- mIsCurrentUserSetup = mDeviceProvisionedController.isCurrentUserSetup();
- }
- };
+ @Override
+ public void onUserSetupChanged() {
+ mIsCurrentUserSetup = mDeviceProvisionedController.isCurrentUserSetup();
+ }
+ };
public NavigationBar(Context context,
WindowManager windowManager,
@@ -406,7 +405,8 @@
StatusBarStateController statusBarStateController,
SysUiState sysUiFlagsContainer,
BroadcastDispatcher broadcastDispatcher,
- CommandQueue commandQueue, Divider divider,
+ CommandQueue commandQueue,
+ Optional<SplitScreen> splitScreenOptional,
Optional<Recents> recentsOptional, Lazy<StatusBar> statusBarLazy,
ShadeController shadeController,
NotificationRemoteInputManager notificationRemoteInputManager,
@@ -430,7 +430,7 @@
mNavBarMode = navigationModeController.addListener(this);
mBroadcastDispatcher = broadcastDispatcher;
mCommandQueue = commandQueue;
- mDivider = divider;
+ mSplitScreenOptional = splitScreenOptional;
mRecentsOptional = recentsOptional;
mSystemActions = systemActions;
mHandler = mainHandler;
@@ -458,10 +458,10 @@
lp.windowAnimations = 0;
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
- LayoutInflater layoutInflater = LayoutInflater.from(mContext);
- NavigationBarFrame frame = (NavigationBarFrame) layoutInflater.inflate(
+ NavigationBarFrame frame = (NavigationBarFrame) LayoutInflater.from(mContext).inflate(
R.layout.navigation_bar_window, null);
- View barView = layoutInflater.inflate(R.layout.navigation_bar, frame);
+ View barView = LayoutInflater.from(frame.getContext()).inflate(
+ R.layout.navigation_bar, frame);
barView.addOnAttachStateChangeListener(this);
if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + barView);
@@ -528,6 +528,7 @@
}
mNavigationBarView.setNavigationIconHints(mNavigationIconHints);
mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
+ mSplitScreenOptional.ifPresent(mNavigationBarView::registerDockedListener);
prepareNavigationBarView();
checkNavBarModes();
@@ -559,7 +560,7 @@
setDisabled2Flags(mDisabledFlags2);
if (mIsOnDefaultDisplay) {
mAssistHandlerViewController =
- new AssistHandleViewController(mHandler, mNavigationBarView);
+ new AssistHandleViewController(mHandler, mNavigationBarView);
getBarTransitions().addDarkIntensityListener(mAssistHandlerViewController);
}
@@ -690,7 +691,8 @@
return;
}
- if (mStartingQuickSwitchRotation == -1 || mDivider.isDividerVisible()) {
+ if (mStartingQuickSwitchRotation == -1 || mSplitScreenOptional
+ .map(SplitScreen::isDividerVisible).orElse(false)) {
// Hide the secondary home handle if we are in multiwindow since apps in multiwindow
// aren't allowed to set the display orientation
resetSecondaryHandle();
@@ -1121,7 +1123,7 @@
}
mMetricsLogger.action(MetricsEvent.ACTION_ASSIST_LONG_PRESS);
mUiEventLogger.log(NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS);
- Bundle args = new Bundle();
+ Bundle args = new Bundle();
args.putInt(
AssistManager.INVOCATION_TYPE_KEY, AssistManager.INVOCATION_HOME_BUTTON_LONG_PRESS);
mAssistManagerLazy.get().startAssist(args);
@@ -1246,10 +1248,12 @@
private boolean onLongPressRecents() {
if (mRecentsOptional.isPresent() || !ActivityTaskManager.supportsMultiWindow(mContext)
- || !mDivider.getView().getSnapAlgorithm().isSplitScreenFeasible()
|| ActivityManager.isLowRamDeviceStatic()
// If we are connected to the overview service, then disable the recents button
- || mOverviewProxyService.getProxy() != null) {
+ || mOverviewProxyService.getProxy() != null
+ || !mSplitScreenOptional.map(splitScreen ->
+ splitScreen.getDividerView().getSnapAlgorithm().isSplitScreenFeasible())
+ .orElse(false)) {
return false;
}
@@ -1311,6 +1315,7 @@
/**
* Returns the system UI flags corresponding the the current accessibility button state
+ *
* @param outFeedbackEnabled if non-null, sets it to true if accessibility feedback is enabled.
*/
public int getA11yButtonState(@Nullable boolean[] outFeedbackEnabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index fd157c6..9b9dc6d 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -55,7 +55,7 @@
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -96,7 +96,7 @@
private final SysUiState mSysUiFlagsContainer;
private final BroadcastDispatcher mBroadcastDispatcher;
private final CommandQueue mCommandQueue;
- private final Divider mDivider;
+ private final Optional<SplitScreen> mSplitScreenOptional;
private final Optional<Recents> mRecentsOptional;
private final Lazy<StatusBar> mStatusBarLazy;
private final ShadeController mShadeController;
@@ -130,7 +130,7 @@
SysUiState sysUiFlagsContainer,
BroadcastDispatcher broadcastDispatcher,
CommandQueue commandQueue,
- Divider divider,
+ Optional<SplitScreen> splitScreenOptional,
Optional<Recents> recentsOptional,
Lazy<StatusBar> statusBarLazy,
ShadeController shadeController,
@@ -152,7 +152,7 @@
mSysUiFlagsContainer = sysUiFlagsContainer;
mBroadcastDispatcher = broadcastDispatcher;
mCommandQueue = commandQueue;
- mDivider = divider;
+ mSplitScreenOptional = splitScreenOptional;
mRecentsOptional = recentsOptional;
mStatusBarLazy = statusBarLazy;
mShadeController = shadeController;
@@ -278,7 +278,7 @@
mSysUiFlagsContainer,
mBroadcastDispatcher,
mCommandQueue,
- mDivider,
+ mSplitScreenOptional,
mRecentsOptional,
mStatusBarLazy,
mShadeController,
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index a335183..8a468f6e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -87,14 +87,13 @@
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.shared.system.WindowManagerWrapper;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.LightBarTransitionsController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.StatusBar;
-import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.function.Consumer;
@@ -329,8 +328,8 @@
mContextualButtonGroup.addButton(accessibilityButton);
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
- mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
mFloatingRotationButton = new FloatingRotationButton(context);
+ mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
mRotationButtonController = new RotationButtonController(mLightContext,
mLightIconColor, mDarkIconColor,
isGesturalMode ? mFloatingRotationButton : rotateSuggestionButton,
@@ -912,9 +911,6 @@
mNavigationInflaterView.setButtonDispatchers(mButtonDispatchers);
getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
-
- Divider divider = Dependency.get(Divider.class);
- divider.registerInSplitScreenListener(mDockedListener);
updateOrientationViews();
reloadNavIcons();
}
@@ -1287,6 +1283,10 @@
return super.onApplyWindowInsets(insets);
}
+ void registerDockedListener(SplitScreen splitScreen) {
+ splitScreen.registerInSplitScreenListener(mDockedListener);
+ }
+
private static void dumpButton(PrintWriter pw, String caption, ButtonDispatcher button) {
pw.print(" " + caption + ": ");
if (button == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedController.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java
rename to packages/SystemUI/src/com/android/systemui/onehanded/OneHandedController.java
index 90e7e12..bb59449 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedController.java
@@ -49,7 +49,7 @@
* Manages and manipulates the one handed states, transitions, and gesture for phones.
*/
@SysUISingleton
-public class OneHandedManagerImpl implements OneHandedManager, Dumpable {
+public class OneHandedController implements Dumpable {
private static final String TAG = "OneHandedManager";
private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE =
"persist.debug.one_handed_offset_percentage";
@@ -106,7 +106,7 @@
* Constructor of OneHandedManager
*/
@Inject
- public OneHandedManagerImpl(Context context,
+ public OneHandedController(Context context,
CommandQueue commandQueue,
DisplayController displayController,
NavigationModeController navigationModeController,
@@ -137,7 +137,7 @@
*/
// TODO(b/161980408): Should remove extra constructor.
@VisibleForTesting
- OneHandedManagerImpl(Context context,
+ OneHandedController(Context context,
CommandQueue commandQueue,
DisplayController displayController,
OneHandedDisplayAreaOrganizer displayAreaOrganizer,
@@ -194,7 +194,6 @@
/**
* Enters one handed mode.
*/
- @Override
public void startOneHanded() {
if (!mDisplayAreaOrganizer.isInOneHanded()) {
final int yOffSet = Math.round(getDisplaySize().y * mOffSetFraction);
@@ -206,7 +205,6 @@
/**
* Exits one handed mode.
*/
- @Override
public void stopOneHanded() {
if (mDisplayAreaOrganizer.isInOneHanded()) {
mDisplayAreaOrganizer.scheduleOffset(0, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java
index 1420811..f3be699 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java
@@ -103,7 +103,7 @@
}
/**
- * Notified by {@link OneHandedManager}, when user update settings of Enabled or Disabled
+ * Notified by {@link OneHandedController}, when user update settings of Enabled or Disabled
*
* @param isEnabled is one handed settings enabled or not
*/
@@ -264,7 +264,7 @@
}
/**
- * The touch(gesture) events to notify {@link OneHandedManager} start or stop one handed
+ * The touch(gesture) events to notify {@link OneHandedController} start or stop one handed
*/
public interface OneHandedGestureEventCallback {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManager.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManager.java
deleted file mode 100644
index 90187a2..0000000
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManager.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.onehanded;
-
-/**
- * The base class of OneHandedManager
- */
-public interface OneHandedManager {
-
- /**
- * Set one handed enabled or disabled
- */
- default void setOneHandedEnabled(boolean enabled) {}
-
- /**
- * Set task stack changed to exit
- */
- default void setTaskChangeToExit(boolean enabled) {}
-
- /**
- * Exit one handed mode
- */
- default void stopOneHanded() {}
-
- /**
- * Trigger one handed mode
- */
- default void startOneHanded() {}
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java
index 0a7eb1b..8265da6 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java
@@ -63,7 +63,7 @@
}
/**
- * Notified by {@link OneHandedManagerImpl}, when user update settings of Enabled or Disabled
+ * Notified by {@link OneHandedController}, when user update settings of Enabled or Disabled
*
* @param isEnabled is one handed settings enabled or not
*/
@@ -166,7 +166,7 @@
}
/**
- * The touch(gesture) events to notify {@link OneHandedManager} start or stop one handed
+ * The touch(gesture) events to notify {@link OneHandedController} start or stop one handed
*/
public interface OneHandedTouchEventCallback {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
index 8ef9b09..0354c72 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
@@ -158,9 +158,7 @@
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
mDisplaySize.x, mTutorialAreaHeight, 0, 0,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
- WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSLUCENT);
lp.gravity = Gravity.TOP | Gravity.LEFT;
lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java
index cebcd4c..3348a06 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java
@@ -59,7 +59,7 @@
"com.android.internal.systemui.onehanded.gestural";
private static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode";
- private final OneHandedManagerImpl mOneHandedManager;
+ private final OneHandedController mOneHandedController;
private final CommandQueue mCommandQueue;
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
private final IOverlayManager mOverlayManager;
@@ -74,8 +74,8 @@
OneHandedEvents.writeEvent(enabled
? OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_ENABLED_ON
: OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_ENABLED_OFF);
- if (mOneHandedManager != null) {
- mOneHandedManager.setOneHandedEnabled(enabled);
+ if (mOneHandedController != null) {
+ mOneHandedController.setOneHandedEnabled(enabled);
}
// Also checks swipe to notification settings since they all need gesture overlay.
@@ -125,8 +125,8 @@
? OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_ON
: OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_OFF);
- if (mOneHandedManager != null) {
- mOneHandedManager.setTaskChangeToExit(enabled);
+ if (mOneHandedController != null) {
+ mOneHandedController.setTaskChangeToExit(enabled);
}
}
};
@@ -138,8 +138,8 @@
final boolean enabled =
OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
mContext.getContentResolver());
- if (mOneHandedManager != null) {
- mOneHandedManager.setSwipeToNotificationEnabled(enabled);
+ if (mOneHandedController != null) {
+ mOneHandedController.setSwipeToNotificationEnabled(enabled);
}
// Also checks one handed mode settings since they all need gesture overlay.
@@ -152,14 +152,14 @@
@Inject
public OneHandedUI(Context context,
CommandQueue commandQueue,
- OneHandedManagerImpl oneHandedManager,
+ OneHandedController oneHandedController,
ScreenLifecycle screenLifecycle) {
super(context);
if (!SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) {
Log.i(TAG, "Device config SUPPORT_ONE_HANDED_MODE off");
mCommandQueue = null;
- mOneHandedManager = null;
+ mOneHandedController = null;
mOverlayManager = null;
mTimeoutHandler = null;
mScreenLifecycle = null;
@@ -167,7 +167,7 @@
}
mCommandQueue = commandQueue;
- mOneHandedManager = oneHandedManager;
+ mOneHandedController = oneHandedController;
mTimeoutHandler = OneHandedTimeoutHandler.get();
mScreenLifecycle = screenLifecycle;
mOverlayManager = IOverlayManager.Stub.asInterface(
@@ -260,13 +260,13 @@
}
private void updateSettings() {
- mOneHandedManager.setOneHandedEnabled(OneHandedSettingsUtil
+ mOneHandedController.setOneHandedEnabled(OneHandedSettingsUtil
.getSettingsOneHandedModeEnabled(mContext.getContentResolver()));
mTimeoutHandler.setTimeout(OneHandedSettingsUtil
.getSettingsOneHandedModeTimeout(mContext.getContentResolver()));
- mOneHandedManager.setTaskChangeToExit(OneHandedSettingsUtil
+ mOneHandedController.setTaskChangeToExit(OneHandedSettingsUtil
.getSettingsTapsAppToExit(mContext.getContentResolver()));
- mOneHandedManager.setSwipeToNotificationEnabled(OneHandedSettingsUtil
+ mOneHandedController.setSwipeToNotificationEnabled(OneHandedSettingsUtil
.getSettingsSwipeToNotificationEnabled(mContext.getContentResolver()));
}
@@ -295,7 +295,7 @@
* Trigger one handed more
*/
public void startOneHanded() {
- mOneHandedManager.startOneHanded();
+ mOneHandedController.startOneHanded();
OneHandedEvents.writeEvent(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_GESTURE_IN);
}
@@ -303,7 +303,7 @@
* Dismiss one handed more
*/
public void stopOneHanded() {
- mOneHandedManager.stopOneHanded();
+ mOneHandedController.stopOneHanded();
OneHandedEvents.writeEvent(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_GESTURE_OUT);
}
@@ -314,8 +314,8 @@
final String innerPrefix = " ";
pw.println(TAG + "one handed states: ");
- if (mOneHandedManager != null) {
- ((OneHandedManagerImpl) mOneHandedManager).dump(fd, pw, args);
+ if (mOneHandedController != null) {
+ mOneHandedController.dump(fd, pw, args);
}
if (mTimeoutHandler != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/dagger/OneHandedModule.java b/packages/SystemUI/src/com/android/systemui/onehanded/dagger/OneHandedModule.java
deleted file mode 100644
index fe5fa2b..0000000
--- a/packages/SystemUI/src/com/android/systemui/onehanded/dagger/OneHandedModule.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.onehanded.dagger;
-
-import com.android.systemui.onehanded.OneHandedManager;
-import com.android.systemui.onehanded.OneHandedManagerImpl;
-
-import dagger.Binds;
-import dagger.Module;
-
-/**
- * Dagger Module for One handed.
- */
-@Module
-public abstract class OneHandedModule {
-
- /** Binds OneHandedManager as the default. */
- @Binds
- public abstract OneHandedManager provideOneHandedManager(
- OneHandedManagerImpl oneHandedManagerImpl);
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
index 4931388..fd8ca80 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
@@ -31,8 +31,6 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import javax.inject.Inject;
-
/**
* Controller class of PiP animations (both from and to PiP mode).
*/
@@ -88,7 +86,6 @@
return handler;
});
- @Inject
PipAnimationController(PipSurfaceTransactionHelper helper) {
mSurfaceTransactionHelper = helper;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
index d6aa61b..b464e8ad 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
@@ -40,13 +40,10 @@
import android.window.WindowContainerTransaction;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
import java.io.PrintWriter;
-import javax.inject.Inject;
-
/**
* Handles bounds calculation for PIP on Phone and other form factors, it keeps tracking variant
* state changes originated from Window Manager and is the source of truth for PiP window bounds.
@@ -57,10 +54,8 @@
private static final String TAG = PipBoundsHandler.class.getSimpleName();
private static final float INVALID_SNAP_FRACTION = -1f;
- private final Context mContext;
private final PipSnapAlgorithm mSnapAlgorithm;
private final DisplayInfo mDisplayInfo = new DisplayInfo();
- private final DisplayController mDisplayController;
private DisplayLayout mDisplayLayout;
private ComponentName mLastPipComponentName;
@@ -82,25 +77,10 @@
private boolean mIsShelfShowing;
private int mShelfHeight;
- private final DisplayController.OnDisplaysChangedListener mDisplaysChangedListener =
- new DisplayController.OnDisplaysChangedListener() {
- @Override
- public void onDisplayAdded(int displayId) {
- if (displayId == mContext.getDisplayId()) {
- mDisplayLayout.set(mDisplayController.getDisplayLayout(displayId));
- }
- }
- };
-
- @Inject
- public PipBoundsHandler(Context context, PipSnapAlgorithm pipSnapAlgorithm,
- DisplayController displayController) {
- mContext = context;
- mSnapAlgorithm = pipSnapAlgorithm;
+ public PipBoundsHandler(Context context) {
+ mSnapAlgorithm = new PipSnapAlgorithm(context);
mDisplayLayout = new DisplayLayout();
- mDisplayController = displayController;
- mDisplayController.addDisplayWindowListener(mDisplaysChangedListener);
- reloadResources();
+ reloadResources(context);
// Initialize the aspect ratio to the default aspect ratio. Don't do this in reload
// resources as it would clobber mAspectRatio when entering PiP from fullscreen which
// triggers a configuration change and the resources to be reloaded.
@@ -110,8 +90,8 @@
/**
* TODO: move the resources to SysUI package.
*/
- private void reloadResources() {
- final Resources res = mContext.getResources();
+ private void reloadResources(Context context) {
+ final Resources res = context.getResources();
mDefaultAspectRatio = res.getFloat(
com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio);
mDefaultStackGravity = res.getInteger(
@@ -133,6 +113,19 @@
com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
}
+ /**
+ * Sets or update latest {@link DisplayLayout} when new display added or rotation callbacks
+ * from {@link DisplayController.OnDisplaysChangedListener}
+ * @param newDisplayLayout latest {@link DisplayLayout}
+ */
+ public void setDisplayLayout(DisplayLayout newDisplayLayout) {
+ mDisplayLayout.set(newDisplayLayout);
+ }
+
+ /**
+ * Update the Min edge size for {@link PipSnapAlgorithm} to calculate corresponding bounds
+ * @param minEdgeSize
+ */
public void setMinEdgeSize(int minEdgeSize) {
mCurrentMinSize = minEdgeSize;
}
@@ -217,6 +210,14 @@
return mReentrySnapFraction != INVALID_SNAP_FRACTION;
}
+ /**
+ * The {@link PipSnapAlgorithm} is couple on display bounds
+ * @return {@link PipSnapAlgorithm}.
+ */
+ public PipSnapAlgorithm getSnapAlgorithm() {
+ return mSnapAlgorithm;
+ }
+
public Rect getDisplayBounds() {
return new Rect(0, 0, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
}
@@ -237,8 +238,8 @@
/**
* Responds to IPinnedStackListener on configuration change.
*/
- public void onConfigurationChanged() {
- reloadResources();
+ public void onConfigurationChanged(Context context) {
+ reloadResources(context);
}
/**
@@ -300,10 +301,10 @@
* aren't in PIP because the rotation layout is used to calculate the proper insets for the
* next enter animation into PIP.
*/
- public void onDisplayRotationChangedNotInPip(int toRotation) {
+ public void onDisplayRotationChangedNotInPip(Context context, int toRotation) {
// Update the display layout, note that we have to do this on every rotation even if we
// aren't in PIP since we need to update the display layout to get the right resources
- mDisplayLayout.rotateTo(mContext.getResources(), toRotation);
+ mDisplayLayout.rotateTo(context.getResources(), toRotation);
// Populate the new {@link #mDisplayInfo}.
// The {@link DisplayInfo} queried from DisplayManager would be the one before rotation,
@@ -319,7 +320,8 @@
*
* @return {@code true} if internal {@link DisplayInfo} is rotated, {@code false} otherwise.
*/
- public boolean onDisplayRotationChanged(Rect outBounds, Rect oldBounds, Rect outInsetBounds,
+ public boolean onDisplayRotationChanged(Context context, Rect outBounds, Rect oldBounds,
+ Rect outInsetBounds,
int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) {
// Bail early if the event is not sent to current {@link #mDisplayInfo}
if ((displayId != mDisplayInfo.displayId) || (fromRotation == toRotation)) {
@@ -342,7 +344,7 @@
final float snapFraction = getSnapFraction(postChangeStackBounds);
// Update the display layout
- mDisplayLayout.rotateTo(mContext.getResources(), toRotation);
+ mDisplayLayout.rotateTo(context.getResources(), toRotation);
// Populate the new {@link #mDisplayInfo}.
// The {@link DisplayInfo} queried from DisplayManager would be the one before rotation,
@@ -546,5 +548,6 @@
pw.println(innerPrefix + "mImeHeight=" + mImeHeight);
pw.println(innerPrefix + "mIsShelfShowing=" + mIsShelfShowing);
pw.println(innerPrefix + "mShelfHeight=" + mShelfHeight);
+ pw.println(innerPrefix + "mSnapAlgorithm" + mSnapAlgorithm);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java b/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
index a9b32d9..5d23e42 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
@@ -22,24 +22,18 @@
import android.graphics.Rect;
import android.util.Size;
-import javax.inject.Inject;
-
/**
* Calculates the snap targets and the snap position for the PIP given a position and a velocity.
* All bounds are relative to the display top/left.
*/
public class PipSnapAlgorithm {
- private final Context mContext;
-
private final float mDefaultSizePercent;
private final float mMinAspectRatioForMinSize;
private final float mMaxAspectRatioForMinSize;
- @Inject
public PipSnapAlgorithm(Context context) {
Resources res = context.getResources();
- mContext = context;
mDefaultSizePercent = res.getFloat(
com.android.internal.R.dimen.config_pictureInPictureDefaultSizePercent);
mMaxAspectRatioForMinSize = res.getFloat(
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
index e88451c..3e98169 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
@@ -27,8 +27,6 @@
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.wm.shell.R;
-import javax.inject.Inject;
-
/**
* Abstracts the common operations on {@link SurfaceControl.Transaction} for PiP transition.
*/
@@ -46,7 +44,6 @@
private final RectF mTmpDestinationRectF = new RectF();
private final Rect mTmpDestinationRect = new Rect();
- @Inject
public PipSurfaceTransactionHelper(Context context, ConfigurationController configController) {
final Resources res = context.getResources();
mContext = context;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 0e60c83..7421ec1 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -58,8 +58,9 @@
import com.android.internal.os.SomeArgs;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.pip.phone.PipUpdateThread;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import java.io.PrintWriter;
@@ -68,10 +69,9 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import java.util.function.Consumer;
-import javax.inject.Inject;
-
/**
* Manages PiP tasks such as resize and offset.
*
@@ -84,7 +84,7 @@
* see also {@link com.android.systemui.pip.phone.PipMotionHelper}.
*/
@SysUISingleton
-public class PipTaskOrganizer extends TaskOrganizer implements
+public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganizer.TaskListener,
DisplayController.OnDisplaysChangedListener {
private static final String TAG = PipTaskOrganizer.class.getSimpleName();
private static final boolean DEBUG = false;
@@ -105,7 +105,8 @@
private final int mEnterExitAnimationDuration;
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
private final Map<IBinder, Configuration> mInitialState = new HashMap<>();
- private final Divider mSplitDivider;
+ private final Optional<SplitScreen> mSplitScreenOptional;
+ protected final ShellTaskOrganizer mTaskOrganizer;
// These callbacks are called on the update thread
private final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
@@ -205,23 +206,24 @@
*/
private boolean mShouldDeferEnteringPip;
- @Inject
public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler,
@NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
- @Nullable Divider divider,
+ Optional<SplitScreen> splitScreenOptional,
@NonNull DisplayController displayController,
- @NonNull PipAnimationController pipAnimationController,
- @NonNull PipUiEventLogger pipUiEventLogger) {
+ @NonNull PipUiEventLogger pipUiEventLogger,
+ @NonNull ShellTaskOrganizer shellTaskOrganizer) {
mMainHandler = new Handler(Looper.getMainLooper());
mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
mPipBoundsHandler = boundsHandler;
mEnterExitAnimationDuration = context.getResources()
.getInteger(R.integer.config_pipResizeAnimationDuration);
mSurfaceTransactionHelper = surfaceTransactionHelper;
- mPipAnimationController = pipAnimationController;
+ mPipAnimationController = new PipAnimationController(mSurfaceTransactionHelper);
mPipUiEventLoggerLogger = pipUiEventLogger;
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
- mSplitDivider = divider;
+ mSplitScreenOptional = splitScreenOptional;
+ mTaskOrganizer = shellTaskOrganizer;
+ mTaskOrganizer.addListener(this, WINDOWING_MODE_PINNED);
displayController.addDisplayWindowListener(this);
}
@@ -316,7 +318,7 @@
: WINDOWING_MODE_FULLSCREEN);
wct.setBounds(mToken, destinationBounds);
wct.setBoundsChangeTransaction(mToken, tx);
- applySyncTransaction(wct, new WindowContainerTransactionCallback() {
+ mTaskOrganizer.applySyncTransaction(wct, new WindowContainerTransactionCallback() {
@Override
public void onTransactionReady(int id, SurfaceControl.Transaction t) {
t.apply();
@@ -335,9 +337,11 @@
wct.setWindowingMode(mToken, getOutPipWindowingMode());
// Simply reset the activity mode set prior to the animation running.
wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
- if (mSplitDivider != null && direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
- wct.reparent(mToken, mSplitDivider.getSecondaryRoot(), true /* onTop */);
- }
+ mSplitScreenOptional.ifPresent(splitScreen -> {
+ if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
+ wct.reparent(mToken, splitScreen.getSecondaryRoot(), true /* onTop */);
+ }
+ });
}
/**
@@ -446,7 +450,7 @@
wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
wct.setBounds(mToken, destinationBounds);
wct.scheduleFinishEnterPip(mToken, destinationBounds);
- applySyncTransaction(wct, new WindowContainerTransactionCallback() {
+ mTaskOrganizer.applySyncTransaction(wct, new WindowContainerTransactionCallback() {
@Override
public void onTransactionReady(int id, SurfaceControl.Transaction t) {
t.apply();
@@ -543,11 +547,6 @@
}
@Override
- public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
- // Do nothing
- }
-
- @Override
public void onFixedRotationStarted(int displayId, int newRotation) {
mShouldDeferEnteringPip = true;
}
@@ -938,20 +937,26 @@
}
/**
- * Sync with {@link #mSplitDivider} on destination bounds if PiP is going to split screen.
+ * Sync with {@link SplitScreen} on destination bounds if PiP is going to split screen.
*
* @param destinationBoundsOut contain the updated destination bounds if applicable
* @return {@code true} if destinationBounds is altered for split screen
*/
private boolean syncWithSplitScreenBounds(Rect destinationBoundsOut) {
- if (mSplitDivider == null || !mSplitDivider.isDividerVisible()) {
- // bail early if system is not in split screen mode
+ if (!mSplitScreenOptional.isPresent()) {
return false;
}
+
+ SplitScreen splitScreen = mSplitScreenOptional.get();
+ if (!splitScreen.isDividerVisible()) {
+ // fail early if system is not in split screen mode
+ return false;
+ }
+
// PiP window will go to split-secondary mode instead of fullscreen, populates the
// split screen bounds here.
- destinationBoundsOut.set(
- mSplitDivider.getView().getNonMinimizedSplitScreenSecondaryBounds());
+ destinationBoundsOut.set(splitScreen.getDividerView()
+ .getNonMinimizedSplitScreenSecondaryBounds());
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.java b/packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.java
index 7ce2028..8bcaa8a 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.java
@@ -22,9 +22,6 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.dagger.SysUISingleton;
-import javax.inject.Inject;
-
-
/**
* Helper class that ends PiP log to UiEvent, see also go/uievent
*/
@@ -35,7 +32,6 @@
private TaskInfo mTaskInfo;
- @Inject
public PipUiEventLogger(UiEventLogger uiEventLogger) {
mUiEventLogger = uiEventLogger;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index facb396..d8864ec 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -46,7 +46,7 @@
import com.android.systemui.model.SysUiState;
import com.android.systemui.pip.BasePipManager;
import com.android.systemui.pip.PipBoundsHandler;
-import com.android.systemui.pip.PipSnapAlgorithm;
+import com.android.systemui.pip.PipSurfaceTransactionHelper;
import com.android.systemui.pip.PipTaskOrganizer;
import com.android.systemui.pip.PipUiEventLogger;
import com.android.systemui.pip.phone.dagger.PipMenuActivityClass;
@@ -56,13 +56,16 @@
import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.WindowManagerWrapper;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.FloatingContentCoordinator;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
import java.io.PrintWriter;
+import java.util.Optional;
import javax.inject.Inject;
@@ -82,15 +85,17 @@
private final Rect mTmpNormalBounds = new Rect();
protected final Rect mReentryBounds = new Rect();
- private PipBoundsHandler mPipBoundsHandler;
+ private DisplayController mDisplayController;
private InputConsumerController mInputConsumerController;
+ private PipAppOpsListener mAppOpsListener;
private PipMediaController mMediaController;
private PipTouchHandler mTouchHandler;
private PipTaskOrganizer mPipTaskOrganizer;
- private PipAppOpsListener mAppOpsListener;
+ private PipSurfaceTransactionHelper mPipSurfaceTransactionHelper;
private IPinnedStackAnimationListener mPinnedStackAnimationRecentsListener;
private boolean mIsInFixedRotation;
+ protected PipBoundsHandler mPipBoundsHandler;
protected PipMenuActivityController mMenuController;
/**
@@ -101,15 +106,16 @@
if (!mPipTaskOrganizer.isInPip() || mPipTaskOrganizer.isDeferringEnterPipAnimation()) {
// Skip if we aren't in PIP or haven't actually entered PIP yet. We still need to update
// the display layout in the bounds handler in this case.
- mPipBoundsHandler.onDisplayRotationChangedNotInPip(toRotation);
+ mPipBoundsHandler.onDisplayRotationChangedNotInPip(mContext, toRotation);
return;
}
// If there is an animation running (ie. from a shelf offset), then ensure that we calculate
// the bounds for the next orientation using the destination bounds of the animation
// TODO: Techincally this should account for movement animation bounds as well
Rect currentBounds = mPipTaskOrganizer.getCurrentOrAnimatingBounds();
- final boolean changed = mPipBoundsHandler.onDisplayRotationChanged(mTmpNormalBounds,
- currentBounds, mTmpInsetBounds, displayId, fromRotation, toRotation, t);
+ final boolean changed = mPipBoundsHandler.onDisplayRotationChanged(mContext,
+ mTmpNormalBounds, currentBounds, mTmpInsetBounds, displayId, fromRotation,
+ toRotation, t);
if (changed) {
// If the pip was in the offset zone earlier, adjust the new bounds to the bottom of the
// movement bounds
@@ -135,16 +141,22 @@
private DisplayController.OnDisplaysChangedListener mFixedRotationListener =
new DisplayController.OnDisplaysChangedListener() {
- @Override
- public void onFixedRotationStarted(int displayId, int newRotation) {
- mIsInFixedRotation = true;
- }
+ @Override
+ public void onFixedRotationStarted(int displayId, int newRotation) {
+ mIsInFixedRotation = true;
+ }
- @Override
- public void onFixedRotationFinished(int displayId) {
- mIsInFixedRotation = false;
- }
- };
+ @Override
+ public void onFixedRotationFinished(int displayId) {
+ mIsInFixedRotation = false;
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ mPipBoundsHandler.setDisplayLayout(
+ mDisplayController.getDisplayLayout(displayId));
+ }
+ };
/**
* Handler for system task stack changes.
@@ -228,7 +240,7 @@
@Override
public void onConfigurationChanged() {
- mHandler.post(() -> mPipBoundsHandler.onConfigurationChanged());
+ mHandler.post(() -> mPipBoundsHandler.onConfigurationChanged(mContext));
}
@Override
@@ -256,15 +268,14 @@
@Inject
public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
@PipMenuActivityClass Class<?> pipMenuActivityClass,
- DisplayController displayController,
- FloatingContentCoordinator floatingContentCoordinator,
- DeviceConfigProxy deviceConfig,
- PipBoundsHandler pipBoundsHandler,
- PipSnapAlgorithm pipSnapAlgorithm,
- PipTaskOrganizer pipTaskOrganizer,
- SysUiState sysUiState,
ConfigurationController configController,
- PipUiEventLogger pipUiEventLogger) {
+ DeviceConfigProxy deviceConfig,
+ DisplayController displayController,
+ Optional<SplitScreen> splitScreenOptional,
+ FloatingContentCoordinator floatingContentCoordinator,
+ SysUiState sysUiState,
+ PipUiEventLogger pipUiEventLogger,
+ ShellTaskOrganizer shellTaskOrganizer) {
mContext = context;
mActivityManager = ActivityManager.getService();
@@ -276,8 +287,12 @@
}
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
- mPipBoundsHandler = pipBoundsHandler;
- mPipTaskOrganizer = pipTaskOrganizer;
+ mDisplayController = displayController;
+ mPipBoundsHandler = new PipBoundsHandler(mContext);
+ mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(context, configController);
+ mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler,
+ mPipSurfaceTransactionHelper, splitScreenOptional, mDisplayController,
+ pipUiEventLogger, shellTaskOrganizer);
mPipTaskOrganizer.registerPipTransitionCallback(this);
mInputConsumerController = InputConsumerController.getPipInputConsumer();
mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher);
@@ -285,8 +300,7 @@
mMediaController, mInputConsumerController);
mTouchHandler = new PipTouchHandler(context, mActivityManager,
mMenuController, mInputConsumerController, mPipBoundsHandler, mPipTaskOrganizer,
- floatingContentCoordinator, deviceConfig, pipSnapAlgorithm, sysUiState,
- pipUiEventLogger);
+ floatingContentCoordinator, deviceConfig, sysUiState, pipUiEventLogger);
mAppOpsListener = new PipAppOpsListener(context, mActivityManager,
mTouchHandler.getMotionHelper());
displayController.addDisplayChangingController(mRotationController);
@@ -301,7 +315,6 @@
configController.addCallback(mOverlayChangedListener);
try {
- mPipTaskOrganizer.registerOrganizer(WINDOWING_MODE_PINNED);
ActivityManager.StackInfo stackInfo = ActivityTaskManager.getService().getStackInfo(
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
if (stackInfo != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index ecd315b..1b84c14 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -58,7 +58,6 @@
import com.android.systemui.model.SysUiState;
import com.android.systemui.pip.PipAnimationController;
import com.android.systemui.pip.PipBoundsHandler;
-import com.android.systemui.pip.PipSnapAlgorithm;
import com.android.systemui.pip.PipTaskOrganizer;
import com.android.systemui.pip.PipUiEventLogger;
import com.android.systemui.shared.system.InputConsumerController;
@@ -99,7 +98,6 @@
private IPinnedStackController mPinnedStackController;
private final PipMenuActivityController mMenuController;
- private final PipSnapAlgorithm mSnapAlgorithm;
private final AccessibilityManager mAccessibilityManager;
private boolean mShowPipMenuOnAnimationEnd = false;
@@ -216,20 +214,19 @@
PipTaskOrganizer pipTaskOrganizer,
FloatingContentCoordinator floatingContentCoordinator,
DeviceConfigProxy deviceConfig,
- PipSnapAlgorithm pipSnapAlgorithm,
SysUiState sysUiState,
PipUiEventLogger pipUiEventLogger) {
// Initialize the Pip input consumer
mContext = context;
mActivityManager = activityManager;
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
+ mPipBoundsHandler = pipBoundsHandler;
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mMenuController = menuController;
mMenuController.addListener(new PipMenuListener());
- mSnapAlgorithm = pipSnapAlgorithm;
mGesture = new DefaultPipTouchGesture();
mMotionHelper = new PipMotionHelper(mContext, pipTaskOrganizer, mMenuController,
- mSnapAlgorithm, floatingContentCoordinator);
+ mPipBoundsHandler.getSnapAlgorithm(), floatingContentCoordinator);
mPipResizeGestureHandler =
new PipResizeGestureHandler(context, pipBoundsHandler, mMotionHelper,
deviceConfig, pipTaskOrganizer, this::getMovementBounds,
@@ -248,11 +245,10 @@
inputConsumerController.setInputListener(this::handleTouchEvent);
inputConsumerController.setRegistrationListener(this::onRegistrationChanged);
- mPipBoundsHandler = pipBoundsHandler;
mFloatingContentCoordinator = floatingContentCoordinator;
mConnection = new PipAccessibilityInteractionConnection(mContext, mMotionHelper,
- pipTaskOrganizer, pipSnapAlgorithm, this::onAccessibilityShowMenu,
- this::updateMovementBounds, mHandler);
+ pipTaskOrganizer, mPipBoundsHandler.getSnapAlgorithm(),
+ this::onAccessibilityShowMenu, this::updateMovementBounds, mHandler);
mPipUiEventLogger = pipUiEventLogger;
@@ -419,7 +415,8 @@
public void adjustBoundsForRotation(Rect outBounds, Rect curBounds, Rect insetBounds) {
final Rect toMovementBounds = new Rect();
- mSnapAlgorithm.getMovementBounds(outBounds, insetBounds, toMovementBounds, 0);
+ mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(outBounds, insetBounds,
+ toMovementBounds, 0);
final int prevBottom = mMovementBounds.bottom - mMovementBoundsExtraOffsets;
if ((prevBottom - mBottomOffsetBufferPx) <= curBounds.top) {
outBounds.offsetTo(outBounds.left, toMovementBounds.bottom);
@@ -450,26 +447,26 @@
// Re-calculate the expanded bounds
mNormalBounds.set(normalBounds);
Rect normalMovementBounds = new Rect();
- mSnapAlgorithm.getMovementBounds(mNormalBounds, insetBounds, normalMovementBounds,
- bottomOffset);
+ mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(mNormalBounds, insetBounds,
+ normalMovementBounds, bottomOffset);
if (mMovementBounds.isEmpty()) {
// mMovementBounds is not initialized yet and a clean movement bounds without
// bottom offset shall be used later in this function.
- mSnapAlgorithm.getMovementBounds(curBounds, insetBounds, mMovementBounds,
- 0 /* bottomOffset */);
+ mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(curBounds, insetBounds,
+ mMovementBounds, 0 /* bottomOffset */);
}
// Calculate the expanded size
float aspectRatio = (float) normalBounds.width() / normalBounds.height();
Point displaySize = new Point();
mContext.getDisplay().getRealSize(displaySize);
- Size expandedSize = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio,
+ Size expandedSize = mPipBoundsHandler.getSnapAlgorithm().getSizeForAspectRatio(aspectRatio,
mExpandedShortestEdgeSize, displaySize.x, displaySize.y);
mExpandedBounds.set(0, 0, expandedSize.getWidth(), expandedSize.getHeight());
Rect expandedMovementBounds = new Rect();
- mSnapAlgorithm.getMovementBounds(mExpandedBounds, insetBounds, expandedMovementBounds,
- bottomOffset);
+ mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(mExpandedBounds, insetBounds,
+ expandedMovementBounds, bottomOffset);
mPipResizeGestureHandler.updateMinSize(mNormalBounds.width(), mNormalBounds.height());
mPipResizeGestureHandler.updateMaxSize(mExpandedBounds.width(), mExpandedBounds.height());
@@ -489,7 +486,7 @@
} else {
final boolean isExpanded = mMenuState == MENU_STATE_FULL && willResizeMenu();
final Rect toMovementBounds = new Rect();
- mSnapAlgorithm.getMovementBounds(curBounds, insetBounds,
+ mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(curBounds, insetBounds,
toMovementBounds, mIsImeShowing ? mImeHeight : 0);
final int prevBottom = mMovementBounds.bottom - mMovementBoundsExtraOffsets;
// This is to handle landscape fullscreen IMEs, don't apply the extra offset in this
@@ -500,8 +497,8 @@
if (isExpanded) {
curBounds.set(mExpandedBounds);
- mSnapAlgorithm.applySnapFraction(curBounds, toMovementBounds,
- mSavedSnapFraction);
+ mPipBoundsHandler.getSnapAlgorithm().applySnapFraction(curBounds,
+ toMovementBounds, mSavedSnapFraction);
}
if (prevBottom < toBottom) {
@@ -608,7 +605,7 @@
.spring(DynamicAnimation.TRANSLATION_Y,
mTargetViewContainer.getHeight(),
mTargetSpringConfig)
- .withEndActions(() -> mTargetViewContainer.setVisibility(View.GONE))
+ .withEndActions(() -> mTargetViewContainer.setVisibility(View.GONE))
.start();
((TransitionDrawable) mTargetViewContainer.getBackground()).reverseTransition(
@@ -844,8 +841,8 @@
if (mDeferResizeToNormalBoundsUntilRotation == -1) {
Rect restoreBounds = new Rect(getUserResizeBounds());
Rect restoredMovementBounds = new Rect();
- mSnapAlgorithm.getMovementBounds(restoreBounds, mInsetBounds,
- restoredMovementBounds, mIsImeShowing ? mImeHeight : 0);
+ mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(restoreBounds,
+ mInsetBounds, restoredMovementBounds, mIsImeShowing ? mImeHeight : 0);
mMotionHelper.animateToUnexpandedState(restoreBounds, mSavedSnapFraction,
restoredMovementBounds, mMovementBounds, false /* immediate */);
mSavedSnapFraction = -1f;
@@ -1025,25 +1022,25 @@
mMenuController.hideMenu();
}
}
- };
+ }
/**
* Updates the current movement bounds based on whether the menu is currently visible and
* resized.
*/
private void updateMovementBounds() {
- mSnapAlgorithm.getMovementBounds(mMotionHelper.getBounds(), mInsetBounds,
- mMovementBounds, mIsImeShowing ? mImeHeight : 0);
+ mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(mMotionHelper.getBounds(),
+ mInsetBounds, mMovementBounds, mIsImeShowing ? mImeHeight : 0);
mMotionHelper.setCurrentMovementBounds(mMovementBounds);
boolean isMenuExpanded = mMenuState == MENU_STATE_FULL;
mPipBoundsHandler.setMinEdgeSize(
- isMenuExpanded && willResizeMenu() ? mExpandedShortestEdgeSize : 0);
+ isMenuExpanded && willResizeMenu() ? mExpandedShortestEdgeSize : 0);
}
private Rect getMovementBounds(Rect curBounds) {
Rect movementBounds = new Rect();
- mSnapAlgorithm.getMovementBounds(curBounds, mInsetBounds,
+ mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(curBounds, mInsetBounds,
movementBounds, mIsImeShowing ? mImeHeight : 0);
return movementBounds;
}
@@ -1075,6 +1072,7 @@
pw.println(innerPrefix + "mSavedSnapFraction=" + mSavedSnapFraction);
pw.println(innerPrefix + "mEnableDragToEdgeDismiss=" + mEnableDismissDragToEdge);
pw.println(innerPrefix + "mMovementBoundsExtraOffsets=" + mMovementBoundsExtraOffsets);
+ mPipBoundsHandler.dump(pw, innerPrefix);
mTouchState.dump(pw, innerPrefix);
mMotionHelper.dump(pw, innerPrefix);
if (mPipResizeGestureHandler != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 74dc003..8d0948b 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -20,6 +20,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import android.annotation.NonNull;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityTaskManager;
@@ -54,14 +55,19 @@
import com.android.systemui.pip.PipBoundsHandler;
import com.android.systemui.pip.PipSurfaceTransactionHelper;
import com.android.systemui.pip.PipTaskOrganizer;
+import com.android.systemui.pip.PipUiEventLogger;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.WindowManagerWrapper;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayController;
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
import javax.inject.Inject;
@@ -111,6 +117,7 @@
private Context mContext;
private PipBoundsHandler mPipBoundsHandler;
private PipTaskOrganizer mPipTaskOrganizer;
+ private PipSurfaceTransactionHelper mPipSurfaceTransactionHelper;
private IActivityTaskManager mActivityTaskManager;
private MediaSessionManager mMediaSessionManager;
private int mState = STATE_NO_PIP;
@@ -229,17 +236,18 @@
@Inject
public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
- PipBoundsHandler pipBoundsHandler,
- PipTaskOrganizer pipTaskOrganizer,
- PipSurfaceTransactionHelper surfaceTransactionHelper,
- Divider divider) {
+ ConfigurationController configController,
+ DisplayController displayController,
+ Optional<SplitScreen> splitScreenOptional,
+ @NonNull PipUiEventLogger pipUiEventLogger,
+ ShellTaskOrganizer shellTaskOrganizer) {
if (mInitialized) {
return;
}
mInitialized = true;
mContext = context;
- mPipBoundsHandler = pipBoundsHandler;
+ mPipBoundsHandler = new PipBoundsHandler(mContext);
// Ensure that we have the display info in case we get calls to update the bounds before the
// listener calls back
final DisplayInfo displayInfo = new DisplayInfo();
@@ -248,7 +256,10 @@
mResizeAnimationDuration = context.getResources()
.getInteger(R.integer.config_pipResizeAnimationDuration);
- mPipTaskOrganizer = pipTaskOrganizer;
+ mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(context, configController);
+ mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler,
+ mPipSurfaceTransactionHelper, splitScreenOptional, displayController,
+ pipUiEventLogger, shellTaskOrganizer);
mPipTaskOrganizer.registerPipTransitionCallback(this);
mActivityTaskManager = ActivityTaskManager.getService();
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
@@ -267,7 +278,6 @@
try {
WindowManagerWrapper.getInstance().addPinnedStackListener(mPinnedStackListener);
- mPipTaskOrganizer.registerOrganizer(WINDOWING_MODE_PINNED);
} catch (RemoteException | UnsupportedOperationException e) {
Log.e(TAG, "Failed to register pinned stack listener", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
index 255ba1b..e57478e 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
@@ -57,7 +57,8 @@
@VisibleForTesting
internal companion object {
val OPS_MIC_CAMERA = intArrayOf(AppOpsManager.OP_CAMERA,
- AppOpsManager.OP_RECORD_AUDIO)
+ AppOpsManager.OP_PHONE_CALL_CAMERA, AppOpsManager.OP_RECORD_AUDIO,
+ AppOpsManager.OP_PHONE_CALL_MICROPHONE)
val OPS_LOCATION = intArrayOf(
AppOpsManager.OP_COARSE_LOCATION,
AppOpsManager.OP_FINE_LOCATION)
@@ -248,9 +249,11 @@
private fun toPrivacyItem(appOpItem: AppOpItem): PrivacyItem? {
val type: PrivacyType = when (appOpItem.code) {
+ AppOpsManager.OP_PHONE_CALL_CAMERA,
AppOpsManager.OP_CAMERA -> PrivacyType.TYPE_CAMERA
- AppOpsManager.OP_COARSE_LOCATION -> PrivacyType.TYPE_LOCATION
+ AppOpsManager.OP_COARSE_LOCATION,
AppOpsManager.OP_FINE_LOCATION -> PrivacyType.TYPE_LOCATION
+ AppOpsManager.OP_PHONE_CALL_MICROPHONE,
AppOpsManager.OP_RECORD_AUDIO -> PrivacyType.TYPE_MICROPHONE
else -> return null
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
index 0347867..1a7e229 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
@@ -38,7 +38,7 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.phone.StatusBar;
import java.util.Optional;
@@ -56,7 +56,7 @@
private final static String TAG = "OverviewProxyRecentsImpl";
@Nullable
private final Lazy<StatusBar> mStatusBarLazy;
- private final Optional<Divider> mDividerOptional;
+ private final Optional<SplitScreen> mSplitScreenOptional;
private Context mContext;
private Handler mHandler;
@@ -66,9 +66,9 @@
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Inject
public OverviewProxyRecentsImpl(Optional<Lazy<StatusBar>> statusBarLazy,
- Optional<Divider> dividerOptional) {
+ Optional<SplitScreen> splitScreenOptional) {
mStatusBarLazy = statusBarLazy.orElse(null);
- mDividerOptional = dividerOptional;
+ mSplitScreenOptional = splitScreenOptional;
}
@Override
@@ -163,12 +163,12 @@
if (runningTask.supportsSplitScreenMultiWindow) {
if (ActivityManagerWrapper.getInstance().setTaskWindowingModeSplitScreenPrimary(
runningTask.id, stackCreateMode, initialBounds)) {
- mDividerOptional.ifPresent(Divider::onDockedTopTask);
-
- // The overview service is handling split screen, so just skip the wait for the
- // first draw and notify the divider to start animating now
- mDividerOptional.ifPresent(Divider::onRecentsDrawn);
-
+ mSplitScreenOptional.ifPresent(splitScreen -> {
+ splitScreen.onDockedTopTask();
+ // The overview service is handling split screen, so just skip the wait
+ // for the first draw and notify the divider to start animating now
+ splitScreen.onRecentsDrawn();
+ });
return true;
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index e931a6b..c0cc586 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -86,7 +86,7 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -123,7 +123,7 @@
private final Context mContext;
private final PipUI mPipUI;
private final Optional<Lazy<StatusBar>> mStatusBarOptionalLazy;
- private final Optional<Divider> mDividerOptional;
+ private final Optional<SplitScreen> mSplitScreenOptional;
private SysUiState mSysUiState;
private final Handler mHandler;
private final Lazy<NavigationBarController> mNavBarControllerLazy;
@@ -232,7 +232,9 @@
}
long token = Binder.clearCallingIdentity();
try {
- mDividerOptional.ifPresent(Divider::onDockedFirstAnimationFrame);
+ mSplitScreenOptional.ifPresent(splitScreen -> {
+ splitScreen.onDockedFirstAnimationFrame();
+ });
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -262,8 +264,8 @@
}
long token = Binder.clearCallingIdentity();
try {
- return mDividerOptional.map(
- divider -> divider.getView().getNonMinimizedSplitScreenSecondaryBounds())
+ return mSplitScreenOptional.map(splitScreen ->
+ splitScreen.getDividerView().getNonMinimizedSplitScreenSecondaryBounds())
.orElse(null);
} finally {
Binder.restoreCallingIdentity(token);
@@ -399,10 +401,8 @@
@Override
public void setSplitScreenMinimized(boolean minimized) {
- Divider divider = mDividerOptional.get();
- if (divider != null) {
- divider.setMinimized(minimized);
- }
+ mSplitScreenOptional.ifPresent(
+ splitScreen -> splitScreen.setMinimized(minimized));
}
@Override
@@ -602,7 +602,7 @@
public OverviewProxyService(Context context, CommandQueue commandQueue,
Lazy<NavigationBarController> navBarControllerLazy, NavigationModeController navModeController,
NotificationShadeWindowController statusBarWinController, SysUiState sysUiState,
- PipUI pipUI, Optional<Divider> dividerOptional,
+ PipUI pipUI, Optional<SplitScreen> splitScreenOptional,
Optional<Lazy<StatusBar>> statusBarOptionalLazy, OneHandedUI oneHandedUI,
BroadcastDispatcher broadcastDispatcher) {
super(broadcastDispatcher);
@@ -613,7 +613,7 @@
mNavBarControllerLazy = navBarControllerLazy;
mStatusBarWinController = statusBarWinController;
mConnectionBackoffAttempts = 0;
- mDividerOptional = dividerOptional;
+ mSplitScreenOptional = splitScreenOptional;
mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
com.android.internal.R.string.config_recentsComponentName));
mQuickStepIntent = new Intent(ACTION_QUICKSTEP)
@@ -755,10 +755,8 @@
startConnectionToCurrentUser();
// Clean up the minimized state if launcher dies
- Divider divider = mDividerOptional.get();
- if (divider != null) {
- divider.setMinimized(false);
- }
+ mSplitScreenOptional.ifPresent(
+ splitScreen -> splitScreen.setMinimized(false));
}
public void startConnectionToCurrentUser() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
index 1d29ac6..a641730 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
@@ -35,7 +35,6 @@
default void showRecentApps(boolean triggeredFromAltTab) {}
default void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {}
default void toggleRecentApps() {}
- default void growRecents() {}
default boolean splitPrimaryTask(int stackCreateMode, Rect initialBounds,
int metricsDockAction) {
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 469c4a7..8ec3db5 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -21,7 +21,6 @@
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
@@ -70,7 +69,6 @@
private static final String ACTION_STOP_NOTIF =
"com.android.systemui.screenrecord.STOP_FROM_NOTIF";
private static final String ACTION_SHARE = "com.android.systemui.screenrecord.SHARE";
- private static final String ACTION_DELETE = "com.android.systemui.screenrecord.DELETE";
private final RecordingController mController;
private final KeyguardDismissUtil mKeyguardDismissUtil;
@@ -184,25 +182,6 @@
// Close quick shade
sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
break;
- case ACTION_DELETE:
- mKeyguardDismissUtil.executeWhenUnlocked(() -> {
- // Close quick shade
- sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
- ContentResolver resolver = getContentResolver();
- Uri uri = Uri.parse(intent.getStringExtra(EXTRA_PATH));
- resolver.delete(uri, null, null);
-
- Toast.makeText(
- this,
- R.string.screenrecord_delete_description,
- Toast.LENGTH_LONG).show();
- Log.d(TAG, "Deleted recording " + uri);
-
- // Remove notification
- mNotificationManager.cancelAsUser(null, NOTIFICATION_VIEW_ID, currentUser);
- return false;
- }, false);
- break;
}
return Service.START_STICKY;
}
@@ -312,16 +291,6 @@
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
.build();
- Notification.Action deleteAction = new Notification.Action.Builder(
- Icon.createWithResource(this, R.drawable.ic_screenrecord),
- getResources().getString(R.string.screenrecord_delete_label),
- PendingIntent.getService(
- this,
- REQUEST_CODE,
- getDeleteIntent(this, uri.toString()),
- PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
- .build();
-
Bundle extras = new Bundle();
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
getResources().getString(R.string.screenrecord_name));
@@ -335,7 +304,6 @@
viewIntent,
PendingIntent.FLAG_IMMUTABLE))
.addAction(shareAction)
- .addAction(deleteAction)
.setAutoCancel(true)
.addExtras(extras);
@@ -414,11 +382,6 @@
.putExtra(EXTRA_PATH, path);
}
- private static Intent getDeleteIntent(Context context, String path) {
- return new Intent(context, RecordingService.class).setAction(ACTION_DELETE)
- .putExtra(EXTRA_PATH, path);
- }
-
@Override
public void onInfo(MediaRecorder mr, int what, int extra) {
Log.d(TAG, "Media recorder info: " + what);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
index 20fa991..6b42f2e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
@@ -22,6 +22,7 @@
import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_OTHER;
import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_OTHER;
import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_OVERVIEW;
+import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_VENDOR_GESTURE;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
@@ -37,6 +38,8 @@
SCREENSHOT_REQUESTED_OVERVIEW(304),
@UiEvent(doc = "screenshot requested from accessibility actions")
SCREENSHOT_REQUESTED_ACCESSIBILITY_ACTIONS(382),
+ @UiEvent(doc = "screenshot requested from vendor gesture")
+ SCREENSHOT_REQUESTED_VENDOR_GESTURE(638),
@UiEvent(doc = "screenshot requested (other)")
SCREENSHOT_REQUESTED_OTHER(305),
@UiEvent(doc = "screenshot was saved")
@@ -81,6 +84,8 @@
return ScreenshotEvent.SCREENSHOT_REQUESTED_OVERVIEW;
case SCREENSHOT_ACCESSIBILITY_ACTIONS:
return ScreenshotEvent.SCREENSHOT_REQUESTED_ACCESSIBILITY_ACTIONS;
+ case SCREENSHOT_VENDOR_GESTURE:
+ return ScreenshotEvent.SCREENSHOT_REQUESTED_VENDOR_GESTURE;
case SCREENSHOT_OTHER:
default:
return ScreenshotEvent.SCREENSHOT_REQUESTED_OTHER;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
new file mode 100644
index 0000000..91ef3c3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot.dagger;
+
+import android.app.Service;
+
+import com.android.systemui.screenshot.TakeScreenshotService;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.multibindings.ClassKey;
+import dagger.multibindings.IntoMap;
+
+/**
+ * Defines injectable resources for Screenshots
+ */
+@Module
+public abstract class ScreenshotModule {
+
+ /** */
+ @Binds
+ @IntoMap
+ @ClassKey(TakeScreenshotService.class)
+ public abstract Service bindTakeScreenshotService(TakeScreenshotService service);
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
index ee3303b..0d92d1e 100644
--- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
@@ -30,8 +30,10 @@
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.recents.Recents;
-import com.android.systemui.stackdivider.Divider;
import com.android.systemui.stackdivider.DividerView;
+import com.android.systemui.stackdivider.SplitScreen;
+
+import java.util.Optional;
import javax.inject.Inject;
@@ -43,7 +45,7 @@
implements ShortcutKeyServiceProxy.Callbacks {
private static final String TAG = "ShortcutKeyDispatcher";
- private final Divider mDivider;
+ private final Optional<SplitScreen> mSplitScreenOptional;
private final Recents mRecents;
private ShortcutKeyServiceProxy mShortcutKeyServiceProxy = new ShortcutKeyServiceProxy(this);
@@ -58,14 +60,16 @@
protected final long SC_DOCK_RIGHT = META_MASK | KeyEvent.KEYCODE_RIGHT_BRACKET;
@Inject
- public ShortcutKeyDispatcher(Context context, Divider divider, Recents recents) {
+ public ShortcutKeyDispatcher(Context context,
+ Optional<SplitScreen> splitScreenOptional, Recents recents) {
super(context);
- mDivider = divider;
+ mSplitScreenOptional = splitScreenOptional;
mRecents = recents;
}
/**
* Registers a shortcut key to window manager.
+ *
* @param shortcutCode packed representation of shortcut key code and meta information
*/
public void registerShortcutKey(long shortcutCode) {
@@ -92,24 +96,28 @@
}
private void handleDockKey(long shortcutCode) {
- if (mDivider == null || !mDivider.isDividerVisible()) {
- // Split the screen
- mRecents.splitPrimaryTask((shortcutCode == SC_DOCK_LEFT)
- ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
- : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, null, -1);
- } else {
- // If there is already a docked window, we respond by resizing the docking pane.
- DividerView dividerView = mDivider.getView();
- DividerSnapAlgorithm snapAlgorithm = dividerView.getSnapAlgorithm();
- int dividerPosition = dividerView.getCurrentPosition();
- DividerSnapAlgorithm.SnapTarget currentTarget =
- snapAlgorithm.calculateNonDismissingSnapTarget(dividerPosition);
- DividerSnapAlgorithm.SnapTarget target = (shortcutCode == SC_DOCK_LEFT)
- ? snapAlgorithm.getPreviousTarget(currentTarget)
- : snapAlgorithm.getNextTarget(currentTarget);
- dividerView.startDragging(true /* animate */, false /* touching */);
- dividerView.stopDragging(target.position, 0f, false /* avoidDismissStart */,
- true /* logMetrics */);
+ if (mSplitScreenOptional.isPresent()) {
+ SplitScreen splitScreen = mSplitScreenOptional.get();
+ if (splitScreen.isDividerVisible()) {
+ // If there is already a docked window, we respond by resizing the docking pane.
+ DividerView dividerView = splitScreen.getDividerView();
+ DividerSnapAlgorithm snapAlgorithm = dividerView.getSnapAlgorithm();
+ int dividerPosition = dividerView.getCurrentPosition();
+ DividerSnapAlgorithm.SnapTarget currentTarget =
+ snapAlgorithm.calculateNonDismissingSnapTarget(dividerPosition);
+ DividerSnapAlgorithm.SnapTarget target = (shortcutCode == SC_DOCK_LEFT)
+ ? snapAlgorithm.getPreviousTarget(currentTarget)
+ : snapAlgorithm.getNextTarget(currentTarget);
+ dividerView.startDragging(true /* animate */, false /* touching */);
+ dividerView.stopDragging(target.position, 0f, false /* avoidDismissStart */,
+ true /* logMetrics */);
+ return;
+ }
}
+
+ // Split the screen
+ mRecents.splitPrimaryTask((shortcutCode == SC_DOCK_LEFT)
+ ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
+ : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, null, -1);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
deleted file mode 100644
index e9c880e..0000000
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.stackdivider;
-
-import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.window.WindowContainerToken;
-
-import com.android.systemui.SystemUI;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.TaskStackChangeListener;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.function.Consumer;
-
-/**
- * Controls the docked stack divider.
- */
-@SysUISingleton
-public class Divider extends SystemUI {
- private final KeyguardStateController mKeyguardStateController;
- private final DividerController mDividerController;
-
- Divider(Context context, DividerController dividerController,
- KeyguardStateController keyguardStateController) {
- super(context);
- mDividerController = dividerController;
- mKeyguardStateController = keyguardStateController;
- }
-
- @Override
- public void start() {
- mDividerController.start();
- // Hide the divider when keyguard is showing. Even though keyguard/statusbar is above
- // everything, it is actually transparent except for notifications, so we still need to
- // hide any surfaces that are below it.
- // TODO(b/148906453): Figure out keyguard dismiss animation for divider view.
- mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
- @Override
- public void onKeyguardShowingChanged() {
- mDividerController.onKeyguardShowingChanged(mKeyguardStateController.isShowing());
- }
- });
- // Don't initialize the divider or anything until we get the default display.
-
- ActivityManagerWrapper.getInstance().registerTaskStackListener(
- new TaskStackChangeListener() {
- @Override
- public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
- boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
- if (!wasVisible || task.configuration.windowConfiguration.getWindowingMode()
- != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- || !mDividerController.isSplitScreenSupported()) {
- return;
- }
-
- if (mDividerController.isMinimized()) {
- onUndockingTask();
- }
- }
-
- @Override
- public void onActivityForcedResizable(String packageName, int taskId,
- int reason) {
- mDividerController.onActivityForcedResizable(packageName, taskId, reason);
- }
-
- @Override
- public void onActivityDismissingDockedStack() {
- mDividerController.onActivityDismissingSplitScreen();
- }
-
- @Override
- public void onActivityLaunchOnSecondaryDisplayFailed() {
- mDividerController.onActivityLaunchOnSecondaryDisplayFailed();
- }
- }
- );
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- mDividerController.dump(pw);
- }
-
- /** Switch to minimized state if appropriate. */
- public void setMinimized(final boolean minimized) {
- mDividerController.setMinimized(minimized);
- }
-
- public boolean isMinimized() {
- return mDividerController.isMinimized();
- }
-
- public boolean isHomeStackResizable() {
- return mDividerController.isHomeStackResizable();
- }
-
- /** Callback for undocking task. */
- public void onUndockingTask() {
- mDividerController.onUndockingTask();
- }
-
- public void onRecentsDrawn() {
- mDividerController.onRecentsDrawn();
- }
-
- public void onDockedFirstAnimationFrame() {
- mDividerController.onDockedFirstAnimationFrame();
- }
-
- public void onDockedTopTask() {
- mDividerController.onDockedTopTask();
- }
-
- public void onAppTransitionFinished() {
- mDividerController.onAppTransitionFinished();
- }
-
- public DividerView getView() {
- return mDividerController.getDividerView();
- }
-
- /** @return the container token for the secondary split root task. */
- public WindowContainerToken getSecondaryRoot() {
- return mDividerController.getSecondaryRoot();
- }
-
- /** Register a listener that gets called whenever the existence of the divider changes */
- public void registerInSplitScreenListener(Consumer<Boolean> listener) {
- mDividerController.registerInSplitScreenListener(listener);
- }
-
- /** {@code true} if this is visible */
- public boolean isDividerVisible() {
- return mDividerController.isDividerVisible();
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
index c915f07..64ee7ed5 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
@@ -38,7 +38,7 @@
class DividerImeController implements DisplayImeController.ImePositionProcessor {
private static final String TAG = "DividerImeController";
- private static final boolean DEBUG = DividerController.DEBUG;
+ private static final boolean DEBUG = SplitScreenController.DEBUG;
private static final float ADJUSTED_NONFOCUS_DIM = 0.3f;
@@ -100,15 +100,15 @@
}
private DividerView getView() {
- return mSplits.mDividerController.getDividerView();
+ return mSplits.mSplitScreenController.getDividerView();
}
private SplitDisplayLayout getLayout() {
- return mSplits.mDividerController.getSplitLayout();
+ return mSplits.mSplitScreenController.getSplitLayout();
}
private boolean isDividerVisible() {
- return mSplits.mDividerController.isDividerVisible();
+ return mSplits.mSplitScreenController.isDividerVisible();
}
private boolean getSecondaryHasFocus(int displayId) {
@@ -151,7 +151,7 @@
mSecondaryHasFocus = getSecondaryHasFocus(displayId);
final boolean targetAdjusted = splitIsVisible && imeShouldShow && mSecondaryHasFocus
&& !imeIsFloating && !getLayout().mDisplayLayout.isLandscape()
- && !mSplits.mDividerController.isMinimized();
+ && !mSplits.mSplitScreenController.isMinimized();
if (mLastAdjustTop < 0) {
mLastAdjustTop = imeShouldShow ? hiddenTop : shownTop;
} else if (mLastAdjustTop != (imeShouldShow ? mShownTop : mHiddenTop)) {
@@ -236,7 +236,7 @@
SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
}
- if (!mSplits.mDividerController.getWmProxy().queueSyncTransactionIfWaiting(wct)) {
+ if (!mSplits.mSplitScreenController.getWmProxy().queueSyncTransactionIfWaiting(wct)) {
WindowOrganizer.applyTransaction(wct);
}
}
@@ -250,7 +250,7 @@
: DisplayImeController.ANIMATION_DURATION_HIDE_MS);
}
}
- mSplits.mDividerController.setAdjustedForIme(mTargetShown && !mPaused);
+ mSplits.mSplitScreenController.setAdjustedForIme(mTargetShown && !mPaused);
}
public void updateAdjustForIme() {
@@ -402,7 +402,7 @@
mTargetAdjusted = mPausedTargetAdjusted;
updateDimTargets();
final DividerView view = getView();
- if ((mTargetAdjusted != mAdjusted) && !mSplits.mDividerController.isMinimized()
+ if ((mTargetAdjusted != mAdjusted) && !mSplits.mSplitScreenController.isMinimized()
&& view != null) {
// End unminimize animations since they conflict with adjustment animations.
view.finishAnimations();
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java
deleted file mode 100644
index 9c21397..0000000
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.stackdivider;
-
-import android.content.Context;
-import android.os.Handler;
-
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.DisplayImeController;
-import com.android.wm.shell.common.SystemWindows;
-import com.android.wm.shell.common.TransactionPool;
-
-import dagger.Module;
-import dagger.Provides;
-
-/**
- * Module which provides a Divider.
- */
-@Module
-public class DividerModule {
- @SysUISingleton
- @Provides
- static Divider provideDivider(Context context, DisplayController displayController,
- SystemWindows systemWindows, DisplayImeController imeController, @Main Handler handler,
- KeyguardStateController keyguardStateController, TransactionPool transactionPool) {
- // TODO(b/161116823): fetch DividerProxy from WM shell lib.
- DividerController dividerController = new DividerController(context, displayController,
- systemWindows, imeController, handler, transactionPool);
- return new Divider(context, dividerController, keyguardStateController);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index e5c02d6..95f048b 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -76,7 +76,7 @@
public class DividerView extends FrameLayout implements OnTouchListener,
OnComputeInternalInsetsListener {
private static final String TAG = "DividerView";
- private static final boolean DEBUG = DividerController.DEBUG;
+ private static final boolean DEBUG = SplitScreenController.DEBUG;
public interface DividerCallbacks {
void onDraggingStart();
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
index ff8bab0..4c26694 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
@@ -69,9 +69,9 @@
}
public ForcedResizableInfoActivityController(Context context,
- DividerController dividerController) {
+ SplitScreenController splitScreenController) {
mContext = context;
- dividerController.registerInSplitScreenListener(mDockedStackExistsListener);
+ splitScreenController.registerInSplitScreenListener(mDockedStackExistsListener);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreen.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreen.java
new file mode 100644
index 0000000..91850cc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreen.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.stackdivider;
+
+import android.window.WindowContainerToken;
+
+import java.io.PrintWriter;
+import java.util.function.Consumer;
+
+/**
+ * Interface to engage split screen feature.
+ */
+public interface SplitScreen {
+ /** Returns {@code true} if split screen is supported on the device. */
+ boolean isSplitScreenSupported();
+
+ /** Called when keyguard showing state changed. */
+ void onKeyguardVisibilityChanged(boolean isShowing);
+
+ /** Returns {@link DividerView}. */
+ DividerView getDividerView();
+
+ /** Returns {@code true} if one of the split screen is in minimized mode. */
+ boolean isMinimized();
+
+ /** Returns {@code true} if the home stack is resizable. */
+ boolean isHomeStackResizable();
+
+ /** Returns {@code true} if the divider is visible. */
+ boolean isDividerVisible();
+
+ /** Switch to minimized state if appropriate. */
+ void setMinimized(boolean minimized);
+
+ /**
+ * Workaround for b/62528361, at the time recents has drawn, it may happen before a
+ * configuration change to the Divider, and internally, the event will be posted to the
+ * subscriber, or DividerView, which has been removed and prevented from resizing. Instead,
+ * register the event handler here and proxy the event to the current DividerView.
+ */
+ void onRecentsDrawn();
+
+ /** Called when there's an activity forced resizable. */
+ void onActivityForcedResizable(String packageName, int taskId, int reason);
+
+ /** Called when there's an activity dismissing split screen. */
+ void onActivityDismissingSplitScreen();
+
+ /** Called when there's an activity launch on secondary display failed. */
+ void onActivityLaunchOnSecondaryDisplayFailed();
+
+ /** Called when there's a task undocking. */
+ void onUndockingTask();
+
+ /** Called when the first docked animation frame rendered. */
+ void onDockedFirstAnimationFrame();
+
+ /** Called when top task docked. */
+ void onDockedTopTask();
+
+ /** Called when app transition finished. */
+ void onAppTransitionFinished();
+
+ /** Dumps current status of Split Screen. */
+ void dump(PrintWriter pw);
+
+ /** Registers listener that gets called whenever the existence of the divider changes. */
+ void registerInSplitScreenListener(Consumer<Boolean> listener);
+
+ /** @return the container token for the secondary split root task. */
+ WindowContainerToken getSecondaryRoot();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenController.java
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java
rename to packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenController.java
index 1ee8abb..11773f6 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenController.java
@@ -35,6 +35,7 @@
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.systemui.R;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
@@ -48,26 +49,34 @@
import java.util.function.Consumer;
/**
- * Controls the docked stack divider.
+ * Controls split screen feature.
*/
-public class DividerController implements DisplayController.OnDisplaysChangedListener {
+public class SplitScreenController implements SplitScreen,
+ DisplayController.OnDisplaysChangedListener {
static final boolean DEBUG = false;
- private static final String TAG = "Divider";
- static final int DEFAULT_APP_TRANSITION_DURATION = 336;
+ private static final String TAG = "Divider";
+ private static final int DEFAULT_APP_TRANSITION_DURATION = 336;
+
+ private final Context mContext;
+ private final DisplayChangeController.OnDisplayChangingListener mRotationController;
+ private final DisplayController mDisplayController;
+ private final DisplayImeController mImeController;
+ private final DividerImeController mImePositionProcessor;
+ private final DividerState mDividerState = new DividerState();
+ private final ForcedResizableInfoActivityController mForcedResizableController;
+ private final Handler mHandler;
+ private final SplitScreenTaskOrganizer mSplits;
+ private final SystemWindows mSystemWindows;
+ final TransactionPool mTransactionPool;
+ private final WindowManagerProxy mWindowManagerProxy;
+
+ private final ArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners =
+ new ArrayList<>();
+
private DividerWindowManager mWindowManager;
private DividerView mView;
- private final DividerState mDividerState = new DividerState();
- private boolean mVisible = false;
- private boolean mMinimized = false;
- private boolean mAdjustedForIme = false;
- private boolean mHomeStackResizable = false;
- private ForcedResizableInfoActivityController mForcedResizableController;
- private SystemWindows mSystemWindows;
- private DisplayController mDisplayController;
- private DisplayImeController mImeController;
- final TransactionPool mTransactionPool;
// Keeps track of real-time split geometry including snap positions and ime adjustments
private SplitDisplayLayout mSplitLayout;
@@ -77,21 +86,16 @@
// layout that we sent back to WM.
private SplitDisplayLayout mRotateSplitLayout;
- private final Handler mHandler;
- private final WindowManagerProxy mWindowManagerProxy;
-
- private final ArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners =
- new ArrayList<>();
-
- private final SplitScreenTaskOrganizer mSplits;
- private final DisplayChangeController.OnDisplayChangingListener mRotationController;
- private final DividerImeController mImePositionProcessor;
- private final Context mContext;
private boolean mIsKeyguardShowing;
+ private boolean mVisible = false;
+ private boolean mMinimized = false;
+ private boolean mAdjustedForIme = false;
+ private boolean mHomeStackResizable = false;
- public DividerController(Context context,
+ public SplitScreenController(Context context,
DisplayController displayController, SystemWindows systemWindows,
- DisplayImeController imeController, Handler handler, TransactionPool transactionPool) {
+ DisplayImeController imeController, Handler handler, TransactionPool transactionPool,
+ ShellTaskOrganizer shellTaskOrganizer) {
mContext = context;
mDisplayController = displayController;
mSystemWindows = systemWindows;
@@ -100,7 +104,7 @@
mForcedResizableController = new ForcedResizableInfoActivityController(context, this);
mTransactionPool = transactionPool;
mWindowManagerProxy = new WindowManagerProxy(mTransactionPool, mHandler);
- mSplits = new SplitScreenTaskOrganizer(this);
+ mSplits = new SplitScreenTaskOrganizer(this, shellTaskOrganizer);
mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mHandler);
mRotationController =
(display, fromRotation, toRotation, wct) -> {
@@ -140,10 +144,7 @@
wct.merge(t, true /* transfer */);
}
};
- }
- /** Inits the divider service. */
- public void start() {
mWindowManager = new DividerWindowManager(mSystemWindows);
mDisplayController.addDisplayWindowListener(this);
// Don't initialize the divider or anything until we get the default display.
@@ -155,15 +156,15 @@
}
/** Called when keyguard showing state changed. */
- public void onKeyguardShowingChanged(boolean isShowing) {
+ public void onKeyguardVisibilityChanged(boolean showing) {
if (!isSplitActive() || mView == null) {
return;
}
- mView.setHidden(isShowing);
- if (!isShowing) {
+ mView.setHidden(showing);
+ if (!showing) {
mImePositionProcessor.updateAdjustForIme();
}
- mIsKeyguardShowing = isShowing;
+ mIsKeyguardShowing = showing;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
index ef5e8a1..325c559 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
@@ -33,9 +33,13 @@
import android.view.SurfaceSession;
import android.window.TaskOrganizer;
-class SplitScreenTaskOrganizer extends TaskOrganizer {
+import com.android.wm.shell.ShellTaskOrganizer;
+
+class SplitScreenTaskOrganizer implements ShellTaskOrganizer.TaskListener {
private static final String TAG = "SplitScreenTaskOrg";
- private static final boolean DEBUG = DividerController.DEBUG;
+ private static final boolean DEBUG = SplitScreenController.DEBUG;
+
+ private final ShellTaskOrganizer mTaskOrganizer;
RunningTaskInfo mPrimary;
RunningTaskInfo mSecondary;
@@ -44,18 +48,20 @@
SurfaceControl mPrimaryDim;
SurfaceControl mSecondaryDim;
Rect mHomeBounds = new Rect();
- final DividerController mDividerController;
+ final SplitScreenController mSplitScreenController;
private boolean mSplitScreenSupported = false;
final SurfaceSession mSurfaceSession = new SurfaceSession();
- SplitScreenTaskOrganizer(DividerController dividerController) {
- mDividerController = dividerController;
+ SplitScreenTaskOrganizer(SplitScreenController splitScreenController,
+ ShellTaskOrganizer shellTaskOrganizer) {
+ mSplitScreenController = splitScreenController;
+ mTaskOrganizer = shellTaskOrganizer;
+ mTaskOrganizer.addListener(this, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
}
void init() throws RemoteException {
- registerOrganizer(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
- registerOrganizer(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
synchronized (this) {
try {
mPrimary = TaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY,
@@ -64,7 +70,7 @@
WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
} catch (Exception e) {
// teardown to prevent callbacks
- unregisterOrganizer();
+ mTaskOrganizer.removeListener(this);
throw e;
}
}
@@ -75,11 +81,11 @@
}
SurfaceControl.Transaction getTransaction() {
- return mDividerController.mTransactionPool.acquire();
+ return mSplitScreenController.mTransactionPool.acquire();
}
void releaseTransaction(SurfaceControl.Transaction t) {
- mDividerController.mTransactionPool.release(t);
+ mSplitScreenController.mTransactionPool.release(t);
}
@Override
@@ -140,7 +146,7 @@
t.apply();
releaseTransaction(t);
- mDividerController.onTaskVanished();
+ mSplitScreenController.onTaskVanished();
}
}
}
@@ -150,7 +156,7 @@
if (taskInfo.displayId != DEFAULT_DISPLAY) {
return;
}
- mDividerController.post(() -> handleTaskInfoChanged(taskInfo));
+ mSplitScreenController.post(() -> handleTaskInfoChanged(taskInfo));
}
/**
@@ -169,7 +175,7 @@
}
final boolean secondaryImpliedMinimize = mSecondary.topActivityType == ACTIVITY_TYPE_HOME
|| (mSecondary.topActivityType == ACTIVITY_TYPE_RECENTS
- && mDividerController.isHomeStackResizable());
+ && mSplitScreenController.isHomeStackResizable());
final boolean primaryWasEmpty = mPrimary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
final boolean secondaryWasEmpty = mSecondary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
if (info.token.asBinder() == mPrimary.token.asBinder()) {
@@ -181,7 +187,7 @@
final boolean secondaryIsEmpty = mSecondary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
final boolean secondaryImpliesMinimize = mSecondary.topActivityType == ACTIVITY_TYPE_HOME
|| (mSecondary.topActivityType == ACTIVITY_TYPE_RECENTS
- && mDividerController.isHomeStackResizable());
+ && mSplitScreenController.isHomeStackResizable());
if (DEBUG) {
Log.d(TAG, "onTaskInfoChanged " + mPrimary + " " + mSecondary);
}
@@ -197,14 +203,14 @@
Log.d(TAG, " at-least one split empty " + mPrimary.topActivityType
+ " " + mSecondary.topActivityType);
}
- if (mDividerController.isDividerVisible()) {
+ if (mSplitScreenController.isDividerVisible()) {
// Was in split-mode, which means we are leaving split, so continue that.
// This happens when the stack in the primary-split is dismissed.
if (DEBUG) {
Log.d(TAG, " was in split, so this means leave it "
+ mPrimary.topActivityType + " " + mSecondary.topActivityType);
}
- mDividerController.startDismissSplit();
+ mSplitScreenController.startDismissSplit();
} else if (!primaryIsEmpty && primaryWasEmpty && secondaryWasEmpty) {
// Wasn't in split-mode (both were empty), but now that the primary split is
// populated, we should fully enter split by moving everything else into secondary.
@@ -213,15 +219,15 @@
if (DEBUG) {
Log.d(TAG, " was not in split, but primary is populated, so enter it");
}
- mDividerController.startEnterSplit();
+ mSplitScreenController.startEnterSplit();
}
} else if (secondaryImpliesMinimize) {
// Both splits are populated but the secondary split has a home/recents stack on top,
// so enter minimized mode.
- mDividerController.ensureMinimizedSplit();
+ mSplitScreenController.ensureMinimizedSplit();
} else {
// Both splits are populated by normal activities, so make sure we aren't minimized.
- mDividerController.ensureNormalSplit();
+ mSplitScreenController.ensureNormalSplit();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java
index f2500e5..13ed02e 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java
@@ -33,7 +33,7 @@
* Helper for serializing sync-transactions and corresponding callbacks.
*/
class SyncTransactionQueue {
- private static final boolean DEBUG = DividerController.DEBUG;
+ private static final boolean DEBUG = SplitScreenController.DEBUG;
private static final String TAG = "SyncTransactionQueue";
// Just a little longer than the sync-engine timeout of 5s
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
index 1079f10..17bf346 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
@@ -55,14 +55,6 @@
void updateNotificationViews(String reason);
/**
- * Returns the maximum number of notifications to show while locked.
- *
- * @param recompute whether something has changed that means we should recompute this value
- * @return the maximum number of notifications to show while locked
- */
- int getMaxNotificationsWhileLocked(boolean recompute);
-
- /**
* Called when the row states are updated by {@link NotificationViewHierarchyManager}.
*/
void onUpdateRowStates();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
index 1fd0b03..24515f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
@@ -164,6 +164,13 @@
default void setRequestTopUi(boolean requestTopUi, String componentTag) {}
/**
+ * Under low light conditions, we might want to increase the display brightness on devices that
+ * don't have an IR camera.
+ * @param brightness float from 0 to 1 or {@code LayoutParams.BRIGHTNESS_OVERRIDE_NONE}
+ */
+ default void setFaceAuthDisplayBrightness(float brightness) {}
+
+ /**
* Custom listener to pipe data back to plugins about whether or not the status bar would be
* collapsed if not for the plugin.
* TODO: Find cleaner way to do this.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java
index 77abcfa..1e935c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java
@@ -85,6 +85,10 @@
return mView.getShelfIcons();
}
+ public @View.Visibility int getVisibility() {
+ return mView.getVisibility();
+ };
+
public void setCollapsedIcons(NotificationIconContainer notificationIcons) {
mView.setCollapsedIcons(notificationIcons);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 1cd1b60..852c055 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -420,11 +420,6 @@
int visibleNotifications = 0;
boolean onKeyguard = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
- int maxNotifications = -1;
- if (onKeyguard && !mBypassController.getBypassEnabled()) {
- maxNotifications = mPresenter.getMaxNotificationsWhileLocked(true /* recompute */);
- }
- mListContainer.setMaxDisplayedNotifications(maxNotifications);
Stack<ExpandableNotificationRow> stack = new Stack<>();
for (int i = N - 1; i >= 0; i--) {
View child = mListContainer.getContainerChildAt(i);
@@ -439,8 +434,6 @@
boolean isChildNotification =
mGroupManager.isChildInGroupWithSummary(entry.getSbn());
- row.setOnKeyguard(onKeyguard);
-
if (!onKeyguard) {
// If mAlwaysExpandNonGroupedNotification is false, then only expand the
// very first notification and if it's not a child of grouped notifications.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index ea614fb..838cf0c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -55,12 +55,13 @@
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.UiBackground;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.NotificationChannels;
import java.util.List;
+import java.util.Optional;
import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -80,13 +81,13 @@
private final CommandQueue mCommandQueue;
private boolean mDockedStackExists;
private KeyguardStateController mKeyguardStateController;
- private final Divider mDivider;
+ private final Optional<SplitScreen> mSplitScreenOptional;
@Inject
public InstantAppNotifier(Context context, CommandQueue commandQueue,
- @UiBackground Executor uiBgExecutor, Divider divider) {
+ @UiBackground Executor uiBgExecutor, Optional<SplitScreen> splitScreenOptional) {
super(context);
- mDivider = divider;
+ mSplitScreenOptional = splitScreenOptional;
mCommandQueue = commandQueue;
mUiBgExecutor = uiBgExecutor;
}
@@ -105,11 +106,11 @@
mCommandQueue.addCallback(this);
mKeyguardStateController.addCallback(this);
- mDivider.registerInSplitScreenListener(
- exists -> {
+ mSplitScreenOptional.ifPresent(splitScreen ->
+ splitScreen.registerInSplitScreenListener(exists -> {
mDockedStackExists = exists;
updateForegroundInstantApps();
- });
+ }));
// Clear out all old notifications on startup (only present in the case where sysui dies)
NotificationManager noMan = mContext.getSystemService(NotificationManager.class);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt
index 17e6289..3bfdf5c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt
@@ -16,9 +16,9 @@
package com.android.systemui.statusbar.notification.collection
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection
/**
* Stores the state that [ShadeListBuilder] assigns to this [ListEntry]
@@ -35,7 +35,6 @@
* parent's section. Null if not attached to the list.
*/
var section: NotifSection?,
- var sectionIndex: Int,
/**
* If a [NotifFilter] is excluding this entry from the list, then that filter. Always null for
@@ -60,7 +59,6 @@
fun clone(other: ListAttachState) {
parent = other.parent
section = other.section
- sectionIndex = other.sectionIndex
excludingFilter = other.excludingFilter
promoter = other.promoter
suppressedChanges.clone(other.suppressedChanges)
@@ -70,7 +68,6 @@
fun reset() {
parent = null
section = null
- sectionIndex = -1
excludingFilter = null
promoter = null
suppressedChanges.reset()
@@ -82,7 +79,6 @@
return ListAttachState(
null,
null,
- -1,
null,
null,
SuppressedAttachState.create())
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
index 786c97d..52c5c3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
@@ -112,11 +112,9 @@
.append(")");
}
- if (entry.getNotifSection() != null) {
- sb.append(" sectionIndex=")
- .append(entry.getSection())
- .append(" sectionName=")
- .append(entry.getNotifSection().getName());
+ if (entry.getSection() != null) {
+ sb.append(" section=")
+ .append(entry.getSection().getLabel());
}
if (includeRecordKeeping) {
@@ -175,12 +173,9 @@
}
if (notifEntry.getAttachState().getSuppressedChanges().getSection() != null) {
- rksb.append("suppressedSectionIndex=")
+ rksb.append("suppressedSection=")
.append(notifEntry.getAttachState().getSuppressedChanges()
- .getSectionIndex())
- .append(" sectionName=")
- .append(notifEntry.getAttachState().getSuppressedChanges()
- .getSection().getName())
+ .getSection())
.append(" ");
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
index 65f5dc4..82c1f24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
@@ -21,7 +21,7 @@
import androidx.annotation.Nullable;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection;
/**
* Abstract superclass for top-level entries, i.e. things that can appear in the final notification
@@ -78,13 +78,12 @@
return mPreviousAttachState.getParent();
}
- /** The section this notification was assigned to (0 to N-1, where N is number of sections). */
- public int getSection() {
- return mAttachState.getSectionIndex();
+ @Nullable public NotifSection getSection() {
+ return mAttachState.getSection();
}
- @Nullable public NotifSection getNotifSection() {
- return mAttachState.getSection();
+ public int getSectionIndex() {
+ return mAttachState.getSection() != null ? mAttachState.getSection().getIndex() : -1;
}
ListAttachState getAttachState() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
index 05dd4df..a1844ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
@@ -24,7 +24,7 @@
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
@@ -155,10 +155,10 @@
* Sections that are used to sort top-level entries. If two entries have the same section,
* NotifComparators are consulted. Sections from this list are called in order for each
* notification passed through the pipeline. The first NotifSection to return true for
- * {@link NotifSection#isInSection(ListEntry)} sets the entry as part of its Section.
+ * {@link NotifSectioner#isInSection(ListEntry)} sets the entry as part of its Section.
*/
- public void setSections(List<NotifSection> sections) {
- mShadeListBuilder.setSections(sections);
+ public void setSections(List<NotifSectioner> sections) {
+ mShadeListBuilder.setSectioners(sections);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index 6cbebf8..2b545c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -28,10 +28,11 @@
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_SORTING;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_TRANSFORMING;
+import static java.util.Objects.requireNonNull;
+
import android.annotation.MainThread;
import android.annotation.Nullable;
import android.util.ArrayMap;
-import android.util.Pair;
import androidx.annotation.NonNull;
@@ -39,6 +40,7 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.statusbar.NotificationInteractionTracker;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
@@ -48,7 +50,7 @@
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
@@ -119,6 +121,8 @@
mLogger = logger;
mInteractionTracker = interactionTracker;
dumpManager.registerDumpable(TAG, this);
+
+ setSectioners(Collections.emptyList());
}
/**
@@ -193,15 +197,17 @@
promoter.setInvalidationListener(this::onPromoterInvalidated);
}
- void setSections(List<NotifSection> sections) {
+ void setSectioners(List<NotifSectioner> sectioners) {
Assert.isMainThread();
mPipelineState.requireState(STATE_IDLE);
mNotifSections.clear();
- for (NotifSection section : sections) {
- mNotifSections.add(section);
- section.setInvalidationListener(this::onNotifSectionInvalidated);
+ for (NotifSectioner sectioner : sectioners) {
+ mNotifSections.add(new NotifSection(sectioner, mNotifSections.size()));
+ sectioner.setInvalidationListener(this::onNotifSectionInvalidated);
}
+
+ mNotifSections.add(new NotifSection(DEFAULT_SECTIONER, mNotifSections.size()));
}
void setNotifStabilityManager(NotifStabilityManager notifStabilityManager) {
@@ -275,7 +281,7 @@
rebuildListIfBefore(STATE_TRANSFORMING);
}
- private void onNotifSectionInvalidated(NotifSection section) {
+ private void onNotifSectionInvalidated(NotifSectioner section) {
Assert.isMainThread();
mLogger.logNotifSectionInvalidated(section.getName(), mPipelineState.getState());
@@ -652,7 +658,6 @@
*/
private void annulAddition(ListEntry entry) {
entry.setParent(null);
- entry.getAttachState().setSectionIndex(-1);
entry.getAttachState().setSection(null);
entry.getAttachState().setPromoter(null);
if (entry.mFirstAddedIteration == mIterationCount) {
@@ -663,12 +668,12 @@
private void sortList() {
// Assign sections to top-level elements and sort their children
for (ListEntry entry : mNotifList) {
- Pair<NotifSection, Integer> sectionWithIndex = applySections(entry);
+ NotifSection section = applySections(entry);
if (entry instanceof GroupEntry) {
GroupEntry parent = (GroupEntry) entry;
for (NotificationEntry child : parent.getChildren()) {
- child.getAttachState().setSection(sectionWithIndex.first);
- child.getAttachState().setSectionIndex(sectionWithIndex.second);
+ child.getAttachState().setSection(section);
+ child.getAttachState().setSection(section);
}
parent.sortChildren(sChildComparator);
}
@@ -736,16 +741,13 @@
mLogger.logSectionChanged(
mIterationCount,
prev.getSection(),
- prev.getSectionIndex(),
- curr.getSection(),
- curr.getSectionIndex());
+ curr.getSection());
}
if (curr.getSuppressedChanges().getSection() != null) {
mLogger.logSectionChangeSuppressed(
mIterationCount,
curr.getSuppressedChanges().getSection(),
- curr.getSuppressedChanges().getSectionIndex(),
curr.getSection());
}
}
@@ -762,7 +764,10 @@
callOnCleanup(mNotifPromoters);
callOnCleanup(mNotifFinalizeFilters);
callOnCleanup(mNotifComparators);
- callOnCleanup(mNotifSections);
+
+ for (int i = 0; i < mNotifSections.size(); i++) {
+ mNotifSections.get(i).getSectioner().onCleanup();
+ }
if (mNotifStabilityManager != null) {
callOnCleanup(List.of(mNotifStabilityManager));
@@ -777,7 +782,9 @@
private final Comparator<ListEntry> mTopLevelComparator = (o1, o2) -> {
- int cmp = Integer.compare(o1.getSection(), o2.getSection());
+ int cmp = Integer.compare(
+ requireNonNull(o1.getSection()).getIndex(),
+ requireNonNull(o2.getSection()).getIndex());
if (cmp == 0) {
for (int i = 0; i < mNotifComparators.size(); i++) {
@@ -855,45 +862,41 @@
return null;
}
- private Pair<NotifSection, Integer> applySections(ListEntry entry) {
- Pair<NotifSection, Integer> sectionWithIndex = findSection(entry);
+ private NotifSection applySections(ListEntry entry) {
+ final NotifSection newSection = findSection(entry);
final ListAttachState prevAttachState = entry.getPreviousAttachState();
+ NotifSection finalSection = newSection;
+
// are we changing sections of this entry?
if (mNotifStabilityManager != null
&& prevAttachState.getParent() != null
- && (sectionWithIndex.first != prevAttachState.getSection()
- || sectionWithIndex.second != prevAttachState.getSectionIndex())) {
+ && newSection != prevAttachState.getSection()) {
// are section changes allowed?
- if (!mNotifStabilityManager.isSectionChangeAllowed(
- entry.getRepresentativeEntry())) {
- entry.getAttachState().getSuppressedChanges().setSection(
- sectionWithIndex.first);
- entry.getAttachState().getSuppressedChanges().setSectionIndex(
- sectionWithIndex.second);
+ if (!mNotifStabilityManager.isSectionChangeAllowed(entry.getRepresentativeEntry())) {
+ // record the section that we wanted to change to
+ entry.getAttachState().getSuppressedChanges().setSection(newSection);
// keep the previous section
- sectionWithIndex = new Pair(
- prevAttachState.getSection(),
- prevAttachState.getSectionIndex());
+ finalSection = prevAttachState.getSection();
}
}
- entry.getAttachState().setSection(sectionWithIndex.first);
- entry.getAttachState().setSectionIndex(sectionWithIndex.second);
+ entry.getAttachState().setSection(finalSection);
- return sectionWithIndex;
+ return finalSection;
}
- private Pair<NotifSection, Integer> findSection(ListEntry entry) {
+ @NonNull
+ private NotifSection findSection(ListEntry entry) {
for (int i = 0; i < mNotifSections.size(); i++) {
- NotifSection sectioner = mNotifSections.get(i);
- if (sectioner.isInSection(entry)) {
- return new Pair<>(sectioner, i);
+ NotifSection section = mNotifSections.get(i);
+ if (section.getSectioner().isInSection(entry)) {
+ return section;
}
}
- return new Pair<>(sDefaultSection, mNotifSections.size());
+ throw new RuntimeException("Missing default sectioner!");
}
private void rebuildListIfBefore(@PipelineState.StateName int state) {
@@ -963,15 +966,15 @@
void onRenderList(@NonNull List<ListEntry> entries);
}
- private static final NotifSection sDefaultSection =
- new NotifSection("UnknownSection") {
+ private static final NotifSectioner DEFAULT_SECTIONER =
+ new NotifSectioner("UnknownSection") {
@Override
public boolean isInSection(ListEntry entry) {
return true;
}
};
- private static final String TAG = "ShadeListBuilder";
-
private static final int MIN_CHILDREN_FOR_GROUP = 2;
+
+ private static final String TAG = "ShadeListBuilder";
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SuppressedAttachState.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SuppressedAttachState.kt
index 5261236..3eb2e61 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SuppressedAttachState.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SuppressedAttachState.kt
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar.notification.collection
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
/**
* Stores the suppressed state that [ShadeListBuilder] assigned to this [ListEntry] before the
@@ -33,22 +33,19 @@
* The assigned section for this ListEntry. If the child of the group, this will be the
* parent's section. Null if not attached to the list.
*/
- var section: NotifSection?,
- var sectionIndex: Int
+ var section: NotifSection?
) {
/** Copies the state of another instance. */
fun clone(other: SuppressedAttachState) {
parent = other.parent
section = other.section
- sectionIndex = other.sectionIndex
}
/** Resets back to a "clean" state (the same as created by the factory method) */
fun reset() {
parent = null
section = null
- sectionIndex = -1
}
companion object {
@@ -56,8 +53,7 @@
fun create(): SuppressedAttachState {
return SuppressedAttachState(
null,
- null,
- -1)
+ null)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
index 0b9bded..c7ac403 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
@@ -29,7 +29,7 @@
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -83,8 +83,8 @@
}
- public NotifSection getSection() {
- return mNotifSection;
+ public NotifSectioner getSectioner() {
+ return mNotifSectioner;
}
/**
@@ -179,7 +179,7 @@
/**
* Puts foreground service notifications into its own section.
*/
- private final NotifSection mNotifSection = new NotifSection("ForegroundService") {
+ private final NotifSectioner mNotifSectioner = new NotifSectioner("ForegroundService") {
@Override
public boolean isInSection(ListEntry entry) {
NotificationEntry notificationEntry = entry.getRepresentativeEntry();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
index c8e859f..dea1162 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
@@ -21,7 +21,7 @@
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
import javax.inject.Inject
@@ -42,7 +42,7 @@
}
}
- private val mNotifSection: NotifSection = object : NotifSection("People") {
+ val sectioner = object : NotifSectioner("People") {
override fun isInSection(entry: ListEntry): Boolean {
return isConversation(entry.representativeEntry!!)
}
@@ -52,10 +52,6 @@
pipeline.addPromoter(notificationPromoter)
}
- fun getSection(): NotifSection {
- return mNotifSection
- }
-
private fun isConversation(entry: NotificationEntry): Boolean =
peopleNotificationIdentifier.getPeopleNotificationType(entry.sbn, entry.ranking) !=
TYPE_NON_PERSON
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
index 6e6ceca..c023400 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
@@ -27,7 +27,7 @@
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder;
@@ -88,8 +88,8 @@
pipeline.addNotificationLifetimeExtender(mLifetimeExtender);
}
- public NotifSection getSection() {
- return mNotifSection;
+ public NotifSectioner getSectioner() {
+ return mNotifSectioner;
}
private void onHeadsUpViewBound(NotificationEntry entry) {
@@ -191,7 +191,7 @@
}
};
- private final NotifSection mNotifSection = new NotifSection("HeadsUp") {
+ private final NotifSectioner mNotifSectioner = new NotifSectioner("HeadsUp") {
@Override
public boolean isInSection(ListEntry entry) {
return isCurrentlyShowingHun(entry);
@@ -207,7 +207,7 @@
endNotifLifetimeExtension();
mCurrentHun = newHUN;
mNotifPromoter.invalidateList();
- mNotifSection.invalidateList();
+ mNotifSectioner.invalidateList();
}
if (!isHeadsUp) {
mHeadsUpViewBinder.unbindHeadsUpView(entry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
index 87ca717..ded5e46 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
@@ -21,7 +21,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
@@ -41,7 +41,7 @@
public class NotifCoordinators implements Dumpable {
private static final String TAG = "NotifCoordinators";
private final List<Coordinator> mCoordinators = new ArrayList<>();
- private final List<NotifSection> mOrderedSections = new ArrayList<>();
+ private final List<NotifSectioner> mOrderedSections = new ArrayList<>();
/**
* Creates all the coordinators.
@@ -81,12 +81,12 @@
// Manually add Ordered Sections
// HeadsUp > FGS > People > Alerting > Silent > Unknown/Default
if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
- mOrderedSections.add(headsUpCoordinator.getSection()); // HeadsUp
+ mOrderedSections.add(headsUpCoordinator.getSectioner()); // HeadsUp
}
- mOrderedSections.add(appOpsCoordinator.getSection()); // ForegroundService
- mOrderedSections.add(conversationCoordinator.getSection()); // People
- mOrderedSections.add(rankingCoordinator.getAlertingSection()); // Alerting
- mOrderedSections.add(rankingCoordinator.getSilentSection()); // Silent
+ mOrderedSections.add(appOpsCoordinator.getSectioner()); // ForegroundService
+ mOrderedSections.add(conversationCoordinator.getSectioner()); // People
+ mOrderedSections.add(rankingCoordinator.getAlertingSectioner()); // Alerting
+ mOrderedSections.add(rankingCoordinator.getSilentSectioner()); // Silent
}
/**
@@ -109,7 +109,7 @@
pw.println("\t" + c.getClass());
}
- for (NotifSection s : mOrderedSections) {
+ for (NotifSectioner s : mOrderedSections) {
pw.println("\t" + s.getName());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
index a32b163..0f08e0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
@@ -22,7 +22,7 @@
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import javax.inject.Inject;
@@ -57,22 +57,22 @@
pipeline.addPreGroupFilter(mDozingFilter);
}
- public NotifSection getAlertingSection() {
- return mAlertingNotifSection;
+ public NotifSectioner getAlertingSectioner() {
+ return mAlertingNotifSectioner;
}
- public NotifSection getSilentSection() {
- return mSilentNotifSection;
+ public NotifSectioner getSilentSectioner() {
+ return mSilentNotifSectioner;
}
- private final NotifSection mAlertingNotifSection = new NotifSection("Alerting") {
+ private final NotifSectioner mAlertingNotifSectioner = new NotifSectioner("Alerting") {
@Override
public boolean isInSection(ListEntry entry) {
return mHighPriorityProvider.isHighPriority(entry);
}
};
- private final NotifSection mSilentNotifSection = new NotifSection("Silent") {
+ private final NotifSectioner mSilentNotifSectioner = new NotifSectioner("Silent") {
@Override
public boolean isInSection(ListEntry entry) {
return !mHighPriorityProvider.isHighPriority(entry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 7c061aa..e5425cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -140,7 +140,7 @@
.build();
ExpandableNotificationRowController rowController =
component.getExpandableNotificationRowController();
- rowController.init();
+ rowController.init(entry);
entry.setRowController(rowController);
bindRow(entry, row);
updateRow(entry, row);
@@ -160,7 +160,6 @@
mNotificationRemoteInputManager.bindRow(row);
row.setOnActivatedListener(mPresenter);
entry.setRow(row);
- row.setEntry(entry);
mNotifBindPipeline.manageRow(entry, row);
mBindRowCallback.onBindRow(row);
}
diff --git a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/WindowManagerShellTest.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
similarity index 60%
copy from libs/WindowManager/Shell/tests/src/com/android/wm/shell/WindowManagerShellTest.java
copy to packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
index f1ead3c..c09122e 100644
--- a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/WindowManagerShellTest.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
@@ -14,25 +14,14 @@
* limitations under the License.
*/
-package com.android.wm.shell;
+package com.android.systemui.statusbar.notification.collection.listbuilder
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for the shell.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class WindowManagerShellTest {
-
- WindowManagerShell mShell;
-
- @Test
- public void testNothing() {
- // Do nothing
- }
+data class NotifSection(
+ val sectioner: NotifSectioner,
+ val index: Int
+) {
+ val label: String
+ get() = "Section($index, \"${sectioner.name}\")"
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
index f7bfeb7..9ee7db7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
@@ -25,7 +25,6 @@
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection
import javax.inject.Inject
class ShadeListBuilderLogger @Inject constructor(
@@ -211,21 +210,17 @@
fun logSectionChanged(
buildId: Int,
prevSection: NotifSection?,
- prevIndex: Int,
- newSection: NotifSection?,
- newIndex: Int
+ newSection: NotifSection?
) {
buffer.log(TAG, INFO, {
long1 = buildId.toLong()
- str1 = prevSection?.name
- int1 = prevIndex
- str2 = newSection?.name
- int2 = newIndex
+ str1 = prevSection?.label
+ str2 = newSection?.label
}, {
if (str1 == null) {
- "(Build $long1) Section assigned: '$str2' (#$int2)"
+ "(Build $long1) Section assigned: $str2"
} else {
- "(Build $long1) Section changed: '$str1' (#$int1) -> '$str2' (#$int2)"
+ "(Build $long1) Section changed: $str1 -> $str2"
}
})
}
@@ -233,17 +228,14 @@
fun logSectionChangeSuppressed(
buildId: Int,
suppressedSection: NotifSection?,
- suppressedSectionIndex: Int,
assignedSection: NotifSection?
) {
buffer.log(TAG, INFO, {
long1 = buildId.toLong()
- str1 = suppressedSection?.name
- int1 = suppressedSectionIndex
- str2 = assignedSection?.name
+ str1 = suppressedSection?.label
+ str2 = assignedSection?.label
}, {
- "(Build $long1) Section change suppressed: '$str1' (#$int1). " +
- "Keeping section: '$str2'"
+ "(Build $long1) Suppressing section change to $str1 (staying at $str2)"
})
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java
similarity index 92%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSection.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java
index fe5ba3c..b57f504 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java
@@ -22,8 +22,8 @@
/**
* Pluggable for participating in notif sectioning. See {@link ShadeListBuilder#setSections}.
*/
-public abstract class NotifSection extends Pluggable<NotifSection> {
- protected NotifSection(String name) {
+public abstract class NotifSectioner extends Pluggable<NotifSectioner> {
+ protected NotifSectioner(String name) {
super(name);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt
index e812494..a1800ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt
@@ -25,10 +25,10 @@
* we should just modify NLC to implement the NodeController interface.
*/
class RootNodeController(
- private val listContainer: NotificationListContainer
+ private val listContainer: NotificationListContainer,
+ override val view: View
) : NodeController {
override val nodeLabel: String = "<root>"
- override val view: View = listContainer as View
override fun getChildAt(index: Int): View? {
return listContainer.getContainerChildAt(index)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
index 118ff4a..3c35b7bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.collection.render
+import android.content.Context
+import android.view.View
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -30,12 +32,15 @@
* currently populate the notification shade.
*/
class ShadeViewManager constructor(
+ context: Context,
listContainer: NotificationListContainer,
logger: ShadeViewDifferLogger,
private val viewBarn: NotifViewBarn,
private val notificationIconAreaController: NotificationIconAreaController
) {
- private val rootController = RootNodeController(listContainer)
+ // We pass a shim view here because the listContainer may not actually have a view associated
+ // with it and the differ never actually cares about the root node's view.
+ private val rootController = RootNodeController(listContainer, View(context))
private val viewDiffer = ShadeViewDiffer(rootController, logger)
fun attach(listBuilder: ShadeListBuilder) {
@@ -82,11 +87,17 @@
}
class ShadeViewManagerFactory @Inject constructor(
+ private val context: Context,
private val logger: ShadeViewDifferLogger,
private val viewBarn: NotifViewBarn,
private val notificationIconAreaController: NotificationIconAreaController
) {
fun create(listContainer: NotificationListContainer): ShadeViewManager {
- return ShadeViewManager(listContainer, logger, viewBarn, notificationIconAreaController)
+ return ShadeViewManager(
+ context,
+ listContainer,
+ logger,
+ viewBarn,
+ notificationIconAreaController)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 9c09cba..46b4973 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -141,7 +141,7 @@
void onExpansionChanged(boolean isExpanded);
}
- private StatusBarStateController mStatusbarStateController;
+ private StatusBarStateController mStatusBarStateController;
private KeyguardBypassController mBypassController;
private LayoutListener mLayoutListener;
private RowContentBindStage mRowContentBindStage;
@@ -463,16 +463,6 @@
}
/**
- * Set the entry for the row.
- *
- * @param entry the entry this row is tied to
- */
- public void setEntry(@NonNull NotificationEntry entry) {
- mEntry = entry;
- cacheIsSystemNotification();
- }
-
- /**
* Marks a content view as freeable, setting it so that future inflations do not reinflate
* and ensuring that the view is freed when it is safe to remove.
*
@@ -1584,6 +1574,7 @@
* Initialize row.
*/
public void initialize(
+ NotificationEntry entry,
String appName,
String notificationKey,
ExpansionLogger logger,
@@ -1598,6 +1589,7 @@
StatusBarStateController statusBarStateController,
PeopleNotificationIdentifier peopleNotificationIdentifier,
OnUserInteractionCallback onUserInteractionCallback) {
+ mEntry = entry;
mAppName = appName;
if (mMenuRow == null) {
mMenuRow = new NotificationMenuRow(mContext, peopleNotificationIdentifier);
@@ -1616,12 +1608,15 @@
mMediaManager = notificationMediaManager;
setOnFeedbackClickListener(onFeedbackClickListener);
mFalsingManager = falsingManager;
- mStatusbarStateController = statusBarStateController;
+ mStatusBarStateController = statusBarStateController;
+
mPeopleNotificationIdentifier = peopleNotificationIdentifier;
for (NotificationContentView l : mLayouts) {
l.setPeopleNotificationIdentifier(mPeopleNotificationIdentifier);
}
mOnUserInteractionCallback = onUserInteractionCallback;
+
+ cacheIsSystemNotification();
}
private void initDimens() {
@@ -2134,8 +2129,8 @@
*/
@Override
public boolean isSoundEffectsEnabled() {
- final boolean mute = mStatusbarStateController != null
- && mStatusbarStateController.isDozing()
+ final boolean mute = mStatusBarStateController != null
+ && mStatusBarStateController.isDozing()
&& mSecureStateProvider != null &&
!mSecureStateProvider.getAsBoolean();
return !mute && super.isSoundEffectsEnabled();
@@ -2259,10 +2254,7 @@
}
}
- /**
- * @param onKeyguard whether to prevent notification expansion
- */
- public void setOnKeyguard(boolean onKeyguard) {
+ void setOnKeyguard(boolean onKeyguard) {
if (onKeyguard != mOnKeyguard) {
boolean wasAboveShelf = isAboveShelf();
final boolean wasExpanded = isExpanded();
@@ -2331,7 +2323,7 @@
}
private boolean isDozing() {
- return mStatusbarStateController != null && mStatusbarStateController.isDozing();
+ return mStatusBarStateController != null && mStatusBarStateController.isDozing();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index f8bc2be..ce760cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -18,6 +18,7 @@
import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import android.view.View;
import android.view.ViewGroup;
@@ -29,6 +30,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.render.NodeController;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
@@ -118,9 +120,10 @@
/**
* Initialize the controller.
*/
- public void init() {
+ public void init(NotificationEntry entry) {
mActivatableNotificationViewController.init();
mView.initialize(
+ entry,
mAppName,
mNotificationKey,
mExpansionLogger,
@@ -135,7 +138,15 @@
mStatusBarStateController,
mPeopleNotificationIdentifier,
mOnUserInteractionCallback
+
);
+ mStatusBarStateController.addCallback(new StatusBarStateController.StateListener() {
+ @Override
+ public void onStateChanged(int newState) {
+ mView.setOnKeyguard(newState == KEYGUARD);
+ }
+ });
+ mView.setOnKeyguard(mStatusBarStateController.getState() == KEYGUARD);
mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
if (mAllowLongPress) {
mView.setLongPressListener((v, x, y, item) -> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 11e698b..d5e5531 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -42,7 +42,7 @@
private static final float MAX_PULSE_HEIGHT = 100000f;
private final SectionProvider mSectionProvider;
- private ArrayList<ExpandableView> mDraggedViews = new ArrayList<>();
+ private ArrayList<View> mDraggedViews = new ArrayList<>();
private int mScrollY;
private int mAnchorViewIndex;
private int mAnchorViewY;
@@ -164,7 +164,7 @@
}
/** Call when dragging begins. */
- public void onBeginDrag(ExpandableView view) {
+ public void onBeginDrag(View view) {
mDraggedViews.add(view);
}
@@ -172,7 +172,7 @@
mDraggedViews.remove(view);
}
- public ArrayList<ExpandableView> getDraggedViews() {
+ public ArrayList<View> getDraggedViews() {
return mDraggedViews;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index d4c270f..b1a9efe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -44,7 +44,6 @@
import android.graphics.Color;
import android.graphics.Outline;
import android.graphics.Paint;
-import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
@@ -54,7 +53,6 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
-import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -94,22 +92,13 @@
import com.android.systemui.ExpandHelper;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.SwipeHelper;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper.DragDownCallback;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.FeatureFlags;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationShelfController;
@@ -145,7 +134,6 @@
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -154,11 +142,8 @@
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.ScrollAdapter;
-import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.Assert;
@@ -178,7 +163,7 @@
/**
* A layout which handles a dynamic amount of notifications and presents them in a scrollable stack.
*/
-public class NotificationStackScrollLayout extends ViewGroup implements ScrollAdapter, Dumpable {
+public class NotificationStackScrollLayout extends ViewGroup implements Dumpable {
public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
private static final String TAG = "StackScroller";
@@ -195,13 +180,12 @@
* gap is drawn between them). In this case we don't want to round their corners.
*/
private static final int DISTANCE_BETWEEN_ADJACENT_SECTIONS_PX = 1;
- private final KeyguardBypassController mKeyguardBypassController;
+ private KeyguardBypassEnabledProvider mKeyguardBypassEnabledProvider;
private final DynamicPrivacyController mDynamicPrivacyController;
private final SysuiStatusBarStateController mStatusbarStateController;
- private final KeyguardMediaController mKeyguardMediaController;
private ExpandHelper mExpandHelper;
- private final NotificationSwipeHelper mSwipeHelper;
+ private NotificationSwipeHelper mSwipeHelper;
private int mCurrentStackHeight = Integer.MAX_VALUE;
private final Paint mBackgroundPaint = new Paint();
private final boolean mShouldDrawNotificationBackground;
@@ -249,11 +233,12 @@
private int mBottomMargin;
private int mBottomInset = 0;
private float mQsExpansionFraction;
+ private int mCurrentUserId;
/**
* The algorithm which calculates the properties for our children
*/
- protected final StackScrollAlgorithm mStackScrollAlgorithm;
+ private final StackScrollAlgorithm mStackScrollAlgorithm;
private final AmbientState mAmbientState;
private NotificationGroupManager mGroupManager;
@@ -326,7 +311,6 @@
* motion.
*/
private int mMaxScrollAfterExpand;
- private ExpandableNotificationRow.LongPressListener mLongPressListener;
boolean mCheckForLeavebehind;
/**
@@ -348,12 +332,7 @@
return true;
}
};
- private final UserChangedListener mLockscreenUserChangeListener = new UserChangedListener() {
- @Override
- public void onUserChanged(int userId) {
- updateSensitiveness(false /* animated */);
- }
- };
+
private StatusBar mStatusBar;
private int[] mTempInt2 = new int[2];
private boolean mGenerateChildOrderChangedEvent;
@@ -368,7 +347,6 @@
private boolean mForceNoOverlappingRendering;
private final ArrayList<Pair<ExpandableNotificationRow, Boolean>> mTmpList = new ArrayList<>();
private FalsingManager mFalsingManager;
- private final ZenModeController mZenController;
private boolean mAnimationRunning;
private ViewTreeObserver.OnPreDrawListener mRunningAnimationUpdater
= new ViewTreeObserver.OnPreDrawListener() {
@@ -498,7 +476,6 @@
private ArrayList<BiConsumer<Float, Float>> mExpandedHeightListeners = new ArrayList<>();
private int mHeadsUpInset;
private HeadsUpAppearanceController mHeadsUpAppearanceController;
- private final NotificationLockscreenUserManager mLockscreenUserManager;
private final Rect mTmpRect = new Rect();
private final FeatureFlags mFeatureFlags;
private final NotifPipeline mNotifPipeline;
@@ -511,7 +488,6 @@
protected final UiEventLogger mUiEventLogger;
private final NotificationRemoteInputManager mRemoteInputManager =
Dependency.get(NotificationRemoteInputManager.class);
- private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class);
private final DisplayMetrics mDisplayMetrics = Dependency.get(DisplayMetrics.class);
private final LockscreenGestureLogger mLockscreenGestureLogger =
@@ -536,11 +512,7 @@
private int mWaterfallTopInset;
private NotificationStackScrollLayoutController mController;
- private SysuiColorExtractor.OnColorsChangedListener mOnColorsChangedListener =
- (colorExtractor, which) -> {
- final boolean useDarkText = mColorExtractor.getNeutralColors().supportsDarkText();
- updateDecorViews(useDarkText);
- };
+ private boolean mKeyguardMediaControllorVisible;
private final ExpandableView.OnHeightChangedListener mOnChildHeightChangedListener =
new ExpandableView.OnHeightChangedListener() {
@@ -555,20 +527,44 @@
}
};
+ private final ScrollAdapter mScrollAdapter = new ScrollAdapter() {
+ @Override
+ public boolean isScrolledToTop() {
+ if (ANCHOR_SCROLLING) {
+ updateScrollAnchor();
+ // TODO: once we're recycling this will need to check the adapter position of the
+ // child
+ return mScrollAnchorView == getFirstChildNotGone() && mScrollAnchorViewY >= 0;
+ } else {
+ return mOwnScrollY == 0;
+ }
+ }
+
+ @Override
+ public boolean isScrolledToBottom() {
+ if (ANCHOR_SCROLLING) {
+ return getMaxPositiveScrollAmount() <= 0;
+ } else {
+ return mOwnScrollY >= getScrollRange();
+ }
+ }
+
+ @Override
+ public View getHostView() {
+ return NotificationStackScrollLayout.this;
+ }
+ };
+
@Inject
public NotificationStackScrollLayout(
@Named(VIEW_CONTEXT) Context context,
AttributeSet attrs,
NotificationRoundnessManager notificationRoundnessManager,
DynamicPrivacyController dynamicPrivacyController,
- SysuiStatusBarStateController statusBarStateController,
+ SysuiStatusBarStateController statusbarStateController,
HeadsUpManagerPhone headsUpManager,
- KeyguardBypassController keyguardBypassController,
- KeyguardMediaController keyguardMediaController,
FalsingManager falsingManager,
- NotificationLockscreenUserManager notificationLockscreenUserManager,
NotificationGutsManager notificationGutsManager,
- ZenModeController zenController,
NotificationSectionsManager notificationSectionsManager,
ForegroundServiceSectionController fgsSectionController,
ForegroundServiceDismissalFeatureController fgsFeatureController,
@@ -583,13 +579,10 @@
mRoundnessManager = notificationRoundnessManager;
- mLockscreenUserManager = notificationLockscreenUserManager;
mNotificationGutsManager = notificationGutsManager;
mHeadsUpManager = headsUpManager;
mHeadsUpManager.setAnimationStateHandler(this::setHeadsUpGoingAwayAnimationsAllowed);
- mKeyguardBypassController = keyguardBypassController;
mFalsingManager = falsingManager;
- mZenController = zenController;
mFgsSectionController = fgsSectionController;
mSectionsManager = notificationSectionsManager;
@@ -608,16 +601,11 @@
mExpandHelper = new ExpandHelper(getContext(), mExpandHelperCallback,
minHeight, maxHeight);
mExpandHelper.setEventSource(this);
- mExpandHelper.setScrollAdapter(this);
- mSwipeHelper = new NotificationSwipeHelper(SwipeHelper.X, mNotificationCallback,
- getContext(), mMenuEventListener, mFalsingManager);
+ mExpandHelper.setScrollAdapter(mScrollAdapter);
+
mStackScrollAlgorithm = createStackScrollAlgorithm(context);
- initView(context);
mShouldDrawNotificationBackground =
res.getBoolean(R.bool.config_drawNotificationBackground);
- mFadeNotificationsOnDismiss =
- res.getBoolean(R.bool.config_fadeNotificationsOnDismiss);
- mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener);
setOutlineProvider(mOutlineProvider);
// Blocking helper manager wants to know the expanded state, update as well.
@@ -667,20 +655,9 @@
}
mDynamicPrivacyController = dynamicPrivacyController;
- mStatusbarStateController = statusBarStateController;
+ mStatusbarStateController = statusbarStateController;
initializeForegroundServiceSection(fgsFeatureController);
mUiEventLogger = uiEventLogger;
- mColorExtractor.addOnColorsChangedListener(mOnColorsChangedListener);
- mKeyguardMediaController = keyguardMediaController;
- keyguardMediaController.setVisibilityChangedListener((visible) -> {
- if (visible) {
- generateAddAnimation(keyguardMediaController.getView(), false /*fromMoreCard */);
- } else {
- generateRemoveAnimation(keyguardMediaController.getView());
- }
- requestChildrenUpdate();
- return null;
- });
}
private void initializeForegroundServiceSection(
@@ -719,7 +696,7 @@
public float getWakeUpHeight() {
ExpandableView firstChild = getFirstChildWithBackground();
if (firstChild != null) {
- if (mKeyguardBypassController.getBypassEnabled()) {
+ if (mKeyguardBypassEnabledProvider.getBypassEnabled()) {
return firstChild.getHeadsUpHeightWithoutHeader();
} else {
return firstChild.getCollapsedHeight();
@@ -794,21 +771,6 @@
};
}
- @Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- ((SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class))
- .addCallback(mStateListener, SysuiStatusBarStateController.RANK_STACK_SCROLLER);
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
- }
-
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public NotificationSwipeActionHelper getSwipeActionHelper() {
return mSwipeHelper;
@@ -898,7 +860,7 @@
}
}
boolean shouldDrawBackground;
- if (mKeyguardBypassController.getBypassEnabled() && onKeyguard()) {
+ if (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard()) {
shouldDrawBackground = isPulseExpanding();
} else {
shouldDrawBackground = !mAmbientState.isDozing() || anySectionHasVisibleChild;
@@ -1013,9 +975,18 @@
}
}
+ private void reinitView() {
+ initView(getContext(), mKeyguardBypassEnabledProvider, mSwipeHelper);
+ }
+
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private void initView(Context context) {
+ void initView(Context context,
+ KeyguardBypassEnabledProvider keyguardBypassEnabledProvider,
+ NotificationSwipeHelper swipeHelper) {
mScroller = new OverScroller(getContext());
+ mKeyguardBypassEnabledProvider = keyguardBypassEnabledProvider;
+ mSwipeHelper = swipeHelper;
+
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setClipChildren(false);
final ViewConfiguration configuration = ViewConfiguration.get(context);
@@ -1227,7 +1198,7 @@
float end = start + child.getActualHeight();
boolean clip = clipStart > start && clipStart < end
|| clipEnd >= start && clipEnd <= end;
- clip &= !(first && isScrolledToTop());
+ clip &= !(first && mScrollAdapter.isScrolledToTop());
child.setDistanceToTopRoundness(clip ? Math.max(start - clipStart, 0)
: ExpandableView.NO_ROUNDNESS);
first = false;
@@ -1287,7 +1258,7 @@
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- private void requestChildrenUpdate() {
+ void requestChildrenUpdate() {
if (!mChildrenUpdateRequested) {
getViewTreeObserver().addOnPreDrawListener(mChildrenUpdater);
mChildrenUpdateRequested = true;
@@ -1417,7 +1388,7 @@
private void notifyAppearChangedListeners() {
float appear;
float expandAmount;
- if (mKeyguardBypassController.getBypassEnabled() && onKeyguard()) {
+ if (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard()) {
appear = calculateAppearFractionBypass();
expandAmount = getPulseHeight();
} else {
@@ -1658,7 +1629,7 @@
* @return the child at the given location.
*/
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
- private ExpandableView getChildAtPosition(float touchX, float touchY,
+ ExpandableView getChildAtPosition(float touchX, float touchY,
boolean requireMinHeight, boolean ignoreDecors) {
// find the view under the pointer, accounting for GONE views
final int count = getChildCount();
@@ -1806,7 +1777,7 @@
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private boolean onKeyguard() {
+ boolean onKeyguard() {
return mStatusBarState == StatusBarState.KEYGUARD;
}
@@ -1819,7 +1790,7 @@
mSwipeHelper.setDensityScale(densityScale);
float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
mSwipeHelper.setPagingTouchSlop(pagingTouchSlop);
- initView(getContext());
+ reinitView();
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@@ -2220,7 +2191,7 @@
springBack();
} else {
float overScrollTop = getCurrentOverScrollAmount(true /* top */);
- if (isScrolledToTop() && mScrollAnchorViewY > 0) {
+ if (mScrollAdapter.isScrolledToTop() && mScrollAnchorViewY > 0) {
notifyOverscrollTopListener(mScrollAnchorViewY,
isRubberbanded(true /* onTop */));
} else {
@@ -2268,7 +2239,7 @@
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void springBack() {
if (ANCHOR_SCROLLING) {
- boolean overScrolledTop = isScrolledToTop() && mScrollAnchorViewY > 0;
+ boolean overScrolledTop = mScrollAdapter.isScrolledToTop() && mScrollAnchorViewY > 0;
int maxPositiveScrollAmount = getMaxPositiveScrollAmount();
boolean overscrolledBottom = maxPositiveScrollAmount < 0;
if (overScrolledTop || overscrolledBottom) {
@@ -2545,8 +2516,8 @@
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updateForwardAndBackwardScrollability() {
- boolean forwardScrollable = mScrollable && !isScrolledToBottom();
- boolean backwardsScrollable = mScrollable && !isScrolledToTop();
+ boolean forwardScrollable = mScrollable && !mScrollAdapter.isScrolledToBottom();
+ boolean backwardsScrollable = mScrollable && !mScrollAdapter.isScrolledToTop();
boolean changed = forwardScrollable != mForwardScrollable
|| backwardsScrollable != mBackwardScrollable;
mForwardScrollable = forwardScrollable;
@@ -2667,7 +2638,7 @@
}
boolean shiftPulsingWithFirst = mHeadsUpManager.getAllEntries().count() <= 1
&& (mAmbientState.isDozing()
- || (mKeyguardBypassController.getBypassEnabled() && onKeyguard));
+ || (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard));
for (NotificationSection section : mSections) {
int minBottomPosition = minTopPosition;
if (section == lastSection) {
@@ -2830,7 +2801,8 @@
mLastScrollerY = 0;
// x velocity is set to 1 to avoid overscroller bug
mScroller.fling(0, 0, 1, velocityY, 0, 0, minY, maxY, 0,
- mExpandedInThisMotion && !isScrolledToTop() ? 0 : Integer.MAX_VALUE / 2);
+ mExpandedInThisMotion
+ && !mScrollAdapter.isScrolledToTop() ? 0 : Integer.MAX_VALUE / 2);
}
}
@@ -2937,7 +2909,7 @@
} else {
mTopPaddingOverflow = 0;
}
- setTopPadding(topPadding, animate && !mKeyguardBypassController.getBypassEnabled());
+ setTopPadding(topPadding, animate && !mKeyguardBypassEnabledProvider.getBypassEnabled());
setExpandedHeight(mExpandedHeight);
}
@@ -3095,7 +3067,7 @@
* @return Whether an animation was generated.
*/
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- private boolean generateRemoveAnimation(ExpandableView child) {
+ boolean generateRemoveAnimation(ExpandableView child) {
if (removeRemovedChildFromHeadsUpChangeAnimations(child)) {
mAddedHeadsUpChildren.remove(child);
return false;
@@ -3332,7 +3304,7 @@
}
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
- void onViewAddedInternal(ExpandableView child) {
+ private void onViewAddedInternal(ExpandableView child) {
updateHideSensitiveForChild(child);
child.setOnHeightChangedListener(mOnChildHeightChangedListener);
generateAddAnimation(child, false /* fromMoreCard */);
@@ -3343,7 +3315,8 @@
}
if (ANCHOR_SCROLLING) {
// TODO: once we're recycling this will need to check the adapter position of the child
- if (child == getFirstChildNotGone() && (isScrolledToTop() || !mIsExpanded)) {
+ if (child == getFirstChildNotGone()
+ && (mScrollAdapter.isScrolledToTop() || !mIsExpanded)) {
// New child was added at the top while we're scrolled to the top;
// make it the new anchor view so that we stay at the top.
mScrollAnchorView = child;
@@ -3361,6 +3334,10 @@
onViewRemovedInternal(row, childrenContainer);
}
+ public void notifyGroupChildAdded(ExpandableView row) {
+ onViewAddedInternal(row);
+ }
+
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void setAnimationsEnabled(boolean animationsEnabled) {
mAnimationsEnabled = animationsEnabled;
@@ -3533,7 +3510,7 @@
boolean performDisappearAnimation = !mIsExpanded
// Only animate if we still have pinned heads up, otherwise we just have the
// regular collapse animation of the lock screen
- || (mKeyguardBypassController.getBypassEnabled() && onKeyguard()
+ || (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard()
&& mHeadsUpManager.hasPinnedHeadsUp());
if (performDisappearAnimation && !isHeadsUp) {
type = row.wasJustClicked()
@@ -3769,11 +3746,6 @@
return y < getHeight() - getEmptyBottomMargin();
}
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void setLongPressListener(ExpandableNotificationRow.LongPressListener listener) {
- mLongPressListener = listener;
- }
-
private float getTouchSlop(MotionEvent event) {
// Adjust the touch slop if another gesture may be being performed.
return event.getClassification() == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE
@@ -4227,7 +4199,7 @@
case MotionEvent.ACTION_DOWN: {
final int y = (int) ev.getY();
- mScrolledToTopOnFirstDown = isScrolledToTop();
+ mScrolledToTopOnFirstDown = mScrollAdapter.isScrolledToTop();
final ExpandableView childAtTouchPos = getChildAtPosition(
ev.getX(), y, false /* requireMinHeight */, false /* ignoreDecors */);
if (childAtTouchPos == null) {
@@ -4386,7 +4358,7 @@
}
@ShadeViewRefactor(RefactorComponent.INPUT)
- private void setSwipingInProgress(boolean swiping) {
+ void setSwipingInProgress(boolean swiping) {
mSwipingInProgress = swiping;
if (swiping) {
requestDisallowInterceptTouchEvent(true);
@@ -4411,32 +4383,8 @@
}
}
- @Override
- @ShadeViewRefactor(RefactorComponent.COORDINATOR)
- public boolean isScrolledToTop() {
- if (ANCHOR_SCROLLING) {
- updateScrollAnchor();
- // TODO: once we're recycling this will need to check the adapter position of the child
- return mScrollAnchorView == getFirstChildNotGone() && mScrollAnchorViewY >= 0;
- } else {
- return mOwnScrollY == 0;
- }
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.COORDINATOR)
- public boolean isScrolledToBottom() {
- if (ANCHOR_SCROLLING) {
- return getMaxPositiveScrollAmount() <= 0;
- } else {
- return mOwnScrollY >= getScrollRange();
- }
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public View getHostView() {
- return this;
+ boolean isScrolledToBottom() {
+ return mScrollAdapter.isScrolledToBottom();
}
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
@@ -4476,7 +4424,7 @@
mStatusBar.resetUserExpandedStates();
clearTemporaryViews();
clearUserLockedViews();
- ArrayList<ExpandableView> draggedViews = mAmbientState.getDraggedViews();
+ ArrayList<View> draggedViews = mAmbientState.getDraggedViews();
if (draggedViews.size() > 0) {
draggedViews.clear();
updateContinuousShadowDrawing();
@@ -4734,8 +4682,7 @@
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private void updateSensitiveness(boolean animate) {
- boolean hideSensitive = mLockscreenUserManager.isAnyProfilePublicMode();
+ void updateSensitiveness(boolean animate, boolean hideSensitive) {
if (hideSensitive != mAmbientState.isHideSensitive()) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -4927,7 +4874,7 @@
// Since we are clipping to the outline we need to make sure that the shadows aren't
// clipped when pulsing
float ownTranslationZ = 0;
- if (mKeyguardBypassController.getBypassEnabled() && mAmbientState.isHiddenAtAll()) {
+ if (mKeyguardBypassEnabledProvider.getBypassEnabled() && mAmbientState.isHiddenAtAll()) {
ExpandableView firstChildNotGone = getFirstChildNotGone();
if (firstChildNotGone != null && firstChildNotGone.showingPulsing()) {
ownTranslationZ = firstChildNotGone.getTranslationZ();
@@ -4992,11 +4939,11 @@
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- void updateEmptyShadeView(boolean visible) {
+ void updateEmptyShadeView(boolean visible, boolean notifVisibleInShade) {
mEmptyShadeView.setVisible(visible, mIsExpanded && mAnimationsEnabled);
int oldTextRes = mEmptyShadeView.getTextResource();
- int newTextRes = mZenController.areNotificationsHiddenInShade()
+ int newTextRes = notifVisibleInShade
? R.string.dnd_suppressing_shade_text : R.string.empty_shade_text;
if (oldTextRes != newTextRes) {
mEmptyShadeView.setText(newTextRes);
@@ -5021,6 +4968,10 @@
handleDismissAllClipping();
}
+ boolean getDismissAllInProgress() {
+ return mDismissAllInProgress;
+ }
+
@ShadeViewRefactor(RefactorComponent.ADAPTER)
private void handleDismissAllClipping() {
final int count = getChildCount();
@@ -5093,7 +5044,7 @@
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- private void requestAnimateEverything() {
+ void requestAnimateEverything() {
if (mIsExpanded && mAnimationsEnabled) {
mEverythingNeedsAnimation = true;
mNeedsAnimation = true;
@@ -5431,17 +5382,17 @@
mAmbientState.setStatusBarState(statusBarState);
}
- private void onStatePostChange() {
+ void onStatePostChange(boolean fromShadeLocked) {
boolean onKeyguard = onKeyguard();
+ mAmbientState.setActivatedChild(null);
+ mAmbientState.setDimmed(onKeyguard);
+
if (mHeadsUpAppearanceController != null) {
mHeadsUpAppearanceController.onStateChanged();
}
- SysuiStatusBarStateController state = (SysuiStatusBarStateController)
- Dependency.get(StatusBarStateController.class);
- updateSensitiveness(state.goingToFullShade() /* animate */);
- setDimmed(onKeyguard, state.fromShadeLocked() /* animate */);
+ setDimmed(onKeyguard, fromShadeLocked);
setExpandingEnabled(!onKeyguard);
ActivatableNotificationView activatedChild = getActivatedChild();
setActivatedChild(null);
@@ -5534,12 +5485,15 @@
ExpandableView child = (ExpandableView) getTransientView(i);
child.dump(fd, pw, args);
}
- ArrayList<ExpandableView> draggedViews = mAmbientState.getDraggedViews();
+ ArrayList<View> draggedViews = mAmbientState.getDraggedViews();
int draggedCount = draggedViews.size();
pw.println(" Dragged Views: " + draggedCount);
for (int i = 0; i < draggedCount; i++) {
- ExpandableView child = (ExpandableView) draggedViews.get(i);
- child.dump(fd, pw, args);
+ View view = draggedViews.get(i);
+ if (view instanceof ExpandableView) {
+ ExpandableView expandableView = (ExpandableView) view;
+ expandableView.dump(fd, pw, args);
+ }
}
}
@@ -5771,7 +5725,7 @@
*/
public float setPulseHeight(float height) {
mAmbientState.setPulseHeight(height);
- if (mKeyguardBypassController.getBypassEnabled()) {
+ if (mKeyguardBypassEnabledProvider.getBypassEnabled()) {
notifyAppearChangedListeners();
}
requestChildrenUpdate();
@@ -5792,6 +5746,10 @@
requestChildrenUpdate();
}
+ public boolean isFullyAwake() {
+ return mAmbientState.isFullyAwake();
+ }
+
public void wakeUpFromPulse() {
setPulseHeight(getWakeUpHeight());
// Let's place the hidden views at the end of the pulsing notification to make sure we have
@@ -5849,6 +5807,39 @@
return mController;
}
+ void setCurrentUserid(int userId) {
+ mCurrentUserId = userId;
+ }
+
+ void onMenuShown(View row) {
+ mSwipeHelper.onMenuShown(row);
+ }
+
+ void onMenuReset(View row) {
+ View translatingParentView = mSwipeHelper.getTranslatingParentView();
+ if (translatingParentView != null && row == translatingParentView) {
+ mSwipeHelper.clearExposedMenuView();
+ mSwipeHelper.clearTranslatingParentView();
+ if (row instanceof ExpandableNotificationRow) {
+ mHeadsUpManager.setMenuShown(
+ ((ExpandableNotificationRow) row).getEntry(), false);
+
+ }
+ }
+ }
+
+ void addSwipedOutView(View v) {
+ mSwipedOutViews.add(v);
+ }
+
+ void addDraggedView(View view) {
+ mAmbientState.onBeginDrag(view);
+ }
+
+ void removeDraggedView(View view) {
+ mAmbientState.onDragFinished(view);
+ }
+
/**
* A listener that is notified when the empty space below the notifications is clicked on
*/
@@ -5916,7 +5907,7 @@
mSectionsManager.updateSectionBoundaries(reason);
}
- private void updateContinuousBackgroundDrawing() {
+ void updateContinuousBackgroundDrawing() {
boolean continuousBackground = !mAmbientState.isFullyAwake()
&& !mAmbientState.getDraggedViews().isEmpty();
if (continuousBackground != mContinuousBackgroundUpdate) {
@@ -5930,7 +5921,7 @@
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- private void updateContinuousShadowDrawing() {
+ void updateContinuousShadowDrawing() {
boolean continuousShadowUpdate = mAnimationRunning
|| !mAmbientState.getDraggedViews().isEmpty();
if (continuousShadowUpdate != mContinuousShadowUpdate) {
@@ -5944,7 +5935,7 @@
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void resetExposedMenuView(boolean animate, boolean force) {
+ void resetExposedMenuView(boolean animate, boolean force) {
mSwipeHelper.resetExposedMenuView(animate, force);
}
@@ -6204,277 +6195,7 @@
}
}
- @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- private final StateListener mStateListener = new StateListener() {
- @Override
- public void onStatePreChange(int oldState, int newState) {
- if (oldState == StatusBarState.SHADE_LOCKED && newState == StatusBarState.KEYGUARD) {
- requestAnimateEverything();
- }
- }
-
- @Override
- public void onStateChanged(int newState) {
- setStatusBarState(newState);
- }
-
- @Override
- public void onStatePostChange() {
- NotificationStackScrollLayout.this.onStatePostChange();
- }
- };
-
- @VisibleForTesting
- @ShadeViewRefactor(RefactorComponent.INPUT)
- protected final OnMenuEventListener mMenuEventListener = new OnMenuEventListener() {
- @Override
- public void onMenuClicked(View view, int x, int y, MenuItem item) {
- if (mLongPressListener == null) {
- return;
- }
- if (view instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) view;
- mMetricsLogger.write(row.getEntry().getSbn().getLogMaker()
- .setCategory(MetricsEvent.ACTION_TOUCH_GEAR)
- .setType(MetricsEvent.TYPE_ACTION)
- );
- }
- mLongPressListener.onLongPress(view, x, y, item);
- }
-
- @Override
- public void onMenuReset(View row) {
- View translatingParentView = mSwipeHelper.getTranslatingParentView();
- if (translatingParentView != null && row == translatingParentView) {
- mSwipeHelper.clearExposedMenuView();
- mSwipeHelper.clearTranslatingParentView();
- if (row instanceof ExpandableNotificationRow) {
- mHeadsUpManager.setMenuShown(
- ((ExpandableNotificationRow) row).getEntry(), false);
-
- }
- }
- }
-
- @Override
- public void onMenuShown(View row) {
- if (row instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow notificationRow = (ExpandableNotificationRow) row;
- mMetricsLogger.write(notificationRow.getEntry().getSbn().getLogMaker()
- .setCategory(MetricsEvent.ACTION_REVEAL_GEAR)
- .setType(MetricsEvent.TYPE_ACTION));
- mHeadsUpManager.setMenuShown(notificationRow.getEntry(), true);
- mSwipeHelper.onMenuShown(row);
- mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
- false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
- false /* resetMenu */);
-
- // Check to see if we want to go directly to the notfication guts
- NotificationMenuRowPlugin provider = notificationRow.getProvider();
- if (provider.shouldShowGutsOnSnapOpen()) {
- MenuItem item = provider.menuItemToExposeOnSnap();
- if (item != null) {
- Point origin = provider.getRevealAnimationOrigin();
- mNotificationGutsManager.openGuts(row, origin.x, origin.y, item);
- } else {
- Log.e(TAG, "Provider has shouldShowGutsOnSnapOpen, but provided no "
- + "menu item in menuItemtoExposeOnSnap. Skipping.");
- }
-
- // Close the menu row since we went directly to the guts
- resetExposedMenuView(false, true);
- }
- }
- }
- };
-
- @ShadeViewRefactor(RefactorComponent.INPUT)
- private final NotificationSwipeHelper.NotificationCallback mNotificationCallback =
- new NotificationSwipeHelper.NotificationCallback() {
- @Override
- public void onDismiss() {
- mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
- false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
- false /* resetMenu */);
- }
-
- @Override
- public void onSnooze(StatusBarNotification sbn,
- NotificationSwipeActionHelper.SnoozeOption snoozeOption) {
- mStatusBar.setNotificationSnoozed(sbn, snoozeOption);
- }
-
- @Override
- public void onSnooze(StatusBarNotification sbn, int hours) {
- mStatusBar.setNotificationSnoozed(sbn, hours);
- }
-
- @Override
- public boolean shouldDismissQuickly() {
- return NotificationStackScrollLayout.this.isExpanded() && mAmbientState.isFullyAwake();
- }
-
- @Override
- public void onDragCancelled(View v) {
- setSwipingInProgress(false);
- mFalsingManager.onNotificationStopDismissing();
- }
-
- /**
- * Handles cleanup after the given {@code view} has been fully swiped out (including
- * re-invoking dismiss logic in case the notification has not made its way out yet).
- */
- @Override
- public void onChildDismissed(View view) {
- if (!(view instanceof ActivatableNotificationView)) {
- return;
- }
- ActivatableNotificationView row = (ActivatableNotificationView) view;
- if (!row.isDismissed()) {
- handleChildViewDismissed(view);
- }
- ViewGroup transientContainer = row.getTransientContainer();
- if (transientContainer != null) {
- transientContainer.removeTransientView(view);
- }
- }
-
- /**
- * Starts up notification dismiss and tells the notification, if any, to remove itself from
- * layout.
- *
- * @param view view (e.g. notification) to dismiss from the layout
- */
-
- public void handleChildViewDismissed(View view) {
- setSwipingInProgress(false);
- if (mDismissAllInProgress) {
- return;
- }
-
- boolean isBlockingHelperShown = false;
-
- mAmbientState.onDragFinished(view);
- updateContinuousShadowDrawing();
-
- if (view instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) view;
- if (row.isHeadsUp()) {
- mHeadsUpManager.addSwipedOutNotification(
- row.getEntry().getSbn().getKey());
- }
- isBlockingHelperShown =
- row.performDismissWithBlockingHelper(false /* fromAccessibility */);
- }
-
- if (view instanceof PeopleHubView) {
- mSectionsManager.hidePeopleRow();
- }
-
- if (!isBlockingHelperShown) {
- mSwipedOutViews.add(view);
- }
- mFalsingManager.onNotificationDismissed();
- if (mFalsingManager.shouldEnforceBouncer()) {
- mStatusBar.executeRunnableDismissingKeyguard(
- null,
- null /* cancelAction */,
- false /* dismissShade */,
- true /* afterKeyguardGone */,
- false /* deferred */);
- }
- }
-
- @Override
- public boolean isAntiFalsingNeeded() {
- return onKeyguard();
- }
-
- @Override
- public View getChildAtPosition(MotionEvent ev) {
- View child = NotificationStackScrollLayout.this.getChildAtPosition(
- ev.getX(),
- ev.getY(),
- true /* requireMinHeight */,
- false /* ignoreDecors */);
- if (child instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- ExpandableNotificationRow parent = row.getNotificationParent();
- if (parent != null && parent.areChildrenExpanded()
- && (parent.areGutsExposed()
- || mSwipeHelper.getExposedMenuView() == parent
- || (parent.getAttachedChildren().size() == 1
- && parent.getEntry().isClearable()))) {
- // In this case the group is expanded and showing the menu for the
- // group, further interaction should apply to the group, not any
- // child notifications so we use the parent of the child. We also do the same
- // if we only have a single child.
- child = parent;
- }
- }
- return child;
- }
-
- @Override
- public void onBeginDrag(View v) {
- mFalsingManager.onNotificationStartDismissing();
- setSwipingInProgress(true);
- mAmbientState.onBeginDrag((ExpandableView) v);
- updateContinuousShadowDrawing();
- updateContinuousBackgroundDrawing();
- requestChildrenUpdate();
- }
-
- @Override
- public void onChildSnappedBack(View animView, float targetLeft) {
- mAmbientState.onDragFinished(animView);
- updateContinuousShadowDrawing();
- updateContinuousBackgroundDrawing();
- if (animView instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) animView;
- if (row.isPinned() && !canChildBeDismissed(row)
- && row.getEntry().getSbn().getNotification().fullScreenIntent
- == null) {
- mHeadsUpManager.removeNotification(row.getEntry().getSbn().getKey(),
- true /* removeImmediately */);
- }
- }
- }
-
- @Override
- public boolean updateSwipeProgress(View animView, boolean dismissable,
- float swipeProgress) {
- // Returning true prevents alpha fading.
- return !mFadeNotificationsOnDismiss;
- }
-
- @Override
- public float getFalsingThresholdFactor() {
- return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
- }
-
- @Override
- public int getConstrainSwipeStartPosition() {
- NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow();
- if (menuRow != null) {
- return Math.abs(menuRow.getMenuSnapTarget());
- }
- return 0;
- }
-
- @Override
- public boolean canChildBeDismissed(View v) {
- return NotificationStackScrollLayout.canChildBeDismissed(v);
- }
-
- @Override
- public boolean canChildBeDismissedInDirection(View v, boolean isRightOrDown) {
- //TODO: b/131242807 for why this doesn't do anything with direction
- return canChildBeDismissed(v);
- }
- };
-
- private static boolean canChildBeDismissed(View v) {
+ static boolean canChildBeDismissed(View v) {
if (v instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
if (row.isBlockingHelperShowingAndTranslationFinished()) {
@@ -6517,7 +6238,7 @@
@SelectedRows int selectedRows) {
if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
if (selectedRows == ROWS_ALL) {
- mNotifCollection.dismissAllNotifications(mLockscreenUserManager.getCurrentUserId());
+ mNotifCollection.dismissAllNotifications(mCurrentUserId);
} else {
final List<Pair<NotificationEntry, DismissedByUserStats>>
entriesWithRowsDismissedFromShade = new ArrayList<>();
@@ -6546,7 +6267,7 @@
}
if (selectedRows == ROWS_ALL) {
try {
- mBarService.onClearAllNotifications(mLockscreenUserManager.getCurrentUserId());
+ mBarService.onClearAllNotifications(mCurrentUserId);
} catch (Exception ex) {
}
}
@@ -6568,6 +6289,10 @@
NotificationLogger.getNotificationLocation(entry)));
}
+ public void setKeyguardMediaControllorVisible(boolean keyguardMediaControllorVisible) {
+ mKeyguardMediaControllorVisible = keyguardMediaControllorVisible;
+ }
+
// ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
@ShadeViewRefactor(RefactorComponent.INPUT)
@@ -6576,8 +6301,7 @@
/* Only ever called as a consequence of a lockscreen expansion gesture. */
@Override
public boolean onDraggedDown(View startingChild, int dragLengthY) {
- boolean canDragDown = hasActiveNotifications()
- || mKeyguardMediaController.getView().getVisibility() == VISIBLE;
+ boolean canDragDown = hasActiveNotifications() || mKeyguardMediaControllorVisible;
if (mStatusBarState == StatusBarState.KEYGUARD && canDragDown) {
mLockscreenGestureLogger.write(
MetricsEvent.ACTION_LS_SHADE,
@@ -6655,7 +6379,7 @@
@Override
public boolean isDragDownAnywhereEnabled() {
return mStatusbarStateController.getState() == StatusBarState.KEYGUARD
- && !mKeyguardBypassController.getBypassEnabled();
+ && !mKeyguardBypassEnabledProvider.getBypassEnabled();
}
};
@@ -6838,4 +6562,8 @@
return INVALID;
}
}
+
+ interface KeyguardBypassEnabledProvider {
+ boolean getBypassEnabled();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 7c29ee2b..73b4cad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -18,18 +18,38 @@
import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
+import android.content.res.Resources;
+import android.graphics.Point;
import android.graphics.PointF;
import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
import android.view.Display;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.widget.FrameLayout;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
+import com.android.systemui.SwipeHelper;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.media.KeyguardMediaController;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.RemoteInputController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
@@ -42,6 +62,7 @@
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -49,6 +70,7 @@
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
import java.util.function.BiConsumer;
@@ -56,11 +78,15 @@
import javax.inject.Inject;
import javax.inject.Named;
+import kotlin.Unit;
+
/**
* Controller for {@link NotificationStackScrollLayout}.
*/
@StatusBarComponent.StatusBarScope
public class NotificationStackScrollLayoutController {
+ private static final String TAG = "StackScrollerController";
+
private final boolean mAllowLongPress;
private final NotificationGutsManager mNotificationGutsManager;
private final HeadsUpManagerPhone mHeadsUpManager;
@@ -68,9 +94,25 @@
private final TunerService mTunerService;
private final DynamicPrivacyController mDynamicPrivacyController;
private final ConfigurationController mConfigurationController;
+ private final ZenModeController mZenModeController;
+ private final MetricsLogger mMetricsLogger;
+ private final FalsingManager mFalsingManager;
+ private final NotificationSectionsManager mNotificationSectionsManager;
+ private final Resources mResources;
+ private final NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder;
+ private final KeyguardMediaController mKeyguardMediaController;
+ private final SysuiStatusBarStateController mStatusBarStateController;
+ private final KeyguardBypassController mKeyguardBypassController;
+ private final SysuiColorExtractor mColorExtractor;
+ private final NotificationLockscreenUserManager mLockscreenUserManager;
+ // TODO: StatusBar should be encapsulated behind a Controller
+ private final StatusBar mStatusBar;
+
+ private NotificationStackScrollLayout mView;
+ private boolean mFadeNotificationsOnDismiss;
+
private final NotificationListContainerImpl mNotificationListContainer =
new NotificationListContainerImpl();
- private NotificationStackScrollLayout mView;
@VisibleForTesting
final View.OnAttachStateChangeListener mOnAttachStateChangeListener =
@@ -78,11 +120,14 @@
@Override
public void onViewAttachedToWindow(View v) {
mConfigurationController.addCallback(mConfigurationListener);
+ mStatusBarStateController.addCallback(
+ mStateListener, SysuiStatusBarStateController.RANK_STACK_SCROLLER);
}
@Override
public void onViewDetachedFromWindow(View v) {
mConfigurationController.removeCallback(mConfigurationListener);
+ mStatusBarStateController.removeCallback(mStateListener);
}
};
@@ -122,6 +167,279 @@
}
};
+ private final StatusBarStateController.StateListener mStateListener =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onStatePreChange(int oldState, int newState) {
+ if (oldState == StatusBarState.SHADE_LOCKED
+ && newState == StatusBarState.KEYGUARD) {
+ mView.requestAnimateEverything();
+ }
+ }
+
+ @Override
+ public void onStateChanged(int newState) {
+ mView.setStatusBarState(newState);
+ }
+
+ @Override
+ public void onStatePostChange() {
+ mView.updateSensitiveness(mStatusBarStateController.goingToFullShade(),
+ mLockscreenUserManager.isAnyProfilePublicMode());
+ mView.onStatePostChange(mStatusBarStateController.fromShadeLocked());
+ }
+ };
+
+ private final UserChangedListener mLockscreenUserChangeListener = new UserChangedListener() {
+ @Override
+ public void onUserChanged(int userId) {
+ mView.setCurrentUserid(userId);
+ mView.updateSensitiveness(false, mLockscreenUserManager.isAnyProfilePublicMode());
+ }
+ };
+
+ private final OnMenuEventListener mMenuEventListener = new OnMenuEventListener() {
+ @Override
+ public void onMenuClicked(
+ View view, int x, int y, NotificationMenuRowPlugin.MenuItem item) {
+ if (!mAllowLongPress) {
+ return;
+ }
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ mMetricsLogger.write(row.getEntry().getSbn().getLogMaker()
+ .setCategory(MetricsEvent.ACTION_TOUCH_GEAR)
+ .setType(MetricsEvent.TYPE_ACTION)
+ );
+ }
+ mNotificationGutsManager.openGuts(view, x, y, item);
+ }
+
+ @Override
+ public void onMenuReset(View row) {
+ mView.onMenuReset(row);
+ }
+
+ @Override
+ public void onMenuShown(View row) {
+ if (row instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow notificationRow = (ExpandableNotificationRow) row;
+ mMetricsLogger.write(notificationRow.getEntry().getSbn().getLogMaker()
+ .setCategory(MetricsEvent.ACTION_REVEAL_GEAR)
+ .setType(MetricsEvent.TYPE_ACTION));
+ mHeadsUpManager.setMenuShown(notificationRow.getEntry(), true);
+ mView.onMenuShown(row);
+ mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
+ false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
+
+ // Check to see if we want to go directly to the notification guts
+ NotificationMenuRowPlugin provider = notificationRow.getProvider();
+ if (provider.shouldShowGutsOnSnapOpen()) {
+ NotificationMenuRowPlugin.MenuItem item = provider.menuItemToExposeOnSnap();
+ if (item != null) {
+ Point origin = provider.getRevealAnimationOrigin();
+ mNotificationGutsManager.openGuts(row, origin.x, origin.y, item);
+ } else {
+ Log.e(TAG, "Provider has shouldShowGutsOnSnapOpen, but provided no "
+ + "menu item in menuItemtoExposeOnSnap. Skipping.");
+ }
+
+ // Close the menu row since we went directly to the guts
+ mView.resetExposedMenuView(false, true);
+ }
+ }
+ }
+ };
+
+ private final NotificationSwipeHelper.NotificationCallback mNotificationCallback =
+ new NotificationSwipeHelper.NotificationCallback() {
+
+ @Override
+ public void onDismiss() {
+ mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
+ false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
+ }
+
+ @Override
+ public void onSnooze(StatusBarNotification sbn,
+ NotificationSwipeActionHelper.SnoozeOption snoozeOption) {
+ mStatusBar.setNotificationSnoozed(sbn, snoozeOption);
+ }
+
+ @Override
+ public void onSnooze(StatusBarNotification sbn, int hours) {
+ mStatusBar.setNotificationSnoozed(sbn, hours);
+ }
+
+ @Override
+ public boolean shouldDismissQuickly() {
+ return mView.isExpanded() && mView.isFullyAwake();
+ }
+
+ @Override
+ public void onDragCancelled(View v) {
+ mView.setSwipingInProgress(false);
+ mFalsingManager.onNotificationStopDismissing();
+ }
+
+ /**
+ * Handles cleanup after the given {@code view} has been fully swiped out (including
+ * re-invoking dismiss logic in case the notification has not made its way out yet).
+ */
+ @Override
+ public void onChildDismissed(View view) {
+ if (!(view instanceof ActivatableNotificationView)) {
+ return;
+ }
+ ActivatableNotificationView row = (ActivatableNotificationView) view;
+ if (!row.isDismissed()) {
+ handleChildViewDismissed(view);
+ }
+ ViewGroup transientContainer = row.getTransientContainer();
+ if (transientContainer != null) {
+ transientContainer.removeTransientView(view);
+ }
+ }
+
+ /**
+ * Starts up notification dismiss and tells the notification, if any, to remove
+ * itself from the layout.
+ *
+ * @param view view (e.g. notification) to dismiss from the layout
+ */
+
+ public void handleChildViewDismissed(View view) {
+ mView.setSwipingInProgress(false);
+ if (mView.getDismissAllInProgress()) {
+ return;
+ }
+
+ boolean isBlockingHelperShown = false;
+
+ mView.removeDraggedView(view);
+ mView.updateContinuousShadowDrawing();
+
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ if (row.isHeadsUp()) {
+ mHeadsUpManager.addSwipedOutNotification(
+ row.getEntry().getSbn().getKey());
+ }
+ isBlockingHelperShown =
+ row.performDismissWithBlockingHelper(false /* fromAccessibility */);
+ }
+
+ if (view instanceof PeopleHubView) {
+ mNotificationSectionsManager.hidePeopleRow();
+ }
+
+ if (!isBlockingHelperShown) {
+ mView.addSwipedOutView(view);
+ }
+ mFalsingManager.onNotificationDismissed();
+ if (mFalsingManager.shouldEnforceBouncer()) {
+ mStatusBar.executeRunnableDismissingKeyguard(
+ null,
+ null /* cancelAction */,
+ false /* dismissShade */,
+ true /* afterKeyguardGone */,
+ false /* deferred */);
+ }
+ }
+
+ @Override
+ public boolean isAntiFalsingNeeded() {
+ return mView.onKeyguard();
+ }
+
+ @Override
+ public View getChildAtPosition(MotionEvent ev) {
+ View child = mView.getChildAtPosition(
+ ev.getX(),
+ ev.getY(),
+ true /* requireMinHeight */,
+ false /* ignoreDecors */);
+ if (child instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ ExpandableNotificationRow parent = row.getNotificationParent();
+ if (parent != null && parent.areChildrenExpanded()
+ && (parent.areGutsExposed()
+ || mSwipeHelper.getExposedMenuView() == parent
+ || (parent.getAttachedChildren().size() == 1
+ && parent.getEntry().isClearable()))) {
+ // In this case the group is expanded and showing the menu for the
+ // group, further interaction should apply to the group, not any
+ // child notifications so we use the parent of the child. We also do the
+ // same if we only have a single child.
+ child = parent;
+ }
+ }
+ return child;
+ }
+
+ @Override
+ public void onBeginDrag(View v) {
+ mFalsingManager.onNotificationStartDismissing();
+ mView.setSwipingInProgress(true);
+ mView.addDraggedView(v);
+ mView.updateContinuousShadowDrawing();
+ mView.updateContinuousBackgroundDrawing();
+ mView.requestChildrenUpdate();
+ }
+
+ @Override
+ public void onChildSnappedBack(View animView, float targetLeft) {
+ mView.addDraggedView(animView);
+ mView.updateContinuousShadowDrawing();
+ mView.updateContinuousBackgroundDrawing();
+ if (animView instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) animView;
+ if (row.isPinned() && !canChildBeDismissed(row)
+ && row.getEntry().getSbn().getNotification().fullScreenIntent
+ == null) {
+ mHeadsUpManager.removeNotification(row.getEntry().getSbn().getKey(),
+ true /* removeImmediately */);
+ }
+ }
+ }
+
+ @Override
+ public boolean updateSwipeProgress(View animView, boolean dismissable,
+ float swipeProgress) {
+ // Returning true prevents alpha fading.
+ return !mFadeNotificationsOnDismiss;
+ }
+
+ @Override
+ public float getFalsingThresholdFactor() {
+ return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
+ }
+
+ @Override
+ public int getConstrainSwipeStartPosition() {
+ NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow();
+ if (menuRow != null) {
+ return Math.abs(menuRow.getMenuSnapTarget());
+ }
+ return 0;
+ }
+
+ @Override
+ public boolean canChildBeDismissed(View v) {
+ return NotificationStackScrollLayout.canChildBeDismissed(v);
+ }
+
+ @Override
+ public boolean canChildBeDismissedInDirection(View v, boolean isRightOrDown) {
+ //TODO: b/131242807 for why this doesn't do anything with direction
+ return canChildBeDismissed(v);
+ }
+ };
+
+ private NotificationSwipeHelper mSwipeHelper;
+
@Inject
public NotificationStackScrollLayoutController(
@Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
@@ -130,7 +448,19 @@
NotificationRoundnessManager notificationRoundnessManager,
TunerService tunerService,
DynamicPrivacyController dynamicPrivacyController,
- ConfigurationController configurationController) {
+ ConfigurationController configurationController,
+ SysuiStatusBarStateController statusBarStateController,
+ KeyguardMediaController keyguardMediaController,
+ KeyguardBypassController keyguardBypassController,
+ ZenModeController zenModeController,
+ SysuiColorExtractor colorExtractor,
+ NotificationLockscreenUserManager lockscreenUserManager,
+ MetricsLogger metricsLogger,
+ FalsingManager falsingManager,
+ NotificationSectionsManager notificationSectionsManager,
+ @Main Resources resources,
+ NotificationSwipeHelper.Builder notificationSwipeHelperBuilder,
+ StatusBar statusBar) {
mAllowLongPress = allowLongPress;
mNotificationGutsManager = notificationGutsManager;
mHeadsUpManager = headsUpManager;
@@ -138,19 +468,42 @@
mTunerService = tunerService;
mDynamicPrivacyController = dynamicPrivacyController;
mConfigurationController = configurationController;
+ mStatusBarStateController = statusBarStateController;
+ mKeyguardMediaController = keyguardMediaController;
+ mKeyguardBypassController = keyguardBypassController;
+ mZenModeController = zenModeController;
+ mColorExtractor = colorExtractor;
+ mLockscreenUserManager = lockscreenUserManager;
+ mMetricsLogger = metricsLogger;
+ mFalsingManager = falsingManager;
+ mNotificationSectionsManager = notificationSectionsManager;
+ mResources = resources;
+ mNotificationSwipeHelperBuilder = notificationSwipeHelperBuilder;
+ mStatusBar = statusBar;
}
public void attach(NotificationStackScrollLayout view) {
mView = view;
mView.setController(this);
- if (mAllowLongPress) {
- mView.setLongPressListener(mNotificationGutsManager::openGuts);
- }
+ mSwipeHelper = mNotificationSwipeHelperBuilder
+ .setSwipeDirection(SwipeHelper.X)
+ .setNotificationCallback(mNotificationCallback)
+ .setOnMenuEventListener(mMenuEventListener)
+ .build();
+
+ mView.initView(mView.getContext(), mKeyguardBypassController::getBypassEnabled,
+ mSwipeHelper);
mHeadsUpManager.addListener(mNotificationRoundnessManager); // TODO: why is this here?
mDynamicPrivacyController.addListener(mDynamicPrivacyControllerListener);
+ mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener);
+ mView.setCurrentUserid(mLockscreenUserManager.getCurrentUserId());
+
+ mFadeNotificationsOnDismiss = // TODO: this should probably be injected directly
+ mResources.getBoolean(R.bool.config_fadeNotificationsOnDismiss);
+
mNotificationRoundnessManager.setOnRoundingChangedCallback(mView::invalidate);
mView.addOnExpandedHeightChangedListener(mNotificationRoundnessManager::setExpanded);
@@ -165,6 +518,23 @@
Settings.Secure.NOTIFICATION_DISMISS_RTL,
Settings.Secure.NOTIFICATION_HISTORY_ENABLED);
+ mColorExtractor.addOnColorsChangedListener((colorExtractor, which) -> {
+ final boolean useDarkText = mColorExtractor.getNeutralColors().supportsDarkText();
+ mView.updateDecorViews(useDarkText);
+ });
+
+ mKeyguardMediaController.setVisibilityChangedListener(visible -> {
+ mView.setKeyguardMediaControllorVisible(visible);
+ if (visible) {
+ mView.generateAddAnimation(
+ mKeyguardMediaController.getView(), false /*fromMoreCard */);
+ } else {
+ mView.generateRemoveAnimation(mKeyguardMediaController.getView());
+ }
+ mView.requestChildrenUpdate();
+ return Unit.INSTANCE;
+ });
+
if (mView.isAttachedToWindow()) {
mOnAttachStateChangeListener.onViewAttachedToWindow(mView);
}
@@ -484,7 +854,7 @@
}
public void updateEmptyShadeView(boolean visible) {
- mView.updateEmptyShadeView(visible);
+ mView.updateEmptyShadeView(visible, mZenModeController.areNotificationsHiddenInShade());
}
public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
@@ -532,6 +902,13 @@
return mView.hasActiveClearableNotifications(selection);
}
+ /**
+ * Set the maximum number of notifications that can currently be displayed
+ */
+ public void setMaxDisplayedNotifications(int maxNotifications) {
+ mNotificationListContainer.setMaxDisplayedNotifications(maxNotifications);
+ }
+
public RemoteInputController.Delegate createDelegate() {
return mView.createDelegate();
}
@@ -646,7 +1023,7 @@
@Override
public void notifyGroupChildAdded(ExpandableView row) {
- mView.onViewAddedInternal(row);
+ mView.notifyGroupChildAdded(row);
}
@Override
@@ -712,7 +1089,7 @@
@Override
public NotificationSwipeActionHelper getSwipeActionHelper() {
- return mView.getSwipeActionHelper();
+ return mSwipeHelper;
}
@Override
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 d3b8a8c..1e80e88 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
@@ -19,15 +19,17 @@
import android.animation.Animator;
import android.animation.ValueAnimator;
-import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Handler;
import android.service.notification.StatusBarNotification;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewConfiguration;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.SwipeHelper;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
@@ -36,6 +38,8 @@
import java.lang.ref.WeakReference;
+import javax.inject.Inject;
+
class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeActionHelper {
@VisibleForTesting
@@ -58,10 +62,10 @@
private boolean mPulsing;
NotificationSwipeHelper(
- int swipeDirection, NotificationCallback callback, Context context,
- NotificationMenuRowPlugin.OnMenuEventListener menuListener,
- FalsingManager falsingManager) {
- super(swipeDirection, callback, context, falsingManager);
+ Resources resources, ViewConfiguration viewConfiguration,
+ FalsingManager falsingManager, int swipeDirection, NotificationCallback callback,
+ NotificationMenuRowPlugin.OnMenuEventListener menuListener) {
+ super(swipeDirection, callback, resources, viewConfiguration, falsingManager);
mMenuListener = menuListener;
mCallback = callback;
mFalsingCheck = () -> resetExposedMenuView(true /* animate */, true /* force */);
@@ -74,7 +78,7 @@
public void clearTranslatingParentView() { setTranslatingParentView(null); }
@VisibleForTesting
- protected void setTranslatingParentView(View view) { mTranslatingParentView = view; };
+ protected void setTranslatingParentView(View view) { mTranslatingParentView = view; }
public void setExposedMenuView(View view) {
mMenuExposedView = view;
@@ -90,7 +94,7 @@
@VisibleForTesting
void setCurrentMenuRow(NotificationMenuRowPlugin menuRow) {
- mCurrMenuRowRef = menuRow != null ? new WeakReference(menuRow) : null;
+ mCurrMenuRowRef = menuRow != null ? new WeakReference<>(menuRow) : null;
}
public NotificationMenuRowPlugin getCurrentMenuRow() {
@@ -470,4 +474,42 @@
void onDismiss();
}
+
+ static class Builder {
+ private final Resources mResources;
+ private final ViewConfiguration mViewConfiguration;
+ private final FalsingManager mFalsingManager;
+ private int mSwipeDirection;
+ private NotificationCallback mNotificationCallback;
+ private NotificationMenuRowPlugin.OnMenuEventListener mOnMenuEventListener;
+
+ @Inject
+ Builder(@Main Resources resources, ViewConfiguration viewConfiguration,
+ FalsingManager falsingManager) {
+ mResources = resources;
+ mViewConfiguration = viewConfiguration;
+ mFalsingManager = falsingManager;
+ }
+
+ Builder setSwipeDirection(int swipeDirection) {
+ mSwipeDirection = swipeDirection;
+ return this;
+ }
+
+ Builder setNotificationCallback(NotificationCallback notificationCallback) {
+ mNotificationCallback = notificationCallback;
+ return this;
+ }
+
+ Builder setOnMenuEventListener(
+ NotificationMenuRowPlugin.OnMenuEventListener onMenuEventListener) {
+ mOnMenuEventListener = onMenuEventListener;
+ return this;
+ }
+
+ NotificationSwipeHelper build() {
+ return new NotificationSwipeHelper(mResources, mViewConfiguration, mFalsingManager,
+ mSwipeDirection, mNotificationCallback, mOnMenuEventListener);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index a6811c6..78fcd82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -45,6 +45,7 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.keyguard.FaceAuthScreenBrightnessController;
import com.android.systemui.statusbar.NotificationMediaManager;
import libcore.io.IoUtils;
@@ -52,6 +53,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Objects;
+import java.util.Optional;
import javax.inject.Inject;
@@ -68,6 +70,7 @@
private final WallpaperManager mWallpaperManager;
private final KeyguardUpdateMonitor mUpdateMonitor;
private final Handler mH;
+ private final Optional<FaceAuthScreenBrightnessController> mFaceAuthScreenBrightnessController;
private boolean mCached;
private Bitmap mCache;
@@ -83,12 +86,14 @@
KeyguardUpdateMonitor keyguardUpdateMonitor,
DumpManager dumpManager,
NotificationMediaManager mediaManager,
+ Optional<FaceAuthScreenBrightnessController> faceAuthScreenBrightnessController,
@Main Handler mainHandler) {
dumpManager.registerDumpable(getClass().getSimpleName(), this);
mWallpaperManager = wallpaperManager;
mCurrentUserId = ActivityManager.getCurrentUser();
mUpdateMonitor = keyguardUpdateMonitor;
mMediaManager = mediaManager;
+ mFaceAuthScreenBrightnessController = faceAuthScreenBrightnessController;
mH = mainHandler;
if (iWallpaperManager != null) {
@@ -128,6 +133,14 @@
return LoaderResult.success(null);
}
+ Bitmap faceAuthWallpaper = null;
+ if (mFaceAuthScreenBrightnessController.isPresent()) {
+ faceAuthWallpaper = mFaceAuthScreenBrightnessController.get().getFaceAuthWallpaper();
+ if (faceAuthWallpaper != null) {
+ return LoaderResult.success(faceAuthWallpaper);
+ }
+ }
+
// Prefer the selected user (when specified) over the current user for the FLAG_SET_LOCK
// wallpaper.
final int lockWallpaperUserId =
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 5974a53..d83758a 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 @@
import static android.view.View.GONE;
+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;
@@ -31,6 +32,7 @@
import android.app.StatusBarManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
@@ -70,6 +72,7 @@
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.DisplayId;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
@@ -85,7 +88,6 @@
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.RemoteInputController;
@@ -231,7 +233,7 @@
BiometricSourceType biometricSourceType) {
boolean
keyguardOrShadeLocked =
- mBarState == StatusBarState.KEYGUARD
+ mBarState == KEYGUARD
|| mBarState == StatusBarState.SHADE_LOCKED;
if (!running && mFirstBypassAttempt && keyguardOrShadeLocked && !mDozing
&& !mDelayShowingKeyguardStatusBar
@@ -259,6 +261,11 @@
private final MediaHierarchyManager mMediaHierarchyManager;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private final Provider<KeyguardClockSwitchController> mKeyguardClockSwitchControllerProvider;
+ // 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;
+ // Current max allowed keyguard notifications determined by measuring the panel
+ private int mMaxAllowedKeyguardNotifications;
private KeyguardAffordanceHelper mAffordanceHelper;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
@@ -482,6 +489,7 @@
@Inject
public NotificationPanelViewController(NotificationPanelView view,
+ @Main Resources resources,
InjectionInflationController injectionInflationController,
NotificationWakeUpCoordinator coordinator, PulseExpansionHandler pulseExpansionHandler,
DynamicPrivacyController dynamicPrivacyController,
@@ -584,6 +592,7 @@
mView.getOverlay().add(new DebugDrawable());
}
+ mMaxKeyguardNotifications = resources.getInteger(R.integer.keyguard_max_notification_count);
onFinishInflate();
}
@@ -761,6 +770,20 @@
mKeyguardBottomArea.setUserSetupComplete(mUserSetupComplete);
}
+ private void updateMaxDisplayedNotifications(boolean recompute) {
+ if (recompute) {
+ mMaxAllowedKeyguardNotifications = Math.max(computeMaxKeyguardNotifications(), 1);
+ }
+
+ if (mKeyguardShowing && !mKeyguardBypassController.getBypassEnabled()) {
+ mNotificationStackScrollLayoutController.setMaxDisplayedNotifications(
+ mMaxAllowedKeyguardNotifications);
+ } else {
+ // no max when not on the keyguard
+ mNotificationStackScrollLayoutController.setMaxDisplayedNotifications(-1);
+ }
+ }
+
public void setKeyguardIndicationController(KeyguardIndicationController indicationController) {
mKeyguardIndicationController = indicationController;
mKeyguardIndicationController.setIndicationArea(mKeyguardBottomArea);
@@ -821,7 +844,7 @@
boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
boolean animateClock = animate || mAnimateNextPositionUpdate;
int stackScrollerPadding;
- if (mBarState != StatusBarState.KEYGUARD) {
+ if (mBarState != KEYGUARD) {
stackScrollerPadding = getUnlockedStackScrollerPadding();
} else {
int totalHeight = mView.getHeight();
@@ -865,20 +888,17 @@
}
/**
- * @param maximum the maximum to return at most
* @return the maximum keyguard notifications that can fit on the screen
*/
- public int computeMaxKeyguardNotifications(int maximum) {
+ private int computeMaxKeyguardNotifications() {
float minPadding = mClockPositionAlgorithm.getMinStackScrollerPadding();
int notificationPadding = Math.max(
1, mResources.getDimensionPixelSize(R.dimen.notification_divider_height));
- NotificationShelf shelf = mNotificationShelfController.getView();
- float
- shelfSize =
- shelf.getVisibility() == View.GONE ? 0
- : shelf.getIntrinsicHeight() + notificationPadding;
- float
- availableSpace =
+ float shelfSize =
+ mNotificationShelfController.getVisibility() == View.GONE
+ ? 0
+ : mNotificationShelfController.getIntrinsicHeight() + notificationPadding;
+ float availableSpace =
mNotificationStackScrollLayoutController.getHeight() - minPadding - shelfSize
- Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding)
- mKeyguardStatusView.getLogoutButtonHeight();
@@ -908,7 +928,8 @@
availableSpace -= mNotificationStackScrollLayoutController
.calculateGapHeight(previousView, child, count);
previousView = child;
- if (availableSpace >= 0 && count < maximum) {
+ if (availableSpace >= 0
+ && (mMaxKeyguardNotifications == -1 || count < mMaxKeyguardNotifications)) {
count++;
} else if (availableSpace > -shelfSize) {
// if we are exactly the last view, then we can show us still!
@@ -1235,7 +1256,7 @@
float vel = getCurrentQSVelocity();
final int
gesture =
- mBarState == StatusBarState.KEYGUARD ? MetricsEvent.ACTION_LS_QS
+ mBarState == KEYGUARD ? MetricsEvent.ACTION_LS_QS
: MetricsEvent.ACTION_SHADE_QS_PULL;
mLockscreenGestureLogger.write(gesture,
(int) ((y - mInitialTouchY) / mStatusBar.getDisplayDensity()),
@@ -1292,7 +1313,7 @@
private boolean handleQsTouch(MotionEvent event) {
final int action = event.getActionMasked();
if (action == MotionEvent.ACTION_DOWN && getExpandedFraction() == 1f
- && mBarState != StatusBarState.KEYGUARD && !mQsExpanded && mQsExpansionEnabled) {
+ && mBarState != KEYGUARD && !mQsExpanded && mQsExpansionEnabled) {
// Down in the empty area while fully expanded - go to QS.
mQsTracking = true;
@@ -1646,7 +1667,7 @@
mKeyguardStateController.getShortenedFadingAwayDuration()).setInterpolator(
Interpolators.ALPHA_OUT).withEndAction(
mAnimateKeyguardBottomAreaInvisibleEndRunnable).start();
- } else if (statusBarState == StatusBarState.KEYGUARD
+ } else if (statusBarState == KEYGUARD
|| statusBarState == StatusBarState.SHADE_LOCKED) {
mKeyguardBottomArea.setVisibility(View.VISIBLE);
mKeyguardBottomArea.setAlpha(1f);
@@ -1659,8 +1680,8 @@
boolean goingToFullShade) {
mKeyguardStatusView.animate().cancel();
mKeyguardStatusViewAnimating = false;
- if ((!keyguardFadingAway && mBarState == StatusBarState.KEYGUARD
- && statusBarState != StatusBarState.KEYGUARD) || goingToFullShade) {
+ if ((!keyguardFadingAway && mBarState == KEYGUARD
+ && statusBarState != KEYGUARD) || goingToFullShade) {
mKeyguardStatusViewAnimating = true;
mKeyguardStatusView.animate().alpha(0f).setStartDelay(0).setDuration(
160).setInterpolator(Interpolators.ALPHA_OUT).withEndAction(
@@ -1671,14 +1692,14 @@
mKeyguardStateController.getShortenedFadingAwayDuration()).start();
}
} else if (mBarState == StatusBarState.SHADE_LOCKED
- && statusBarState == StatusBarState.KEYGUARD) {
+ && statusBarState == KEYGUARD) {
mKeyguardStatusView.setVisibility(View.VISIBLE);
mKeyguardStatusViewAnimating = true;
mKeyguardStatusView.setAlpha(0f);
mKeyguardStatusView.animate().alpha(1f).setStartDelay(0).setDuration(
320).setInterpolator(Interpolators.ALPHA_IN).withEndAction(
mAnimateKeyguardStatusViewVisibleEndRunnable);
- } else if (statusBarState == StatusBarState.KEYGUARD) {
+ } else if (statusBarState == KEYGUARD) {
if (keyguardFadingAway) {
mKeyguardStatusViewAnimating = true;
mKeyguardStatusView.animate().alpha(0).translationYBy(
@@ -1698,7 +1719,7 @@
private void updateQsState() {
mNotificationStackScrollLayoutController.setQsExpanded(mQsExpanded);
mNotificationStackScrollLayoutController.setScrollingEnabled(
- mBarState != StatusBarState.KEYGUARD && (!mQsExpanded
+ mBarState != KEYGUARD && (!mQsExpanded
|| mQsExpansionFromOverscroll));
updateEmptyShadeView();
@@ -1725,7 +1746,7 @@
updateQsExpansion();
requestScrollerTopPaddingUpdate(false /* animate */);
updateHeaderKeyguardAlpha();
- if (mBarState == StatusBarState.SHADE_LOCKED || mBarState == StatusBarState.KEYGUARD) {
+ if (mBarState == StatusBarState.SHADE_LOCKED || mBarState == KEYGUARD) {
updateKeyguardBottomAreaAlpha();
updateBigClockAlpha();
}
@@ -1767,7 +1788,7 @@
// Upon initialisation when we are not layouted yet we don't want to announce that we
// are fully expanded, hence the != 0.0f check.
return mResources.getString(R.string.accessibility_desc_quick_settings);
- } else if (mBarState == StatusBarState.KEYGUARD) {
+ } else if (mBarState == KEYGUARD) {
return mResources.getString(R.string.accessibility_desc_lock_screen);
} else {
return mResources.getString(R.string.accessibility_desc_notification_shade);
@@ -1785,7 +1806,7 @@
// for a nice motion.
int maxNotificationPadding = getKeyguardNotificationStaticPadding();
int maxQsPadding = mQsMaxExpansionHeight + mQsNotificationTopPadding;
- int max = mBarState == StatusBarState.KEYGUARD ? Math.max(
+ int max = mBarState == KEYGUARD ? Math.max(
maxNotificationPadding, maxQsPadding) : maxQsPadding;
return (int) MathUtils.lerp((float) mQsMinExpansionHeight, (float) max,
getExpandedFraction());
@@ -1973,7 +1994,7 @@
@Override
protected boolean canCollapsePanelOnTouch() {
if (!isInSettings()) {
- return mBarState == StatusBarState.KEYGUARD
+ return mBarState == KEYGUARD
|| mIsPanelCollapseOnQQS
|| mNotificationStackScrollLayoutController.isScrolledToBottom();
} else {
@@ -1983,7 +2004,7 @@
@Override
protected int getMaxPanelHeight() {
- if (mKeyguardBypassController.getBypassEnabled() && mBarState == StatusBarState.KEYGUARD) {
+ if (mKeyguardBypassController.getBypassEnabled() && mBarState == KEYGUARD) {
return getMaxPanelHeightBypass();
} else {
return getMaxPanelHeightNonBypass();
@@ -1992,7 +2013,7 @@
private int getMaxPanelHeightNonBypass() {
int min = mStatusBarMinHeight;
- if (!(mBarState == StatusBarState.KEYGUARD)
+ if (!(mBarState == KEYGUARD)
&& mNotificationStackScrollLayoutController.getNotGoneChildCount() == 0) {
int minHeight = (int) (mQsMinExpansionHeight + getOverExpansionAmount());
min = Math.max(min, minHeight);
@@ -2095,7 +2116,7 @@
int maxHeight = mNotificationStackScrollLayoutController.getHeight() - emptyBottomMargin;
maxHeight += mNotificationStackScrollLayoutController.getTopPaddingOverflow();
- if (mBarState == StatusBarState.KEYGUARD) {
+ if (mBarState == KEYGUARD) {
int
minKeyguardPanelBottom =
mClockPositionAlgorithm.getExpandedClockPosition()
@@ -2132,7 +2153,7 @@
maxQsHeight = (int) mQsSizeChangeAnimator.getAnimatedValue();
}
float totalHeight = Math.max(maxQsHeight,
- mBarState == StatusBarState.KEYGUARD ? mClockPositionResult.stackScrollerPadding
+ mBarState == KEYGUARD ? mClockPositionResult.stackScrollerPadding
: 0) + notificationHeight
+ mNotificationStackScrollLayoutController.getTopPaddingOverflow();
if (totalHeight > mNotificationStackScrollLayoutController.getHeight()) {
@@ -2151,7 +2172,7 @@
&& !mHeadsUpManager.hasPinnedHeadsUp()) {
alpha = getFadeoutAlpha();
}
- if (mBarState == StatusBarState.KEYGUARD && !mHintAnimationRunning
+ if (mBarState == KEYGUARD && !mHintAnimationRunning
&& !mKeyguardBypassController.getBypassEnabled()) {
alpha *= mClockPositionResult.clockAlpha;
}
@@ -2190,14 +2211,14 @@
* Hides the header when notifications are colliding with it.
*/
private void updateHeader() {
- if (mBarState == StatusBarState.KEYGUARD) {
+ if (mBarState == KEYGUARD) {
updateHeaderKeyguardAlpha();
}
updateQsExpansion();
}
protected float getHeaderTranslation() {
- if (mBarState == StatusBarState.KEYGUARD && !mKeyguardBypassController.getBypassEnabled()) {
+ if (mBarState == KEYGUARD && !mKeyguardBypassController.getBypassEnabled()) {
return -mQs.getQsMinExpansionHeight();
}
float appearAmount = mNotificationStackScrollLayoutController
@@ -2227,7 +2248,7 @@
*/
private float getKeyguardContentsAlpha() {
float alpha;
- if (mBarState == StatusBarState.KEYGUARD) {
+ if (mBarState == KEYGUARD) {
// When on Keyguard, we hide the header as soon as we expanded close enough to the
// header
@@ -2376,7 +2397,7 @@
if (mConflictingQsExpansionGesture || mQsExpandImmediate) {
return;
}
- if (mBarState != StatusBarState.KEYGUARD) {
+ if (mBarState != KEYGUARD) {
mNotificationStackScrollLayoutController.setOnHeightChangedListener(null);
if (isPixels) {
mNotificationStackScrollLayoutController.setOverScrolledPixels(
@@ -2398,7 +2419,7 @@
mQsExpandImmediate = true;
mNotificationStackScrollLayoutController.setShouldShowShelfOnly(true);
}
- if (mBarState == StatusBarState.KEYGUARD || mBarState == StatusBarState.SHADE_LOCKED) {
+ if (mBarState == KEYGUARD || mBarState == StatusBarState.SHADE_LOCKED) {
mAffordanceHelper.animateHideLeftRightIcon();
}
mNotificationStackScrollLayoutController.onPanelTrackingStarted();
@@ -2413,7 +2434,7 @@
true /* animate */);
}
mNotificationStackScrollLayoutController.onPanelTrackingStopped();
- if (expand && (mBarState == StatusBarState.KEYGUARD
+ if (expand && (mBarState == KEYGUARD
|| mBarState == StatusBarState.SHADE_LOCKED)) {
if (!mHintAnimationRunning) {
mAffordanceHelper.reset(true);
@@ -2564,7 +2585,7 @@
@Override
protected boolean onMiddleClicked() {
switch (mBarState) {
- case StatusBarState.KEYGUARD:
+ case KEYGUARD:
if (!mDozingOnDown) {
if (mKeyguardBypassController.getBypassEnabled()) {
mUpdateMonitor.requestFaceAuth();
@@ -2579,7 +2600,7 @@
return true;
case StatusBarState.SHADE_LOCKED:
if (!mQsExpanded) {
- mStatusBarStateController.setState(StatusBarState.KEYGUARD);
+ mStatusBarStateController.setState(KEYGUARD);
}
return true;
case StatusBarState.SHADE:
@@ -2750,7 +2771,7 @@
}
private boolean isOnKeyguard() {
- return mBarState == StatusBarState.KEYGUARD;
+ return mBarState == KEYGUARD;
}
public void setPanelScrimMinFraction(float minFraction) {
@@ -2925,7 +2946,7 @@
mBottomAreaShadeAlphaAnimator.cancel();
}
- if (mBarState == StatusBarState.KEYGUARD || mBarState == StatusBarState.SHADE_LOCKED) {
+ if (mBarState == KEYGUARD || mBarState == StatusBarState.SHADE_LOCKED) {
updateDozingVisibilities(animate);
}
@@ -2953,7 +2974,7 @@
public void setAmbientIndicationBottomPadding(int ambientIndicationBottomPadding) {
if (mAmbientIndicationBottomPadding != ambientIndicationBottomPadding) {
mAmbientIndicationBottomPadding = ambientIndicationBottomPadding;
- mStatusBar.updateKeyguardMaxNotifications();
+ updateMaxDisplayedNotifications(true);
}
}
@@ -3057,7 +3078,7 @@
private void updateShowEmptyShadeView() {
boolean
showEmptyShadeView =
- mBarState != StatusBarState.KEYGUARD && !mEntryManager.hasActiveNotifications();
+ mBarState != KEYGUARD && !mEntryManager.hasActiveNotifications();
showEmptyShadeView(showEmptyShadeView);
}
@@ -3127,6 +3148,7 @@
mNotificationStackScrollLayoutController.setScrimController(scrimController);
updateShowEmptyShadeView();
mNotificationShelfController = notificationShelfController;
+ updateMaxDisplayedNotifications(true);
}
public void showTransientIndication(int id) {
@@ -3506,7 +3528,7 @@
@Override
public boolean needsAntiFalsing() {
- return mBarState == StatusBarState.KEYGUARD;
+ return mBarState == KEYGUARD;
}
}
@@ -3619,14 +3641,15 @@
boolean goingToFullShade = mStatusBarStateController.goingToFullShade();
boolean keyguardFadingAway = mKeyguardStateController.isKeyguardFadingAway();
int oldState = mBarState;
- boolean keyguardShowing = statusBarState == StatusBarState.KEYGUARD;
+ boolean keyguardShowing = statusBarState == KEYGUARD;
+
setKeyguardStatusViewVisibility(statusBarState, keyguardFadingAway, goingToFullShade);
setKeyguardBottomAreaVisibility(statusBarState, goingToFullShade);
mBarState = statusBarState;
mKeyguardShowing = keyguardShowing;
- if (oldState == StatusBarState.KEYGUARD && (goingToFullShade
+ if (oldState == KEYGUARD && (goingToFullShade
|| statusBarState == StatusBarState.SHADE_LOCKED)) {
animateKeyguardStatusBarOut();
long
@@ -3635,7 +3658,7 @@
: mKeyguardStateController.calculateGoingToFullShadeDelay();
mQs.animateHeaderSlidingIn(delay);
} else if (oldState == StatusBarState.SHADE_LOCKED
- && statusBarState == StatusBarState.KEYGUARD) {
+ && statusBarState == KEYGUARD) {
animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
mNotificationStackScrollLayoutController.resetScrollPosition();
// Only animate header if the header is visible. If not, it will partially
@@ -3657,7 +3680,9 @@
if (keyguardShowing) {
updateDozingVisibilities(false /* animate */);
}
- // THe update needs to happen after the headerSlide in above, otherwise the translation
+
+ updateMaxDisplayedNotifications(false);
+ // The update needs to happen after the headerSlide in above, otherwise the translation
// would reset
updateQSPulseExpansion();
maybeAnimateBottomAreaAlpha();
@@ -3713,6 +3738,7 @@
int oldTop, int oldRight, int oldBottom) {
DejankUtils.startDetectingBlockingIpcs("NVP#onLayout");
super.onLayoutChange(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom);
+ updateMaxDisplayedNotifications(true);
setIsFullWidth(mNotificationStackScrollLayoutController.getWidth() == mView.getWidth());
// Update Clock Pivot
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index 3c43a17..9ea402d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -101,6 +101,7 @@
mCallbacks = Lists.newArrayList();
private final SysuiColorExtractor mColorExtractor;
+ private float mFaceAuthDisplayBrightness = LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
@Inject
public NotificationShadeWindowControllerImpl(Context context, WindowManager windowManager,
@@ -232,6 +233,12 @@
mScreenBrightnessDoze = value / 255f;
}
+ @Override
+ public void setFaceAuthDisplayBrightness(float brightness) {
+ mFaceAuthDisplayBrightness = brightness;
+ apply(mCurrentState);
+ }
+
private void setKeyguardDark(boolean dark) {
int vis = mNotificationShadeView.getSystemUiVisibility();
if (dark) {
@@ -436,7 +443,7 @@
if (state.mForceDozeBrightness) {
mLpChanged.screenBrightness = mScreenBrightnessDoze;
} else {
- mLpChanged.screenBrightness = LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
+ mLpChanged.screenBrightness = mFaceAuthDisplayBrightness;
}
}
@@ -645,6 +652,7 @@
pw.println(TAG + ":");
pw.println(" mKeyguardDisplayMode=" + mKeyguardDisplayMode);
pw.println(mCurrentState);
+ mNotificationShadeView.getViewRootImpl().dump(" ", fd, pw, args);
}
@Override
@@ -701,6 +709,7 @@
boolean mHeadsUpShowing;
boolean mForceCollapsed;
boolean mForceDozeBrightness;
+ int mFaceAuthDisplayBrightness;
boolean mForceUserActivity;
boolean mLaunchingActivity;
boolean mBackdropShowing;
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 ac329e2..965368e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -1325,7 +1325,6 @@
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
int oldTop, int oldRight, int oldBottom) {
- mStatusBar.onPanelLaidOut();
requestPanelHeightUpdate();
mHasLayoutedSinceDown = true;
if (mUpdateFlingOnLayout) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 6e37f90..115d164 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -177,7 +177,7 @@
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.shared.system.WindowManagerWrapper;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.AutoHideUiElement;
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.CommandQueue;
@@ -388,7 +388,7 @@
private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
private final Provider<StatusBarComponent.Builder> mStatusBarComponentBuilder;
private final PluginManager mPluginManager;
- private final Optional<Divider> mDividerOptional;
+ private final Optional<SplitScreen> mSplitScreenOptional;
private final StatusBarNotificationActivityStarter.Builder
mStatusBarNotificationActivityStarterBuilder;
private final ShadeController mShadeController;
@@ -721,7 +721,7 @@
Optional<Recents> recentsOptional,
Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
PluginManager pluginManager,
- Optional<Divider> dividerOptional,
+ Optional<SplitScreen> splitScreenOptional,
LightsOutNotifController lightsOutNotifController,
StatusBarNotificationActivityStarter.Builder
statusBarNotificationActivityStarterBuilder,
@@ -803,7 +803,7 @@
mRecentsOptional = recentsOptional;
mStatusBarComponentBuilder = statusBarComponentBuilder;
mPluginManager = pluginManager;
- mDividerOptional = dividerOptional;
+ mSplitScreenOptional = splitScreenOptional;
mStatusBarNotificationActivityStarterBuilder = statusBarNotificationActivityStarterBuilder;
mShadeController = shadeController;
mSuperStatusBarViewFactory = superStatusBarViewFactory;
@@ -1550,31 +1550,32 @@
if (!mRecentsOptional.isPresent()) {
return false;
}
- Divider divider = null;
- if (mDividerOptional.isPresent()) {
- divider = mDividerOptional.get();
- }
- if (divider == null || !divider.isDividerVisible()) {
- final int navbarPos = WindowManagerWrapper.getInstance().getNavBarPosition(mDisplayId);
- if (navbarPos == NAV_BAR_POS_INVALID) {
- return false;
- }
- int createMode = navbarPos == NAV_BAR_POS_LEFT
- ? SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT
- : SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
- return mRecentsOptional.get().splitPrimaryTask(createMode, null, metricsDockAction);
- } else {
- if (divider.isMinimized() && !divider.isHomeStackResizable()) {
- // Undocking from the minimized state is not supported
- return false;
- } else {
- divider.onUndockingTask();
- if (metricsUndockAction != -1) {
- mMetricsLogger.action(metricsUndockAction);
+
+ if (mSplitScreenOptional.isPresent()) {
+ SplitScreen splitScreen = mSplitScreenOptional.get();
+ if (splitScreen.isDividerVisible()) {
+ if (splitScreen.isMinimized()
+ && !splitScreen.isHomeStackResizable()) {
+ // Undocking from the minimized state is not supported
+ return false;
+ } else {
+ splitScreen.onUndockingTask();
+ if (metricsUndockAction != -1) {
+ mMetricsLogger.action(metricsUndockAction);
+ }
}
+ return true;
}
}
- return true;
+
+ final int navbarPos = WindowManagerWrapper.getInstance().getNavBarPosition(mDisplayId);
+ if (navbarPos == NAV_BAR_POS_INVALID) {
+ return false;
+ }
+ int createMode = navbarPos == NAV_BAR_POS_LEFT
+ ? SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT
+ : SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
+ return mRecentsOptional.get().splitPrimaryTask(createMode, null, metricsDockAction);
}
/**
@@ -3916,14 +3917,14 @@
@Override
public void appTransitionCancelled(int displayId) {
if (displayId == mDisplayId) {
- mDividerOptional.ifPresent(Divider::onAppTransitionFinished);
+ mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.onAppTransitionFinished());
}
}
@Override
public void appTransitionFinished(int displayId) {
if (displayId == mDisplayId) {
- mDividerOptional.ifPresent(Divider::onAppTransitionFinished);
+ mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.onAppTransitionFinished());
}
}
@@ -4221,25 +4222,6 @@
KeyboardShortcuts.dismiss();
}
- /**
- * Called when the notification panel layouts
- */
- public void onPanelLaidOut() {
- updateKeyguardMaxNotifications();
- }
-
- public void updateKeyguardMaxNotifications() {
- if (mState == StatusBarState.KEYGUARD) {
- // Since the number of notifications is determined based on the height of the view, we
- // need to update them.
- int maxBefore = mPresenter.getMaxNotificationsWhileLocked(false /* recompute */);
- int maxNotifications = mPresenter.getMaxNotificationsWhileLocked(true /* recompute */);
- if (maxBefore != maxNotifications) {
- mViewHierarchyManager.updateRowStates();
- }
- }
- }
-
public void executeActionDismissingKeyguard(Runnable action, boolean afterKeyguardGone) {
if (!mDeviceProvisionedController.isDeviceProvisioned()) return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 7ee501c..777bf3f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -50,6 +50,7 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.keyguard.FaceAuthScreenBrightnessController;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -68,6 +69,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Optional;
import javax.inject.Inject;
@@ -103,6 +105,7 @@
private final ConfigurationController mConfigurationController;
private final NavigationModeController mNavigationModeController;
private final NotificationShadeWindowController mNotificationShadeWindowController;
+ private final Optional<FaceAuthScreenBrightnessController> mFaceAuthScreenBrightnessController;
private final BouncerExpansionCallback mExpansionCallback = new BouncerExpansionCallback() {
@Override
public void onFullyShown() {
@@ -212,6 +215,7 @@
DockManager dockManager,
NotificationShadeWindowController notificationShadeWindowController,
KeyguardStateController keyguardStateController,
+ Optional<FaceAuthScreenBrightnessController> faceAuthScreenBrightnessController,
NotificationMediaManager notificationMediaManager) {
mContext = context;
mViewMediatorCallback = callback;
@@ -224,6 +228,7 @@
mKeyguardUpdateManager = keyguardUpdateMonitor;
mStatusBarStateController = sysuiStatusBarStateController;
mDockManager = dockManager;
+ mFaceAuthScreenBrightnessController = faceAuthScreenBrightnessController;
}
@Override
@@ -248,6 +253,11 @@
notificationPanelViewController.addExpansionListener(this);
mBypassController = bypassController;
mNotificationContainer = notificationContainer;
+ mFaceAuthScreenBrightnessController.ifPresent((it) -> {
+ View overlay = new View(mContext);
+ container.addView(overlay);
+ it.attach(overlay);
+ });
registerListeners();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 67adaaa..024a0b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -110,7 +110,6 @@
private final AboveShelfObserver mAboveShelfObserver;
private final DozeScrimController mDozeScrimController;
private final ScrimController mScrimController;
- private final Context mContext;
private final KeyguardIndicationController mKeyguardIndicationController;
private final StatusBar mStatusBar;
private final ShadeController mShadeController;
@@ -119,7 +118,6 @@
private final AccessibilityManager mAccessibilityManager;
private final KeyguardManager mKeyguardManager;
private final ActivityLaunchAnimator mActivityLaunchAnimator;
- private final int mMaxAllowedKeyguardNotifications;
private final IStatusBarService mBarService;
private final DynamicPrivacyController mDynamicPrivacyController;
private boolean mReinflateNotificationsOnUserSwitched;
@@ -127,7 +125,6 @@
private TextView mNotificationPanelDebugText;
protected boolean mVrMode;
- private int mMaxKeyguardNotifications;
public StatusBarNotificationPresenter(Context context,
NotificationPanelViewController panel,
@@ -145,7 +142,6 @@
CommandQueue commandQueue,
InitController initController,
NotificationInterruptStateProvider notificationInterruptStateProvider) {
- mContext = context;
mKeyguardStateController = keyguardStateController;
mNotificationPanel = panel;
mHeadsUpManager = headsUp;
@@ -163,8 +159,6 @@
mDozeScrimController = dozeScrimController;
mScrimController = scrimController;
mKeyguardManager = context.getSystemService(KeyguardManager.class);
- mMaxAllowedKeyguardNotifications = context.getResources().getInteger(
- R.integer.keyguard_max_notification_count);
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
@@ -397,17 +391,6 @@
}
@Override
- public int getMaxNotificationsWhileLocked(boolean recompute) {
- if (recompute) {
- mMaxKeyguardNotifications = Math.max(1,
- mNotificationPanel.computeMaxKeyguardNotifications(
- mMaxAllowedKeyguardNotifications));
- return mMaxKeyguardNotifications;
- }
- return mMaxKeyguardNotifications;
- }
-
- @Override
public void onUpdateRowStates() {
mNotificationPanel.onUpdateRowStates();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 2768b82..72067d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -46,7 +46,7 @@
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -180,7 +180,7 @@
Optional<Recents> recentsOptional,
Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
PluginManager pluginManager,
- Optional<Divider> dividerOptional,
+ Optional<SplitScreen> splitScreenOptional,
LightsOutNotifController lightsOutNotifController,
StatusBarNotificationActivityStarter.Builder
statusBarNotificationActivityStarterBuilder,
@@ -260,7 +260,7 @@
recentsOptional,
statusBarComponentBuilder,
pluginManager,
- dividerOptional,
+ splitScreenOptional,
lightsOutNotifController,
statusBarNotificationActivityStarterBuilder,
shadeController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 33b1a4a..f39acf9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -39,6 +39,7 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dump.DumpManager;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -58,6 +59,7 @@
private static final String TAG = "BluetoothController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private final DumpManager mDumpManager;
private final LocalBluetoothManager mLocalBluetoothManager;
private final UserManager mUserManager;
private final int mCurrentUser;
@@ -77,8 +79,13 @@
/**
*/
@Inject
- public BluetoothControllerImpl(Context context, @Background Looper bgLooper,
- @Main Looper mainLooper, @Nullable LocalBluetoothManager localBluetoothManager) {
+ public BluetoothControllerImpl(
+ Context context,
+ DumpManager dumpManager,
+ @Background Looper bgLooper,
+ @Main Looper mainLooper,
+ @Nullable LocalBluetoothManager localBluetoothManager) {
+ mDumpManager = dumpManager;
mLocalBluetoothManager = localBluetoothManager;
mBgHandler = new Handler(bgLooper);
mHandler = new H(mainLooper);
@@ -90,6 +97,7 @@
}
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mCurrentUser = ActivityManager.getCurrentUser();
+ mDumpManager.registerDumpable(TAG, this);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
index b7bc8c8..302301d 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
@@ -24,7 +24,6 @@
import com.android.systemui.dagger.SystemServicesModule;
import com.android.systemui.dagger.SystemUIBinder;
import com.android.systemui.dagger.SystemUIModule;
-import com.android.systemui.onehanded.dagger.OneHandedModule;
import dagger.Subcomponent;
@@ -36,7 +35,6 @@
DefaultComponentBinder.class,
DependencyProvider.class,
DependencyBinder.class,
- OneHandedModule.class,
SystemServicesModule.class,
SystemUIBinder.class,
SystemUIModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index ca9cb08..e7c10f1 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
@@ -42,7 +42,6 @@
import com.android.systemui.qs.tileimpl.QSFactoryImpl;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsImplementation;
-import com.android.systemui.stackdivider.DividerModule;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
@@ -76,7 +75,6 @@
* overridden by the System UI implementation.
*/
@Module(includes = {
- DividerModule.class,
QSModule.class,
WMShellModule.class
},
diff --git a/packages/SystemUI/src/com/android/systemui/util/DeviceConfigProxy.java b/packages/SystemUI/src/com/android/systemui/util/DeviceConfigProxy.java
index 3a2172a..66f8f74 100644
--- a/packages/SystemUI/src/com/android/systemui/util/DeviceConfigProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/util/DeviceConfigProxy.java
@@ -25,13 +25,11 @@
import java.util.concurrent.Executor;
-import javax.inject.Inject;
-
/**
* Wrapper around DeviceConfig useful for testing.
*/
public class DeviceConfigProxy {
- @Inject
+
public DeviceConfigProxy() {
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt b/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt
index f22f59b..bcfb2af 100644
--- a/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt
@@ -4,8 +4,7 @@
import android.util.Log
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.util.FloatingContentCoordinator.FloatingContent
-import java.util.*
-import javax.inject.Inject
+import java.util.HashMap
/** Tag for debug logging. */
private const val TAG = "FloatingCoordinator"
@@ -20,9 +19,9 @@
* other content out of the way. [onContentRemoved] should be called when the content is removed or
* no longer visible.
*/
-@SysUISingleton
-class FloatingContentCoordinator @Inject constructor() {
+@SysUISingleton
+class FloatingContentCoordinator constructor() {
/**
* Represents a piece of floating content, such as PIP or the Bubbles stack. Provides methods
* that allow the [FloatingContentCoordinator] to determine the current location of the content,
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
new file mode 100644
index 0000000..4922600
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wmshell;
+
+import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+
+import android.app.ActivityManager;
+import android.content.Context;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.SystemUI;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.stackdivider.SplitScreen;
+import com.android.wm.shell.common.DisplayImeController;
+
+import java.util.Optional;
+
+import javax.inject.Inject;
+
+/**
+ * Proxy in SysUiScope to delegate events to controllers in WM Shell library.
+ */
+@SysUISingleton
+public final class WMShell extends SystemUI {
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final DisplayImeController mDisplayImeController;
+ private final Optional<SplitScreen> mSplitScreenOptional;
+
+ @Inject
+ WMShell(Context context, KeyguardUpdateMonitor keyguardUpdateMonitor,
+ DisplayImeController displayImeController,
+ Optional<SplitScreen> splitScreenOptional) {
+ super(context);
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mDisplayImeController = displayImeController;
+ mSplitScreenOptional = splitScreenOptional;
+ }
+
+ @Override
+ public void start() {
+ // This is to prevent circular init problem by separating registration step out of its
+ // constructor. And make sure the initialization of DisplayImeController won't depend on
+ // specific feature anymore.
+ mDisplayImeController.startMonitorDisplays();
+
+ mSplitScreenOptional.ifPresent(this::initSplitScreen);
+ }
+
+ private void initSplitScreen(SplitScreen splitScreen) {
+ mKeyguardUpdateMonitor.registerCallback(new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onKeyguardVisibilityChanged(boolean showing) {
+ // Hide the divider when keyguard is showing. Even though keyguard/statusbar is
+ // above everything, it is actually transparent except for notifications, so
+ // we still need to hide any surfaces that are below it.
+ // TODO(b/148906453): Figure out keyguard dismiss animation for divider view.
+ splitScreen.onKeyguardVisibilityChanged(showing);
+ }
+ });
+
+ ActivityManagerWrapper.getInstance().registerTaskStackListener(
+ new TaskStackChangeListener() {
+ @Override
+ public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+ boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+ if (!wasVisible || task.configuration.windowConfiguration.getWindowingMode()
+ != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ || !splitScreen.isSplitScreenSupported()) {
+ return;
+ }
+
+ if (splitScreen.isMinimized()) {
+ splitScreen.onUndockingTask();
+ }
+ }
+
+ @Override
+ public void onActivityForcedResizable(String packageName, int taskId,
+ int reason) {
+ splitScreen.onActivityForcedResizable(packageName, taskId, reason);
+ }
+
+ @Override
+ public void onActivityDismissingDockedStack() {
+ splitScreen.onActivityDismissingSplitScreen();
+ }
+
+ @Override
+ public void onActivityLaunchOnSecondaryDisplayFailed() {
+ splitScreen.onActivityLaunchOnSecondaryDisplayFailed();
+ }
+ });
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index ac47660..0a3172ce 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -20,12 +20,19 @@
import android.os.Handler;
import android.view.IWindowManager;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.pip.PipUiEventLogger;
+import com.android.systemui.stackdivider.SplitScreen;
+import com.android.systemui.util.DeviceConfigProxy;
+import com.android.systemui.util.FloatingContentCoordinator;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TransactionPool;
+import dagger.BindsOptionalOf;
import dagger.Module;
import dagger.Provides;
@@ -35,7 +42,7 @@
*/
// TODO(b/162923491): Move most of these dependencies into WMSingleton scope.
@Module
-public class WMShellBaseModule {
+public abstract class WMShellBaseModule {
@SysUISingleton
@Provides
static TransactionPool provideTransactionPool() {
@@ -51,8 +58,37 @@
@SysUISingleton
@Provides
+ static DeviceConfigProxy provideDeviceConfigProxy() {
+ return new DeviceConfigProxy();
+ }
+
+ @SysUISingleton
+ @Provides
+ static FloatingContentCoordinator provideFloatingContentCoordinator() {
+ return new FloatingContentCoordinator();
+ }
+
+ @SysUISingleton
+ @Provides
+ static PipUiEventLogger providePipUiEventLogger(UiEventLogger uiEventLogger) {
+ return new PipUiEventLogger(uiEventLogger);
+ }
+
+ @SysUISingleton
+ @Provides
static SystemWindows provideSystemWindows(DisplayController displayController,
IWindowManager wmService) {
return new SystemWindows(displayController, wmService);
}
+
+ @SysUISingleton
+ @Provides
+ static ShellTaskOrganizer provideShellTaskOrganizer() {
+ ShellTaskOrganizer organizer = new ShellTaskOrganizer();
+ organizer.registerOrganizer();
+ return organizer;
+ }
+
+ @BindsOptionalOf
+ abstract SplitScreen optionalSplitScreen();
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 44bb6ac..7b45476 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -16,6 +16,7 @@
package com.android.systemui.wmshell;
+import android.content.Context;
import android.os.Handler;
import android.view.IWindowManager;
@@ -23,8 +24,12 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.pip.phone.PipMenuActivity;
import com.android.systemui.pip.phone.dagger.PipMenuActivityClass;
+import com.android.systemui.stackdivider.SplitScreen;
+import com.android.systemui.stackdivider.SplitScreenController;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TransactionPool;
import dagger.Module;
@@ -42,8 +47,7 @@
static DisplayImeController provideDisplayImeController(IWindowManager wmService,
DisplayController displayController, @Main Handler mainHandler,
TransactionPool transactionPool) {
- return new DisplayImeController.Builder(wmService, displayController, mainHandler,
- transactionPool).build();
+ return new DisplayImeController(wmService, displayController, mainHandler, transactionPool);
}
/** TODO(b/150319024): PipMenuActivity will move to a Window */
@@ -53,4 +57,14 @@
static Class<?> providePipMenuActivityClass() {
return PipMenuActivity.class;
}
+
+ @SysUISingleton
+ @Provides
+ static SplitScreen provideSplitScreen(Context context,
+ DisplayController displayController, SystemWindows systemWindows,
+ DisplayImeController displayImeController, @Main Handler handler,
+ TransactionPool transactionPool, ShellTaskOrganizer shellTaskOrganizer) {
+ return new SplitScreenController(context, displayController, systemWindows,
+ displayImeController, handler, transactionPool, shellTaskOrganizer);
+ }
}
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index c6331682..db87845 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -80,6 +80,8 @@
android:excludeFromRecents="true"
/>
+ <activity android:name="com.android.systemui.screenshot.ScrollViewActivity"
+ android:exported="false" />
<provider
android:name="androidx.lifecycle.ProcessLifecycleOwnerInitializer"
tools:replace="android:authorities"
diff --git a/packages/SystemUI/tests/res/values/strings.xml b/packages/SystemUI/tests/res/values/strings.xml
new file mode 100644
index 0000000..b9f24c8
--- /dev/null
+++ b/packages/SystemUI/tests/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <string name="test_content">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ultrices condimentum ultricies. Sed elementum at massa id sagittis. Nullam dictum massa lorem, nec ornare nunc pharetra vitae. Duis ultrices, felis eu condimentum congue, erat orci efficitur purus, ac rutrum odio lacus sed sapien. Suspendisse erat augue, eleifend eget auctor sagittis, porta eget nibh. Mauris pulvinar urna non justo condimentum, ut vehicula sapien finibus. Aliquam nibh magna, tincidunt ut viverra sed, placerat et turpis. Nam placerat, dui sed tincidunt consectetur, ante velit posuere mauris, tincidunt finibus velit lectus ac tortor. Cras eget lectus feugiat, porttitor velit nec, malesuada massa.</string>
+
+</resources>
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapperTest.kt
index 861c620..690b9a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapperTest.kt
@@ -25,6 +25,7 @@
import com.android.systemui.util.time.FakeSystemClock
import org.junit.After
import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -78,4 +79,15 @@
assertEquals(list, wrapper.readFavorites())
}
+
+ @Test
+ fun testSaveEmptyOnNonExistingFile() {
+ if (file.exists()) {
+ file.delete()
+ }
+
+ wrapper.storeFavorites(emptyList())
+
+ assertFalse(file.exists())
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt
new file mode 100644
index 0000000..58cb032
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard
+
+import android.animation.ValueAnimator
+import android.content.res.Resources
+import android.hardware.biometrics.BiometricSourceType
+import android.os.Handler
+import android.provider.Settings.System.SCREEN_BRIGHTNESS_FLOAT
+import android.testing.AndroidTestingRunner
+import android.util.TypedValue
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.Dumpable
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.NotificationShadeWindowController
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.settings.GlobalSettings
+import com.android.systemui.util.settings.SystemSettings
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.anyString
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+const val INITIAL_BRIGHTNESS = 0.5f
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class FaceAuthScreenBrightnessControllerTest : SysuiTestCase() {
+
+ @Mock
+ lateinit var whiteOverlay: View
+ @Mock
+ lateinit var dumpManager: DumpManager
+ @Mock
+ lateinit var resources: Resources
+ @Mock
+ lateinit var mainHandler: Handler
+ @Mock
+ lateinit var globalSettings: GlobalSettings
+ @Mock
+ lateinit var systemSettings: SystemSettings
+ @Mock
+ lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock
+ lateinit var notificationShadeWindowController: NotificationShadeWindowController
+ @Mock
+ lateinit var animator: ValueAnimator
+ @Captor
+ lateinit var keyguardUpdateCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback>
+ lateinit var faceAuthScreenBrightnessController: FaceAuthScreenBrightnessController
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ faceAuthScreenBrightnessController = object : FaceAuthScreenBrightnessController(
+ notificationShadeWindowController, keyguardUpdateMonitor, resources, globalSettings,
+ systemSettings, mainHandler, dumpManager) {
+ override fun createAnimator(start: Float, end: Float) = animator
+ }
+ `when`(systemSettings.getFloat(eq(SCREEN_BRIGHTNESS_FLOAT))).thenReturn(INITIAL_BRIGHTNESS)
+ faceAuthScreenBrightnessController.attach(whiteOverlay)
+ verify(keyguardUpdateMonitor).registerCallback(capture(keyguardUpdateCallback))
+ }
+
+ @Test
+ fun init_registersDumpManager() {
+ verify(dumpManager).registerDumpable(anyString(), any(Dumpable::class.java))
+ }
+
+ @Test
+ fun init_registersKeyguardCallback() {
+ verify(keyguardUpdateMonitor)
+ .registerCallback(any(KeyguardUpdateMonitorCallback::class.java))
+ }
+
+ @Test
+ fun onBiometricRunningChanged_animatesBrightness() {
+ clearInvocations(whiteOverlay)
+ keyguardUpdateCallback.value
+ .onBiometricRunningStateChanged(true, BiometricSourceType.FACE)
+ verify(whiteOverlay).visibility = eq(View.VISIBLE)
+ verify(animator).start()
+ }
+
+ @Test
+ fun faceAuthWallpaper_whenFaceIsDisabledForUser() {
+ faceAuthScreenBrightnessController.useFaceAuthWallpaper = true
+ faceAuthScreenBrightnessController.faceAuthWallpaper
+ verify(resources, never()).openRawResource(anyInt(), any(TypedValue::class.java))
+ }
+
+ @Test
+ fun faceAuthWallpaper_whenFaceFlagIsDisabled() {
+ faceAuthScreenBrightnessController.useFaceAuthWallpaper = true
+ faceAuthScreenBrightnessController.faceAuthWallpaper
+ verify(resources, never()).openRawResource(anyInt(), any(TypedValue::class.java))
+ }
+
+ @Test
+ fun faceAuthWallpaper_whenFaceIsEnabledForUser() {
+ faceAuthScreenBrightnessController.useFaceAuthWallpaper = true
+ `when`(keyguardUpdateMonitor.isFaceAuthEnabledForUser(anyInt())).thenReturn(true)
+ faceAuthScreenBrightnessController.faceAuthWallpaper
+ verify(resources).openRawResource(anyInt(), any(TypedValue::class.java))
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt
index ca8f79d..da1ec98 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt
@@ -21,6 +21,7 @@
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Before
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
@@ -59,6 +60,7 @@
}
@Test
+ @Ignore("Flaky")
fun switchPlayersPlaying() {
val playerIsPlaying1 = mock(MediaControlPanel::class.java)
whenever(playerIsPlaying1.isPlaying).thenReturn(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
index 7a8e4f7..f385243 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
@@ -155,6 +155,22 @@
}
@Test
+ fun testOnMediaDataLoaded_migratesKeys_noTimeoutExtension() {
+ // From not playing
+ mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData)
+ clearInvocations(mediaController)
+
+ // Migrate, still not playing
+ val playingState = mock(android.media.session.PlaybackState::class.java)
+ `when`(playingState.state).thenReturn(PlaybackState.STATE_PAUSED)
+ `when`(mediaController.playbackState).thenReturn(playingState)
+ mediaTimeoutListener.onMediaDataLoaded("NEWKEY", KEY, mediaData)
+
+ // Never cancels callback, or schedule another one
+ verify(cancellationRunnable, never()).run()
+ }
+
+ @Test
fun testOnPlaybackStateChanged_schedulesTimeout_whenPaused() {
// Assuming we're registered
testOnMediaDataLoaded_registersPlaybackListener()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
index 2e4d8a7..57dbac5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
@@ -52,7 +52,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -61,13 +61,13 @@
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import java.util.Optional;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Optional;
+
/** atest NavigationBarControllerTest */
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -90,13 +90,13 @@
mock(AccessibilityManagerWrapper.class),
mock(DeviceProvisionedController.class),
mock(MetricsLogger.class),
- mock(OverviewProxyService.class),
+ mock(OverviewProxyService.class),
mock(NavigationModeController.class),
mock(StatusBarStateController.class),
mock(SysUiState.class),
mock(BroadcastDispatcher.class),
mock(CommandQueue.class),
- mock(Divider.class),
+ Optional.of(mock(SplitScreen.class)),
Optional.of(mock(Recents.class)),
() -> mock(StatusBar.class),
mock(ShadeController.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index a643c2d..389c5a0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -68,7 +68,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -121,7 +121,6 @@
mDependency.injectMockDependency(KeyguardStateController.class);
mDependency.injectMockDependency(StatusBarStateController.class);
mDependency.injectMockDependency(NavigationBarController.class);
- mDependency.injectMockDependency(Divider.class);
mOverviewProxyService = mDependency.injectMockDependency(OverviewProxyService.class);
TestableLooper.get(this).runWithLooper(() -> {
mHandler = new Handler();
@@ -224,7 +223,7 @@
mMockSysUiState,
mBroadcastDispatcher,
mCommandQueue,
- mock(Divider.class),
+ Optional.of(mock(SplitScreen.class)),
Optional.of(mock(Recents.class)),
() -> mock(StatusBar.class),
mock(ShadeController.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedControllerTest.java
similarity index 90%
rename from packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedControllerTest.java
index d7dba5f..02d587d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedControllerTest.java
@@ -46,9 +46,9 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
-public class OneHandedManagerImplTest extends OneHandedTestCase {
+public class OneHandedControllerTest extends OneHandedTestCase {
Display mDisplay;
- OneHandedManagerImpl mOneHandedManagerImpl;
+ OneHandedController mOneHandedController;
OneHandedTimeoutHandler mTimeoutHandler;
@Mock
@@ -70,7 +70,7 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mDisplay = mContext.getDisplay();
- mOneHandedManagerImpl = new OneHandedManagerImpl(
+ mOneHandedController = new OneHandedController(
getContext(),
mCommandQueue,
mMockDisplayController,
@@ -102,7 +102,7 @@
@Test
public void testStartOneHanded() {
- mOneHandedManagerImpl.startOneHanded();
+ mOneHandedController.startOneHanded();
verify(mMockDisplayAreaOrganizer).scheduleOffset(anyInt(), anyInt());
}
@@ -110,7 +110,7 @@
@Test
public void testStopOneHanded() {
when(mMockDisplayAreaOrganizer.isInOneHanded()).thenReturn(false);
- mOneHandedManagerImpl.stopOneHanded();
+ mOneHandedController.stopOneHanded();
verify(mMockDisplayAreaOrganizer, never()).scheduleOffset(anyInt(), anyInt());
}
@@ -122,7 +122,7 @@
@Test
public void testStopOneHanded_shouldRemoveTimer() {
- mOneHandedManagerImpl.stopOneHanded();
+ mOneHandedController.stopOneHanded();
verify(mTimeoutHandler).removeTimer();
}
@@ -130,7 +130,7 @@
@Test
public void testUpdateIsEnabled() {
final boolean enabled = true;
- mOneHandedManagerImpl.setOneHandedEnabled(enabled);
+ mOneHandedController.setOneHandedEnabled(enabled);
verify(mMockTouchHandler, times(2)).onOneHandedEnabled(enabled);
}
@@ -138,7 +138,7 @@
@Test
public void testUpdateSwipeToNotificationIsEnabled() {
final boolean enabled = true;
- mOneHandedManagerImpl.setSwipeToNotificationEnabled(enabled);
+ mOneHandedController.setSwipeToNotificationEnabled(enabled);
verify(mMockTouchHandler, times(2)).onOneHandedEnabled(enabled);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java
index 95a230f..756382a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java
@@ -30,8 +30,8 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.model.SysUiState;
-import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.wm.shell.common.DisplayController;
import org.junit.Before;
@@ -48,7 +48,7 @@
OneHandedTouchHandler mTouchHandler;
OneHandedTutorialHandler mTutorialHandler;
OneHandedGestureHandler mGestureHandler;
- OneHandedManagerImpl mOneHandedManagerImpl;
+ OneHandedController mOneHandedController;
@Mock
CommandQueue mCommandQueue;
@Mock
@@ -66,7 +66,7 @@
mTutorialHandler = new OneHandedTutorialHandler(mContext);
mGestureHandler = Mockito.spy(new OneHandedGestureHandler(
mContext, mMockDisplayController, mMockNavigationModeController));
- mOneHandedManagerImpl = new OneHandedManagerImpl(
+ mOneHandedController = new OneHandedController(
getContext(),
mCommandQueue,
mMockDisplayController,
@@ -93,15 +93,15 @@
public void testReceiveNewConfig_whenSetOneHandedEnabled() {
// 1st called at init
verify(mGestureHandler).onOneHandedEnabled(true);
- mOneHandedManagerImpl.setOneHandedEnabled(true);
+ mOneHandedController.setOneHandedEnabled(true);
// 2nd called by setOneHandedEnabled()
verify(mGestureHandler, times(2)).onOneHandedEnabled(true);
}
@Test
public void testOneHandedDisabled_shouldDisposeInputChannel() {
- mOneHandedManagerImpl.setOneHandedEnabled(false);
- mOneHandedManagerImpl.setSwipeToNotificationEnabled(false);
+ mOneHandedController.setOneHandedEnabled(false);
+ mOneHandedController.setSwipeToNotificationEnabled(false);
assertThat(mGestureHandler.mInputMonitor).isNull();
assertThat(mGestureHandler.mInputEventReceiver).isNull();
@@ -111,7 +111,7 @@
public void testChangeNavBarTo2Button_shouldDisposeInputChannel() {
// 1st called at init
verify(mGestureHandler).onOneHandedEnabled(true);
- mOneHandedManagerImpl.setOneHandedEnabled(true);
+ mOneHandedController.setOneHandedEnabled(true);
// 2nd called by setOneHandedEnabled()
verify(mGestureHandler, times(2)).onOneHandedEnabled(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java
index 8ae632d..3c3ace0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java
@@ -28,8 +28,8 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.model.SysUiState;
-import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.wm.shell.common.DisplayController;
import org.junit.Before;
@@ -46,7 +46,7 @@
OneHandedTouchHandler mTouchHandler;
OneHandedTutorialHandler mTutorialHandler;
OneHandedGestureHandler mGestureHandler;
- OneHandedManagerImpl mOneHandedManagerImpl;
+ OneHandedController mOneHandedController;
@Mock
CommandQueue mCommandQueue;
@Mock
@@ -64,7 +64,7 @@
mTouchHandler = Mockito.spy(new OneHandedTouchHandler());
mGestureHandler = new OneHandedGestureHandler(mContext, mMockDisplayController,
mMockNavigationModeController);
- mOneHandedManagerImpl = new OneHandedManagerImpl(
+ mOneHandedController = new OneHandedController(
getContext(),
mCommandQueue,
mMockDisplayController,
@@ -88,14 +88,14 @@
@Test
public void testOneHandedDisabled_shouldDisposeInputChannel() {
- mOneHandedManagerImpl.setOneHandedEnabled(false);
+ mOneHandedController.setOneHandedEnabled(false);
assertThat(mTouchHandler.mInputMonitor).isNull();
assertThat(mTouchHandler.mInputEventReceiver).isNull();
}
@Test
public void testOneHandedEnabled_monitorInputChannel() {
- mOneHandedManagerImpl.setOneHandedEnabled(true);
+ mOneHandedController.setOneHandedEnabled(true);
assertThat(mTouchHandler.mInputMonitor).isNotNull();
assertThat(mTouchHandler.mInputEventReceiver).isNotNull();
}
@@ -104,7 +104,7 @@
public void testReceiveNewConfig_whenSetOneHandedEnabled() {
// 1st called at init
verify(mTouchHandler).onOneHandedEnabled(true);
- mOneHandedManagerImpl.setOneHandedEnabled(true);
+ mOneHandedController.setOneHandedEnabled(true);
// 2nd called by setOneHandedEnabled()
verify(mTouchHandler, times(2)).onOneHandedEnabled(true);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java
index c75a8d2..1bffbf7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java
@@ -24,8 +24,8 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.model.SysUiState;
-import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.wm.shell.common.DisplayController;
import org.junit.Before;
@@ -42,7 +42,7 @@
OneHandedTouchHandler mTouchHandler;
OneHandedTutorialHandler mTutorialHandler;
OneHandedGestureHandler mGestureHandler;
- OneHandedManagerImpl mOneHandedManagerImpl;
+ OneHandedController mOneHandedController;
@Mock
CommandQueue mCommandQueue;
@Mock
@@ -61,7 +61,7 @@
mTutorialHandler = Mockito.spy(new OneHandedTutorialHandler(mContext));
mGestureHandler = new OneHandedGestureHandler(mContext, mMockDisplayController,
mMockNavigationModeController);
- mOneHandedManagerImpl = new OneHandedManagerImpl(
+ mOneHandedController = new OneHandedController(
getContext(),
mCommandQueue,
mMockDisplayController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java
index f0e713e..ae3df5d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java
@@ -48,7 +48,7 @@
OneHandedUI mOneHandedUI;
ScreenLifecycle mScreenLifecycle;
@Mock
- OneHandedManagerImpl mMockOneHandedManagerImpl;
+ OneHandedController mOneHandedController;
@Mock
OneHandedTimeoutHandler mMockTimeoutHandler;
@@ -59,7 +59,7 @@
mScreenLifecycle = new ScreenLifecycle();
mOneHandedUI = new OneHandedUI(mContext,
mCommandQueue,
- mMockOneHandedManagerImpl,
+ mOneHandedController,
mScreenLifecycle);
mOneHandedUI.start();
mKeyguardUpdateMonitor = mDependency.injectMockDependency(KeyguardUpdateMonitor.class);
@@ -74,14 +74,14 @@
public void testStartOneHanded() {
mOneHandedUI.startOneHanded();
- verify(mMockOneHandedManagerImpl).startOneHanded();
+ verify(mOneHandedController).startOneHanded();
}
@Test
public void testStopOneHanded() {
mOneHandedUI.stopOneHanded();
- verify(mMockOneHandedManagerImpl).stopOneHanded();
+ verify(mOneHandedController).stopOneHanded();
}
@Test
@@ -89,7 +89,7 @@
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.TAPS_APP_TO_EXIT, 1);
- verify(mMockOneHandedManagerImpl).setTaskChangeToExit(true);
+ verify(mOneHandedController).setTaskChangeToExit(true);
}
@Test
@@ -97,7 +97,7 @@
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ONE_HANDED_MODE_ENABLED, 1);
- verify(mMockOneHandedManagerImpl).setOneHandedEnabled(true);
+ verify(mOneHandedController).setOneHandedEnabled(true);
}
@Test
@@ -115,7 +115,7 @@
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 1);
- verify(mMockOneHandedManagerImpl).setSwipeToNotificationEnabled(true);
+ verify(mOneHandedController).setSwipeToNotificationEnabled(true);
}
@Ignore("Clarifying do not receive callback")
@@ -123,14 +123,14 @@
public void testKeyguardBouncerShowing_shouldStopOneHanded() {
mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true);
- verify(mMockOneHandedManagerImpl).stopOneHanded();
+ verify(mOneHandedController).stopOneHanded();
}
@Test
public void testScreenTurningOff_shouldStopOneHanded() {
mScreenLifecycle.dispatchScreenTurningOff();
- verify(mMockOneHandedManagerImpl).stopOneHanded();
+ verify(mOneHandedController).stopOneHanded();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java
index e9d2b73..cdb1770 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java
@@ -19,7 +19,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
import android.content.ComponentName;
import android.graphics.Rect;
@@ -33,7 +32,6 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
-import com.android.wm.shell.common.DisplayController;
import org.junit.Before;
import org.junit.Test;
@@ -65,8 +63,7 @@
@Before
public void setUp() throws Exception {
initializeMockResources();
- mPipBoundsHandler = new PipBoundsHandler(mContext, new PipSnapAlgorithm(mContext),
- mock(DisplayController.class));
+ mPipBoundsHandler = new PipBoundsHandler(mContext);
mTestComponentName1 = new ComponentName(mContext, "component1");
mTestComponentName2 = new ComponentName(mContext, "component2");
@@ -113,7 +110,7 @@
res.addOverride(com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio,
newDefaultAspectRatio);
- mPipBoundsHandler.onConfigurationChanged();
+ mPipBoundsHandler.onConfigurationChanged(mContext);
assertEquals("Default aspect ratio should be reloaded",
mPipBoundsHandler.getDefaultAspectRatio(), newDefaultAspectRatio,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
index 9f67722..c8d4aca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
@@ -72,9 +72,6 @@
private InputConsumerController mInputConsumerController;
@Mock
- private PipBoundsHandler mPipBoundsHandler;
-
- @Mock
private PipTaskOrganizer mPipTaskOrganizer;
@Mock
@@ -89,6 +86,7 @@
@Mock
private PipUiEventLogger mPipUiEventLogger;
+ private PipBoundsHandler mPipBoundsHandler;
private PipSnapAlgorithm mPipSnapAlgorithm;
private PipMotionHelper mMotionHelper;
private PipResizeGestureHandler mPipResizeGestureHandler;
@@ -104,11 +102,13 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mPipBoundsHandler = new PipBoundsHandler(mContext);
+ mPipSnapAlgorithm = mPipBoundsHandler.getSnapAlgorithm();
mPipSnapAlgorithm = new PipSnapAlgorithm(mContext);
mPipTouchHandler = new PipTouchHandler(mContext, mActivityManager,
mPipMenuActivityController, mInputConsumerController, mPipBoundsHandler,
- mPipTaskOrganizer, mFloatingContentCoordinator, mDeviceConfigProxy,
- mPipSnapAlgorithm, mSysUiState, mPipUiEventLogger);
+ mPipTaskOrganizer, mFloatingContentCoordinator, mDeviceConfigProxy, mSysUiState,
+ mPipUiEventLogger);
mMotionHelper = Mockito.spy(mPipTouchHandler.getMotionHelper());
mPipResizeGestureHandler = Mockito.spy(mPipTouchHandler.getPipResizeGestureHandler());
mPipTouchHandler.setPipMotionHelper(mMotionHelper);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureTest.java
new file mode 100644
index 0000000..e7ef64e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot;
+
+import static org.junit.Assert.fail;
+
+import android.content.Intent;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.RemoteException;
+import android.testing.AndroidTestingRunner;
+import android.util.Log;
+import android.view.Display;
+import android.view.IScrollCaptureClient;
+import android.view.IScrollCaptureController;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests the of internal framework Scroll Capture API from SystemUI.
+ */
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class ScrollCaptureTest extends SysuiTestCase {
+ private static final String TAG = "ScrollCaptureTest";
+
+ /**
+ * Verifies that a request traverses from SystemUI, to WindowManager and to the app process and
+ * is returned without error. Device must be unlocked.
+ */
+ @Test
+ public void testBasicOperation() throws InterruptedException {
+ IWindowManager wms = WindowManagerGlobal.getWindowManagerService();
+
+ // Start an activity to be on top that will be targeted
+ InstrumentationRegistry.getInstrumentation().startActivitySync(
+ new Intent(mContext, ScrollViewActivity.class).addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK));
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ try {
+ wms.requestScrollCapture(Display.DEFAULT_DISPLAY, null, -1,
+ new IScrollCaptureController.Stub() {
+ @Override
+ public void onClientConnected(
+ IScrollCaptureClient client, Rect scrollBounds,
+ Point positionInWindow) {
+ Log.d(TAG,
+ "client connected: " + client + "[scrollBounds= " + scrollBounds
+ + ", positionInWindow=" + positionInWindow + "]");
+ latch.countDown();
+ }
+
+ @Override
+ public void onClientUnavailable() {
+ }
+
+ @Override
+ public void onCaptureStarted() {
+ }
+
+ @Override
+ public void onCaptureBufferSent(long frameNumber, Rect capturedArea) {
+ }
+
+ @Override
+ public void onConnectionClosed() {
+ }
+ });
+ } catch (RemoteException e) {
+ Log.e(TAG, "request failed", e);
+ fail("caught remote exception " + e);
+ }
+ latch.await(1000, TimeUnit.MILLISECONDS);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollViewActivity.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollViewActivity.java
new file mode 100644
index 0000000..bd37259
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollViewActivity.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.TypedValue;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+
+public class ScrollViewActivity extends Activity {
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ ScrollView scrollView = new ScrollView(this);
+ LinearLayout linearLayout = new LinearLayout(this);
+ linearLayout.setOrientation(LinearLayout.VERTICAL);
+ TextView text = new TextView(this);
+ text.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 40);
+ text.setText(com.android.systemui.R.string.test_content);
+ linearLayout.addView(text);
+ scrollView.addView(linearLayout);
+ setContentView(scrollView);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 1259d28..d2bf483 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -19,7 +19,6 @@
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
@@ -219,7 +218,7 @@
mViewHierarchyManager.onDynamicPrivacyChanged();
}
return null;
- }).when(mListContainer).setMaxDisplayedNotifications(anyInt());
+ }).when(mListContainer).onNotificationViewUpdateFinished();
// WHEN we call updateNotificationViews()
mViewHierarchyManager.updateNotificationViews();
@@ -247,7 +246,7 @@
mViewHierarchyManager.onDynamicPrivacyChanged();
}
return null;
- }).when(mListContainer).setMaxDisplayedNotifications(anyInt());
+ }).when(mListContainer).onNotificationViewUpdateFinished();
// WHEN we call updateNotificationViews() and drain the looper
mViewHierarchyManager.updateNotificationViews();
@@ -262,7 +261,6 @@
private class FakeListContainer implements NotificationListContainer {
final LinearLayout mLayout = new LinearLayout(mContext);
final List<View> mRows = Lists.newArrayList();
- private boolean mMakeReentrantCallDuringSetMaxDisplayedNotifications;
@Override
public void setChildTransferInProgress(boolean childTransferInProgress) {}
@@ -322,9 +320,6 @@
@Override
public void setMaxDisplayedNotifications(int maxNotifications) {
- if (mMakeReentrantCallDuringSetMaxDisplayedNotifications) {
- mViewHierarchyManager.onDynamicPrivacyChanged();
- }
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index d4718e7..fc0201a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -346,7 +346,6 @@
setSmartActions(mEntry.getKey(), null);
mEntryManager.updateNotificationRanking(mRankingMap);
- verify(mRow, never()).setEntry(eq(mEntry));
assertNull(mEntry.getSmartActions());
}
@@ -360,7 +359,6 @@
setSmartActions(mEntry.getKey(), new ArrayList<>(Arrays.asList(createAction())));
mEntryManager.updateNotificationRanking(mRankingMap);
- verify(mRow, never()).setEntry(eq(mEntry));
assertEquals(1, mEntry.getSmartActions().size());
assertEquals("action", mEntry.getSmartActions().get(0).title);
}
@@ -375,7 +373,6 @@
setSmartActions(mEntry.getKey(), new ArrayList<>(Arrays.asList(createAction())));
mEntryManager.updateNotificationRanking(mRankingMap);
- verify(mRow, never()).setEntry(eq(mEntry));
assertEquals(1, mEntry.getSmartActions().size());
assertEquals("action", mEntry.getSmartActions().get(0).title);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
index 1523653..3dc29a1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
@@ -53,7 +53,6 @@
/* ListEntry properties */
private GroupEntry mParent;
- private int mSection = -1;
/* If set, use this creation time instead of mClock.uptimeMillis */
private long mCreationTime = -1;
@@ -68,7 +67,6 @@
mRankingBuilder = new RankingBuilder(source.getRanking());
mParent = source.getParent();
- mSection = source.getSection();
mCreationTime = source.getCreationTime();
}
@@ -104,7 +102,6 @@
/* ListEntry properties */
entry.setParent(mParent);
- entry.getAttachState().setSectionIndex(mSection);
return entry;
}
@@ -117,14 +114,6 @@
}
/**
- * Sets the section.
- */
- public NotificationEntryBuilder setSection(int section) {
- mSection = section;
- return this;
- }
-
- /**
* Sets the SBN directly. If set, causes all calls to delegated SbnBuilder methods to be
* ignored.
*/
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index 6fa5055..8acb705 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -35,6 +35,8 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static java.util.Collections.singletonList;
+
import android.os.SystemClock;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -46,6 +48,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.statusbar.NotificationInteractionTracker;
import com.android.systemui.statusbar.notification.collection.ShadeListBuilder.OnRenderListListener;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
@@ -54,7 +57,7 @@
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
import com.android.systemui.util.time.FakeSystemClock;
@@ -71,7 +74,6 @@
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -496,7 +498,7 @@
assertTrue(entry.hasFinishedInitialization());
// WHEN the pipeline is kicked off
- mReadyForBuildListener.onBuildList(Arrays.asList(entry));
+ mReadyForBuildListener.onBuildList(singletonList(entry));
// THEN the entry's initialization time is reset
assertFalse(entry.hasFinishedInitialization());
@@ -609,13 +611,18 @@
// GIVEN a filter that removes all PACKAGE_4 notifs and sections that divide
// notifs based on package name
mListBuilder.addPreGroupFilter(new PackageFilter(PACKAGE_4));
- final NotifSection pkg1Section = spy(new PackageSection(PACKAGE_1));
- final NotifSection pkg2Section = spy(new PackageSection(PACKAGE_2));
+ final NotifSectioner pkg1Sectioner = spy(new PackageSectioner(PACKAGE_1));
+ final NotifSectioner pkg2Sectioner = spy(new PackageSectioner(PACKAGE_2));
// NOTE: no package 3 section explicitly added, so notifs with package 3 will get set by
// ShadeListBuilder's sDefaultSection which will demote it to the last section
- final NotifSection pkg4Section = spy(new PackageSection(PACKAGE_4));
- final NotifSection pkg5Section = spy(new PackageSection(PACKAGE_5));
- mListBuilder.setSections(Arrays.asList(pkg1Section, pkg2Section, pkg4Section, pkg5Section));
+ final NotifSectioner pkg4Sectioner = spy(new PackageSectioner(PACKAGE_4));
+ final NotifSectioner pkg5Sectioner = spy(new PackageSectioner(PACKAGE_5));
+ mListBuilder.setSectioners(
+ Arrays.asList(pkg1Sectioner, pkg2Sectioner, pkg4Sectioner, pkg5Sectioner));
+
+ final NotifSection pkg1Section = new NotifSection(pkg1Sectioner, 0);
+ final NotifSection pkg2Section = new NotifSection(pkg2Sectioner, 1);
+ final NotifSection pkg5Section = new NotifSection(pkg5Sectioner, 3);
// WHEN we build a list with different packages
addNotif(0, PACKAGE_4);
@@ -648,72 +655,61 @@
// THEN the first section (pkg1Section) is called on all top level elements (but
// no children and no entries that were filtered out)
- verify(pkg1Section).isInSection(mEntrySet.get(1));
- verify(pkg1Section).isInSection(mEntrySet.get(2));
- verify(pkg1Section).isInSection(mEntrySet.get(3));
- verify(pkg1Section).isInSection(mEntrySet.get(7));
- verify(pkg1Section).isInSection(mEntrySet.get(8));
- verify(pkg1Section).isInSection(mEntrySet.get(9));
- verify(pkg1Section).isInSection(mBuiltList.get(3));
+ verify(pkg1Sectioner).isInSection(mEntrySet.get(1));
+ verify(pkg1Sectioner).isInSection(mEntrySet.get(2));
+ verify(pkg1Sectioner).isInSection(mEntrySet.get(3));
+ verify(pkg1Sectioner).isInSection(mEntrySet.get(7));
+ verify(pkg1Sectioner).isInSection(mEntrySet.get(8));
+ verify(pkg1Sectioner).isInSection(mEntrySet.get(9));
+ verify(pkg1Sectioner).isInSection(mBuiltList.get(3));
- verify(pkg1Section, never()).isInSection(mEntrySet.get(0));
- verify(pkg1Section, never()).isInSection(mEntrySet.get(4));
- verify(pkg1Section, never()).isInSection(mEntrySet.get(5));
- verify(pkg1Section, never()).isInSection(mEntrySet.get(6));
- verify(pkg1Section, never()).isInSection(mEntrySet.get(10));
+ verify(pkg1Sectioner, never()).isInSection(mEntrySet.get(0));
+ verify(pkg1Sectioner, never()).isInSection(mEntrySet.get(4));
+ verify(pkg1Sectioner, never()).isInSection(mEntrySet.get(5));
+ verify(pkg1Sectioner, never()).isInSection(mEntrySet.get(6));
+ verify(pkg1Sectioner, never()).isInSection(mEntrySet.get(10));
// THEN the last section (pkg5Section) is not called on any of the entries that were
// filtered or already in a section
- verify(pkg5Section, never()).isInSection(mEntrySet.get(0));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(1));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(2));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(4));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(5));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(6));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(7));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(8));
- verify(pkg5Section, never()).isInSection(mEntrySet.get(10));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(0));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(1));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(2));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(4));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(5));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(6));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(7));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(8));
+ verify(pkg5Sectioner, never()).isInSection(mEntrySet.get(10));
- verify(pkg5Section).isInSection(mEntrySet.get(3));
- verify(pkg5Section).isInSection(mEntrySet.get(9));
+ verify(pkg5Sectioner).isInSection(mEntrySet.get(3));
+ verify(pkg5Sectioner).isInSection(mEntrySet.get(9));
// THEN the correct section is assigned for entries in pkg1Section
- assertEquals(pkg1Section, mEntrySet.get(2).getNotifSection());
- assertEquals(0, mEntrySet.get(2).getSection());
- assertEquals(pkg1Section, mEntrySet.get(7).getNotifSection());
- assertEquals(0, mEntrySet.get(7).getSection());
+ assertEquals(pkg1Section, mEntrySet.get(2).getSection());
+ assertEquals(pkg1Section, mEntrySet.get(7).getSection());
// THEN the correct section is assigned for entries in pkg2Section
- assertEquals(pkg2Section, mEntrySet.get(1).getNotifSection());
- assertEquals(1, mEntrySet.get(1).getSection());
- assertEquals(pkg2Section, mEntrySet.get(8).getNotifSection());
- assertEquals(1, mEntrySet.get(8).getSection());
- assertEquals(pkg2Section, mBuiltList.get(3).getNotifSection());
- assertEquals(1, mBuiltList.get(3).getSection());
+ assertEquals(pkg2Section, mEntrySet.get(1).getSection());
+ assertEquals(pkg2Section, mEntrySet.get(8).getSection());
+ assertEquals(pkg2Section, mBuiltList.get(3).getSection());
// THEN no section was assigned to entries in pkg4Section (since they were filtered)
- assertEquals(null, mEntrySet.get(0).getNotifSection());
- assertEquals(-1, mEntrySet.get(0).getSection());
- assertEquals(null, mEntrySet.get(10).getNotifSection());
- assertEquals(-1, mEntrySet.get(10).getSection());
-
+ assertNull(mEntrySet.get(0).getSection());
+ assertNull(mEntrySet.get(10).getSection());
// THEN the correct section is assigned for entries in pkg5Section
- assertEquals(pkg5Section, mEntrySet.get(9).getNotifSection());
- assertEquals(3, mEntrySet.get(9).getSection());
+ assertEquals(pkg5Section, mEntrySet.get(9).getSection());
// THEN the children entries are assigned the same section as its parent
- assertEquals(mBuiltList.get(3).getNotifSection(), child(5).entry.getNotifSection());
assertEquals(mBuiltList.get(3).getSection(), child(5).entry.getSection());
- assertEquals(mBuiltList.get(3).getNotifSection(), child(6).entry.getNotifSection());
assertEquals(mBuiltList.get(3).getSection(), child(6).entry.getSection());
}
@Test
public void testNotifUsesDefaultSection() {
// GIVEN a Section for Package2
- final NotifSection pkg2Section = spy(new PackageSection(PACKAGE_2));
- mListBuilder.setSections(Arrays.asList(pkg2Section));
+ final NotifSectioner pkg2Section = spy(new PackageSectioner(PACKAGE_2));
+ mListBuilder.setSectioners(singletonList(pkg2Section));
// WHEN we build a list with pkg1 and pkg2 packages
addNotif(0, PACKAGE_1);
@@ -727,8 +723,8 @@
);
// THEN the entry that didn't have an explicit section gets assigned the DefaultSection
- assertEquals(1, notif(0).entry.getSection());
- assertNotNull(notif(0).entry.getNotifSection());
+ assertNotNull(notif(0).entry.getSection());
+ assertEquals(1, notif(0).entry.getSectionIndex());
}
@Test
@@ -763,15 +759,15 @@
// GIVEN a bunch of registered listeners and pluggables
NotifFilter preGroupFilter = spy(new PackageFilter(PACKAGE_1));
NotifPromoter promoter = spy(new IdPromoter(3));
- NotifSection section = spy(new PackageSection(PACKAGE_1));
+ NotifSectioner section = spy(new PackageSectioner(PACKAGE_1));
NotifComparator comparator = spy(new HypeComparator(PACKAGE_4));
NotifFilter preRenderFilter = spy(new PackageFilter(PACKAGE_5));
mListBuilder.addPreGroupFilter(preGroupFilter);
mListBuilder.addOnBeforeTransformGroupsListener(mOnBeforeTransformGroupsListener);
mListBuilder.addPromoter(promoter);
mListBuilder.addOnBeforeSortListener(mOnBeforeSortListener);
- mListBuilder.setComparators(Collections.singletonList(comparator));
- mListBuilder.setSections(Arrays.asList(section));
+ mListBuilder.setComparators(singletonList(comparator));
+ mListBuilder.setSectioners(singletonList(section));
mListBuilder.addOnBeforeFinalizeFilterListener(mOnBeforeFinalizeFilterListener);
mListBuilder.addFinalizeFilter(preRenderFilter);
mListBuilder.addOnBeforeRenderListListener(mOnBeforeRenderListListener);
@@ -821,13 +817,13 @@
// GIVEN a variety of pluggables
NotifFilter packageFilter = new PackageFilter(PACKAGE_1);
NotifPromoter idPromoter = new IdPromoter(4);
- NotifSection section = new PackageSection(PACKAGE_1);
+ NotifSectioner section = new PackageSectioner(PACKAGE_1);
NotifComparator hypeComparator = new HypeComparator(PACKAGE_2);
mListBuilder.addPreGroupFilter(packageFilter);
mListBuilder.addPromoter(idPromoter);
- mListBuilder.setSections(Arrays.asList(section));
- mListBuilder.setComparators(Collections.singletonList(hypeComparator));
+ mListBuilder.setSectioners(singletonList(section));
+ mListBuilder.setComparators(singletonList(hypeComparator));
// GIVEN a set of random notifs
addNotif(0, PACKAGE_1);
@@ -973,7 +969,7 @@
RecordingOnBeforeSortListener listener =
new RecordingOnBeforeSortListener();
mListBuilder.addOnBeforeSortListener(listener);
- mListBuilder.setComparators(Arrays.asList(new HypeComparator(PACKAGE_3)));
+ mListBuilder.setComparators(singletonList(new HypeComparator(PACKAGE_3)));
// GIVEN some new notifs out of order
addNotif(0, PACKAGE_1);
@@ -1093,7 +1089,7 @@
NotifComparator comparator = new HypeComparator(PACKAGE_5);
OnBeforeRenderListListener listener =
(list) -> comparator.invalidateList();
- mListBuilder.setComparators(Collections.singletonList(comparator));
+ mListBuilder.setComparators(singletonList(comparator));
mListBuilder.addOnBeforeRenderListListener(listener);
// WHEN we try to run the pipeline and the comparator is invalidated
@@ -1420,10 +1416,10 @@
}
/** Represents a section for the passed pkg */
- private static class PackageSection extends NotifSection {
+ private static class PackageSectioner extends NotifSectioner {
private final String mPackage;
- PackageSection(String pkg) {
+ PackageSectioner(String pkg) {
super("PackageSection_" + pkg);
mPackage = pkg;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java
index ce8ce2e..639e791 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java
@@ -21,11 +21,9 @@
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_MIN;
-import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -37,7 +35,6 @@
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import android.util.ArraySet;
import androidx.test.filters.SmallTest;
@@ -48,8 +45,7 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
-import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -61,8 +57,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.List;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -78,7 +72,7 @@
private AppOpsCoordinator mAppOpsCoordinator;
private NotifFilter mForegroundFilter;
private NotifLifetimeExtender mForegroundNotifLifetimeExtender;
- private NotifSection mFgsSection;
+ private NotifSectioner mFgsSection;
private FakeSystemClock mClock = new FakeSystemClock();
private FakeExecutor mExecutor = new FakeExecutor(mClock);
@@ -111,7 +105,7 @@
lifetimeExtenderCaptor.capture());
mForegroundNotifLifetimeExtender = lifetimeExtenderCaptor.getValue();
- mFgsSection = mAppOpsCoordinator.getSection();
+ mFgsSection = mAppOpsCoordinator.getSectioner();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
index be5c8a8..c49393d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
@@ -25,7 +25,7 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
import org.junit.Assert.assertFalse
@@ -45,7 +45,7 @@
class ConversationCoordinatorTest : SysuiTestCase() {
// captured listeners and pluggables:
private lateinit var promoter: NotifPromoter
- private lateinit var peopleSection: NotifSection
+ private lateinit var peopleSectioner: NotifSectioner
@Mock
private lateinit var pipeline: NotifPipeline
@@ -70,7 +70,7 @@
verify(pipeline).addPromoter(notifPromoterCaptor.capture())
promoter = notifPromoterCaptor.value
- peopleSection = coordinator.getSection()
+ peopleSectioner = coordinator.sectioner
entry = NotificationEntryBuilder().setChannel(channel).build()
}
@@ -88,7 +88,7 @@
entry.sbn, entry.ranking)).thenReturn(TYPE_PERSON)
// only put people notifications in this section
- assertTrue(peopleSection.isInSection(entry))
- assertFalse(peopleSection.isInSection(NotificationEntryBuilder().build()))
+ assertTrue(peopleSectioner.isInSection(entry))
+ assertFalse(peopleSectioner.isInSection(NotificationEntryBuilder().build()))
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
index 730481a..fa992a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
@@ -36,7 +36,7 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder;
@@ -64,7 +64,7 @@
private NotifPromoter mNotifPromoter;
private NotifLifetimeExtender mNotifLifetimeExtender;
private OnHeadsUpChangedListener mOnHeadsUpChangedListener;
- private NotifSection mNotifSection;
+ private NotifSectioner mNotifSectioner;
@Mock private NotifPipeline mNotifPipeline;
@Mock private HeadsUpManager mHeadsUpManager;
@@ -111,7 +111,7 @@
mNotifLifetimeExtender = notifLifetimeExtenderCaptor.getValue();
mOnHeadsUpChangedListener = headsUpChangedListenerCaptor.getValue();
- mNotifSection = mCoordinator.getSection();
+ mNotifSectioner = mCoordinator.getSectioner();
mNotifLifetimeExtender.setCallback(mEndLifetimeExtension);
mEntry = new NotificationEntryBuilder().build();
}
@@ -132,8 +132,8 @@
setCurrentHUN(mEntry);
// THEN only section the current HUN, mEntry
- assertTrue(mNotifSection.isInSection(mEntry));
- assertFalse(mNotifSection.isInSection(new NotificationEntryBuilder().build()));
+ assertTrue(mNotifSectioner.isInSection(mEntry));
+ assertFalse(mNotifSectioner.isInSection(new NotificationEntryBuilder().build()));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
index 5f10f38..3a7d28a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
@@ -36,7 +36,7 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import org.junit.Before;
@@ -61,8 +61,8 @@
private NotifFilter mCapturedSuspendedFilter;
private NotifFilter mCapturedDozingFilter;
- private NotifSection mAlertingSection;
- private NotifSection mSilentSection;
+ private NotifSectioner mAlertingSectioner;
+ private NotifSectioner mSilentSectioner;
@Before
public void setup() {
@@ -76,8 +76,8 @@
mCapturedSuspendedFilter = mNotifFilterCaptor.getAllValues().get(0);
mCapturedDozingFilter = mNotifFilterCaptor.getAllValues().get(1);
- mAlertingSection = rankingCoordinator.getAlertingSection();
- mSilentSection = rankingCoordinator.getSilentSection();
+ mAlertingSectioner = rankingCoordinator.getAlertingSectioner();
+ mSilentSectioner = rankingCoordinator.getSilentSectioner();
}
@Test
@@ -146,8 +146,8 @@
when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(true);
// THEN entry is in the alerting section
- assertTrue(mAlertingSection.isInSection(mEntry));
- assertFalse(mSilentSection.isInSection(mEntry));
+ assertTrue(mAlertingSectioner.isInSection(mEntry));
+ assertFalse(mSilentSectioner.isInSection(mEntry));
}
@Test
@@ -156,8 +156,8 @@
when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
// THEN entry is in the silent section
- assertFalse(mAlertingSection.isInSection(mEntry));
- assertTrue(mSilentSection.isInSection(mEntry));
+ assertFalse(mAlertingSectioner.isInSection(mEntry));
+ assertTrue(mSilentSectioner.isInSection(mEntry));
}
private RankingBuilder getRankingForUnfilteredNotif() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 9a8678f0..df26c5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -406,12 +406,12 @@
entry.setRow(row);
mIconManager.createIcons(entry);
- row.setEntry(entry);
mBindPipelineEntryListener.onEntryInit(entry);
mBindPipeline.manageRow(entry, row);
row.initialize(
+ entry,
APP_NAME,
entry.getKey(),
mock(ExpansionLogger.class),
@@ -426,6 +426,7 @@
mStatusBarStateController,
mPeopleNotificationIdentifier,
mock(OnUserInteractionCallback.class));
+
row.setAboveShelfChangedListener(aboveShelf -> { });
mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags);
inflateAndWait(entry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 9a6674e..fa9ea6b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -18,15 +18,12 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertNull;
import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doNothing;
@@ -36,30 +33,25 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.metrics.LogMaker;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import android.view.View;
import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
-import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.FeatureFlags;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -87,14 +79,13 @@
import com.android.systemui.statusbar.notification.row.FooterView;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.KeyguardBypassEnabledProvider;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.leak.LeakDetector;
import org.junit.After;
@@ -103,7 +94,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -135,14 +125,12 @@
@Mock private NotificationIconAreaController mNotificationIconAreaController;
@Mock private MetricsLogger mMetricsLogger;
@Mock private NotificationRoundnessManager mNotificationRoundnessManager;
- @Mock private KeyguardBypassController mKeyguardBypassController;
- @Mock private KeyguardMediaController mKeyguardMediaController;
- @Mock private ZenModeController mZenModeController;
+ @Mock private KeyguardBypassEnabledProvider mKeyguardBypassEnabledProvider;
@Mock private NotificationSectionsManager mNotificationSectionsManager;
@Mock private NotificationSection mNotificationSection;
- @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
@Mock private FeatureFlags mFeatureFlags;
- private UserChangedListener mUserChangedListener;
+ @Mock private SysuiStatusBarStateController mStatusBarStateController;
+ @Mock private NotificationSwipeHelper mNotificationSwipeHelper;
private NotificationEntryManager mEntryManager;
private int mOriginalInterruptionModelSetting;
private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake();
@@ -172,8 +160,6 @@
mDependency.injectMockDependency(ShadeController.class);
when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
- ArgumentCaptor<UserChangedListener> userChangedCaptor = ArgumentCaptor
- .forClass(UserChangedListener.class);
mEntryManager = new NotificationEntryManager(
mock(NotificationEntryManagerLogger.class),
mock(NotificationGroupManager.class),
@@ -211,17 +197,15 @@
// which refer to members of NotificationStackScrollLayout. The spy
// holds a copy of the CUT's instances of these KeyguardBypassController, so they still
// refer to the CUT's member variables, not the spy's member variables.
- mStackScrollerInternal = new NotificationStackScrollLayout(getContext(), null,
+ mStackScrollerInternal = new NotificationStackScrollLayout(
+ getContext(),
+ null,
mNotificationRoundnessManager,
mock(DynamicPrivacyController.class),
- mock(SysuiStatusBarStateController.class),
+ mStatusBarStateController,
mHeadsUpManager,
- mKeyguardBypassController,
- mKeyguardMediaController,
new FalsingManagerFake(),
- mLockscreenUserManager,
mock(NotificationGutsManager.class),
- mZenModeController,
mNotificationSectionsManager,
mock(ForegroundServiceSectionController.class),
mock(ForegroundServiceDismissalFeatureController.class),
@@ -231,8 +215,8 @@
mock(NotifCollection.class),
mUiEventLoggerFake
);
- verify(mLockscreenUserManager).addUserChangedListener(userChangedCaptor.capture());
- mUserChangedListener = userChangedCaptor.getValue();
+ mStackScrollerInternal.initView(getContext(), mKeyguardBypassEnabledProvider,
+ mNotificationSwipeHelper);
mStackScroller = spy(mStackScrollerInternal);
mStackScroller.setShelfController(notificationShelfController);
mStackScroller.setStatusBar(mBar);
@@ -269,9 +253,8 @@
@Test
public void updateEmptyView_dndSuppressing() {
when(mEmptyShadeView.willBeGone()).thenReturn(true);
- when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(true);
- mStackScroller.updateEmptyShadeView(true);
+ mStackScroller.updateEmptyShadeView(true, true);
verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
}
@@ -280,9 +263,8 @@
public void updateEmptyView_dndNotSuppressing() {
mStackScroller.setEmptyShadeView(mEmptyShadeView);
when(mEmptyShadeView.willBeGone()).thenReturn(true);
- when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(false);
- mStackScroller.updateEmptyShadeView(true);
+ mStackScroller.updateEmptyShadeView(true, false);
verify(mEmptyShadeView).setText(R.string.empty_shade_text);
}
@@ -291,12 +273,10 @@
public void updateEmptyView_noNotificationsToDndSuppressing() {
mStackScroller.setEmptyShadeView(mEmptyShadeView);
when(mEmptyShadeView.willBeGone()).thenReturn(true);
- when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(false);
- mStackScroller.updateEmptyShadeView(true);
+ mStackScroller.updateEmptyShadeView(true, false);
verify(mEmptyShadeView).setText(R.string.empty_shade_text);
- when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(true);
- mStackScroller.updateEmptyShadeView(true);
+ mStackScroller.updateEmptyShadeView(true, true);
verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
}
@@ -312,12 +292,6 @@
}
@Test
- public void testOnStatePostChange_verifyIfProfileIsPublic() {
- mUserChangedListener.onUserChanged(0);
- verify(mLockscreenUserManager).isAnyProfilePublicMode();
- }
-
- @Test
public void manageNotifications_visible() {
FooterView view = mock(FooterView.class);
mStackScroller.setFooterView(view);
@@ -446,86 +420,22 @@
@Test
@UiThreadTest
public void testSetIsBeingDraggedResetsExposedMenu() {
- NotificationSwipeHelper swipeActionHelper =
- (NotificationSwipeHelper) mStackScroller.getSwipeActionHelper();
- swipeActionHelper.setExposedMenuView(new View(mContext));
mStackScroller.setIsBeingDragged(true);
- assertNull(swipeActionHelper.getExposedMenuView());
+ verify(mNotificationSwipeHelper).resetExposedMenuView(true, true);
}
@Test
@UiThreadTest
public void testPanelTrackingStartResetsExposedMenu() {
- NotificationSwipeHelper swipeActionHelper =
- (NotificationSwipeHelper) mStackScroller.getSwipeActionHelper();
- swipeActionHelper.setExposedMenuView(new View(mContext));
mStackScroller.onPanelTrackingStarted();
- assertNull(swipeActionHelper.getExposedMenuView());
+ verify(mNotificationSwipeHelper).resetExposedMenuView(true, true);
}
@Test
@UiThreadTest
public void testDarkModeResetsExposedMenu() {
- NotificationSwipeHelper swipeActionHelper =
- (NotificationSwipeHelper) mStackScroller.getSwipeActionHelper();
- swipeActionHelper.setExposedMenuView(new View(mContext));
mStackScroller.setHideAmount(0.1f, 0.1f);
- assertNull(swipeActionHelper.getExposedMenuView());
- }
-
- class LogMatcher implements ArgumentMatcher<LogMaker> {
- private int mCategory, mType;
-
- LogMatcher(int category, int type) {
- mCategory = category;
- mType = type;
- }
- public boolean matches(LogMaker l) {
- return (l.getCategory() == mCategory)
- && (l.getType() == mType);
- }
-
- public String toString() {
- return String.format("LogMaker(%d, %d)", mCategory, mType);
- }
- }
-
- private LogMaker logMatcher(int category, int type) {
- return argThat(new LogMatcher(category, type));
- }
-
- @Test
- @UiThreadTest
- public void testOnMenuClickedLogging() {
- // Set up the object under test to have a valid mLongPressListener. We're testing an
- // anonymous-class member, mMenuEventListener, so we need to modify the state of the
- // class itself, not the Mockito spy copied from it. See notes in setup.
- mStackScrollerInternal.setLongPressListener(
- mock(ExpandableNotificationRow.LongPressListener.class));
-
- ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
- when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker(
- MetricsProto.MetricsEvent.VIEW_UNKNOWN));
-
- mStackScroller.mMenuEventListener.onMenuClicked(row, 0, 0, mock(
- NotificationMenuRowPlugin.MenuItem.class));
- verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data
- verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_TOUCH_GEAR,
- MetricsProto.MetricsEvent.TYPE_ACTION));
- }
-
- @Test
- @UiThreadTest
- public void testOnMenuShownLogging() { ;
-
- ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
- when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker(
- MetricsProto.MetricsEvent.VIEW_UNKNOWN));
-
- mStackScroller.mMenuEventListener.onMenuShown(row);
- verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data
- verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_REVEAL_GEAR,
- MetricsProto.MetricsEvent.TYPE_ACTION));
+ verify(mNotificationSwipeHelper).resetExposedMenuView(true, true);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
index e3acf02..4fffd3e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
@@ -17,25 +17,49 @@
package com.android.systemui.statusbar.notification.stack;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.res.Resources;
+import android.metrics.LogMaker;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.media.KeyguardMediaController;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -55,20 +79,46 @@
@Mock
private TunerService mTunerService;
@Mock
- private AmbientState mAmbientState;
- @Mock
private DynamicPrivacyController mDynamicPrivacyController;
@Mock
private ConfigurationController mConfigurationController;
@Mock
private NotificationStackScrollLayout mNotificationStackScrollLayout;
+ @Mock
+ private ZenModeController mZenModeController;
+ @Mock
+ private KeyguardMediaController mKeyguardMediaController;
+ @Mock
+ private SysuiStatusBarStateController mSysuiStatusBarStateController;
+ @Mock
+ private KeyguardBypassController mKeyguardBypassController;
+ @Mock
+ private SysuiColorExtractor mColorExtractor;
+ @Mock
+ private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
+ @Mock
+ private MetricsLogger mMetricsLogger;
+ @Mock
+ private FalsingManager mFalsingManager;
+ @Mock
+ private NotificationSectionsManager mNotificationSectionsManager;
+ @Mock
+ private Resources mResources;
+ @Mock(answer = Answers.RETURNS_SELF)
+ private NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder;
+ @Mock
+ private NotificationSwipeHelper mNotificationSwipeHelper;
+ @Mock
+ private StatusBar mStatusBar;
- NotificationStackScrollLayoutController mController;
+ private NotificationStackScrollLayoutController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ when(mNotificationSwipeHelperBuilder.build()).thenReturn(mNotificationSwipeHelper);
+
mController = new NotificationStackScrollLayoutController(
true,
mNotificationGutsManager,
@@ -76,7 +126,19 @@
mNotificationRoundnessManager,
mTunerService,
mDynamicPrivacyController,
- mConfigurationController
+ mConfigurationController,
+ mSysuiStatusBarStateController,
+ mKeyguardMediaController,
+ mKeyguardBypassController,
+ mZenModeController,
+ mColorExtractor,
+ mNotificationLockscreenUserManager,
+ mMetricsLogger,
+ mFalsingManager,
+ mNotificationSectionsManager,
+ mResources,
+ mNotificationSwipeHelperBuilder,
+ mStatusBar
);
when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true);
@@ -112,4 +174,140 @@
mController.mConfigurationListener.onDensityOrFontScaleChanged();
verify(mNotificationStackScrollLayout).reinflateViews();
}
+
+ @Test
+ public void testUpdateEmptyShadeView_notificationsVisible() {
+ when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(true);
+ mController.attach(mNotificationStackScrollLayout);
+
+ mController.updateEmptyShadeView(true /* visible */);
+ verify(mNotificationStackScrollLayout).updateEmptyShadeView(
+ true /* visible */,
+ true /* notifVisibleInShade */);
+ reset(mNotificationStackScrollLayout);
+ mController.updateEmptyShadeView(false /* visible */);
+ verify(mNotificationStackScrollLayout).updateEmptyShadeView(
+ false /* visible */,
+ true /* notifVisibleInShade */);
+ }
+
+ @Test
+ public void testUpdateEmptyShadeView_notificationsHidden() {
+ when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(false);
+ mController.attach(mNotificationStackScrollLayout);
+
+ mController.updateEmptyShadeView(true /* visible */);
+ verify(mNotificationStackScrollLayout).updateEmptyShadeView(
+ true /* visible */,
+ false /* notifVisibleInShade */);
+ reset(mNotificationStackScrollLayout);
+ mController.updateEmptyShadeView(false /* visible */);
+ verify(mNotificationStackScrollLayout).updateEmptyShadeView(
+ false /* visible */,
+ false /* notifVisibleInShade */);
+ }
+
+ @Test
+ public void testOnUserChange_verifySensitiveProfile() {
+ when(mNotificationLockscreenUserManager.isAnyProfilePublicMode()).thenReturn(true);
+
+ ArgumentCaptor<UserChangedListener> userChangedCaptor = ArgumentCaptor
+ .forClass(UserChangedListener.class);
+
+ mController.attach(mNotificationStackScrollLayout);
+ verify(mNotificationLockscreenUserManager)
+ .addUserChangedListener(userChangedCaptor.capture());
+ reset(mNotificationStackScrollLayout);
+
+ UserChangedListener changedListener = userChangedCaptor.getValue();
+ changedListener.onUserChanged(0);
+ verify(mNotificationStackScrollLayout).setCurrentUserid(0);
+ verify(mNotificationStackScrollLayout).updateSensitiveness(false, true);
+ }
+
+ @Test
+ public void testOnStatePostChange_verifyIfProfileIsPublic() {
+ when(mNotificationLockscreenUserManager.isAnyProfilePublicMode()).thenReturn(true);
+
+ ArgumentCaptor<StatusBarStateController.StateListener> stateListenerArgumentCaptor =
+ ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
+
+ mController.attach(mNotificationStackScrollLayout);
+ verify(mSysuiStatusBarStateController).addCallback(
+ stateListenerArgumentCaptor.capture(), anyInt());
+
+ StatusBarStateController.StateListener stateListener =
+ stateListenerArgumentCaptor.getValue();
+
+ stateListener.onStatePostChange();
+ verify(mNotificationStackScrollLayout).updateSensitiveness(false, true);
+ }
+
+
+ @Test
+ public void testOnMenuShownLogging() { ;
+
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
+ when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker(
+ MetricsProto.MetricsEvent.VIEW_UNKNOWN));
+
+
+ ArgumentCaptor<OnMenuEventListener> onMenuEventListenerArgumentCaptor =
+ ArgumentCaptor.forClass(OnMenuEventListener.class);
+
+ mController.attach(mNotificationStackScrollLayout);
+ verify(mNotificationSwipeHelperBuilder).setOnMenuEventListener(
+ onMenuEventListenerArgumentCaptor.capture());
+
+ OnMenuEventListener onMenuEventListener = onMenuEventListenerArgumentCaptor.getValue();
+
+ onMenuEventListener.onMenuShown(row);
+ verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data
+ verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_REVEAL_GEAR,
+ MetricsProto.MetricsEvent.TYPE_ACTION));
+ }
+
+ @Test
+ public void testOnMenuClickedLogging() {
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
+ when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker(
+ MetricsProto.MetricsEvent.VIEW_UNKNOWN));
+
+
+ ArgumentCaptor<OnMenuEventListener> onMenuEventListenerArgumentCaptor =
+ ArgumentCaptor.forClass(OnMenuEventListener.class);
+
+ mController.attach(mNotificationStackScrollLayout);
+ verify(mNotificationSwipeHelperBuilder).setOnMenuEventListener(
+ onMenuEventListenerArgumentCaptor.capture());
+
+ OnMenuEventListener onMenuEventListener = onMenuEventListenerArgumentCaptor.getValue();
+
+ onMenuEventListener.onMenuClicked(row, 0, 0, mock(
+ NotificationMenuRowPlugin.MenuItem.class));
+ verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data
+ verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_TOUCH_GEAR,
+ MetricsProto.MetricsEvent.TYPE_ACTION));
+ }
+
+ private LogMaker logMatcher(int category, int type) {
+ return argThat(new LogMatcher(category, type));
+ }
+
+ static class LogMatcher implements ArgumentMatcher<LogMaker> {
+ private int mCategory, mType;
+
+ LogMatcher(int category, int type) {
+ mCategory = category;
+ mType = type;
+ }
+ public boolean matches(LogMaker l) {
+ return (l.getCategory() == mCategory)
+ && (l.getType() == mType);
+ }
+
+ public String toString() {
+ return String.format("LogMaker(%d, %d)", mCategory, mType);
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
index 323d8bd..0faf5d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -35,6 +35,7 @@
import android.testing.TestableLooper;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewConfiguration;
import androidx.test.filters.SmallTest;
@@ -78,7 +79,8 @@
mCallback = mock(NotificationSwipeHelper.NotificationCallback.class);
mListener = mock(NotificationMenuRowPlugin.OnMenuEventListener.class);
mSwipeHelper = spy(new NotificationSwipeHelper(
- SwipeHelper.X, mCallback, mContext, mListener, new FalsingManagerFake()));
+ mContext.getResources(), ViewConfiguration.get(mContext),
+ new FalsingManagerFake(), SwipeHelper.X, mCallback, mListener));
mView = mock(View.class);
mEvent = mock(MotionEvent.class);
mMenuRow = mock(NotificationMenuRowPlugin.class);
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 c9e9d94..04e870d 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
@@ -52,6 +52,7 @@
import com.android.internal.util.LatencyTracker;
import com.android.keyguard.KeyguardClockSwitch;
import com.android.keyguard.KeyguardClockSwitchController;
+import com.android.keyguard.KeyguardStatusView;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
@@ -217,6 +218,8 @@
when(mKeyguardBottomArea.getRightView()).thenReturn(mock(KeyguardAffordanceView.class));
when(mView.findViewById(R.id.big_clock_container)).thenReturn(mBigClockContainer);
when(mView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame);
+ when(mView.findViewById(R.id.keyguard_status_view))
+ .thenReturn(mock(KeyguardStatusView.class));
FlingAnimationUtils.Builder flingAnimationUtilsBuilder = new FlingAnimationUtils.Builder(
mDisplayMetrics);
@@ -239,6 +242,7 @@
mStatusBarStateController,
new FalsingManagerFake());
mNotificationPanelViewController = new NotificationPanelViewController(mView,
+ mResources,
mInjectionInflationController,
coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
mFalsingManager, mShadeController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index ccc3078..2f45113 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -43,6 +43,7 @@
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.keyguard.FaceAuthScreenBrightnessController;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.plugins.FalsingManager;
@@ -58,6 +59,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Optional;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -89,6 +92,8 @@
private View mNotificationContainer;
@Mock
private KeyguardBypassController mBypassController;
+ @Mock
+ private FaceAuthScreenBrightnessController mFaceAuthScreenBrightnessController;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Before
@@ -108,6 +113,7 @@
mock(DockManager.class),
mock(NotificationShadeWindowController.class),
mKeyguardStateController,
+ mFaceAuthScreenBrightnessController,
mock(NotificationMediaManager.class));
mStatusBarKeyguardViewManager.registerStatusBar(mStatusBar, mContainer,
mNotificationPanelView, mBiometrucUnlockController, mDismissCallbackRegistry,
@@ -274,11 +280,12 @@
DockManager dockManager,
NotificationShadeWindowController notificationShadeWindowController,
KeyguardStateController keyguardStateController,
+ FaceAuthScreenBrightnessController faceAuthScreenBrightnessController,
NotificationMediaManager notificationMediaManager) {
super(context, callback, lockPatternUtils, sysuiStatusBarStateController,
configurationController, keyguardUpdateMonitor, navigationModeController,
dockManager, notificationShadeWindowController, keyguardStateController,
- notificationMediaManager);
+ Optional.of(faceAuthScreenBrightnessController), notificationMediaManager);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 8462386..87aee3f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -96,7 +96,7 @@
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationListener;
@@ -238,7 +238,7 @@
@Mock private StatusBarComponent.Builder mStatusBarComponentBuilder;
@Mock private StatusBarComponent mStatusBarComponent;
@Mock private PluginManager mPluginManager;
- @Mock private Divider mDivider;
+ @Mock private SplitScreen mSplitScreen;
@Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
@Mock private LightsOutNotifController mLightsOutNotifController;
@Mock private ViewMediatorCallback mViewMediatorCallback;
@@ -397,7 +397,7 @@
Optional.of(mRecents),
mStatusBarComponentBuilderProvider,
mPluginManager,
- Optional.of(mDivider),
+ Optional.of(mSplitScreen),
mLightsOutNotifController,
mStatusBarNotificationActivityStarterBuilder,
mShadeController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
index fbbfa96..3dd36d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
@@ -41,6 +41,7 @@
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dump.DumpManager;
import org.junit.Before;
import org.junit.Test;
@@ -58,6 +59,7 @@
private CachedBluetoothDeviceManager mMockDeviceManager;
private LocalBluetoothAdapter mMockAdapter;
private TestableLooper mTestableLooper;
+ private DumpManager mMockDumpManager;
private BluetoothControllerImpl mBluetoothControllerImpl;
private List<CachedBluetoothDevice> mDevices;
@@ -75,8 +77,10 @@
when(mMockBluetoothManager.getEventManager()).thenReturn(mock(BluetoothEventManager.class));
when(mMockBluetoothManager.getProfileManager())
.thenReturn(mock(LocalBluetoothProfileManager.class));
+ mMockDumpManager = mock(DumpManager.class);
mBluetoothControllerImpl = new BluetoothControllerImpl(mContext,
+ mMockDumpManager,
mTestableLooper.getLooper(),
mTestableLooper.getLooper(),
mMockBluetoothManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java b/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java
index 260ff2d..33ece00 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java
@@ -70,9 +70,7 @@
for (Pair<Executor, OnPropertiesChangedListener> listener : mListeners) {
Properties.Builder propBuilder = new Properties.Builder(namespace);
- for (String key : mProperties.get(namespace).keySet()) {
- propBuilder.setString(key, mProperties.get(namespace).get(key));
- }
+ propBuilder.setString(name, value);
listener.first.execute(() -> listener.second.onPropertiesChanged(propBuilder.build()));
}
return true;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFakeTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFakeTest.java
new file mode 100644
index 0000000..64e8957
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFakeTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util;
+
+import static android.provider.DeviceConfig.Properties;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.provider.DeviceConfig.OnPropertiesChangedListener;
+
+import androidx.annotation.NonNull;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DeviceConfigProxyFakeTest extends SysuiTestCase {
+ private static final String NAMESPACE = "foobar";
+
+ private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
+
+ private DeviceConfigProxyFake mDeviceConfigProxyFake;
+
+ @Before
+ public void setup() {
+ mDeviceConfigProxyFake = new DeviceConfigProxyFake();
+ }
+
+ @Test
+ public void testOnPropertiesChanged() {
+ TestableListener onPropertiesChangedListener = new TestableListener();
+ String key = "foo";
+ String value = "bar";
+
+ mDeviceConfigProxyFake.addOnPropertiesChangedListener(
+ NAMESPACE, mFakeExecutor, onPropertiesChangedListener);
+
+ mDeviceConfigProxyFake.setProperty(NAMESPACE, key, value, false);
+ mFakeExecutor.runAllReady();
+ assertThat(onPropertiesChangedListener.mProperties).isNotNull();
+ assertThat(onPropertiesChangedListener.mProperties.getKeyset().size()).isEqualTo(1);
+ assertThat(onPropertiesChangedListener.mProperties.getString(key, "")).isEqualTo(value);
+ }
+
+ @Test
+ public void testOnMultiplePropertiesChanged() {
+ TestableListener onPropertiesChangedListener = new TestableListener();
+ String keyA = "foo";
+ String valueA = "bar";
+ String keyB = "bada";
+ String valueB = "boom";
+
+ mDeviceConfigProxyFake.addOnPropertiesChangedListener(
+ NAMESPACE, mFakeExecutor, onPropertiesChangedListener);
+ mDeviceConfigProxyFake.setProperty(NAMESPACE, keyA, valueA, false);
+ mFakeExecutor.runAllReady();
+ assertThat(onPropertiesChangedListener.mProperties).isNotNull();
+ assertThat(onPropertiesChangedListener.mProperties.getKeyset().size()).isEqualTo(1);
+ assertThat(onPropertiesChangedListener.mProperties.getString(keyA, "")).isEqualTo(valueA);
+
+ mDeviceConfigProxyFake.setProperty(NAMESPACE, keyB, valueB, false);
+ mFakeExecutor.runAllReady();
+ assertThat(onPropertiesChangedListener.mProperties).isNotNull();
+ assertThat(onPropertiesChangedListener.mProperties.getKeyset().size()).isEqualTo(1);
+ assertThat(onPropertiesChangedListener.mProperties.getString(keyB, "")).isEqualTo(valueB);
+ }
+
+ private static class TestableListener implements OnPropertiesChangedListener {
+ Properties mProperties;
+
+ TestableListener() {
+ }
+ @Override
+ public void onPropertiesChanged(@NonNull Properties properties) {
+ mProperties = properties;
+ }
+ }
+}
diff --git a/packages/Tethering/AndroidManifestBase.xml b/packages/Tethering/AndroidManifestBase.xml
index fa85f66..97c3988 100644
--- a/packages/Tethering/AndroidManifestBase.xml
+++ b/packages/Tethering/AndroidManifestBase.xml
@@ -23,6 +23,7 @@
<application
android:label="Tethering"
android:defaultToDeviceProtectedStorage="true"
- android:directBootAware="true">
+ android:directBootAware="true"
+ android:usesCleartextTraffic="true">
</application>
</manifest>
diff --git a/services/Android.bp b/services/Android.bp
index b348b91..ef52c2a 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -156,10 +156,14 @@
java_library {
name: "android_system_server_stubs_current",
+ defaults: ["android_stubs_dists_default"],
srcs: [":services-stubs.sources"],
installable: false,
static_libs: ["android_module_lib_stubs_current"],
sdk_version: "none",
system_modules: "none",
java_version: "1.8",
+ dist: {
+ dir: "apistubs/android/system-server",
+ },
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 669bb24..a75b64c 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -284,11 +284,13 @@
* Computes partial interactive region of given windowId.
*
* @param windowId The windowId
+ * @param forceComputeRegion set outRegion when the windowId matches one on the screen even
+ * though the region is not covered by other windows above it.
* @param outRegion The output to which to write the bounds.
- * @return true if outRegion is not empty.
+ * @return {@code true} if outRegion is not empty.
*/
boolean computePartialInteractiveRegionForWindowLocked(int windowId,
- @NonNull Region outRegion) {
+ boolean forceComputeRegion, @NonNull Region outRegion) {
if (mWindows == null) {
return false;
}
@@ -309,6 +311,9 @@
currentWindow.getRegionInScreen(currentWindowRegions);
outRegion.set(currentWindowRegions);
windowInteractiveRegion = outRegion;
+ if (forceComputeRegion) {
+ windowInteractiveRegionChanged = true;
+ }
continue;
}
} else if (currentWindow.getType()
@@ -1240,10 +1245,13 @@
*/
public boolean computePartialInteractiveRegionForWindowLocked(int windowId,
@NonNull Region outRegion) {
- windowId = resolveParentWindowIdLocked(windowId);
- final DisplayWindowsObserver observer = getDisplayWindowObserverByWindowIdLocked(windowId);
+ final int parentWindowId = resolveParentWindowIdLocked(windowId);
+ final DisplayWindowsObserver observer = getDisplayWindowObserverByWindowIdLocked(
+ parentWindowId);
+
if (observer != null) {
- return observer.computePartialInteractiveRegionForWindowLocked(windowId, outRegion);
+ return observer.computePartialInteractiveRegionForWindowLocked(parentWindowId,
+ parentWindowId != windowId, outRegion);
}
return false;
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 a2d58c8..b587dd3 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -561,24 +561,6 @@
// stream consistent.
sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
}
- if (mGestureDetector.isMultiFingerGesturesEnabled()
- && mGestureDetector.isTwoFingerPassthroughEnabled()) {
- if (event.getPointerCount() == 3) {
- boolean isOnBottomEdge = false;
- // If three fingers go down on the bottom edge of the screen, delegate immediately.
- final long screenHeight = mContext.getResources().getDisplayMetrics().heightPixels;
- for (int i = 0; i < TouchState.MAX_POINTER_COUNT; ++i) {
- if (mReceivedPointerTracker.getReceivedPointerDownY(i)
- > (screenHeight - mEdgeSwipeHeightPixels)) {
- isOnBottomEdge = true;
- }
- }
- if (isOnBottomEdge) {
- mState.startDelegating();
- mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
- }
- }
- }
}
/**
@@ -644,12 +626,34 @@
break;
default:
if (mGestureDetector.isMultiFingerGesturesEnabled()) {
- return;
+ if (mGestureDetector.isTwoFingerPassthroughEnabled()) {
+ if (event.getPointerCount() == 3) {
+ boolean isOnBottomEdge = true;
+ // If three fingers went down on the bottom edge of the screen, delegate
+ // immediately.
+ final long screenHeight =
+ mContext.getResources().getDisplayMetrics().heightPixels;
+ for (int i = 0; i < TouchState.MAX_POINTER_COUNT; ++i) {
+ if (mReceivedPointerTracker.getReceivedPointerDownY(i)
+ < (screenHeight - mEdgeSwipeHeightPixels)) {
+ isOnBottomEdge = false;
+ }
+ }
+ if (isOnBottomEdge) {
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "Three-finger edge swipe detected.");
+ }
+ mState.startDelegating();
+ mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
+ }
+ }
+ }
+ } else {
+ // More than two pointers are delegated to the view hierarchy.
+ mState.startDelegating();
+ event = MotionEvent.obtainNoHistory(event);
+ mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
}
- // More than two pointers are delegated to the view hierarchy.
- mState.startDelegating();
- event = MotionEvent.obtainNoHistory(event);
- mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
break;
}
}
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index ad1986a6..cf9324c 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -302,24 +302,11 @@
String packageName, int userId);
/**
- * Do a straight uid lookup for the given package/application in the given user. This enforces
- * app visibility rules and permissions. Call {@link #getPackageUidInternal} for the internal
- * implementation.
- * @deprecated Use {@link PackageManager#getPackageUid(String, int)}
- * @return The app's uid, or < 0 if the package was not found in that user
- */
- @Deprecated
- public abstract int getPackageUid(String packageName,
- @PackageInfoFlags int flags, int userId);
-
- /**
* Do a straight uid lookup for the given package/application in the given user.
* @see PackageManager#getPackageUidAsUser(String, int, int)
* @return The app's uid, or < 0 if the package was not found in that user
- * TODO(b/148235092): rename this to getPackageUid
*/
- public abstract int getPackageUidInternal(String packageName,
- @PackageInfoFlags int flags, int userId);
+ public abstract int getPackageUid(String packageName, @PackageInfoFlags int flags, int userId);
/**
* Retrieve all of the information we know about a particular package/application.
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index b72985c..27c5d4a 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2160,7 +2160,7 @@
Slog.i(TAG, "Remounting storage for pid: " + pid);
final String[] sharedPackages =
mPmInternal.getSharedUserPackagesForPackage(packageName, userId);
- final int uid = mPmInternal.getPackageUidInternal(packageName, 0, userId);
+ final int uid = mPmInternal.getPackageUid(packageName, 0 /* flags */, userId);
final String[] packages =
sharedPackages.length != 0 ? sharedPackages : new String[]{packageName};
try {
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index df966c1..34e6370 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -47,8 +47,8 @@
*
* {@hide}
*/
-public class SystemServiceManager {
- private static final String TAG = "SystemServiceManager";
+public final class SystemServiceManager {
+ private static final String TAG = SystemServiceManager.class.getSimpleName();
private static final boolean DEBUG = false;
private static final int SERVICE_CALL_WARN_TIME_MS = 50;
@@ -250,76 +250,76 @@
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
}
- private @NonNull TargetUser getTargetUser(@UserIdInt int userHandle) {
+ private @NonNull TargetUser getTargetUser(@UserIdInt int userId) {
final TargetUser targetUser;
synchronized (mTargetUsers) {
- targetUser = mTargetUsers.get(userHandle);
+ targetUser = mTargetUsers.get(userId);
}
- Preconditions.checkState(targetUser != null, "No TargetUser for " + userHandle);
+ Preconditions.checkState(targetUser != null, "No TargetUser for " + userId);
return targetUser;
}
/**
* Starts the given user.
*/
- public void startUser(final @NonNull TimingsTraceAndSlog t, final @UserIdInt int userHandle) {
+ public void startUser(@NonNull TimingsTraceAndSlog t, @UserIdInt int userId) {
// Create cached TargetUser
- final UserInfo userInfo = mUserManagerInternal.getUserInfo(userHandle);
- Preconditions.checkState(userInfo != null, "No UserInfo for " + userHandle);
+ final UserInfo userInfo = mUserManagerInternal.getUserInfo(userId);
+ Preconditions.checkState(userInfo != null, "No UserInfo for " + userId);
synchronized (mTargetUsers) {
- mTargetUsers.put(userHandle, new TargetUser(userInfo));
+ mTargetUsers.put(userId, new TargetUser(userInfo));
}
- onUser(t, START, userHandle);
+ onUser(t, START, userId);
}
/**
* Unlocks the given user.
*/
- public void unlockUser(final @UserIdInt int userHandle) {
- onUser(UNLOCKING, userHandle);
+ public void unlockUser(@UserIdInt int userId) {
+ onUser(UNLOCKING, userId);
}
/**
* Called after the user was unlocked.
*/
- public void onUserUnlocked(final @UserIdInt int userHandle) {
- onUser(UNLOCKED, userHandle);
+ public void onUserUnlocked(@UserIdInt int userId) {
+ onUser(UNLOCKED, userId);
}
/**
* Switches to the given user.
*/
- public void switchUser(final @UserIdInt int from, final @UserIdInt int to) {
+ public void switchUser(@UserIdInt int from, @UserIdInt int to) {
onUser(TimingsTraceAndSlog.newAsyncLog(), SWITCH, to, from);
}
/**
* Stops the given user.
*/
- public void stopUser(final @UserIdInt int userHandle) {
- onUser(STOP, userHandle);
+ public void stopUser(@UserIdInt int userId) {
+ onUser(STOP, userId);
}
/**
* Cleans up the given user.
*/
- public void cleanupUser(final @UserIdInt int userHandle) {
- onUser(CLEANUP, userHandle);
+ public void cleanupUser(@UserIdInt int userId) {
+ onUser(CLEANUP, userId);
// Remove cached TargetUser
synchronized (mTargetUsers) {
- mTargetUsers.remove(userHandle);
+ mTargetUsers.remove(userId);
}
}
- private void onUser(@NonNull String onWhat, @UserIdInt int userHandle) {
- onUser(TimingsTraceAndSlog.newAsyncLog(), onWhat, userHandle);
+ private void onUser(@NonNull String onWhat, @UserIdInt int userId) {
+ onUser(TimingsTraceAndSlog.newAsyncLog(), onWhat, userId);
}
private void onUser(@NonNull TimingsTraceAndSlog t, @NonNull String onWhat,
- @UserIdInt int userHandle) {
- onUser(t, onWhat, userHandle, UserHandle.USER_NULL);
+ @UserIdInt int userId) {
+ onUser(t, onWhat, userId, UserHandle.USER_NULL);
}
private void onUser(@NonNull TimingsTraceAndSlog t, @NonNull String onWhat,
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 6d71c8e..eb8308b 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -315,11 +315,10 @@
private List<Map<Pair<Integer, ApnSetting>, PreciseDataConnectionState>>
mPreciseDataConnectionStates;
- static final int ENFORCE_COARSE_LOCATION_PERMISSION_MASK =
- PhoneStateListener.LISTEN_REGISTRATION_FAILURE
- | PhoneStateListener.LISTEN_BARRING_INFO;
-
- static final int ENFORCE_FINE_LOCATION_PERMISSION_MASK =
+ // Starting in Q, almost all cellular location requires FINE location enforcement.
+ // Prior to Q, cellular was available with COARSE location enforcement. Bits in this
+ // list will be checked for COARSE on apps targeting P or earlier and FINE on Q or later.
+ static final int ENFORCE_LOCATION_PERMISSION_MASK =
PhoneStateListener.LISTEN_CELL_LOCATION
| PhoneStateListener.LISTEN_CELL_INFO
| PhoneStateListener.LISTEN_REGISTRATION_FAILURE
@@ -376,7 +375,7 @@
+ " newDefaultPhoneId=" + newDefaultPhoneId);
}
- //Due to possible risk condition,(notify call back using the new
+ //Due to possible race condition,(notify call back using the new
//defaultSubId comes before new defaultSubId update) we need to recall all
//possible missed notify callback
synchronized (mRecords) {
@@ -909,7 +908,8 @@
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
try {
if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[phoneId]);
- if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
// null will be translated to empty CellLocation object in client.
r.callback.onCellLocationChanged(mCellIdentity[phoneId]);
}
@@ -964,7 +964,8 @@
try {
if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
+ mCellInfo.get(phoneId));
- if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
}
} catch (RemoteException ex) {
@@ -1518,7 +1519,8 @@
for (Record r : mRecords) {
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO) &&
idMatch(r.subId, subId, phoneId) &&
- checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) {
try {
if (DBG_LOC) {
log("notifyCellInfoForSubscriber: mCellInfo=" + cellInfo
@@ -1797,7 +1799,8 @@
for (Record r : mRecords) {
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) &&
idMatch(r.subId, subId, phoneId) &&
- checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) {
try {
if (DBG_LOC) {
log("notifyCellLocation: cellLocation=" + cellLocation
@@ -2103,20 +2106,20 @@
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
mOutgoingCallEmergencyNumber[phoneId] = emergencyNumber;
- for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL)
- && idMatch(r.subId, subId, phoneId)) {
- try {
- r.callback.onOutgoingEmergencyCall(emergencyNumber);
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
- }
+ }
+ for (Record r : mRecords) {
+ // Send to all listeners regardless of subscription
+ if (r.matchPhoneStateListenerEvent(
+ PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL)) {
+ try {
+ r.callback.onOutgoingEmergencyCall(emergencyNumber, subId);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
}
}
}
- handleRemoveListLocked();
}
+ handleRemoveListLocked();
}
@Override
@@ -2544,16 +2547,11 @@
boolean shouldCheckLocationPermissions = false;
- if ((events & ENFORCE_FINE_LOCATION_PERMISSION_MASK) != 0) {
+ if ((events & ENFORCE_LOCATION_PERMISSION_MASK) != 0) {
// Everything that requires fine location started in Q. So far...
locationQueryBuilder.setMinSdkVersionForFine(Build.VERSION_CODES.Q);
- // If we're enforcing fine starting in Q, we also want to enforce coarse starting in Q.
- locationQueryBuilder.setMinSdkVersionForCoarse(Build.VERSION_CODES.Q);
- locationQueryBuilder.setMinSdkVersionForEnforcement(Build.VERSION_CODES.Q);
- shouldCheckLocationPermissions = true;
- }
-
- if ((events & ENFORCE_COARSE_LOCATION_PERMISSION_MASK) != 0) {
+ // If we're enforcing fine starting in Q, we also want to enforce coarse even for
+ // older SDK versions.
locationQueryBuilder.setMinSdkVersionForCoarse(0);
locationQueryBuilder.setMinSdkVersionForEnforcement(0);
shouldCheckLocationPermissions = true;
@@ -2750,8 +2748,16 @@
try {
if (VDBG) log("checkPossibleMissNotify: onServiceStateChanged state=" +
mServiceState[phoneId]);
- r.callback.onServiceStateChanged(
- new ServiceState(mServiceState[phoneId]));
+ ServiceState ss = new ServiceState(mServiceState[phoneId]);
+ if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ r.callback.onServiceStateChanged(ss);
+ } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) {
+ r.callback.onServiceStateChanged(
+ ss.createLocationInfoSanitizedCopy(false));
+ } else {
+ r.callback.onServiceStateChanged(
+ ss.createLocationInfoSanitizedCopy(true));
+ }
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
@@ -2796,7 +2802,8 @@
log("checkPossibleMissNotify: onCellInfoChanged[" + phoneId + "] = "
+ mCellInfo.get(phoneId));
}
- if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
}
} catch (RemoteException ex) {
@@ -2862,7 +2869,8 @@
log("checkPossibleMissNotify: onCellLocationChanged mCellIdentity = "
+ mCellIdentity[phoneId]);
}
- if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
// null will be translated to empty CellLocation object in client.
r.callback.onCellLocationChanged(mCellIdentity[phoneId]);
}
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 96d973e..687af10 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.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 @@
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 @@
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 @@
}
};
+ /** 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 @@
// 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 @@
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 @@
}
}
- /** 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 @@
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 @@
}
}
+ /** 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 @@
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 @@
// 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 @@
// 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 @@
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 @@
@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 @@
}
/** 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/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 1815dac..990a547 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -99,6 +99,7 @@
"android.hardware.audio@4.0::IDevicesFactory",
"android.hardware.audio@5.0::IDevicesFactory",
"android.hardware.audio@6.0::IDevicesFactory",
+ "android.hardware.audio@7.0::IDevicesFactory",
"android.hardware.biometrics.face@1.0::IBiometricsFace",
"android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint",
"android.hardware.bluetooth@1.0::IBluetoothHci",
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 6328cb60..c31d732 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -453,16 +453,16 @@
}
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
- int callingPid, int callingUid, boolean fgRequired, String callingPackage,
- @Nullable String callingFeatureId, final int userId)
+ int callingPid, int callingUid, boolean fgRequired, boolean hideFgNotification,
+ String callingPackage, @Nullable String callingFeatureId, final int userId)
throws TransactionTooLargeException {
return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired,
- callingPackage, callingFeatureId, userId, false);
+ hideFgNotification, callingPackage, callingFeatureId, userId, false);
}
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
- int callingPid, int callingUid, boolean fgRequired, String callingPackage,
- @Nullable String callingFeatureId, final int userId,
+ int callingPid, int callingUid, boolean fgRequired, boolean hideFgNotification,
+ String callingPackage, @Nullable String callingFeatureId, final int userId,
boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
+ " type=" + resolvedType + " args=" + service.getExtras());
@@ -626,6 +626,7 @@
r.startRequested = true;
r.delayedStop = false;
r.fgRequired = fgRequired;
+ r.hideFgNotification = hideFgNotification;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants, callingUid));
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index e9539be..fede1d2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -89,6 +89,7 @@
static final String KEY_MEMORY_INFO_THROTTLE_TIME = "memory_info_throttle_time";
static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration";
static final String KEY_PENDINGINTENT_WARNING_THRESHOLD = "pendingintent_warning_threshold";
+ static final String KEY_MIN_CRASH_INTERVAL = "min_crash_interval";
private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
@@ -122,6 +123,8 @@
private static final long DEFAULT_MEMORY_INFO_THROTTLE_TIME = 5*60*1000;
private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000;
private static final int DEFAULT_PENDINGINTENT_WARNING_THRESHOLD = 2000;
+ private static final int DEFAULT_MIN_CRASH_INTERVAL = 2 * 60 * 1000;
+
// Flag stored in the DeviceConfig API.
/**
@@ -281,6 +284,12 @@
// this long.
public long TOP_TO_FGS_GRACE_DURATION = DEFAULT_TOP_TO_FGS_GRACE_DURATION;
+ /**
+ * The minimum time we allow between crashes, for us to consider this
+ * application to be bad and stop its services and reject broadcasts.
+ */
+ public static int MIN_CRASH_INTERVAL = DEFAULT_MIN_CRASH_INTERVAL;
+
// Indicates whether the activity starts logging is enabled.
// Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
volatile boolean mFlagActivityStartsLoggingEnabled;
@@ -650,6 +659,8 @@
DEFAULT_MEMORY_INFO_THROTTLE_TIME);
TOP_TO_FGS_GRACE_DURATION = mParser.getDurationMillis(KEY_TOP_TO_FGS_GRACE_DURATION,
DEFAULT_TOP_TO_FGS_GRACE_DURATION);
+ MIN_CRASH_INTERVAL = mParser.getInt(KEY_MIN_CRASH_INTERVAL,
+ DEFAULT_MIN_CRASH_INTERVAL);
PENDINGINTENT_WARNING_THRESHOLD = mParser.getInt(KEY_PENDINGINTENT_WARNING_THRESHOLD,
DEFAULT_PENDINGINTENT_WARNING_THRESHOLD);
@@ -866,6 +877,8 @@
pw.println(MEMORY_INFO_THROTTLE_TIME);
pw.print(" "); pw.print(KEY_TOP_TO_FGS_GRACE_DURATION); pw.print("=");
pw.println(TOP_TO_FGS_GRACE_DURATION);
+ pw.print(" "); pw.print(KEY_MIN_CRASH_INTERVAL); pw.print("=");
+ pw.println(MIN_CRASH_INTERVAL);
pw.print(" "); pw.print(KEY_IMPERCEPTIBLE_KILL_EXEMPT_PROC_STATES); pw.print("=");
pw.println(Arrays.toString(IMPERCEPTIBLE_KILL_EXEMPT_PROC_STATES.toArray()));
pw.print(" "); pw.print(KEY_IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES); pw.print("=");
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3e600b7..6e1e3d0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1370,6 +1370,10 @@
final Injector mInjector;
+ /** The package verifier app. */
+ private String mPackageVerifier;
+ private int mPackageVerifierUid = UserHandle.USER_NULL;
+
static final class ProcessChangeItem {
static final int CHANGE_ACTIVITIES = 1<<0;
static final int CHANGE_FOREGROUND_SERVICES = 1<<1;
@@ -2246,6 +2250,18 @@
if (phase == PHASE_SYSTEM_SERVICES_READY) {
mService.mBatteryStatsService.systemServicesReady();
mService.mServices.systemServicesReady();
+ mService.mPackageVerifier = ArrayUtils.firstOrNull(
+ LocalServices.getService(PackageManagerInternal.class).getKnownPackageNames(
+ PackageManagerInternal.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM));
+ if (mService.mPackageVerifier != null) {
+ try {
+ mService.mPackageVerifierUid =
+ getContext().getPackageManager().getPackageUid(
+ mService.mPackageVerifier, UserHandle.USER_SYSTEM);
+ } catch (NameNotFoundException e) {
+ Slog.wtf(TAG, "Package manager couldn't get package verifier uid", e);
+ }
+ }
} else if (phase == PHASE_ACTIVITY_MANAGER_READY) {
mService.startBroadcastObservers();
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
@@ -13263,8 +13279,8 @@
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
- String resolvedType, boolean requireForeground, String callingPackage,
- String callingFeatureId, int userId)
+ String resolvedType, boolean requireForeground, boolean hideForegroundNotification,
+ String callingPackage, String callingFeatureId, int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("startService");
// Refuse possible leaked file descriptors
@@ -13276,17 +13292,27 @@
throw new IllegalArgumentException("callingPackage cannot be null");
}
+ final int callingUid = Binder.getCallingUid();
+ if (requireForeground && hideForegroundNotification) {
+ if (!UserHandle.isSameApp(callingUid, mPackageVerifierUid)
+ || !callingPackage.equals(mPackageVerifier)) {
+ throw new IllegalArgumentException(
+ "Only the package verifier can hide its foreground service notification");
+ }
+ Slog.i(TAG, "Foreground service notification hiding requested by " + callingPackage);
+ }
+
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"*** startService: " + service + " type=" + resolvedType + " fg=" + requireForeground);
synchronized(this) {
final int callingPid = Binder.getCallingPid();
- final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res;
try {
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
- requireForeground, callingPackage, callingFeatureId, userId);
+ requireForeground, hideForegroundNotification,
+ callingPackage, callingFeatureId, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -17670,7 +17696,7 @@
ComponentName res;
try {
res = mServices.startServiceLocked(null, service,
- resolvedType, -1, uid, fgRequired, callingPackage,
+ resolvedType, -1, uid, fgRequired, false, callingPackage,
callingFeatureId, userId, allowBackgroundActivityStarts);
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 149e3ba..a512cca 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -654,7 +654,7 @@
pw.println("Starting service: " + intent);
pw.flush();
ComponentName cn = mInterface.startService(null, intent, intent.getType(),
- asForeground, SHELL_PACKAGE_NAME, null, mUserId);
+ asForeground, false, SHELL_PACKAGE_NAME, null, mUserId);
if (cn == null) {
err.println("Error: Not found; no service started.");
return -1;
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 2e92ac0..5268359 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -716,7 +716,7 @@
// back in the pending list.
ServiceRecord sr = app.getRunningServiceAt(i);
// If the service was restarted a while ago, then reset crash count, else increment it.
- if (now > sr.restartTime + ProcessList.MIN_CRASH_INTERVAL) {
+ if (now > sr.restartTime + ActivityManagerConstants.MIN_CRASH_INTERVAL) {
sr.crashCount = 1;
} else {
sr.crashCount++;
@@ -729,7 +729,7 @@
}
}
- if (crashTime != null && now < crashTime + ProcessList.MIN_CRASH_INTERVAL) {
+ if (crashTime != null && now < crashTime + ActivityManagerConstants.MIN_CRASH_INTERVAL) {
// The process crashed again very quickly. If it was a bound foreground service, let's
// try to restart again in a while, otherwise the process loses!
Slog.w(TAG, "Process " + app.processName
@@ -771,7 +771,7 @@
data.taskId = affectedTaskId;
}
if (data != null && crashTimePersistent != null
- && now < crashTimePersistent + ProcessList.MIN_CRASH_INTERVAL) {
+ && now < crashTimePersistent + ActivityManagerConstants.MIN_CRASH_INTERVAL) {
data.repeating = true;
}
}
@@ -853,7 +853,7 @@
mAppsNotReportingCrashes.contains(proc.info.packageName);
final long now = SystemClock.uptimeMillis();
final boolean shouldThottle = crashShowErrorTime != null
- && now < crashShowErrorTime + ProcessList.MIN_CRASH_INTERVAL;
+ && now < crashShowErrorTime + ActivityManagerConstants.MIN_CRASH_INTERVAL;
if ((mService.mAtmInternal.canShowErrorDialogs() || showBackground)
&& !crashSilenced && !shouldThottle
&& (showFirstCrash || showFirstCrashDevOption || data.repeating)) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 4673ecd..76089f8 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -154,10 +154,6 @@
static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
"persist.sys.vold_app_data_isolation_enabled";
- // The minimum time we allow between crashes, for us to consider this
- // application to be bad and stop and its services and reject broadcasts.
- static final int MIN_CRASH_INTERVAL = 60 * 1000;
-
// OOM adjustments for processes in various states:
// Uninitialized value for any major or minor adj fields
@@ -4070,7 +4066,8 @@
boolean enqueueLocked(ProcessRecord app, String reason, int requester) {
// Throttle the killing request for potential bad app to avoid cpu thrashing
Long last = app.isolated ? null : mLastProcessKillTimes.get(app.processName, app.uid);
- if (last != null && SystemClock.uptimeMillis() < last + MIN_CRASH_INTERVAL) {
+ if ((last != null) && (SystemClock.uptimeMillis()
+ < (last + ActivityManagerConstants.MIN_CRASH_INTERVAL))) {
return false;
}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 66677b67..5b12c8c 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -104,6 +104,7 @@
boolean whitelistManager; // any bindings to this service have BIND_ALLOW_WHITELIST_MANAGEMENT?
boolean delayed; // are we waiting to start this service in the background?
boolean fgRequired; // is the service required to go foreground after starting?
+ boolean hideFgNotification; // Hide the fg service notification
boolean fgWaiting; // is a timeout for going foreground already scheduled?
boolean isForeground; // is service currently in foreground mode?
int foregroundId; // Notification ID of last foreground req.
@@ -836,6 +837,9 @@
}
public void postNotification() {
+ if (hideFgNotification) {
+ return;
+ }
final int appUid = appInfo.uid;
final int appPid = app.pid;
if (foregroundId != 0 && foregroundNoti != null) {
@@ -928,7 +932,7 @@
}
if (localForegroundNoti.getSmallIcon() == null) {
// Notifications whose icon is 0 are defined to not show
- // a notification, silently ignoring it. We don't want to
+ // a notification. We don't want to
// just ignore it, we want to prevent the service from
// being foreground.
throw new RuntimeException("invalid service notification: "
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index bf7c68a..673ca1f 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -285,6 +285,8 @@
private static final int MSG_PLAYBACK_CONFIG_CHANGE = 29;
private static final int MSG_BROADCAST_MICROPHONE_MUTE = 30;
private static final int MSG_CHECK_MODE_FOR_UID = 31;
+ private static final int MSG_STREAM_DEVICES_CHANGED = 32;
+ private static final int MSG_UPDATE_VOLUME_STATES_FOR_DEVICE = 33;
// start of messages handled under wakelock
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
// and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -1303,6 +1305,19 @@
}
/**
+ * Asynchronously update volume states for the given device.
+ *
+ * @param device a single audio device, ensure that this is not a devices bitmask
+ * @param caller caller of this method
+ */
+ private void postUpdateVolumeStatesForAudioDevice(int device, String caller) {
+ sendMsg(mAudioHandler,
+ MSG_UPDATE_VOLUME_STATES_FOR_DEVICE,
+ SENDMSG_QUEUE, device /*arg1*/, 0 /*arg2*/, caller /*obj*/,
+ 0 /*delay*/);
+ }
+
+ /**
* Update volume states for the given device.
*
* This will initialize the volume index if no volume index is available.
@@ -1311,10 +1326,14 @@
* @param device a single audio device, ensure that this is not a devices bitmask
* @param caller caller of this method
*/
- private void updateVolumeStatesForAudioDevice(int device, String caller) {
+ private void onUpdateVolumeStatesForAudioDevice(int device, String caller) {
final int numStreamTypes = AudioSystem.getNumStreamTypes();
- for (int streamType = 0; streamType < numStreamTypes; streamType++) {
- updateVolumeStates(device, streamType, caller);
+ synchronized (mSettingsLock) {
+ synchronized (VolumeStreamState.class) {
+ for (int streamType = 0; streamType < numStreamTypes; streamType++) {
+ updateVolumeStates(device, streamType, caller);
+ }
+ }
}
}
@@ -1346,7 +1365,7 @@
device)) {
mStreamStates[streamType].checkFixedVolumeDevices();
- // Unmute streams if required if device is full volume
+ // Unmute streams if required and device is full volume
if (isStreamMute(streamType) && mFullVolumeDevices.contains(device)) {
mStreamStates[streamType].mute(false);
}
@@ -4948,18 +4967,20 @@
}
}
- private void observeDevicesForStreams(int skipStream) {
- synchronized (VolumeStreamState.class) {
- for (int stream = 0; stream < mStreamStates.length; stream++) {
- if (stream != skipStream) {
- int devices = mStreamStates[stream].observeDevicesForStream_syncVSS(
- false /*checkOthers*/);
+ private void onObserveDevicesForAllStreams(int skipStream) {
+ synchronized (mSettingsLock) {
+ synchronized (VolumeStreamState.class) {
+ for (int stream = 0; stream < mStreamStates.length; stream++) {
+ if (stream != skipStream) {
+ int devices = mStreamStates[stream].observeDevicesForStream_syncVSS(
+ false /*checkOthers*/);
- Set<Integer> devicesSet = AudioSystem.generateAudioDeviceTypesSet(devices);
- for (Integer device : devicesSet) {
- // Update volume states for devices routed for the stream
- updateVolumeStates(device, stream,
- "AudioService#observeDevicesForStreams");
+ Set<Integer> devicesSet = AudioSystem.generateAudioDeviceTypesSet(devices);
+ for (Integer device : devicesSet) {
+ // Update volume states for devices routed for the stream
+ updateVolumeStates(device, stream,
+ "AudioService#onObserveDevicesForAllStreams");
+ }
}
}
}
@@ -4969,14 +4990,16 @@
/** only public for mocking/spying, do not call outside of AudioService */
@VisibleForTesting
public void postObserveDevicesForAllStreams() {
- sendMsg(mAudioHandler,
- MSG_OBSERVE_DEVICES_FOR_ALL_STREAMS,
- SENDMSG_QUEUE, 0 /*arg1*/, 0 /*arg2*/, null /*obj*/,
- 0 /*delay*/);
+ postObserveDevicesForAllStreams(-1);
}
- private void onObserveDevicesForAllStreams() {
- observeDevicesForStreams(-1);
+ /** only public for mocking/spying, do not call outside of AudioService */
+ @VisibleForTesting
+ public void postObserveDevicesForAllStreams(int skipStream) {
+ sendMsg(mAudioHandler,
+ MSG_OBSERVE_DEVICES_FOR_ALL_STREAMS,
+ SENDMSG_QUEUE, skipStream /*arg1*/, 0 /*arg2*/, null /*obj*/,
+ 0 /*delay*/);
}
/**
@@ -5029,7 +5052,8 @@
+ Integer.toHexString(audioSystemDeviceOut) + " from:" + caller));
// make sure we have a volume entry for this device, and that volume is updated according
// to volume behavior
- updateVolumeStatesForAudioDevice(audioSystemDeviceOut, "setDeviceVolumeBehavior:" + caller);
+ postUpdateVolumeStatesForAudioDevice(audioSystemDeviceOut,
+ "setDeviceVolumeBehavior:" + caller);
}
/**
@@ -5660,6 +5684,7 @@
}
}
+ @GuardedBy("VolumeStreamState.class")
public int observeDevicesForStream_syncVSS(boolean checkOthers) {
if (!mSystemServer.isPrivileged()) {
return AudioSystem.DEVICE_NONE;
@@ -5672,15 +5697,19 @@
mObservedDevices = devices;
if (checkOthers) {
// one stream's devices have changed, check the others
- observeDevicesForStreams(mStreamType);
+ postObserveDevicesForAllStreams(mStreamType);
}
// log base stream changes to the event log
if (mStreamVolumeAlias[mStreamType] == mStreamType) {
EventLogTags.writeStreamDevicesChanged(mStreamType, prevDevices, devices);
}
- sendBroadcastToAll(mStreamDevicesChanged
- .putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, prevDevices)
- .putExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, devices));
+ // send STREAM_DEVICES_CHANGED_ACTION on the message handler so it is scheduled after
+ // the postObserveDevicesForStreams is handled
+ sendMsg(mAudioHandler,
+ MSG_STREAM_DEVICES_CHANGED,
+ SENDMSG_QUEUE, prevDevices /*arg1*/, devices /*arg2*/,
+ // ok to send reference to this object, it is final
+ mStreamDevicesChanged /*obj*/, 0 /*delay*/);
return devices;
}
@@ -6452,7 +6481,7 @@
break;
case MSG_OBSERVE_DEVICES_FOR_ALL_STREAMS:
- onObserveDevicesForAllStreams();
+ onObserveDevicesForAllStreams(/*skipStream*/ msg.arg1);
break;
case MSG_HDMI_VOLUME_CHECK:
@@ -6495,6 +6524,16 @@
mModeLogger.log(new PhoneStateEvent(h.getPackage(), h.getPid()));
}
break;
+
+ case MSG_STREAM_DEVICES_CHANGED:
+ sendBroadcastToAll(((Intent) msg.obj)
+ .putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, msg.arg1)
+ .putExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, msg.arg2));
+ break;
+
+ case MSG_UPDATE_VOLUME_STATES_FOR_DEVICE:
+ onUpdateVolumeStatesForAudioDevice(msg.arg1, (String) msg.obj);
+ break;
}
}
}
@@ -7251,7 +7290,7 @@
// HDMI output
removeAudioSystemDeviceOutFromFullVolumeDevices(AudioSystem.DEVICE_OUT_HDMI);
}
- updateVolumeStatesForAudioDevice(AudioSystem.DEVICE_OUT_HDMI,
+ postUpdateVolumeStatesForAudioDevice(AudioSystem.DEVICE_OUT_HDMI,
"HdmiPlaybackClient.DisplayStatusCallback");
}
}
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 7f9b3c9..a75a80a 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -21,23 +21,14 @@
import static android.Manifest.permission.INTERNET;
import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.UPDATE_DEVICE_STATS;
+import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
-import static android.net.INetd.PERMISSION_INTERNET;
-import static android.net.INetd.PERMISSION_NETWORK;
-import static android.net.INetd.PERMISSION_NONE;
-import static android.net.INetd.PERMISSION_SYSTEM;
-import static android.net.INetd.PERMISSION_UNINSTALLED;
-import static android.net.INetd.PERMISSION_UPDATE_DEVICE_STATS;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.os.Process.INVALID_UID;
import static android.os.Process.SYSTEM_UID;
-import static com.android.internal.util.ArrayUtils.convertToIntArray;
-
import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -56,9 +47,11 @@
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
+import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
@@ -72,6 +65,7 @@
import java.util.Map.Entry;
import java.util.Set;
+
/**
* A utility class to inform Netd of UID permisisons.
* Does a mass update at boot and then monitors for app install/remove.
@@ -120,51 +114,9 @@
public int getDeviceFirstSdkInt() {
return Build.VERSION.FIRST_SDK_INT;
}
-
- /**
- * Check whether given uid has specific permission.
- */
- public int uidPermission(@NonNull final String permission, final int uid) {
- return ActivityManager.checkUidPermission(permission, uid);
- }
}
- /**
- * A data class to store each uid Netd permission information. Netd permissions includes
- * PERMISSION_NETWORK, PERMISSION_SYSTEM, PERMISSION_INTERNET, PERMISSION_UPDATE_DEVICE_STATS
- * and OR'd with the others. Default permission is PERMISSION_NONE and PERMISSION_UNINSTALLED
- * will be set if all packages are removed from the uid.
- */
- public static class UidNetdPermissionInfo {
- private final int mNetdPermissions;
-
- UidNetdPermissionInfo() {
- this(PERMISSION_NONE);
- }
-
- UidNetdPermissionInfo(int permissions) {
- mNetdPermissions = permissions;
- }
-
- /** Plus given permissions and return new UidNetdPermissionInfo instance. */
- public UidNetdPermissionInfo plusNetdPermissions(int permissions) {
- return new UidNetdPermissionInfo(mNetdPermissions | permissions);
- }
-
- /** Return whether package is uninstalled. */
- public boolean isPackageUninstalled() {
- return mNetdPermissions == PERMISSION_UNINSTALLED;
- }
-
- /** Check that uid has given permissions */
- public boolean hasNetdPermissions(final int permissions) {
- if (isPackageUninstalled()) return false;
- if (permissions == PERMISSION_NONE) return true;
- return (mNetdPermissions & permissions) == permissions;
- }
- }
-
- public PermissionMonitor(Context context, INetd netd) {
+ public PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd) {
this(context, netd, new Dependencies());
}
@@ -195,7 +147,7 @@
return;
}
- final SparseArray<UidNetdPermissionInfo> netdPermsUids = new SparseArray<>();
+ SparseIntArray netdPermsUids = new SparseIntArray();
for (PackageInfo app : apps) {
int uid = app.applicationInfo != null ? app.applicationInfo.uid : INVALID_UID;
@@ -204,9 +156,8 @@
}
mAllApps.add(UserHandle.getAppId(uid));
- final boolean isNetwork = hasPermission(CHANGE_NETWORK_STATE, uid);
- final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(uid)
- || isCarryoverPackage(app.applicationInfo);
+ boolean isNetwork = hasNetworkPermission(app);
+ boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
if (isNetwork || hasRestrictedPermission) {
Boolean permission = mApps.get(uid);
@@ -217,13 +168,10 @@
}
}
- // Skip already checked uid.
- if (netdPermsUids.get(uid) != null) continue;
-
//TODO: unify the management of the permissions into one codepath.
- final UidNetdPermissionInfo permInfo =
- new UidNetdPermissionInfo(getNetdPermissionMask(uid));
- netdPermsUids.put(uid, permInfo);
+ int otherNetdPerms = getNetdPermissionMask(app.requestedPermissions,
+ app.requestedPermissionsFlags);
+ netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
}
List<UserInfo> users = mUserManager.getUsers(true); // exclude dying users
@@ -238,17 +186,15 @@
for (int i = 0; i < systemPermission.size(); i++) {
ArraySet<String> perms = systemPermission.valueAt(i);
int uid = systemPermission.keyAt(i);
- int netdPermission = PERMISSION_NONE;
+ int netdPermission = 0;
// Get the uids of native services that have UPDATE_DEVICE_STATS or INTERNET permission.
if (perms != null) {
netdPermission |= perms.contains(UPDATE_DEVICE_STATS)
- ? PERMISSION_UPDATE_DEVICE_STATS : 0;
- netdPermission |= perms.contains(INTERNET) ? PERMISSION_INTERNET : 0;
+ ? INetd.PERMISSION_UPDATE_DEVICE_STATS : 0;
+ netdPermission |= perms.contains(INTERNET)
+ ? INetd.PERMISSION_INTERNET : 0;
}
- final UidNetdPermissionInfo permInfo = netdPermsUids.get(uid);
- netdPermsUids.put(uid, permInfo != null
- ? permInfo.plusNetdPermissions(netdPermission)
- : new UidNetdPermissionInfo(netdPermission));
+ netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission);
}
log("Users: " + mUsers.size() + ", Apps: " + mApps.size());
update(mUsers, mApps, true);
@@ -261,34 +207,48 @@
}
@VisibleForTesting
- boolean hasPermission(@NonNull final String permission, final int uid) {
- return mDeps.uidPermission(permission, uid) == PackageManager.PERMISSION_GRANTED;
+ boolean hasPermission(@NonNull final PackageInfo app, @NonNull final String permission) {
+ if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) {
+ return false;
+ }
+ final int index = ArrayUtils.indexOf(app.requestedPermissions, permission);
+ if (index < 0 || index >= app.requestedPermissionsFlags.length) return false;
+ return (app.requestedPermissionsFlags[index] & REQUESTED_PERMISSION_GRANTED) != 0;
}
@VisibleForTesting
- // TODO : remove this check in the future(b/162295056). All apps should just request the
- // appropriate permission for their use case since android Q.
- boolean isCarryoverPackage(@Nullable final ApplicationInfo appInfo) {
- if (appInfo == null) return false;
- return (appInfo.targetSdkVersion < VERSION_Q && isVendorApp(appInfo))
- // Backward compatibility for b/114245686, on devices that launched before Q daemons
- // and apps running as the system UID are exempted from this check.
- || (appInfo.uid == SYSTEM_UID && mDeps.getDeviceFirstSdkInt() < VERSION_Q);
+ boolean hasNetworkPermission(@NonNull final PackageInfo app) {
+ return hasPermission(app, CHANGE_NETWORK_STATE);
}
@VisibleForTesting
- boolean hasRestrictedNetworkPermission(final int uid) {
- return hasPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, uid)
- || hasPermission(PERMISSION_MAINLINE_NETWORK_STACK, uid)
- || hasPermission(NETWORK_STACK, uid);
+ boolean hasRestrictedNetworkPermission(@NonNull final PackageInfo app) {
+ // TODO : remove this check in the future(b/31479477). All apps should just
+ // request the appropriate permission for their use case since android Q.
+ if (app.applicationInfo != null) {
+ // Backward compatibility for b/114245686, on devices that launched before Q daemons
+ // and apps running as the system UID are exempted from this check.
+ if (app.applicationInfo.uid == SYSTEM_UID && mDeps.getDeviceFirstSdkInt() < VERSION_Q) {
+ return true;
+ }
+
+ if (app.applicationInfo.targetSdkVersion < VERSION_Q
+ && isVendorApp(app.applicationInfo)) {
+ return true;
+ }
+ }
+
+ return hasPermission(app, PERMISSION_MAINLINE_NETWORK_STACK)
+ || hasPermission(app, NETWORK_STACK)
+ || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
}
/** Returns whether the given uid has using background network permission. */
public synchronized boolean hasUseBackgroundNetworksPermission(final int uid) {
// Apps with any of the CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_INTERNAL or
// CONNECTIVITY_USE_RESTRICTED_NETWORKS permission has the permission to use background
- // networks. mApps contains the result of checks for both CHANGE_NETWORK_STATE permission
- // and hasRestrictedNetworkPermission. If uid is in the mApps list that means uid has one of
+ // networks. mApps contains the result of checks for both hasNetworkPermission and
+ // hasRestrictedNetworkPermission. If uid is in the mApps list that means uid has one of
// permissions at least.
return mApps.containsKey(uid);
}
@@ -313,11 +273,11 @@
}
try {
if (add) {
- mNetd.networkSetPermissionForUser(PERMISSION_NETWORK, convertToIntArray(network));
- mNetd.networkSetPermissionForUser(PERMISSION_SYSTEM, convertToIntArray(system));
+ mNetd.networkSetPermissionForUser(INetd.PERMISSION_NETWORK, toIntArray(network));
+ mNetd.networkSetPermissionForUser(INetd.PERMISSION_SYSTEM, toIntArray(system));
} else {
- mNetd.networkClearPermissionForUser(convertToIntArray(network));
- mNetd.networkClearPermissionForUser(convertToIntArray(system));
+ mNetd.networkClearPermissionForUser(toIntArray(network));
+ mNetd.networkClearPermissionForUser(toIntArray(system));
}
} catch (RemoteException e) {
loge("Exception when updating permissions: " + e);
@@ -363,15 +323,14 @@
}
@VisibleForTesting
- protected Boolean highestPermissionForUid(Boolean currentPermission, String name, int uid) {
+ protected Boolean highestPermissionForUid(Boolean currentPermission, String name) {
if (currentPermission == SYSTEM) {
return currentPermission;
}
try {
final PackageInfo app = mPackageManager.getPackageInfo(name, GET_PERMISSIONS);
- final boolean isNetwork = hasPermission(CHANGE_NETWORK_STATE, uid);
- final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(uid)
- || isCarryoverPackage(app.applicationInfo);
+ final boolean isNetwork = hasNetworkPermission(app);
+ final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
if (isNetwork || hasRestrictedPermission) {
currentPermission = hasRestrictedPermission;
}
@@ -382,15 +341,24 @@
return currentPermission;
}
- private UidNetdPermissionInfo getPermissionForUid(final int uid) {
+ private int getPermissionForUid(final int uid) {
+ int permission = INetd.PERMISSION_NONE;
// Check all the packages for this UID. The UID has the permission if any of the
// packages in it has the permission.
final String[] packages = mPackageManager.getPackagesForUid(uid);
- if (packages == null || packages.length <= 0) {
+ if (packages != null && packages.length > 0) {
+ for (String name : packages) {
+ final PackageInfo app = getPackageInfo(name);
+ if (app != null && app.requestedPermissions != null) {
+ permission |= getNetdPermissionMask(app.requestedPermissions,
+ app.requestedPermissionsFlags);
+ }
+ }
+ } else {
// The last package of this uid is removed from device. Clean the package up.
- return new UidNetdPermissionInfo(PERMISSION_UNINSTALLED);
+ permission = INetd.PERMISSION_UNINSTALLED;
}
- return new UidNetdPermissionInfo(getNetdPermissionMask(uid));
+ return permission;
}
/**
@@ -407,7 +375,7 @@
// If multiple packages share a UID (cf: android:sharedUserId) and ask for different
// permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
- final Boolean permission = highestPermissionForUid(mApps.get(uid), packageName, uid);
+ final Boolean permission = highestPermissionForUid(mApps.get(uid), packageName);
if (permission != mApps.get(uid)) {
mApps.put(uid, permission);
@@ -463,7 +431,7 @@
String[] packages = mPackageManager.getPackagesForUid(uid);
if (packages != null && packages.length > 0) {
for (String name : packages) {
- permission = highestPermissionForUid(permission, name, uid);
+ permission = highestPermissionForUid(permission, name);
if (permission == SYSTEM) {
// An app with this UID still has the SYSTEM permission.
// Therefore, this UID must already have the SYSTEM permission.
@@ -499,13 +467,19 @@
sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
}
- private int getNetdPermissionMask(final int uid) {
- int permissions = PERMISSION_NONE;
- if (hasPermission(INTERNET, uid)) {
- permissions |= PERMISSION_INTERNET;
- }
- if (hasPermission(UPDATE_DEVICE_STATS, uid)) {
- permissions |= PERMISSION_UPDATE_DEVICE_STATS;
+ private static int getNetdPermissionMask(String[] requestedPermissions,
+ int[] requestedPermissionsFlags) {
+ int permissions = 0;
+ if (requestedPermissions == null || requestedPermissionsFlags == null) return permissions;
+ for (int i = 0; i < requestedPermissions.length; i++) {
+ if (requestedPermissions[i].equals(INTERNET)
+ && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) {
+ permissions |= INetd.PERMISSION_INTERNET;
+ }
+ if (requestedPermissions[i].equals(UPDATE_DEVICE_STATS)
+ && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) {
+ permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS;
+ }
}
return permissions;
}
@@ -640,28 +614,28 @@
* permission information to netd.
*
* @param uid the app uid of the package installed
- * @param permissionInfo the permission info of given uid.
+ * @param permissions the permissions the app requested and netd cares about.
*
* @hide
*/
@VisibleForTesting
- void sendPackagePermissionsForUid(int uid, UidNetdPermissionInfo permissionInfo) {
- final SparseArray<UidNetdPermissionInfo> uidsPermInfo = new SparseArray<>();
- uidsPermInfo.put(uid, permissionInfo);
- sendPackagePermissionsToNetd(uidsPermInfo);
+ void sendPackagePermissionsForUid(int uid, int permissions) {
+ SparseIntArray netdPermissionsAppIds = new SparseIntArray();
+ netdPermissionsAppIds.put(uid, permissions);
+ sendPackagePermissionsToNetd(netdPermissionsAppIds);
}
/**
* Called by packageManagerService to send IPC to netd. Grant or revoke the INTERNET
* and/or UPDATE_DEVICE_STATS permission of the uids in array.
*
- * @param uidsPermInfo permission info array generated from each uid. If the uid permission is
- * PERMISSION_NONE or PERMISSION_UNINSTALLED, revoke all permissions of that
- * uid.
+ * @param netdPermissionsAppIds integer pairs of uids and the permission granted to it. If the
+ * permission is 0, revoke all permissions of that uid.
+ *
* @hide
*/
@VisibleForTesting
- void sendPackagePermissionsToNetd(final SparseArray<UidNetdPermissionInfo> uidsPermInfo) {
+ void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) {
if (mNetd == null) {
Log.e(TAG, "Failed to get the netd service");
return;
@@ -671,44 +645,50 @@
ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>();
ArrayList<Integer> noPermissionAppIds = new ArrayList<>();
ArrayList<Integer> uninstalledAppIds = new ArrayList<>();
- for (int i = 0; i < uidsPermInfo.size(); i++) {
- final int uid = uidsPermInfo.keyAt(i);
- final UidNetdPermissionInfo permInfo = uidsPermInfo.valueAt(i);
- if (permInfo.hasNetdPermissions(
- PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS)) {
- allPermissionAppIds.add(uid);
- } else if (permInfo.hasNetdPermissions(PERMISSION_INTERNET)) {
- internetPermissionAppIds.add(uid);
- } else if (permInfo.hasNetdPermissions(PERMISSION_UPDATE_DEVICE_STATS)) {
- updateStatsPermissionAppIds.add(uid);
- } else if (permInfo.isPackageUninstalled()) {
- uninstalledAppIds.add(uid);
- } else {
- noPermissionAppIds.add(uid);
+ for (int i = 0; i < netdPermissionsAppIds.size(); i++) {
+ int permissions = netdPermissionsAppIds.valueAt(i);
+ switch(permissions) {
+ case (INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS):
+ allPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
+ break;
+ case INetd.PERMISSION_INTERNET:
+ internetPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
+ break;
+ case INetd.PERMISSION_UPDATE_DEVICE_STATS:
+ updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
+ break;
+ case INetd.PERMISSION_NONE:
+ noPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
+ break;
+ case INetd.PERMISSION_UNINSTALLED:
+ uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i));
+ default:
+ Log.e(TAG, "unknown permission type: " + permissions + "for uid: "
+ + netdPermissionsAppIds.keyAt(i));
}
}
try {
// TODO: add a lock inside netd to protect IPC trafficSetNetPermForUids()
if (allPermissionAppIds.size() != 0) {
mNetd.trafficSetNetPermForUids(
- PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS,
- convertToIntArray(allPermissionAppIds));
+ INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
+ ArrayUtils.convertToIntArray(allPermissionAppIds));
}
if (internetPermissionAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(PERMISSION_INTERNET,
- convertToIntArray(internetPermissionAppIds));
+ mNetd.trafficSetNetPermForUids(INetd.PERMISSION_INTERNET,
+ ArrayUtils.convertToIntArray(internetPermissionAppIds));
}
if (updateStatsPermissionAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(PERMISSION_UPDATE_DEVICE_STATS,
- convertToIntArray(updateStatsPermissionAppIds));
+ mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UPDATE_DEVICE_STATS,
+ ArrayUtils.convertToIntArray(updateStatsPermissionAppIds));
}
if (noPermissionAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(PERMISSION_NONE,
- convertToIntArray(noPermissionAppIds));
+ mNetd.trafficSetNetPermForUids(INetd.PERMISSION_NONE,
+ ArrayUtils.convertToIntArray(noPermissionAppIds));
}
if (uninstalledAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(PERMISSION_UNINSTALLED,
- convertToIntArray(uninstalledAppIds));
+ mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UNINSTALLED,
+ ArrayUtils.convertToIntArray(uninstalledAppIds));
}
} catch (RemoteException e) {
Log.e(TAG, "Pass appId list of special permission failed." + e);
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 041bedc..ec12a97 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -210,6 +210,7 @@
private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarm";
private static final String SYNC_LOOP_WAKE_LOCK = "SyncLoopWakeLock";
+ private static final boolean USE_WTF_FOR_ACCOUNT_ERROR = false;
private static final int SYNC_OP_STATE_VALID = 0;
// "1" used to include errors 3, 4 and 5 but now it's split up.
@@ -3446,7 +3447,7 @@
if (isLoggable) {
Slog.v(TAG, " Dropping sync operation: account doesn't exist.");
}
- Slog.wtf(TAG, "SYNC_OP_STATE_INVALID: account doesn't exist.");
+ logAccountError("SYNC_OP_STATE_INVALID: account doesn't exist.");
return SYNC_OP_STATE_INVALID_NO_ACCOUNT;
}
// Drop this sync request if it isn't syncable.
@@ -3456,14 +3457,14 @@
Slog.v(TAG, " Dropping sync operation: "
+ "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
}
- Slog.wtf(TAG, "SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS");
+ logAccountError("SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS");
return SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS;
}
if (state == AuthorityInfo.NOT_SYNCABLE) {
if (isLoggable) {
Slog.v(TAG, " Dropping sync operation: isSyncable == NOT_SYNCABLE");
}
- Slog.wtf(TAG, "SYNC_OP_STATE_INVALID: NOT_SYNCABLE");
+ logAccountError("SYNC_OP_STATE_INVALID: NOT_SYNCABLE");
return SYNC_OP_STATE_INVALID_NOT_SYNCABLE;
}
@@ -3482,12 +3483,20 @@
if (isLoggable) {
Slog.v(TAG, " Dropping sync operation: disallowed by settings/network.");
}
- Slog.wtf(TAG, "SYNC_OP_STATE_INVALID: disallowed by settings/network");
+ logAccountError("SYNC_OP_STATE_INVALID: disallowed by settings/network");
return SYNC_OP_STATE_INVALID_SYNC_DISABLED;
}
return SYNC_OP_STATE_VALID;
}
+ private void logAccountError(String message) {
+ if (USE_WTF_FOR_ACCOUNT_ERROR) {
+ Slog.wtf(TAG, message);
+ } else {
+ Slog.e(TAG, message);
+ }
+ }
+
private boolean dispatchSyncOperation(SyncOperation op) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Slog.v(TAG, "dispatchSyncOperation: we are going to sync " + op);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index dab8c7f..2c632d9 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -2174,10 +2174,14 @@
}
}
- if (callingUid == Process.SYSTEM_UID
- || checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) {
- flags |= VIRTUAL_DISPLAY_FLAG_TRUSTED;
- } else {
+ if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) {
+ if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) {
+ throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to "
+ + "create a trusted virtual display.");
+ }
+ }
+
+ if ((flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == 0) {
flags &= ~VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 9ab410d..3fddd5a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2591,7 +2591,7 @@
if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
mCurMethod = IInputMethod.Stub.asInterface(service);
final String curMethodPackage = mCurIntent.getComponent().getPackageName();
- final int curMethodUid = mPackageManagerInternal.getPackageUidInternal(
+ final int curMethodUid = mPackageManagerInternal.getPackageUid(
curMethodPackage, 0 /* flags */, mSettings.getCurrentUserId());
if (curMethodUid < 0) {
Slog.e(TAG, "Failed to get UID for package=" + curMethodPackage);
diff --git a/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java b/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
index e3074db..ddd56c8 100644
--- a/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
+++ b/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
@@ -123,6 +123,10 @@
final VerifyCredentialResponse response = spManager.verifyChallengeInternal(
getGatekeeperService(), userAuthInfo.gatekeeperPassword, challenge,
userAuthInfo.userId);
+ if (response == null) {
+ Slog.wtf(TAG, "VerifyChallenge failed, null response");
+ continue;
+ }
if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
Slog.wtf(TAG, "VerifyChallenge failed, response: "
+ response.getResponseCode());
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 0044d89..26c3132 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -33,7 +33,7 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
import static com.android.internal.widget.LockPatternUtils.USER_FRP;
-import static com.android.internal.widget.LockPatternUtils.VERIFY_FLAG_RETURN_GK_PW;
+import static com.android.internal.widget.LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE;
import static com.android.internal.widget.LockPatternUtils.frpCredentialEnabled;
import static com.android.internal.widget.LockPatternUtils.userOwnsFrpCredential;
@@ -104,6 +104,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
+import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -123,7 +124,6 @@
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
import com.android.server.locksettings.LockSettingsStorage.PersistentData;
import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult;
@@ -155,6 +155,7 @@
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
+import java.util.Random;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -186,6 +187,14 @@
private static final String SYNTHETIC_PASSWORD_UPDATE_TIME_KEY = "sp-handle-ts";
private static final String USER_SERIAL_NUMBER_KEY = "serial-number";
+ // Duration that LockSettingsService will store the gatekeeper password for. This allows
+ // multiple biometric enrollments without prompting the user to enter their password via
+ // ConfirmLockPassword/ConfirmLockPattern multiple times. This needs to be at least the duration
+ // from the start of the first biometric sensor's enrollment to the start of the last biometric
+ // sensor's enrollment. If biometric enrollment requests a password handle that has expired, the
+ // user's credential must be presented again, e.g. via ConfirmLockPattern/ConfirmLockPassword.
+ private static final int GK_PW_HANDLE_STORE_DURATION_MS = 10 * 60 * 1000; // 10 minutes
+
// Order of holding lock: mSeparateChallengeLock -> mSpManager -> this
// Do not call into ActivityManager while holding mSpManager lock.
private final Object mSeparateChallengeLock = new Object();
@@ -202,6 +211,8 @@
private final LockSettingsStrongAuth mStrongAuth;
private final SynchronizedStrongAuthTracker mStrongAuthTracker;
private final BiometricDeferredQueue mBiometricDeferredQueue;
+ private final LongSparseArray<byte[]> mGatekeeperPasswords;
+ private final Random mRandom;
private final NotificationManager mNotificationManager;
private final UserManager mUserManager;
@@ -559,6 +570,8 @@
mStorageManager = injector.getStorageManager();
mStrongAuthTracker = injector.getStrongAuthTracker();
mStrongAuthTracker.register(mStrongAuth);
+ mGatekeeperPasswords = new LongSparseArray<>();
+ mRandom = new SecureRandom();
mSpManager = injector.getSyntheticPasswordManager(mStorage);
mManagedProfilePasswordCache = injector.getManagedProfilePasswordCache();
@@ -1017,7 +1030,7 @@
mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
}
- private final void checkPasswordReadPermission(int userId) {
+ private final void checkPasswordReadPermission() {
mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
}
@@ -1077,7 +1090,9 @@
public void setSeparateProfileChallengeEnabled(int userId, boolean enabled,
LockscreenCredential managedUserPassword) {
checkWritePermission(userId);
- if (!mHasSecureLockScreen) {
+ if (!mHasSecureLockScreen
+ && managedUserPassword != null
+ && managedUserPassword.getType() != CREDENTIAL_TYPE_NONE) {
throw new UnsupportedOperationException(
"This operation requires secure lock screen feature.");
}
@@ -1547,7 +1562,8 @@
public boolean setLockCredential(LockscreenCredential credential,
LockscreenCredential savedCredential, int userId) {
- if (!mHasSecureLockScreen) {
+ if (!mHasSecureLockScreen
+ && credential != null && credential.getType() != CREDENTIAL_TYPE_NONE) {
throw new UnsupportedOperationException(
"This operation requires secure lock screen feature");
}
@@ -1923,7 +1939,7 @@
@Override
public VerifyCredentialResponse checkCredential(LockscreenCredential credential, int userId,
ICheckCredentialProgressCallback progressCallback) {
- checkPasswordReadPermission(userId);
+ checkPasswordReadPermission();
try {
return doVerifyCredential(credential, userId, progressCallback, 0 /* flags */);
} finally {
@@ -1935,7 +1951,7 @@
@Nullable
public VerifyCredentialResponse verifyCredential(LockscreenCredential credential,
int userId, int flags) {
- checkPasswordReadPermission(userId);
+ checkPasswordReadPermission();
try {
return doVerifyCredential(credential, userId, null /* progressCallback */, flags);
} finally {
@@ -1944,18 +1960,36 @@
}
@Override
- public VerifyCredentialResponse verifyGatekeeperPassword(byte[] gatekeeperPassword,
+ public VerifyCredentialResponse verifyGatekeeperPasswordHandle(long gatekeeperPasswordHandle,
long challenge, int userId) {
- checkPasswordReadPermission(userId);
+ checkPasswordReadPermission();
- VerifyCredentialResponse response;
+ final VerifyCredentialResponse response;
+ final byte[] gatekeeperPassword;
+
+ synchronized (mGatekeeperPasswords) {
+ gatekeeperPassword = mGatekeeperPasswords.get(gatekeeperPasswordHandle);
+ }
+
synchronized (mSpManager) {
- response = mSpManager.verifyChallengeInternal(getGateKeeperService(),
- gatekeeperPassword, challenge, userId);
+ if (gatekeeperPassword == null) {
+ response = VerifyCredentialResponse.ERROR;
+ } else {
+ response = mSpManager.verifyChallengeInternal(getGateKeeperService(),
+ gatekeeperPassword, challenge, userId);
+ }
}
return response;
}
+ @Override
+ public void removeGatekeeperPasswordHandle(long gatekeeperPasswordHandle) {
+ checkPasswordReadPermission();
+ synchronized (mGatekeeperPasswords) {
+ mGatekeeperPasswords.remove(gatekeeperPasswordHandle);
+ }
+ }
+
/*
* Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero
* format.
@@ -2012,7 +2046,7 @@
@Override
public VerifyCredentialResponse verifyTiedProfileChallenge(LockscreenCredential credential,
int userId, @LockPatternUtils.VerifyFlag int flags) {
- checkPasswordReadPermission(userId);
+ checkPasswordReadPermission();
if (!isManagedProfileWithUnifiedLock(userId)) {
throw new IllegalArgumentException("User id must be managed profile with unified lock");
}
@@ -2179,7 +2213,7 @@
}
mFirstCallToVold = false;
- checkPasswordReadPermission(userId);
+ checkPasswordReadPermission();
// There's no guarantee that this will safely connect, but if it fails
// we will simply show the lock screen when we shouldn't, so relatively
@@ -2269,13 +2303,13 @@
@Override
public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
- checkPasswordReadPermission(UserHandle.USER_ALL);
+ checkPasswordReadPermission();
mStrongAuth.registerStrongAuthTracker(tracker);
}
@Override
public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
- checkPasswordReadPermission(UserHandle.USER_ALL);
+ checkPasswordReadPermission();
mStrongAuth.unregisterStrongAuthTracker(tracker);
}
@@ -2305,7 +2339,7 @@
@Override
public int getStrongAuthForUser(int userId) {
- checkPasswordReadPermission(userId);
+ checkPasswordReadPermission();
return mStrongAuthTracker.getStrongAuthForUser(userId);
}
@@ -2648,7 +2682,7 @@
final AuthenticationResult authResult;
VerifyCredentialResponse response;
- final boolean returnGkPw = (flags & VERIFY_FLAG_RETURN_GK_PW) != 0;
+ final boolean requestGkPw = (flags & VERIFY_FLAG_REQUEST_GK_PW_HANDLE) != 0;
synchronized (mSpManager) {
if (!isSyntheticPasswordBasedCredentialLocked(userId)) {
@@ -2690,14 +2724,43 @@
}
}
- if (response.isMatched() && returnGkPw) {
- return new VerifyCredentialResponse.Builder()
- .setGatekeeperPassword(authResult.authToken.deriveGkPassword()).build();
+ if (response.isMatched() && requestGkPw) {
+ final long handle = storeGatekeeperPasswordTemporarily(
+ authResult.authToken.deriveGkPassword());
+ return new VerifyCredentialResponse.Builder().setGatekeeperPasswordHandle(handle)
+ .build();
} else {
return response;
}
}
+ /**
+ * Stores the gatekeeper password temporarily.
+ * @param gatekeeperPassword unlocked upon successful Synthetic Password
+ * @return non-zero handle to the gatekeeper password, which can be used for a set amount of
+ * time.
+ */
+ private long storeGatekeeperPasswordTemporarily(byte[] gatekeeperPassword) {
+ long handle = 0L;
+
+ synchronized (mGatekeeperPasswords) {
+ while (handle == 0L || mGatekeeperPasswords.get(handle) != null) {
+ handle = mRandom.nextLong();
+ }
+ mGatekeeperPasswords.put(handle, gatekeeperPassword);
+ }
+
+ final long finalHandle = handle;
+ mHandler.postDelayed(() -> {
+ synchronized (mGatekeeperPasswords) {
+ Slog.d(TAG, "Removing handle: " + finalHandle);
+ mGatekeeperPasswords.remove(finalHandle);
+ }
+ }, GK_PW_HANDLE_STORE_DURATION_MS);
+
+ return handle;
+ }
+
private void onCredentialVerified(AuthenticationToken authToken, PasswordMetrics metrics,
int userId) {
@@ -2935,7 +2998,7 @@
*/
@Override
public byte[] getHashFactor(LockscreenCredential currentCredential, int userId) {
- checkPasswordReadPermission(userId);
+ checkPasswordReadPermission();
try {
if (isManagedProfileWithUnifiedLock(userId)) {
try {
@@ -3013,7 +3076,7 @@
@Override
public boolean hasPendingEscrowToken(int userId) {
- checkPasswordReadPermission(userId);
+ checkPasswordReadPermission();
synchronized (mSpManager) {
return !mSpManager.getPendingTokensForUser(userId).isEmpty();
}
@@ -3199,6 +3262,8 @@
mRebootEscrowManager.dump(pw);
pw.println();
pw.decreaseIndent();
+
+ pw.println("PasswordHandleCount: " + mGatekeeperPasswords.size());
}
/**
@@ -3361,7 +3426,8 @@
@Override
public boolean setLockCredentialWithToken(LockscreenCredential credential, long tokenHandle,
byte[] token, int userId) {
- if (!mHasSecureLockScreen) {
+ if (!mHasSecureLockScreen
+ && credential != null && credential.getType() != CREDENTIAL_TYPE_NONE) {
throw new UnsupportedOperationException(
"This operation requires secure lock screen feature.");
}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 8777cea..1e02f49 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -36,6 +36,7 @@
import android.media.session.MediaController.PlaybackInfo;
import android.media.session.MediaSession;
import android.media.session.MediaSession.QueueItem;
+import android.media.session.ParcelableListBinder;
import android.media.session.PlaybackState;
import android.net.Uri;
import android.os.Binder;
@@ -905,14 +906,24 @@
}
@Override
- public void setQueue(ParceledListSlice queue) throws RemoteException {
+ public void resetQueue() throws RemoteException {
synchronized (mLock) {
- mQueue = queue == null ? null : (List<QueueItem>) queue.getList();
+ mQueue = null;
}
mHandler.post(MessageHandler.MSG_UPDATE_QUEUE);
}
@Override
+ public IBinder getBinderForSetQueue() throws RemoteException {
+ return new ParcelableListBinder<QueueItem>((list) -> {
+ synchronized (mLock) {
+ mQueue = list;
+ }
+ mHandler.post(MessageHandler.MSG_UPDATE_QUEUE);
+ });
+ }
+
+ @Override
public void setQueueTitle(CharSequence title) throws RemoteException {
mQueueTitle = title;
mHandler.post(MessageHandler.MSG_UPDATE_QUEUE_TITLE);
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index a8a0e2e..9521611 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -1918,7 +1918,7 @@
final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
final long token = Binder.clearCallingIdentity();
try {
- // Don't perform sanity check between controllerPackageName and controllerUid.
+ // Don't perform check between controllerPackageName and controllerUid.
// When an (activity|service) runs on the another apps process by specifying
// android:process in the AndroidManifest.xml, then PID and UID would have the
// running process' information instead of the (activity|service) that has created
diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
index 0575ac6..d202a2a 100644
--- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
+++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
@@ -100,11 +100,16 @@
if (match != null) continue;
// Create listener for every newly added sub. Also store subscriberId into it to
- // prevent binder call to telephony when querying RAT.
+ // prevent binder call to telephony when querying RAT. If the subscriberId is empty
+ // for any reason, such as SIM PIN locked, skip registration.
+ // SubscriberId will be unavailable again if 1. modem crashed 2. reboot
+ // 3. re-insert SIM. If that happens, the listeners will be eventually synchronized
+ // with active sub list once all subscriberIds are ready.
final String subscriberId = mTeleManager.getSubscriberId(subId);
if (TextUtils.isEmpty(subscriberId)) {
- Log.wtf(NetworkStatsService.TAG,
- "Empty subscriberId for newly added sub: " + subId);
+ Log.d(NetworkStatsService.TAG, "Empty subscriberId for newly added sub "
+ + subId + ", skip listener registration");
+ continue;
}
final RatTypeListener listener =
new RatTypeListener(mExecutor, this, subId, subscriberId);
@@ -113,6 +118,7 @@
// Register listener to the telephony manager that associated with specific sub.
mTeleManager.createForSubscriptionId(subId)
.listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE);
+ Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + subId);
}
for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) {
@@ -165,6 +171,7 @@
private void handleRemoveRatTypeListener(@NonNull RatTypeListener listener) {
mTeleManager.createForSubscriptionId(listener.mSubId)
.listen(listener, PhoneStateListener.LISTEN_NONE);
+ Log.d(NetworkStatsService.TAG, "RAT type listener unregistered for sub " + listener.mSubId);
mRatListeners.remove(listener);
// Removal of subscriptions doesn't generate RAT changed event, fire it for every
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 9f9235d..0465855 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -6103,7 +6103,8 @@
protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
if (isBlocked(r)) {
if (DBG) {
- Slog.e(TAG, "Suppressing notification from package by user request.");
+ Slog.e(TAG, "Suppressing notification from package " + r.getSbn().getPackageName()
+ + " by user request.");
}
usageStats.registerBlocked(r);
return true;
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index 617f687..a234f5a 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -605,7 +605,7 @@
private boolean isPlatformSignedAppWithAutomaticProfilesPermission(
String packageName, int[] profileIds) {
for (int userId : profileIds) {
- final int uid = mInjector.getPackageManagerInternal().getPackageUidInternal(
+ final int uid = mInjector.getPackageManagerInternal().getPackageUid(
packageName, /* flags= */ 0, userId);
if (uid == -1) {
continue;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 8af7463..4b246c3 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -1284,14 +1284,21 @@
pw.increaseIndent();
List<PackageInstallerSession> finalizedSessions = new ArrayList<>();
+ List<PackageInstallerSession> orphanedChildSessions = new ArrayList<>();
int N = mSessions.size();
for (int i = 0; i < N; i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
- // Do not print finalized staged session as active install sessions
final PackageInstallerSession rootSession = session.hasParentSessionId()
? getSession(session.getParentSessionId())
: session;
+ // Do not print orphaned child sessions as active install sessions
+ if (rootSession == null) {
+ orphanedChildSessions.add(session);
+ continue;
+ }
+
+ // Do not print finalized staged session as active install sessions
if (rootSession.isStagedAndInTerminalState()) {
finalizedSessions.add(session);
continue;
@@ -1303,6 +1310,21 @@
pw.println();
pw.decreaseIndent();
+ if (!orphanedChildSessions.isEmpty()) {
+ // Presence of orphaned sessions indicate leak in cleanup for multi-package and
+ // should be cleaned up.
+ pw.println("Orphaned install sessions:");
+ pw.increaseIndent();
+ N = orphanedChildSessions.size();
+ for (int i = 0; i < N; i++) {
+ final PackageInstallerSession session = orphanedChildSessions.get(i);
+ session.dump(pw);
+ pw.println();
+ }
+ pw.println();
+ pw.decreaseIndent();
+ }
+
pw.println("Finalized install sessions:");
pw.increaseIndent();
N = finalizedSessions.size();
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 28c5e96..ed62362 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.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;
@@ -1325,6 +1326,7 @@
final int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE);
final int sessionIndex = mChildSessionsRemaining.indexOfKey(sessionId);
+ final String message = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
if (PackageInstaller.STATUS_SUCCESS == status) {
mChildSessionsRemaining.removeAt(sessionIndex);
if (mChildSessionsRemaining.size() == 0) {
@@ -1341,10 +1343,9 @@
intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
PackageInstallerSession.this.sessionId);
mChildSessionsRemaining.clear(); // we're done. Don't send any more.
- try {
- mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
- } catch (IntentSender.SendIntentException ignore) {
- }
+ destroyInternal();
+ dispatchSessionFinished(INSTALL_FAILED_INTERNAL_ERROR,
+ "Child session " + sessionId + " failed: " + message, null);
}
});
}
@@ -1554,12 +1555,28 @@
}
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 @@
}
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 @@
"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 @@
@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 @@
if (returnCode == PackageManager.INSTALL_SUCCEEDED) {
onVerificationComplete();
} else {
- destroyInternal();
- dispatchSessionFinished(returnCode, msg, extras);
+ onSessionVerificationFailure(returnCode, msg);
}
}
};
@@ -1946,9 +1981,13 @@
}
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 9c8b972..c05bc45 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -367,7 +367,6 @@
import com.android.server.pm.permission.BasePermission;
import com.android.server.pm.permission.PermissionManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
-import com.android.server.pm.permission.PermissionsState;
import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.rollback.RollbackManagerInternal;
import com.android.server.security.VerityUtils;
@@ -1818,7 +1817,7 @@
synchronized (mLock) {
removeMessages(WRITE_SETTINGS);
removeMessages(WRITE_PACKAGE_RESTRICTIONS);
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
mDirtyUsers.clear();
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
@@ -1838,6 +1837,7 @@
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mLock) {
removeMessages(WRITE_PACKAGE_LIST);
+ mPermissionManager.writePermissionsStateToPackageSettingsTEMP();
mSettings.writePackageListLPr(msg.arg1);
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
@@ -2518,7 +2518,7 @@
}
mSettings.onVolumeForgotten(fsUuid);
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
}
};
@@ -3442,6 +3442,7 @@
+ ((SystemClock.uptimeMillis()-startTime)/1000f)
+ " seconds");
+ mPermissionManager.readPermissionsStateFromPackageSettingsTEMP();
// If the platform SDK has changed since the last time we booted,
// we need to re-grant app permission to catch any new ones that
// appear. This is really a hack, and means that apps can in some
@@ -3561,7 +3562,7 @@
// can downgrade to reader
t.traceBegin("write settings");
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
t.traceEnd();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
@@ -3765,7 +3766,7 @@
Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e);
}
mPermissionManager.updatePermissions(pkg.getPackageName(), pkg);
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
} catch (PackageManagerException e) {
// Whoops! Something went very wrong; roll back to the stub and disable the package
@@ -3776,9 +3777,8 @@
// If we don't, installing the system package fails during scan
enableSystemPackageLPw(stubPkg);
}
- installPackageFromSystemLIF(stubPkg.getCodePath(),
- null /*allUserHandles*/, null /*origUserHandles*/,
- null /*origPermissionsState*/, true /*writeSettings*/);
+ installPackageFromSystemLIF(stubPkg.getCodePath(), null /*allUserHandles*/,
+ null /*origUserHandles*/, true /*writeSettings*/);
} catch (PackageManagerException pme) {
// Serious WTF; we have to be able to install the stub
Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.getPackageName(),
@@ -3792,7 +3792,7 @@
stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED,
UserHandle.USER_SYSTEM, "android");
}
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
}
return false;
@@ -5806,10 +5806,6 @@
private void updateSequenceNumberLP(PackageSetting pkgSetting, int[] userList) {
for (int i = userList.length - 1; i >= 0; --i) {
final int userId = userList[i];
- // don't add instant app to the list of updates
- if (pkgSetting.getInstantApp(userId)) {
- continue;
- }
SparseArray<String> changedPackages = mChangedPackages.get(userId);
if (changedPackages == null) {
changedPackages = new SparseArray<>();
@@ -5854,6 +5850,11 @@
for (int i = sequenceNumber; i < mChangedPackagesSequenceNumber; i++) {
final String packageName = changedPackages.get(i);
if (packageName != null) {
+ // Filter out the changes if the calling package should not be able to see it.
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
+ continue;
+ }
packageNames.add(packageName);
}
}
@@ -11680,8 +11681,9 @@
if (DEBUG_ABI_SELECTION) {
Slog.d(TAG, "Resolved nativeLibraryRoot for " + parsedPackage.getPackageName()
- + " to root=" + parsedPackage.getNativeLibraryRootDir() + ", isa="
- + parsedPackage.isNativeLibraryRootRequiresIsa());
+ + " to root=" + parsedPackage.getNativeLibraryRootDir()
+ + ", to dir=" + parsedPackage.getNativeLibraryDir()
+ + ", isa=" + parsedPackage.isNativeLibraryRootRequiresIsa());
}
// Push the derived path down into PackageSettings so we know what to
@@ -11689,9 +11691,10 @@
pkgSetting.legacyNativeLibraryPathString = parsedPackage.getNativeLibraryRootDir();
if (DEBUG_ABI_SELECTION) {
- Log.d(TAG, "Abis for package[" + parsedPackage.getPackageName() + "] are" +
- " primary=" + AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage) +
- " secondary=" + AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage));
+ Log.d(TAG, "Abis for package[" + parsedPackage.getPackageName() + "] are"
+ + " primary=" + pkgSetting.primaryCpuAbiString
+ + " secondary=" + pkgSetting.primaryCpuAbiString
+ + " abiOverride=" + pkgSetting.cpuAbiOverrideString);
}
if ((scanFlags & SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {
@@ -13092,7 +13095,7 @@
return true;
}
if (sendRemoved) {
- killApplication(packageName, UserHandle.getUid(userId, pkgSetting.appId),
+ killApplication(packageName, pkgSetting.appId, userId,
"hiding pkg");
sendApplicationHiddenForUser(packageName, pkgSetting, userId);
return true;
@@ -15198,6 +15201,13 @@
}
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);
@@ -16280,7 +16290,7 @@
res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
//to update install status
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings");
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -17610,12 +17620,13 @@
}
boolean isUpdatedSystemAppFromExistingSetting = pkgSetting != null
&& pkgSetting.getPkgState().isUpdatedSystemApp();
+ final String abiOverride = deriveAbiOverride(args.abiOverride, pkgSetting);
AndroidPackage oldPackage = mPackages.get(pkgName);
boolean isUpdatedSystemAppInferred = oldPackage != null && oldPackage.isSystem();
final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
derivedAbi = mInjector.getAbiHelper().derivePackageAbi(parsedPackage,
isUpdatedSystemAppFromExistingSetting || isUpdatedSystemAppInferred,
- args.abiOverride);
+ abiOverride);
derivedAbi.first.applyTo(parsedPackage);
derivedAbi.second.applyTo(parsedPackage);
} catch (PackageManagerException pme) {
@@ -18877,6 +18888,10 @@
if (outInfo != null) {
outInfo.removedAppId = removedAppId;
}
+ if ((deletedPs.sharedUser == null || deletedPs.sharedUser.packages.size() == 0)
+ && !isUpdatedSystemApp(deletedPs)) {
+ mPermissionManager.removePermissionsStateTEMP(removedAppId);
+ }
mPermissionManager.updatePermissions(deletedPs.name, null);
if (deletedPs.sharedUser != null) {
// Remove permissions associated with package. Since runtime
@@ -18886,10 +18901,10 @@
// package is successful and this causes a change in gids.
boolean shouldKill = false;
for (int userId : UserManagerService.getInstance().getUserIds()) {
- final int userIdToKill = mSettings.updateSharedUserPermsLPw(deletedPs,
- userId);
- shouldKill |= userIdToKill == UserHandle.USER_ALL
- || userIdToKill >= UserHandle.USER_SYSTEM;
+ final int userIdToKill = mPermissionManager
+ .revokeSharedUserPermissionsForDeletedPackageTEMP(deletedPs,
+ userId);
+ shouldKill |= userIdToKill != UserHandle.USER_NULL;
}
// If gids changed, kill all affected packages.
if (shouldKill) {
@@ -18933,7 +18948,7 @@
// can downgrade to reader
if (writeSettings) {
// Save settings now
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
if (installedStateChanged) {
mSettings.writeKernelMappingLPr(deletedPs);
@@ -19020,8 +19035,7 @@
if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
try {
installPackageFromSystemLIF(disabledPs.getCodePathString(), allUserHandles,
- outInfo == null ? null : outInfo.origUsers, deletedPs.getPermissionsState(),
- writeSettings);
+ outInfo == null ? null : outInfo.origUsers, writeSettings);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to restore system package:" + deletedPkg.getPackageName() + ": "
+ e.getMessage());
@@ -19052,9 +19066,8 @@
* Installs a package that's already on the system partition.
*/
private AndroidPackage installPackageFromSystemLIF(@NonNull String codePathString,
- @Nullable int[] allUserHandles, @Nullable int[] origUserHandles,
- @Nullable PermissionsState origPermissionState, boolean writeSettings)
- throws PackageManagerException {
+ @Nullable int[] allUserHandles, @Nullable int[] origUserHandles, boolean writeSettings)
+ throws PackageManagerException {
final File codePath = new File(codePathString);
@ParseFlags int parseFlags =
mDefParseFlags
@@ -19091,12 +19104,8 @@
synchronized (mLock) {
PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName());
- // Propagate the permissions state as we do not want to drop on the floor
- // runtime permissions. The update permissions method below will take
- // care of removing obsolete permissions and grant install permissions.
- if (origPermissionState != null) {
- ps.getPermissionsState().copyFrom(origPermissionState);
- }
+ // The update permissions method below will take care of removing obsolete permissions
+ // and granting install permissions.
mPermissionManager.updatePermissions(pkg.getPackageName(), pkg);
final boolean applyUserRestrictions
@@ -19130,7 +19139,7 @@
}
// can downgrade to reader here
if (writeSettings) {
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
}
return pkg;
@@ -19204,7 +19213,7 @@
} else {
ps.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER;
}
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
return true;
}
@@ -20396,7 +20405,7 @@
(parser1, userId1) -> {
synchronized (mLock) {
mSettings.readAllDomainVerificationsLPr(parser1, userId1);
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
});
} catch (Exception e) {
@@ -21747,6 +21756,8 @@
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
+ mPermissionManager.writePermissionsStateToPackageSettingsTEMP();
+
DumpState dumpState = new DumpState();
boolean fullPreferred = false;
boolean checkin = false;
@@ -21942,7 +21953,7 @@
dumpState.setDump(DumpState.DUMP_SERVICE_PERMISSIONS);
} else if ("write".equals(cmd)) {
synchronized (mLock) {
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
pw.println("Settings written.");
return;
}
@@ -22660,7 +22671,7 @@
// Yay, everything is now upgraded
ver.forceCurrent();
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
for (PackageFreezer freezer : freezers) {
@@ -22710,7 +22721,7 @@
AttributeCache.instance().removePackage(ps.name);
}
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
}
@@ -23623,6 +23634,8 @@
synchronized (mLock) {
mDirtyUsers.remove(userId);
mUserNeedsBadging.delete(userId);
+ mPermissionManager.onUserRemoved(userId);
+ mPermissionManager.writePermissionsStateToPackageSettingsTEMP();
mSettings.removeUserLPw(userId);
mPendingBroadcasts.remove(userId);
mInstantAppRegistry.onUserRemovedLPw(userId);
@@ -23723,7 +23736,9 @@
boolean readPermissionStateForUser(@UserIdInt int userId) {
synchronized (mPackages) {
+ mPermissionManager.writePermissionsStateToPackageSettingsTEMP();
mSettings.readPermissionStateForUserSyncLPr(userId);
+ mPermissionManager.readPermissionsStateFromPackageSettingsTEMP();
return mPmInternal.isPermissionUpgradeNeeded(userId);
}
}
@@ -24596,12 +24611,6 @@
@Override
public int getPackageUid(String packageName, int flags, int userId) {
return PackageManagerService.this
- .getPackageUid(packageName, flags, userId);
- }
-
- @Override
- public int getPackageUidInternal(String packageName, int flags, int userId) {
- return PackageManagerService.this
.getPackageUidInternal(packageName, flags, userId, Process.SYSTEM_UID);
}
@@ -25179,7 +25188,7 @@
if (async) {
scheduleWriteSettingsLocked();
} else {
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
}
}
@@ -25226,7 +25235,7 @@
return;
}
mSettings.mReadExternalStorageEnforced = enforced ? Boolean.TRUE : Boolean.FALSE;
- mSettings.writeLPr();
+ writeSettingsLPrTEMP();
}
}
@@ -25740,6 +25749,17 @@
public List<String> getMimeGroup(String packageName, String mimeGroup) {
return mSettings.mPackages.get(packageName).getMimeGroup(mimeGroup);
}
+
+ /**
+ * Temporary method that wraps mSettings.writeLPr() and calls
+ * mPermissionManager.writePermissionsStateToPackageSettingsTEMP() beforehand.
+ *
+ * TODO(zhanghai): This should be removed once we finish migration of permission storage.
+ */
+ private void writeSettingsLPrTEMP() {
+ mPermissionManager.writePermissionsStateToPackageSettingsTEMP();
+ mSettings.writeLPr();
+ }
}
interface PackageSender {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index de0e4b5..491b4fc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -34,7 +34,6 @@
import android.content.Intent;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.ResolveInfo;
@@ -68,7 +67,6 @@
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.PackageDexUsage;
import com.android.server.pm.parsing.pkg.AndroidPackage;
-import com.android.server.pm.permission.PermissionsState;
import dalvik.system.VMRuntime;
@@ -968,20 +966,6 @@
}
/**
- * Returns the {@link PermissionsState} for the given package. If the {@link PermissionsState}
- * could not be found, {@code null} will be returned.
- */
- public static PermissionsState getPermissionsState(
- PackageManagerInternal packageManagerInternal, AndroidPackage pkg) {
- final PackageSetting packageSetting = packageManagerInternal.getPackageSetting(
- pkg.getPackageName());
- if (packageSetting == null) {
- return null;
- }
- return packageSetting.getPermissionsState();
- }
-
- /**
* Recursively create target directory
*/
public static void makeDirRecursive(File targetDir, int mode) throws ErrnoException {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 32ec052..4d2e22a 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 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 @@
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 @@
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 @@
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 @@
}
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 @@
}
}
- 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 @@
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) {
- }
- }
+ case "--staged-ready-timeout":
+ stagedReadyTimeoutMs = Long.parseLong(getNextArgRequired());
break;
- case "--no-wait":
- waitForStagedSessionReady = false;
- break;
+ default:
+ throw new IllegalArgumentException("Unknown option: " + opt);
}
}
final int sessionId = Integer.parseInt(getNextArg());
@@ -1403,11 +1410,11 @@
}
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 @@
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 @@
}
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;
@@ -3199,12 +3197,24 @@
return 0;
}
+ private long getFileStatSize(File file) {
+ final ParcelFileDescriptor pfd = openFileForSystem(file.getPath(), "r");
+ if (pfd == null) {
+ throw new IllegalArgumentException("Error: Can't open file: " + file.getPath());
+ }
+ try {
+ return pfd.getStatSize();
+ } finally {
+ IoUtils.closeQuietly(pfd);
+ }
+ }
+
private void processArgForLocalFile(String arg, PackageInstaller.Session session) {
final String inPath = arg;
final File file = new File(inPath);
final String name = file.getName();
- final long size = file.length();
+ final long size = getFileStatSize(file);
final Metadata metadata = Metadata.forLocalFile(inPath);
byte[] v4signatureBytes = null;
@@ -3601,7 +3611,7 @@
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:");
@@ -3629,9 +3639,11 @@
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/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index acb149b..659e2a3 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -955,93 +955,6 @@
}
}
- /*
- * Update the shared user setting when a package with a shared user id is removed. The gids
- * associated with each permission of the deleted package are removed from the shared user'
- * gid list only if its not in use by other permissions of packages in the shared user setting.
- *
- * @return the affected user id
- */
- @UserIdInt
- int updateSharedUserPermsLPw(PackageSetting deletedPs, int userId) {
- if ((deletedPs == null) || (deletedPs.pkg == null)) {
- Slog.i(PackageManagerService.TAG,
- "Trying to update info for null package. Just ignoring");
- return UserHandle.USER_NULL;
- }
-
- // No sharedUserId
- if (deletedPs.sharedUser == null) {
- return UserHandle.USER_NULL;
- }
-
- SharedUserSetting sus = deletedPs.sharedUser;
-
- int affectedUserId = UserHandle.USER_NULL;
- // Update permissions
- for (String eachPerm : deletedPs.pkg.getRequestedPermissions()) {
- BasePermission bp = mPermissions.getPermission(eachPerm);
- if (bp == null) {
- continue;
- }
-
- // Check if another package in the shared user needs the permission.
- boolean used = false;
- for (PackageSetting pkg : sus.packages) {
- if (pkg.pkg != null
- && !pkg.pkg.getPackageName().equals(deletedPs.pkg.getPackageName())
- && pkg.pkg.getRequestedPermissions().contains(eachPerm)) {
- used = true;
- break;
- }
- }
- if (used) {
- continue;
- }
-
- PermissionsState permissionsState = sus.getPermissionsState();
- PackageSetting disabledPs = getDisabledSystemPkgLPr(deletedPs.pkg.getPackageName());
-
- // If the package is shadowing is a disabled system package,
- // do not drop permissions that the shadowed package requests.
- if (disabledPs != null) {
- boolean reqByDisabledSysPkg = false;
- for (String permission : disabledPs.pkg.getRequestedPermissions()) {
- if (permission.equals(eachPerm)) {
- reqByDisabledSysPkg = true;
- break;
- }
- }
- if (reqByDisabledSysPkg) {
- continue;
- }
- }
-
- // Try to revoke as an install permission which is for all users.
- // The package is gone - no need to keep flags for applying policy.
- permissionsState.updatePermissionFlags(bp, userId,
- PackageManager.MASK_PERMISSION_FLAGS_ALL, 0);
-
- if (permissionsState.revokeInstallPermission(bp) ==
- PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
- affectedUserId = UserHandle.USER_ALL;
- }
-
- // Try to revoke as an install permission which is per user.
- if (permissionsState.revokeRuntimePermission(bp, userId) ==
- PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
- if (affectedUserId == UserHandle.USER_NULL) {
- affectedUserId = userId;
- } else if (affectedUserId != userId) {
- // Multiple users affected.
- affectedUserId = UserHandle.USER_ALL;
- }
- }
- }
-
- return affectedUserId;
- }
-
int removePackageLPw(String name) {
final PackageSetting p = mPackages.get(name);
if (p != null) {
@@ -4638,6 +4551,7 @@
? "true" : "false");
pw.print(prefix); pw.print(" primaryCpuAbi="); pw.println(ps.primaryCpuAbiString);
pw.print(prefix); pw.print(" secondaryCpuAbi="); pw.println(ps.secondaryCpuAbiString);
+ pw.print(prefix); pw.print(" cpuAbiOverride="); pw.println(ps.cpuAbiOverrideString);
}
pw.print(prefix); pw.print(" versionCode="); pw.print(ps.versionCode);
if (pkg != null) {
@@ -5533,32 +5447,11 @@
// Make sure we do not
mHandler.removeMessages(userId);
- for (SettingBase sb : mPackages.values()) {
- revokeRuntimePermissionsAndClearFlags(sb, userId);
- }
-
- for (SettingBase sb : mSharedUsers.values()) {
- revokeRuntimePermissionsAndClearFlags(sb, userId);
- }
-
mPermissionUpgradeNeeded.delete(userId);
mVersions.delete(userId);
mFingerprints.remove(userId);
}
- private void revokeRuntimePermissionsAndClearFlags(SettingBase sb, int userId) {
- PermissionsState permissionsState = sb.getPermissionsState();
- for (PermissionState permissionState
- : permissionsState.getRuntimePermissionStates(userId)) {
- BasePermission bp = mPermissions.getPermission(permissionState.getName());
- if (bp != null) {
- permissionsState.revokeRuntimePermission(bp, userId);
- permissionsState.updatePermissionFlags(bp, userId,
- PackageManager.MASK_PERMISSION_FLAGS_ALL, 0);
- }
- }
- }
-
public void deleteUserRuntimePermissionsFile(int userId) {
mPersistence.deleteForUser(UserHandle.of(userId));
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 700f7be..8412077 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -3301,7 +3301,7 @@
final long token = Binder.clearCallingIdentity();
try {
- int packageUid = mPackageManagerInternal.getPackageUidInternal(packageName,
+ int packageUid = mPackageManagerInternal.getPackageUid(packageName,
PackageManager.MATCH_DIRECT_BOOT_AUTO, userId);
// Grant read uri permission to the caller on behalf of the shortcut owner. All
// granted permissions are revoked when the default launcher changes, or when
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 6d80f08..0c4eaec3 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.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 @@
* 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 @@
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 @@
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 @@
* 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 @@
}
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 @@
} 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 @@
}
}
- 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;
}
@@ -1005,7 +987,7 @@
// will be deleted.
}
root.setStagedSessionFailed(
- SessionInfo.STAGED_SESSION_OTHER_ERROR,
+ SessionInfo.STAGED_SESSION_CONFLICT,
"Session was blocking rollback session: " + session.sessionId);
Slog.i(TAG, "Session " + root.sessionId + " is marked failed due to "
+ "blocking rollback session: " + session.sessionId);
@@ -1047,7 +1029,7 @@
/**
* <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 @@
}
}
- void markStagedSessionsAsSuccessful() {
+ private void markStagedSessionsAsSuccessful() {
synchronized (mSuccessfulStagedSessionIds) {
for (int i = 0; i < mSuccessfulStagedSessionIds.size(); i++) {
mApexManager.markStagedSessionSuccessful(mSuccessfulStagedSessionIds.get(i));
@@ -1242,30 +1224,10 @@
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 @@
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 @@
}
/**
- * 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/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index cfa0449..962638b 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -38,7 +38,6 @@
import com.android.server.pm.DumpState;
import com.android.server.pm.PackageManagerService;
-import com.android.server.pm.PackageSetting;
import com.android.server.pm.PackageSettingBase;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -420,8 +419,7 @@
}
public void enforceDeclaredUsedAndRuntimeOrDevelopment(AndroidPackage pkg,
- PackageSetting pkgSetting) {
- final PermissionsState permsState = pkgSetting.getPermissionsState();
+ PermissionsState permsState) {
int index = pkg.getRequestedPermissions().indexOf(name);
if (!permsState.hasRequestedPermission(name) && index == -1) {
throw new SecurityException("Package " + pkg.getPackageName()
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 1be7415..f5dd918 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -162,6 +162,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -227,6 +228,9 @@
/** Internal connection to the user manager */
private final UserManagerInternal mUserManagerInt;
+ /** Maps from App ID to PermissionsState */
+ private final SparseArray<PermissionsState> mAppIdStates = new SparseArray<>();
+
/** Permission controller: User space permission management */
private PermissionControllerManager mPermissionControllerManager;
@@ -671,11 +675,6 @@
if (pkg == null) {
return 0;
}
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- pkg.getPackageName());
- if (ps == null) {
- return 0;
- }
synchronized (mLock) {
if (mSettings.getPermissionLocked(permName) == null) {
return 0;
@@ -684,7 +683,11 @@
if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
return 0;
}
- PermissionsState permissionsState = ps.getPermissionsState();
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + packageName);
+ return 0;
+ }
return permissionsState.getPermissionFlags(permName, userId);
}
@@ -771,9 +774,7 @@
}
final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- packageName);
- if (pkg == null || ps == null) {
+ if (pkg == null) {
Log.e(TAG, "Unknown package: " + packageName);
return;
}
@@ -789,7 +790,12 @@
throw new IllegalArgumentException("Unknown permission: " + permName);
}
- final PermissionsState permissionsState = ps.getPermissionsState();
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + packageName);
+ return;
+ }
+
final boolean hadState =
permissionsState.getRuntimePermissionState(permName, userId) != null;
if (!hadState) {
@@ -864,12 +870,11 @@
final boolean[] changed = new boolean[1];
mPackageManagerInt.forEachPackage(pkg -> {
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- pkg.getPackageName());
- if (ps == null) {
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
return;
}
- final PermissionsState permissionsState = ps.getPermissionsState();
changed[0] |= permissionsState.updatePermissionFlagsForAllPermissions(
userId, effectiveFlagMask, effectiveFlagValues);
mOnPermissionChangeListeners.onPermissionsChanged(pkg.getUid());
@@ -923,12 +928,11 @@
}
final int uid = UserHandle.getUid(userId, pkg.getUid());
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- pkg.getPackageName());
- if (ps == null) {
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
return PackageManager.PERMISSION_DENIED;
}
- final PermissionsState permissionsState = ps.getPermissionsState();
if (checkSinglePermissionInternal(uid, permissionsState, permissionName)) {
return PackageManager.PERMISSION_GRANTED;
@@ -1139,9 +1143,9 @@
final long identity = Binder.clearCallingIdentity();
try {
- final PermissionsState permissionsState =
- PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg);
+ final PermissionsState permissionsState = getPermissionsState(pkg);
if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + packageName);
return null;
}
@@ -1451,7 +1455,13 @@
throw new IllegalArgumentException("Unknown package: " + packageName);
}
- bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, ps);
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
+ return;
+ }
+
+ bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, permissionsState);
// If a permission review is required for legacy apps we represent
// their permissions as always granted runtime ones since we need
@@ -1464,8 +1474,6 @@
final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid()));
- final PermissionsState permissionsState = ps.getPermissionsState();
-
final int flags = permissionsState.getPermissionFlags(permName, userId);
if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
Log.e(TAG, "Cannot grant system fixed permission "
@@ -1599,9 +1607,7 @@
"revokeRuntimePermission");
final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- packageName);
- if (pkg == null || ps == null) {
+ if (pkg == null) {
Log.e(TAG, "Unknown package: " + packageName);
return;
}
@@ -1613,7 +1619,13 @@
throw new IllegalArgumentException("Unknown permission: " + permName);
}
- bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, ps);
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
+ return;
+ }
+
+ bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, permissionsState);
// If a permission review is required for legacy apps we represent
// their permissions as always granted runtime ones since we need
@@ -1624,8 +1636,6 @@
return;
}
- final PermissionsState permissionsState = ps.getPermissionsState();
-
final int flags = permissionsState.getPermissionFlags(permName, userId);
// Only the system may revoke SYSTEM_FIXED permissions.
if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0
@@ -2456,14 +2466,36 @@
}
}
+ private void onUserRemoved(@UserIdInt int userId) {
+ synchronized (mLock) {
+ final int appIdStatesSize = mAppIdStates.size();
+ for (int i = 0; i < appIdStatesSize; i++) {
+ PermissionsState permissionsState = mAppIdStates.valueAt(i);
+ for (PermissionState permissionState
+ : permissionsState.getRuntimePermissionStates(userId)) {
+ BasePermission bp = mSettings.getPermission(permissionState.getName());
+ if (bp != null) {
+ permissionsState.revokeRuntimePermission(bp, userId);
+ permissionsState.updatePermissionFlags(bp, userId,
+ PackageManager.MASK_PERMISSION_FLAGS_ALL, 0);
+ }
+ }
+ }
+ }
+ }
+
@NonNull
private Set<String> getGrantedPermissions(@NonNull String packageName,
@UserIdInt int userId) {
final PackageSetting ps = mPackageManagerInt.getPackageSetting(packageName);
if (ps == null) {
- return null;
+ return Collections.emptySet();
}
- final PermissionsState permissionsState = ps.getPermissionsState();
+ final PermissionsState permissionsState = getPermissionsState(ps);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + packageName);
+ return Collections.emptySet();
+ }
if (!ps.getInstantApp(userId)) {
return permissionsState.getPermissions(userId);
} else {
@@ -2503,7 +2535,11 @@
if (ps == null) {
return null;
}
- final PermissionsState permissionsState = ps.getPermissionsState();
+ final PermissionsState permissionsState = getPermissionsState(ps);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + packageName);
+ return null;
+ }
return permissionsState.computeGids(userId);
}
@@ -2541,8 +2577,7 @@
if (ps == null) {
return;
}
-
- final PermissionsState permissionsState = ps.getPermissionsState();
+ final PermissionsState permissionsState = getOrCreatePermissionsState(ps);
final int[] userIds = getAllUserIds();
@@ -2614,8 +2649,8 @@
// changed runtime permissions here are promotion of an install to
// runtime and revocation of a runtime from a shared user.
synchronized (mLock) {
- updatedUserIds = revokeUnusedSharedUserPermissionsLocked(ps.getSharedUser(),
- userIds);
+ updatedUserIds = revokeUnusedSharedUserPermissionsLocked(
+ ps.getSharedUser().getPackages(), permissionsState, userIds);
if (!ArrayUtils.isEmpty(updatedUserIds)) {
runtimePermissionsRevoked = true;
}
@@ -3091,6 +3126,8 @@
updatedUserIds);
}
+ // TODO: Kill UIDs whose GIDs or runtime permissions changed. This might be more important
+ // for shared users.
// Persist the runtime permissions state for users with changes. If permissions
// were revoked because no app in the shared user declares them we have to
// write synchronously to avoid losing runtime permissions state.
@@ -3554,37 +3591,15 @@
final PackageSetting disabledPs = mPackageManagerInt
.getDisabledSystemPackage(pkg.getPackageName());
final AndroidPackage disabledPkg = disabledPs == null ? null : disabledPs.pkg;
- if (disabledPs != null
- && disabledPs.getPermissionsState().hasInstallPermission(perm)) {
- // If the original was granted this permission, we take
- // that grant decision as read and propagate it to the
- // update.
- if ((privilegedPermission && disabledPs.isPrivileged())
- || (oemPermission && disabledPs.isOem()
- && canGrantOemPermission(disabledPs, perm))) {
- allowed = true;
- }
- } else {
- // The system apk may have been updated with an older
- // version of the one on the data partition, but which
- // granted a new system permission that it didn't have
- // before. In this case we do want to allow the app to
- // now get the new permission if the ancestral apk is
- // privileged to get it.
- if (disabledPs != null && disabledPkg != null
- && isPackageRequestingPermission(disabledPkg, perm)
- && ((privilegedPermission && disabledPs.isPrivileged())
- || (oemPermission && disabledPs.isOem()
- && canGrantOemPermission(disabledPs, perm)))) {
- allowed = true;
- }
+ if (disabledPkg != null && isPackageRequestingPermission(disabledPkg, perm)
+ && ((privilegedPermission && disabledPkg.isPrivileged())
+ || (oemPermission && canGrantOemPermission(disabledPkg,
+ perm)))) {
+ allowed = true;
}
} else {
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- pkg.getPackageName());
allowed = (privilegedPermission && pkg.isPrivileged())
- || (oemPermission && pkg.isOem()
- && canGrantOemPermission(ps, perm));
+ || (oemPermission && canGrantOemPermission(pkg, perm));
}
// In any case, don't grant a privileged permission to privileged vendor apps, if
// the permission's protectionLevel does not have the extra 'vendorPrivileged'
@@ -3735,16 +3750,16 @@
return false;
}
- private static boolean canGrantOemPermission(PackageSetting ps, String permission) {
- if (!ps.isOem()) {
+ private static boolean canGrantOemPermission(AndroidPackage pkg, String permission) {
+ if (!pkg.isOem()) {
return false;
}
// all oem permissions must explicitly be granted or denied
final Boolean granted =
- SystemConfig.getInstance().getOemPermissions(ps.name).get(permission);
+ SystemConfig.getInstance().getOemPermissions(pkg.getPackageName()).get(permission);
if (granted == null) {
throw new IllegalStateException("OEM permission" + permission + " requested by package "
- + ps.name + " must be explicitly declared granted or not");
+ + pkg.getPackageName() + " must be explicitly declared granted or not");
}
return Boolean.TRUE == granted;
}
@@ -3757,12 +3772,11 @@
}
// Legacy apps have the permission and get user consent on launch.
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- pkg.getPackageName());
- if (ps == null) {
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
return false;
}
- final PermissionsState permissionsState = ps.getPermissionsState();
return permissionsState.isPermissionReviewRequired(userId);
}
@@ -3787,14 +3801,12 @@
private void grantRequestedRuntimePermissionsForUser(AndroidPackage pkg, int userId,
String[] grantedPermissions, int callingUid, PermissionCallback callback) {
- PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- pkg.getPackageName());
- if (ps == null) {
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
return;
}
- PermissionsState permissionsState = ps.getPermissionsState();
-
final int immutableFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
| PackageManager.FLAG_PERMISSION_POLICY_FIXED;
@@ -3838,9 +3850,9 @@
private void setWhitelistedRestrictedPermissionsForUsers(@NonNull AndroidPackage pkg,
@UserIdInt int[] userIds, @Nullable List<String> permissions, int callingUid,
@PermissionWhitelistFlags int whitelistFlags, PermissionCallback callback) {
- final PermissionsState permissionsState =
- PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg);
+ final PermissionsState permissionsState = getPermissionsState(pkg);
if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
return;
}
@@ -3958,9 +3970,11 @@
for (int j = 0; j < oldGrantedCount; j++) {
final String permission = oldPermsForUser.valueAt(j);
// Sometimes we create a new permission state instance during update.
- final PermissionsState newPermissionsState =
- PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt,
- pkg);
+ final PermissionsState newPermissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
+ continue;
+ }
if (!newPermissionsState.hasPermission(permission, userId)) {
callback.onPermissionRevoked(pkg.getUid(), userId, null);
break;
@@ -3970,12 +3984,100 @@
}
}
+ @UserIdInt
+ private int revokeSharedUserPermissionsForDeletedPackage(@NonNull PackageSetting deletedPs,
+ @UserIdInt int userId) {
+ if ((deletedPs == null) || (deletedPs.pkg == null)) {
+ Slog.i(TAG, "Trying to update info for null package. Just ignoring");
+ return UserHandle.USER_NULL;
+ }
+
+ SharedUserSetting sus = deletedPs.getSharedUser();
+
+ // No sharedUserId
+ if (sus == null) {
+ return UserHandle.USER_NULL;
+ }
+
+ int affectedUserId = UserHandle.USER_NULL;
+ // Update permissions
+ for (String eachPerm : deletedPs.pkg.getRequestedPermissions()) {
+ BasePermission bp = mSettings.getPermission(eachPerm);
+ if (bp == null) {
+ continue;
+ }
+
+ // Check if another package in the shared user needs the permission.
+ boolean used = false;
+ final List<AndroidPackage> pkgs = sus.getPackages();
+ if (pkgs != null) {
+ for (AndroidPackage pkg : pkgs) {
+ if (pkg != null
+ && !pkg.getPackageName().equals(deletedPs.pkg.getPackageName())
+ && pkg.getRequestedPermissions().contains(eachPerm)) {
+ used = true;
+ break;
+ }
+ }
+ }
+ if (used) {
+ continue;
+ }
+
+ PermissionsState permissionsState = getPermissionsState(deletedPs.pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + deletedPs.pkg.getPackageName());
+ continue;
+ }
+
+ PackageSetting disabledPs = mPackageManagerInt.getDisabledSystemPackage(
+ deletedPs.pkg.getPackageName());
+
+ // If the package is shadowing is a disabled system package,
+ // do not drop permissions that the shadowed package requests.
+ if (disabledPs != null) {
+ boolean reqByDisabledSysPkg = false;
+ for (String permission : disabledPs.pkg.getRequestedPermissions()) {
+ if (permission.equals(eachPerm)) {
+ reqByDisabledSysPkg = true;
+ break;
+ }
+ }
+ if (reqByDisabledSysPkg) {
+ continue;
+ }
+ }
+
+ // Try to revoke as an install permission which is for all users.
+ // The package is gone - no need to keep flags for applying policy.
+ permissionsState.updatePermissionFlags(bp, userId,
+ PackageManager.MASK_PERMISSION_FLAGS_ALL, 0);
+
+ if (permissionsState.revokeInstallPermission(bp)
+ == PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
+ affectedUserId = UserHandle.USER_ALL;
+ }
+
+ // Try to revoke as a runtime permission which is per user.
+ if (permissionsState.revokeRuntimePermission(bp, userId)
+ == PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
+ if (affectedUserId == UserHandle.USER_NULL) {
+ affectedUserId = userId;
+ } else if (affectedUserId != userId) {
+ // Multiple users affected.
+ affectedUserId = UserHandle.USER_ALL;
+ }
+ }
+ }
+
+ return affectedUserId;
+ }
+
@GuardedBy("mLock")
private int[] revokeUnusedSharedUserPermissionsLocked(
- SharedUserSetting suSetting, int[] allUserIds) {
+ List<AndroidPackage> pkgList, PermissionsState permissionsState, int[] allUserIds) {
// Collect all used permissions in the UID
final ArraySet<String> usedPermissions = new ArraySet<>();
- final List<AndroidPackage> pkgList = suSetting.getPackages();
if (pkgList == null || pkgList.size() == 0) {
return EmptyArray.INT;
}
@@ -3993,7 +4095,6 @@
}
}
- PermissionsState permissionsState = suSetting.getPermissionsState();
// Prune install permissions
List<PermissionState> installPermStates = permissionsState.getInstallPermissionStates();
final int installPermCount = installPermStates.size();
@@ -4279,12 +4380,11 @@
}
} else {
mPackageManagerInt.forEachPackage(p -> {
- PackageSetting ps = mPackageManagerInt.getPackageSetting(
- p.getPackageName());
- if (ps == null) {
+ final PermissionsState permissionsState = getPermissionsState(p);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + p.getPackageName());
return;
}
- PermissionsState permissionsState = ps.getPermissionsState();
if (permissionsState.getInstallPermissionState(bp.getName()) != null) {
permissionsState.revokeInstallPermission(bp);
permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
@@ -4695,6 +4795,67 @@
return mBackgroundPermissions;
}
+ @Nullable
+ private PermissionsState getPermissionsState(@NonNull PackageSetting ps) {
+ return getPermissionsState(ps.getAppId());
+ }
+
+ @Nullable
+ private PermissionsState getPermissionsState(@NonNull AndroidPackage pkg) {
+ return getPermissionsState(pkg.getUid());
+ }
+
+ @Nullable
+ private PermissionsState getPermissionsState(int appId) {
+ synchronized (mLock) {
+ return mAppIdStates.get(appId);
+ }
+ }
+
+ @Nullable
+ private PermissionsState getOrCreatePermissionsState(@NonNull PackageSetting ps) {
+ return getOrCreatePermissionsState(ps.getAppId());
+ }
+
+ @Nullable
+ private PermissionsState getOrCreatePermissionsState(int appId) {
+ synchronized (mLock) {
+ PermissionsState state = mAppIdStates.get(appId);
+ if (state == null) {
+ state = new PermissionsState();
+ mAppIdStates.put(appId, state);
+ }
+ return state;
+ }
+ }
+
+ private void removePermissionsState(int appId) {
+ synchronized (mLock) {
+ mAppIdStates.remove(appId);
+ }
+ }
+
+ private void readPermissionsStateFromPackageSettings() {
+ mPackageManagerInt.forEachPackageSetting(ps -> {
+ synchronized (mLock) {
+ mAppIdStates.put(ps.getAppId(), new PermissionsState(ps.getPermissionsState()));
+ }
+ });
+ }
+
+ private void writePermissionsStateToPackageSettings() {
+ mPackageManagerInt.forEachPackageSetting(ps -> {
+ synchronized (mLock) {
+ final PermissionsState permissionsState = mAppIdStates.get(ps.getAppId());
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + ps.name);
+ return;
+ }
+ ps.getPermissionsState().copyFrom(permissionsState);
+ }
+ });
+ }
+
private class PermissionManagerServiceInternalImpl extends PermissionManagerServiceInternal {
@Override
public void systemReady() {
@@ -4726,6 +4887,29 @@
public void removeAllPermissions(AndroidPackage pkg, boolean chatty) {
PermissionManagerService.this.removeAllPermissions(pkg, chatty);
}
+ @Override
+ public void readPermissionsStateFromPackageSettingsTEMP() {
+ PermissionManagerService.this.readPermissionsStateFromPackageSettings();
+ }
+ @Override
+ public void writePermissionsStateToPackageSettingsTEMP() {
+ PermissionManagerService.this.writePermissionsStateToPackageSettings();
+ }
+ @Override
+ public void onUserRemoved(@UserIdInt int userId) {
+ PermissionManagerService.this.onUserRemoved(userId);
+ }
+ @Override
+ public void removePermissionsStateTEMP(int appId) {
+ PermissionManagerService.this.removePermissionsState(appId);
+ }
+ @Override
+ @UserIdInt
+ public int revokeSharedUserPermissionsForDeletedPackageTEMP(
+ @NonNull PackageSetting deletedPs, @UserIdInt int userId) {
+ return PermissionManagerService.this.revokeSharedUserPermissionsForDeletedPackage(
+ deletedPs, userId);
+ }
@NonNull
@Override
public Set<String> getGrantedPermissions(@NonNull String packageName,
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index cfa371d..f319bf4 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -24,6 +24,7 @@
import android.content.pm.PermissionInfo;
import android.permission.PermissionManagerInternal;
+import com.android.server.pm.PackageSetting;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.util.ArrayList;
@@ -265,6 +266,52 @@
public abstract void removeAllPermissions(@NonNull AndroidPackage pkg, boolean chatty);
/**
+ * Read {@code PermissionsState} from package settings.
+ *
+ * TODO(zhanghai): This is a temporary method because we should not expose
+ * {@code PackageSetting} which is a implementation detail that permission should not know.
+ * Instead, it should retrieve the legacy state via a defined API.
+ */
+ public abstract void readPermissionsStateFromPackageSettingsTEMP();
+
+ /**
+ * Write {@code PermissionsState} from to settings.
+ *
+ * TODO(zhanghai): This is a temporary method and should be removed once we migrated persistence
+ * for permission.
+ */
+ public abstract void writePermissionsStateToPackageSettingsTEMP();
+
+ /**
+ * Notify that a user has been removed and its permission state should be removed as well.
+ */
+ public abstract void onUserRemoved(@UserIdInt int userId);
+
+ /**
+ * Remove the {@code PermissionsState} associated with an app ID, called the same time as the
+ * removal of a {@code PackageSetitng}.
+ *
+ * TODO(zhanghai): This is a temporary method before we figure out a way to get notified of app
+ * ID removal via API.
+ */
+ public abstract void removePermissionsStateTEMP(int appId);
+
+ /**
+ * Update the shared user setting when a package with a shared user id is removed. The gids
+ * associated with each permission of the deleted package are removed from the shared user'
+ * gid list only if its not in use by other permissions of packages in the shared user setting.
+ *
+ * TODO(zhanghai): We should not need this when permission no longer sees an incomplete package
+ * state where the updated system package is uninstalled but the disabled system package is yet
+ * to be installed. Then we should handle this in restorePermissionState().
+ *
+ * @return the affected user id, may be a real user ID, USER_ALL, or USER_NULL when none.
+ */
+ @UserIdInt
+ public abstract int revokeSharedUserPermissionsForDeletedPackageTEMP(
+ @NonNull PackageSetting deletedPs, @UserIdInt int userId);
+
+ /**
* Get all the permissions granted to a package.
*/
@NonNull
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 548cd70..137c587 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 @@
}
@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 @@
}
@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 651eafd..b96d65c 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 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 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 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 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 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 @@
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 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 @@
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 @@
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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
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/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 8f0fd60..d4375eb 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -94,6 +94,7 @@
private static final int MSG_USER_ACTIVITY = 1;
private static final int MSG_BROADCAST = 2;
private static final int MSG_WIRELESS_CHARGING_STARTED = 3;
+ private static final int MSG_BROADCAST_ENHANCED_PREDICTION = 4;
private static final int MSG_PROFILE_TIMED_OUT = 5;
private static final int MSG_WIRED_CHARGING_STARTED = 6;
@@ -701,6 +702,16 @@
mPolicy.userActivity();
}
+ void postEnhancedDischargePredictionBroadcast(long delayMs) {
+ mHandler.sendEmptyMessageDelayed(MSG_BROADCAST_ENHANCED_PREDICTION, delayMs);
+ }
+
+ private void sendEnhancedDischargePredictionBroadcast() {
+ Intent intent = new Intent(PowerManager.ACTION_ENHANCED_DISCHARGE_PREDICTION_CHANGED)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ }
+
private void sendNextBroadcast() {
final int powerState;
synchronized (mLock) {
@@ -872,6 +883,10 @@
case MSG_WIRELESS_CHARGING_STARTED:
showWirelessChargingStarted(msg.arg1, msg.arg2);
break;
+ case MSG_BROADCAST_ENHANCED_PREDICTION:
+ removeMessages(MSG_BROADCAST_ENHANCED_PREDICTION);
+ sendEnhancedDischargePredictionBroadcast();
+ break;
case MSG_PROFILE_TIMED_OUT:
lockProfile(msg.arg1);
break;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 882ed1b..9ff164a 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -56,6 +56,7 @@
import android.os.IPowerManager;
import android.os.Looper;
import android.os.Message;
+import android.os.ParcelDuration;
import android.os.PowerManager;
import android.os.PowerManager.ServiceType;
import android.os.PowerManager.WakeData;
@@ -89,11 +90,13 @@
import android.view.KeyEvent;
import com.android.internal.BrightnessSynchronizer;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.Preconditions;
import com.android.server.EventLogTags;
import com.android.server.LockGuard;
import com.android.server.RescueParty;
@@ -238,6 +241,18 @@
private static final int HALT_MODE_REBOOT = 1;
private static final int HALT_MODE_REBOOT_SAFE_MODE = 2;
+ /**
+ * How stale we'll allow the enhanced discharge prediction values to get before considering them
+ * invalid.
+ */
+ private static final long ENHANCED_DISCHARGE_PREDICTION_TIMEOUT_MS = 30 * 60 * 1000L;
+
+ /**
+ * The minimum amount of time between sending consequent
+ * {@link PowerManager#ACTION_ENHANCED_DISCHARGE_PREDICTION_CHANGED} broadcasts.
+ */
+ private static final long ENHANCED_DISCHARGE_PREDICTION_BROADCAST_MIN_DELAY_MS = 60 * 1000L;
+
private final Context mContext;
private final ServiceThread mHandlerThread;
private final Handler mHandler;
@@ -380,6 +395,34 @@
// The current battery level percentage.
private int mBatteryLevel;
+ /**
+ * The lock that should be held when interacting with {@link #mEnhancedDischargeTimeElapsed},
+ * {@link #mLastEnhancedDischargeTimeUpdatedElapsed}, and
+ * {@link #mEnhancedDischargePredictionIsPersonalized}.
+ */
+ private final Object mEnhancedDischargeTimeLock = new Object();
+
+ /**
+ * The time (in the elapsed realtime timebase) at which the battery level will reach 0%. This
+ * is provided as an enhanced estimate and only valid if
+ * {@link #mLastEnhancedDischargeTimeUpdatedElapsed} is greater than 0.
+ */
+ @GuardedBy("mEnhancedDischargeTimeLock")
+ private long mEnhancedDischargeTimeElapsed;
+
+ /**
+ * Timestamp (in the elapsed realtime timebase) of last update to enhanced battery estimate
+ * data.
+ */
+ @GuardedBy("mEnhancedDischargeTimeLock")
+ private long mLastEnhancedDischargeTimeUpdatedElapsed;
+
+ /**
+ * Whether or not the current enhanced discharge prediction is personalized to the user.
+ */
+ @GuardedBy("mEnhancedDischargeTimeLock")
+ private boolean mEnhancedDischargePredictionIsPersonalized;
+
// The battery level percentage at the time the dream started.
// This is used to terminate a dream and go to sleep if the battery is
// draining faster than it is charging and the user activity timeout has expired.
@@ -3737,6 +3780,13 @@
pw.println(" mProximityPositive=" + mProximityPositive);
pw.println(" mBootCompleted=" + mBootCompleted);
pw.println(" mSystemReady=" + mSystemReady);
+ synchronized (mEnhancedDischargeTimeLock) {
+ pw.println(" mEnhancedDischargeTimeElapsed=" + mEnhancedDischargeTimeElapsed);
+ pw.println(" mLastEnhancedDischargeTimeUpdatedElapsed="
+ + mLastEnhancedDischargeTimeUpdatedElapsed);
+ pw.println(" mEnhancedDischargePredictionIsPersonalized="
+ + mEnhancedDischargePredictionIsPersonalized);
+ }
pw.println(" mHalAutoSuspendModeEnabled=" + mHalAutoSuspendModeEnabled);
pw.println(" mHalInteractiveModeEnabled=" + mHalInteractiveModeEnabled);
pw.println(" mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
@@ -3952,6 +4002,16 @@
proto.write(PowerManagerServiceDumpProto.IS_PROXIMITY_POSITIVE, mProximityPositive);
proto.write(PowerManagerServiceDumpProto.IS_BOOT_COMPLETED, mBootCompleted);
proto.write(PowerManagerServiceDumpProto.IS_SYSTEM_READY, mSystemReady);
+ synchronized (mEnhancedDischargeTimeLock) {
+ proto.write(PowerManagerServiceDumpProto.ENHANCED_DISCHARGE_TIME_ELAPSED,
+ mEnhancedDischargeTimeElapsed);
+ proto.write(
+ PowerManagerServiceDumpProto.LAST_ENHANCED_DISCHARGE_TIME_UPDATED_ELAPSED,
+ mLastEnhancedDischargeTimeUpdatedElapsed);
+ proto.write(
+ PowerManagerServiceDumpProto.IS_ENHANCED_DISCHARGE_PREDICTION_PERSONALIZED,
+ mEnhancedDischargePredictionIsPersonalized);
+ }
proto.write(
PowerManagerServiceDumpProto.IS_HAL_AUTO_SUSPEND_MODE_ENABLED,
mHalAutoSuspendModeEnabled);
@@ -3959,7 +4019,8 @@
PowerManagerServiceDumpProto.IS_HAL_AUTO_INTERACTIVE_MODE_ENABLED,
mHalInteractiveModeEnabled);
- final long activeWakeLocksToken = proto.start(PowerManagerServiceDumpProto.ACTIVE_WAKE_LOCKS);
+ final long activeWakeLocksToken = proto.start(
+ PowerManagerServiceDumpProto.ACTIVE_WAKE_LOCKS);
proto.write(
PowerManagerServiceDumpProto.ActiveWakeLocksProto.IS_CPU,
(mWakeLockSummary & WAKE_LOCK_CPU) != 0);
@@ -4262,6 +4323,7 @@
if (wcd != null) {
wcd.dumpDebug(proto, PowerManagerServiceDumpProto.WIRELESS_CHARGER_DETECTOR);
}
+
proto.flush();
}
@@ -5022,6 +5084,96 @@
}
@Override // Binder call
+ public void setBatteryDischargePrediction(@NonNull ParcelDuration timeRemaining,
+ boolean isPersonalized) {
+ // Get current time before acquiring the lock so that the calculated end time is as
+ // accurate as possible.
+ final long nowElapsed = SystemClock.elapsedRealtime();
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+
+ final long timeRemainingMs = timeRemaining.getDuration().toMillis();
+ // A non-positive number means the battery should be dead right now...
+ Preconditions.checkArgumentPositive(timeRemainingMs,
+ "Given time remaining is not positive: " + timeRemainingMs);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ if (mIsPowered) {
+ throw new IllegalStateException(
+ "Discharge prediction can't be set while the device is charging");
+ }
+ }
+
+ final long broadcastDelayMs;
+ synchronized (mEnhancedDischargeTimeLock) {
+ if (mLastEnhancedDischargeTimeUpdatedElapsed > nowElapsed) {
+ // Another later call made it into the block first. Keep the latest info.
+ return;
+ }
+ broadcastDelayMs = Math.max(0,
+ ENHANCED_DISCHARGE_PREDICTION_BROADCAST_MIN_DELAY_MS
+ - (nowElapsed - mLastEnhancedDischargeTimeUpdatedElapsed));
+
+ // No need to persist the discharge prediction values since they'll most likely
+ // be wrong immediately after a reboot anyway.
+ mEnhancedDischargeTimeElapsed = nowElapsed + timeRemainingMs;
+ mEnhancedDischargePredictionIsPersonalized = isPersonalized;
+ mLastEnhancedDischargeTimeUpdatedElapsed = nowElapsed;
+ }
+ mNotifier.postEnhancedDischargePredictionBroadcast(broadcastDelayMs);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ private boolean isEnhancedDischargePredictionValidLocked(long nowElapsed) {
+ return mLastEnhancedDischargeTimeUpdatedElapsed > 0
+ && nowElapsed < mEnhancedDischargeTimeElapsed
+ && nowElapsed - mLastEnhancedDischargeTimeUpdatedElapsed
+ < ENHANCED_DISCHARGE_PREDICTION_TIMEOUT_MS;
+ }
+
+ @Override // Binder call
+ public ParcelDuration getBatteryDischargePrediction() {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ if (mIsPowered) {
+ return null;
+ }
+ }
+ synchronized (mEnhancedDischargeTimeLock) {
+ // Get current time after acquiring the lock so that the calculated duration
+ // is as accurate as possible.
+ final long nowElapsed = SystemClock.elapsedRealtime();
+ if (isEnhancedDischargePredictionValidLocked(nowElapsed)) {
+ return new ParcelDuration(mEnhancedDischargeTimeElapsed - nowElapsed);
+ }
+ }
+ return new ParcelDuration(mBatteryStats.computeBatteryTimeRemaining());
+ } catch (RemoteException e) {
+ // Shouldn't happen in-process.
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ return null;
+ }
+
+ @Override // Binder call
+ public boolean isBatteryDischargePredictionPersonalized() {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mEnhancedDischargeTimeLock) {
+ return isEnhancedDischargePredictionValidLocked(SystemClock.elapsedRealtime())
+ && mEnhancedDischargePredictionIsPersonalized;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
public boolean isDeviceIdleMode() {
final long ident = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java
index 6dc1d692..0abeac8 100644
--- a/services/core/java/com/android/server/storage/StorageSessionController.java
+++ b/services/core/java/com/android/server/storage/StorageSessionController.java
@@ -336,11 +336,12 @@
}
/**
- * Returns {@code true} if {@code vol} is an emulated or public volume,
+ * Returns {@code true} if {@code vol} is an emulated or visible public volume,
* {@code false} otherwise
**/
public static boolean isEmulatedOrPublic(VolumeInfo vol) {
- return vol.type == VolumeInfo.TYPE_EMULATED || vol.type == VolumeInfo.TYPE_PUBLIC;
+ return vol.type == VolumeInfo.TYPE_EMULATED
+ || (vol.type == VolumeInfo.TYPE_PUBLIC && vol.isVisible());
}
/** Exception thrown when communication with the {@link ExternalStorageService} fails. */
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index a106dc6..0b0bb70 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -258,7 +258,7 @@
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
- final int packageUid = pm.getPackageUidInternal(packageName,
+ final int packageUid = pm.getPackageUid(packageName,
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, callingUserId);
if (packageUid != callingUid) {
throw new SecurityException(
@@ -336,7 +336,7 @@
if (toPackage != null) {
mAmInternal.enforceCallingPermission(FORCE_PERSISTABLE_URI_PERMISSIONS,
"takePersistableUriPermission");
- uid = mPmInternal.getPackageUidInternal(toPackage, 0, userId);
+ uid = mPmInternal.getPackageUid(toPackage, 0 /* flags */, userId);
} else {
enforceNotIsolatedCaller("takePersistableUriPermission");
uid = Binder.getCallingUid();
@@ -401,7 +401,7 @@
if (toPackage != null) {
mAmInternal.enforceCallingPermission(FORCE_PERSISTABLE_URI_PERMISSIONS,
"releasePersistableUriPermission");
- uid = mPmInternal.getPackageUidInternal(toPackage, 0, userId);
+ uid = mPmInternal.getPackageUid(toPackage, 0 /* flags */ , userId);
} else {
enforceNotIsolatedCaller("releasePersistableUriPermission");
uid = Binder.getCallingUid();
@@ -600,7 +600,7 @@
if (needed != null) {
targetUid = needed.targetUid;
} else {
- targetUid = mPmInternal.getPackageUidInternal(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
+ targetUid = mPmInternal.getPackageUid(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
targetUserId);
if (targetUid < 0) {
if (DEBUG) Slog.v(TAG, "Can't grant URI permission no uid for: " + targetPkg
@@ -690,7 +690,7 @@
final ProviderInfo pi = getProviderInfo(uri.getAuthority(), sourceUserId,
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
if (pi != null && sourcePkg.equals(pi.packageName)) {
- int targetUid = mPmInternal.getPackageUidInternal(
+ int targetUid = mPmInternal.getPackageUid(
targetPkg, MATCH_UNINSTALLED_PACKAGES, targetUserId);
if (targetUid != -1) {
final GrantUri grantUri = new GrantUri(sourceUserId, uri,
@@ -787,7 +787,7 @@
if (targetPkg == null) {
throw new NullPointerException("targetPkg");
}
- int targetUid = mPmInternal.getPackageUidInternal(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
+ int targetUid = mPmInternal.getPackageUid(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
targetUserId);
targetUid = checkGrantUriPermissionUnlocked(callingUid, targetPkg, grantUri, modeFlags,
@@ -1108,7 +1108,7 @@
int targetUid = lastTargetUid;
if (targetUid < 0 && targetPkg != null) {
- targetUid = mPmInternal.getPackageUidInternal(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
+ targetUid = mPmInternal.getPackageUid(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
UserHandle.getUserId(callingUid));
if (targetUid < 0) {
if (DEBUG) Slog.v(TAG, "Can't grant URI permission no uid for: " + targetPkg);
@@ -1462,7 +1462,8 @@
boolean printed = false;
int dumpUid = -2;
if (dumpPackage != null) {
- dumpUid = mPmInternal.getPackageUidInternal(dumpPackage, MATCH_ANY_USER, 0);
+ dumpUid = mPmInternal.getPackageUid(dumpPackage,
+ MATCH_ANY_USER, 0 /* userId */);
}
for (int i = 0; i < mGrantedUriPermissions.size(); i++) {
int uid = mGrantedUriPermissions.keyAt(i);
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 9bbeb72..90a153b 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -209,8 +209,8 @@
private void grantVisibilityToCaller(String webViewPackageName, int callingUid) {
final PackageManagerInternal pmInternal = LocalServices.getService(
PackageManagerInternal.class);
- final int webviewUid = pmInternal.getPackageUidInternal(
- webViewPackageName, 0, UserHandle.getUserId(callingUid));
+ final int webviewUid = pmInternal.getPackageUid(
+ webViewPackageName, 0 /* flags */, UserHandle.getUserId(callingUid));
pmInternal.grantImplicitAccess(UserHandle.getUserId(callingUid), null,
UserHandle.getAppId(callingUid), webviewUid,
true /*direct*/);
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 1536473..4c2d0d0 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 @@
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 @@
}
// 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 @@
// 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 @@
// 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 64fa6ca..964de13 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1334,7 +1334,7 @@
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 @@
: inMultiWindowMode()
? task.getBounds()
: getRootTask().getParent().getBounds();
- mLetterbox.layout(spaceToFill, w.getFrameLw(), mTmpPoint);
+ mLetterbox.layout(spaceToFill, w.getFrame(), mTmpPoint);
} else if (mLetterbox != null) {
mLetterbox.hide();
}
@@ -2786,8 +2786,7 @@
}
makeFinishingLocked();
- final boolean activityRemoved = destroyImmediately(true /* removeFromApp */,
- "finish-imm:" + reason);
+ final boolean activityRemoved = destroyImmediately("finish-imm:" + reason);
// If the display does not have running activity, the configuration may need to be
// updated for restoring original orientation of the display.
@@ -2835,7 +2834,7 @@
* @return {@code true} if activity was immediately removed from history, {@code false}
* otherwise.
*/
- boolean destroyImmediately(boolean removeFromApp, String reason) {
+ boolean destroyImmediately(String reason) {
if (DEBUG_SWITCH || DEBUG_CLEANUP) {
Slog.v(TAG_SWITCH, "Removing activity from " + reason + ": token=" + this
+ ", app=" + (hasProcess() ? app.mName : "(null)"));
@@ -2857,17 +2856,9 @@
cleanUp(false /* cleanServices */, false /* setState */);
if (hasProcess()) {
- if (removeFromApp) {
- 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 */);
- }
+ app.removeActivity(this, true /* keepAssociation */);
+ if (!app.hasActivities()) {
+ mAtmService.clearHeavyWeightProcessIfEquals(app);
}
boolean skipDestroy = false;
@@ -2934,7 +2925,7 @@
+ " pausing=" + stack.mPausingActivity
+ " for reason " + reason);
}
- return destroyImmediately(true /* removeFromApp */, reason);
+ return destroyImmediately(reason);
}
return false;
}
@@ -4305,7 +4296,7 @@
} 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;
}
@@ -4487,16 +4478,40 @@
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;
}
}
@@ -4664,7 +4679,7 @@
// case where this is the top activity in a pinned stack.
final boolean isTop = this == stack.getTopNonFinishingActivity();
final boolean isTopNotPinnedStack = stack.isAttached()
- && stack.getDisplayArea().isTopNotPinnedStack(stack);
+ && stack.getDisplayArea().isTopNotFinishNotPinnedStack(stack);
final boolean visibleIgnoringDisplayStatus = stack.checkKeyguardVisibility(this,
visibleIgnoringKeyguard, isTop && isTopNotPinnedStack);
@@ -4806,6 +4821,7 @@
Slog.v(TAG_VISIBILITY, "Start visible activity, " + this);
}
setState(STARTED, "makeActiveIfNeeded");
+
try {
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
StartActivityItem.obtain());
@@ -5113,7 +5129,7 @@
if (DEBUG_STATES) Slog.v(TAG_STATES, "Stop failed; moving to STOPPED: " + this);
setState(STOPPED, "stopIfPossible");
if (deferRelaunchUntilPaused) {
- destroyImmediately(true /* removeFromApp */, "stop-except");
+ destroyImmediately("stop-except");
}
}
}
@@ -5154,7 +5170,7 @@
clearOptionsLocked();
} else {
if (deferRelaunchUntilPaused) {
- destroyImmediately(true /* removeFromApp */, "stop-config");
+ destroyImmediately("stop-config");
mRootWindowContainer.resumeFocusedStacksTopActivities();
} else {
mRootWindowContainer.updatePreviousProcess(this);
@@ -5580,9 +5596,9 @@
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()
@@ -5597,7 +5613,7 @@
if (findMainWindow(false /* includeStartingApp */) != w) {
mNumInterestingWindows++;
}
- if (w.isDrawnLw()) {
+ if (w.isDrawn()) {
mNumDrawnWindows++;
if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) {
@@ -5610,7 +5626,7 @@
isInterestingAndDrawn = true;
}
}
- } else if (w.isDrawnLw()) {
+ } else if (w.isDrawn()) {
// The starting window for this container is drawn.
mStackSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(this);
startingDisplayed = true;
@@ -6139,7 +6155,7 @@
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;
@@ -6165,7 +6181,7 @@
// 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();
@@ -7104,7 +7120,7 @@
if (!attachedToProcess()) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Config is destroying non-running " + this);
- destroyImmediately(true /* removeFromApp */, "config");
+ 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.
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 2c475e0..34f7f79 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -41,10 +41,8 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static android.os.Process.INVALID_UID;
-import static android.os.Process.SYSTEM_UID;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Display.TYPE_VIRTUAL;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
@@ -1869,7 +1867,7 @@
for (int i = 0; i < numFinishingActivities; i++) {
final ActivityRecord r = finishingActivities.get(i);
if (r.isInHistory()) {
- r.destroyImmediately(true /* removeFromApp */, "finish-" + reason);
+ r.destroyImmediately("finish-" + reason);
}
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index f615838..4c93b9e 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1693,8 +1693,9 @@
// we need to resolve resultTo to a uid as grantImplicitAccess deals explicitly in UIDs
final PackageManagerInternal pmInternal =
mService.getPackageManagerInternalLocked();
- final int resultToUid = pmInternal.getPackageUidInternal(
- mStartActivity.resultTo.info.packageName, 0, mStartActivity.mUserId);
+ final int resultToUid = pmInternal.getPackageUid(
+ mStartActivity.resultTo.info.packageName, 0 /* flags */,
+ mStartActivity.mUserId);
pmInternal.grantImplicitAccess(mStartActivity.mUserId, mIntent,
UserHandle.getAppId(mStartActivity.info.applicationInfo.uid) /*recipient*/,
resultToUid /*visible*/, true /*direct*/);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 403f225..2adaa52 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3379,7 +3379,7 @@
if (r == null || !r.isDestroyable()) {
return false;
}
- r.destroyImmediately(true /* removeFromApp */, "app-req");
+ r.destroyImmediately("app-req");
return r.isState(DESTROYING, DESTROYED);
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java
index c144755..8568d5f 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 @@
}
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 @@
}
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 @@
} 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/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2e87981..2f7cc69 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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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",
@@ -3982,9 +3982,6 @@
mDisplayFrames.onDisplayInfoUpdated(mDisplayInfo,
calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
- // TODO: Not sure if we really need to set the rotation here since we are updating from
- // the display info above...
- mDisplayFrames.mRotation = getRotation();
mDisplayPolicy.beginLayoutLw(mDisplayFrames, getConfiguration().uiMode);
int seq = mLayoutSeq + 1;
@@ -4602,9 +4599,9 @@
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 2e03cb8..1c147c2 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.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;
@@ -246,6 +246,9 @@
| View.STATUS_BAR_TRANSPARENT
| View.NAVIGATION_BAR_TRANSPARENT;
+ private static final int[] SHOW_TYPES_FOR_SWIPE = {ITYPE_NAVIGATION_BAR, ITYPE_STATUS_BAR};
+ private static final int[] SHOW_TYPES_FOR_PANIC = {ITYPE_NAVIGATION_BAR};
+
private final WindowManagerService mService;
private final Context mContext;
private final Context mUiContext;
@@ -413,7 +416,7 @@
private boolean mAllowLockscreenWhenOn;
@VisibleForTesting
- InputConsumer mInputConsumer = null;
+ EventReceiverInputConsumer mInputConsumer;
private PointerLocationView mPointerLocationView;
@@ -459,7 +462,7 @@
}
break;
case MSG_DISPOSE_INPUT_CONSUMER:
- disposeInputConsumer((InputConsumer) msg.obj);
+ disposeInputConsumer((EventReceiverInputConsumer) msg.obj);
break;
case MSG_ENABLE_POINTER_LOCATION:
enablePointerLocation();
@@ -1123,7 +1126,7 @@
// 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) -> {
@@ -1200,11 +1203,11 @@
// 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);
}
};
}
@@ -2072,7 +2075,7 @@
// 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
@@ -2093,14 +2096,14 @@
// 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()) {
@@ -2108,11 +2111,11 @@
}
}
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) {
@@ -2214,8 +2217,8 @@
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);
@@ -2620,12 +2623,10 @@
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);
}
}
@@ -2642,8 +2643,8 @@
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
@@ -2655,8 +2656,8 @@
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="
@@ -2664,8 +2665,8 @@
}
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);
}
@@ -2726,8 +2727,7 @@
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;
}
@@ -2913,7 +2913,7 @@
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
@@ -3353,8 +3353,15 @@
return;
}
+ final InsetsState requestedState = controlTarget.getRequestedInsetsState();
+ final @InsetsType int restorePositionTypes =
+ (requestedState.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)
+ ? Type.navigationBars() : 0)
+ | (requestedState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR)
+ ? Type.statusBars() : 0);
+
if (swipeTarget == mNavigationBar
- && !getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)) {
+ && (restorePositionTypes & Type.navigationBars()) != 0) {
// Don't show status bar when swiping on already visible navigation bar.
// But restore the position of navigation bar if it has been moved by the control
// target.
@@ -3362,14 +3369,13 @@
return;
}
- int insetsTypesToShow = Type.systemBars();
-
if (controlTarget.canShowTransient()) {
- insetsTypesToShow &= ~mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
- new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
- }
- if (insetsTypesToShow != 0) {
- controlTarget.showInsets(insetsTypesToShow, false);
+ // Show transient bars if they are hidden; restore position if they are visible.
+ mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_SWIPE);
+ controlTarget.showInsets(restorePositionTypes, false);
+ } else {
+ // Restore visibilities and positions of system bars.
+ controlTarget.showInsets(Type.statusBars() | Type.navigationBars(), false);
}
} else {
boolean sb = mStatusBarController.checkShowTransientBarLw();
@@ -3389,7 +3395,7 @@
mImmersiveModeConfirmation.confirmCurrentPrompt();
}
- private void disposeInputConsumer(InputConsumer inputConsumer) {
+ private void disposeInputConsumer(EventReceiverInputConsumer inputConsumer) {
if (inputConsumer != null) {
inputConsumer.dispose();
}
@@ -3770,8 +3776,7 @@
// we're no longer on the Keyguard and the screen is ready. We can now request the bars.
mPendingPanicGestureUptime = 0;
if (!isNavBarEmpty(vis)) {
- mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
- new int[] {ITYPE_NAVIGATION_BAR}));
+ mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_PANIC);
}
}
@@ -4163,6 +4168,6 @@
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/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 133b111..c9f463b 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -283,8 +283,9 @@
mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
mDragWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
mDragWindowHandle.visible = true;
- mDragWindowHandle.canReceiveKeys = false;
- mDragWindowHandle.hasFocus = true;
+ // Allows the system to consume keys when dragging is active. This can also be used to
+ // modify the drag state on key press. Example, cancel drag on escape key.
+ mDragWindowHandle.focusable = true;
mDragWindowHandle.hasWallpaper = false;
mDragWindowHandle.paused = false;
mDragWindowHandle.ownerPid = Process.myPid();
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 86e2698..f0f3385 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 @@
|| (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/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 3b24584b..a79d3bb 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -80,8 +80,7 @@
mWindowHandle.layoutParamsFlags = 0;
mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
mWindowHandle.visible = true;
- mWindowHandle.canReceiveKeys = false;
- mWindowHandle.hasFocus = false;
+ mWindowHandle.focusable = false;
mWindowHandle.hasWallpaper = false;
mWindowHandle.paused = false;
mWindowHandle.ownerPid = Process.myPid();
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 0fe9735..fb511e0 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.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 @@
*/
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 @@
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 @@
}
}
- @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,8 +227,13 @@
}
}
- 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
+ + ", display: " + mDisplayId);
+ }
+
if (mInputConsumers.containsKey(name)) {
throw new IllegalStateException("Existing input consumer found with name: " + name
+ ", display: " + mDisplayId);
@@ -256,6 +263,11 @@
// stack, and we need FLAG_NOT_TOUCH_MODAL to ensure other events fall through
consumer.mWindowHandle.layoutParamsFlags |= FLAG_NOT_TOUCH_MODAL;
break;
+ case INPUT_CONSUMER_RECENTS_ANIMATION:
+ break;
+ default:
+ throw new IllegalArgumentException("Illegal input consumer : " + name
+ + ", display: " + mDisplayId);
}
addInputConsumer(name, consumer);
}
@@ -271,8 +283,7 @@
inputWindowHandle.layoutParamsType = type;
inputWindowHandle.dispatchingTimeoutMillis = child.getInputDispatchingTimeoutMillis();
inputWindowHandle.visible = isVisible;
- inputWindowHandle.canReceiveKeys = child.canReceiveKeys();
- inputWindowHandle.hasFocus = hasFocus;
+ inputWindowHandle.focusable = hasFocus;
inputWindowHandle.hasWallpaper = hasWallpaper;
inputWindowHandle.paused = child.mActivityRecord != null ? child.mActivityRecord.paused : false;
inputWindowHandle.ownerPid = child.mSession.mPid;
@@ -280,7 +291,7 @@
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;
@@ -463,9 +474,6 @@
mDisplayContent.forAllWindows(this,
true /* traverseTopToBottom */);
- if (mAddWallpaperInputConsumerHandle) {
- mWallpaperInputConsumer.show(mInputTransaction, 0);
- }
if (!mUpdateInputWindowsImmediately) {
mDisplayContent.getPendingTransaction().merge(mInputTransaction);
mDisplayContent.scheduleAnimation();
@@ -572,8 +580,7 @@
inputWindowHandle.layoutParamsType = type;
inputWindowHandle.dispatchingTimeoutMillis = 0; // it should never receive input
inputWindowHandle.visible = isVisible;
- inputWindowHandle.canReceiveKeys = false;
- inputWindowHandle.hasFocus = false;
+ inputWindowHandle.focusable = false;
inputWindowHandle.inputFeatures = INPUT_FEATURE_NO_INPUT_CHANNEL;
inputWindowHandle.scaleFactor = 1;
inputWindowHandle.layoutParamsFlags =
diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java
index 3ffc26a..5e7ed3f 100644
--- a/services/core/java/com/android/server/wm/InsetsControlTarget.java
+++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import android.inputmethodservice.InputMethodService;
+import android.view.InsetsState;
import android.view.WindowInsets.Type.InsetsType;
/**
@@ -38,6 +39,13 @@
}
/**
+ * @return The requested {@link InsetsState} of this target.
+ */
+ default InsetsState getRequestedInsetsState() {
+ return InsetsState.EMPTY;
+ }
+
+ /**
* Instructs the control target to show inset sources.
*
* @param types to specify which types of insets source window should be shown.
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index b7287e7..18a2503 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -42,7 +42,6 @@
import android.view.SurfaceControl;
import android.view.SyncRtSurfaceTransactionApplier;
import android.view.ViewRootImpl;
-import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimation;
import android.view.WindowInsetsAnimation.Bounds;
import android.view.WindowInsetsAnimationControlListener;
@@ -153,15 +152,13 @@
return provider != null && provider.hasWindow() && !provider.getSource().isVisible();
}
- @InsetsType int showTransient(IntArray types) {
- @InsetsType int showingTransientTypes = 0;
+ void showTransient(@InternalInsetsType int[] types) {
boolean changed = false;
- for (int i = types.size() - 1; i >= 0; i--) {
- final int type = types.get(i);
+ for (int i = types.length - 1; i >= 0; i--) {
+ final @InternalInsetsType int type = types[i];
if (!isHidden(type)) {
continue;
}
- showingTransientTypes |= InsetsState.toPublicType(type);
if (mShowingTransientTypes.indexOf(type) != -1) {
continue;
}
@@ -189,7 +186,6 @@
}
});
}
- return showingTransientTypes;
}
void hideTransient() {
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index d1eb795..e00c9e7 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 @@
// 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 @@
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/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 143fbb0..6882dc4 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -821,7 +821,7 @@
: null;
if (targetAppMainWindow != null) {
targetAppMainWindow.getBounds(mTmpRect);
- inputWindowHandle.hasFocus = hasFocus;
+ inputWindowHandle.focusable = hasFocus;
inputWindowHandle.touchableRegion.set(mTmpRect);
return true;
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index aeaffd9..21e30ce 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 @@
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;
@@ -2716,7 +2716,7 @@
+ " resumed=" + r.getStack().mResumedActivity + " pausing="
+ r.getStack().mPausingActivity + " for reason " + mDestroyAllActivitiesReason);
- r.destroyImmediately(true /* removeFromTask */, mDestroyAllActivitiesReason);
+ r.destroyImmediately(mDestroyAllActivitiesReason);
}
// Tries to put all activity stacks to sleep. Returns true if all stacks were
@@ -3124,7 +3124,6 @@
FinishDisabledPackageActivitiesHelper mFinishDisabledPackageActivitiesHelper =
new FinishDisabledPackageActivitiesHelper();
class FinishDisabledPackageActivitiesHelper {
- private boolean mDidSomething;
private String mPackageName;
private Set<String> mFilterByClasses;
private boolean mDoit;
@@ -3132,11 +3131,10 @@
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 @@
mUserId = userId;
mOnlyRemoveNoProcess = onlyRemoveNoProcess;
mLastTask = null;
- mHomeActivity = null;
}
boolean process(String packageName, Set<String> filterByClasses,
@@ -3152,14 +3149,35 @@
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 @@
}
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/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 3c8036d..25732e7 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -101,7 +101,6 @@
private final Transformation mRotateExitTransformation = new Transformation();
private final Transformation mRotateEnterTransformation = new Transformation();
// Complete transformations being applied.
- private final Transformation mEnterTransformation = new Transformation();
private final Matrix mSnapshotInitialMatrix = new Matrix();
private final WindowManagerService mService;
/** Only used for custom animations and not screen rotation. */
@@ -309,8 +308,6 @@
pw.print(" "); mRotateExitTransformation.printShortString(pw); pw.println();
pw.print(prefix); pw.print("mRotateEnterAnimation="); pw.print(mRotateEnterAnimation);
pw.print(" "); mRotateEnterTransformation.printShortString(pw); pw.println();
- pw.print(prefix); pw.print("mEnterTransformation=");
- mEnterTransformation.printShortString(pw); pw.println();
pw.print(prefix); pw.print("mSnapshotInitialMatrix=");
mSnapshotInitialMatrix.dump(pw); pw.println();
pw.print(prefix); pw.print("mForceDefaultOrientation="); pw.print(mForceDefaultOrientation);
@@ -508,10 +505,6 @@
return mCurRotation != mOriginalRotation;
}
- public Transformation getEnterTransformation() {
- return mEnterTransformation;
- }
-
/**
* Utility class that runs a {@link ScreenRotationAnimation} on the {@link
* SurfaceAnimationRunner}.
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 0529abf..e77a535 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -783,7 +783,7 @@
* taskAppeared callback, and emit a taskRemoved callback when the Task is vanished.
*/
ITaskOrganizer mTaskOrganizer;
- private int mLastTaskOrganizerWindowingMode = -1;
+
/**
* Prevent duplicate calls to onTaskAppeared.
*/
@@ -798,6 +798,7 @@
* organizer for ordering purposes.</li>
* </ul>
*/
+ @VisibleForTesting
boolean mCreatedByOrganizer;
/**
@@ -2788,8 +2789,16 @@
// For calculating screen layout, we need to use the non-decor inset screen area for the
// calculation for compatibility reasons, i.e. screen area without system bars that
// could never go away in Honeycomb.
- final int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density);
- final int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
+ int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density);
+ int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
+ // Use overrides if provided. If both overrides are provided, mTmpNonDecorBounds is
+ // undefined so it can't be used.
+ if (inOutConfig.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
+ compatScreenWidthDp = inOutConfig.screenWidthDp;
+ }
+ if (inOutConfig.screenHeightDp != Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
+ compatScreenHeightDp = inOutConfig.screenHeightDp;
+ }
// Reducing the screen layout starting from its parent config.
inOutConfig.screenLayout = computeScreenLayoutOverride(parentConfig.screenLayout,
compatScreenWidthDp, compatScreenHeightDp);
@@ -3820,7 +3829,10 @@
@Override
boolean fillsParent() {
- return matchParentBounds();
+ // From the perspective of policy, we still want to report that this task fills parent
+ // in fullscreen windowing mode even it doesn't match parent bounds because there will be
+ // letterbox around its real content.
+ return getWindowingMode() == WINDOWING_MODE_FULLSCREEN || matchParentBounds();
}
@Override
@@ -4820,19 +4832,18 @@
return false;
}
- ITaskOrganizer previousOrganizer = mTaskOrganizer;
+ ITaskOrganizer prevOrganizer = mTaskOrganizer;
// Update the new task organizer before calling sendTaskVanished since it could result in
// a new SurfaceControl getting created that would notify the old organizer about it.
mTaskOrganizer = organizer;
// Let the old organizer know it has lost control.
- sendTaskVanished(previousOrganizer);
+ sendTaskVanished(prevOrganizer);
if (mTaskOrganizer != null) {
sendTaskAppeared();
} else {
// No longer managed by any organizer.
mTaskAppearedSent = false;
- mLastTaskOrganizerWindowingMode = -1;
setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, false /* set */);
if (mCreatedByOrganizer) {
removeImmediately();
@@ -4853,29 +4864,16 @@
*/
boolean updateTaskOrganizerState(boolean forceUpdate) {
if (!isRootTask()) {
- final boolean result = setTaskOrganizer(null);
- mLastTaskOrganizerWindowingMode = -1;
- return result;
+ return setTaskOrganizer(null);
}
final int windowingMode = getWindowingMode();
- if (!forceUpdate && windowingMode == mLastTaskOrganizerWindowingMode) {
- // If our windowing mode hasn't actually changed, then just stick
- // with our old organizer. This lets us implement the semantic
- // where SysUI can continue to manage it's old tasks
- // while CTS temporarily takes over the registration.
+ final TaskOrganizerController controller = mWmService.mAtmService.mTaskOrganizerController;
+ final ITaskOrganizer organizer = controller.getTaskOrganizer(windowingMode);
+ if (!forceUpdate && mTaskOrganizer == organizer) {
return false;
}
- /*
- * Different windowing modes may be managed by different task organizers. If
- * getTaskOrganizer returns null, we still call setTaskOrganizer to
- * make sure we clear it.
- */
- final ITaskOrganizer org =
- mWmService.mAtmService.mTaskOrganizerController.getTaskOrganizer(windowingMode);
- final boolean result = setTaskOrganizer(org);
- mLastTaskOrganizerWindowingMode = org != null ? windowingMode : -1;
- return result;
+ return setTaskOrganizer(organizer);
}
@Override
@@ -6192,10 +6190,6 @@
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;
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 3251110..6550167 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -1489,9 +1489,13 @@
return stack == getTopStack();
}
- boolean isTopNotPinnedStack(Task stack) {
+ boolean isTopNotFinishNotPinnedStack(Task stack) {
for (int i = getStackCount() - 1; i >= 0; --i) {
final Task current = getStackAt(i);
+ final ActivityRecord topAct = current.getTopNonFinishingActivity();
+ if (topAct == null) {
+ continue;
+ }
if (!current.inPinnedWindowingMode()) {
return current == stack;
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 04d134c..f8465dd 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -20,6 +20,8 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_CONFIGS;
import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_WINDOW_CONFIGS;
@@ -35,7 +37,6 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
-import android.util.SparseArray;
import android.view.SurfaceControl;
import android.window.ITaskOrganizer;
import android.window.ITaskOrganizerController;
@@ -46,9 +47,12 @@
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
+import java.util.Set;
import java.util.WeakHashMap;
import java.util.function.Consumer;
@@ -58,7 +62,6 @@
*/
class TaskOrganizerController extends ITaskOrganizerController.Stub {
private static final String TAG = "TaskOrganizerController";
- private static final LinkedList<IBinder> EMPTY_LIST = new LinkedList<>();
/**
* Masks specifying which configurations are important to report back to an organizer when
@@ -67,6 +70,16 @@
private static final int REPORT_CONFIGS = CONTROLLABLE_CONFIGS;
private static final int REPORT_WINDOW_CONFIGS = CONTROLLABLE_WINDOW_CONFIGS;
+ // The set of modes that are currently supports
+ // TODO: Remove once the task organizer can support all modes
+ @VisibleForTesting
+ static final int[] SUPPORTED_WINDOWING_MODES = {
+ WINDOWING_MODE_PINNED,
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
+ WINDOWING_MODE_MULTI_WINDOW,
+ };
+
private final WindowManagerGlobalLock mGlobalLock;
private class DeathRecipient implements IBinder.DeathRecipient {
@@ -233,9 +246,7 @@
void dispose() {
// Move organizer from managing specific windowing modes
- for (int i = mTaskOrganizersForWindowingMode.size() - 1; i >= 0; --i) {
- mTaskOrganizersForWindowingMode.valueAt(i).remove(mOrganizer.getBinder());
- }
+ mTaskOrganizers.remove(mOrganizer.mTaskOrganizer);
// Update tasks currently managed by this organizer to the next one available if
// possible.
@@ -257,8 +268,8 @@
}
}
- private final SparseArray<LinkedList<IBinder>> mTaskOrganizersForWindowingMode =
- new SparseArray<>();
+ // List of task organizers by priority
+ private final LinkedList<ITaskOrganizer> mTaskOrganizers = new LinkedList<>();
private final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap<>();
private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>();
@@ -285,59 +296,28 @@
public void setDeferTaskOrgCallbacksConsumer(Consumer<Runnable> consumer) {
mDeferTaskOrgCallbacksConsumer = consumer;
}
-
/**
- * Register a TaskOrganizer to manage tasks as they enter the given windowing mode.
- * If there was already a TaskOrganizer for this windowing mode it will be evicted
- * but will continue to organize it's existing tasks.
+ * Register a TaskOrganizer to manage tasks as they enter the a supported windowing mode.
*/
@Override
- public void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode) {
- if (windowingMode == WINDOWING_MODE_PINNED) {
- if (!mService.mSupportsPictureInPicture) {
- throw new UnsupportedOperationException("Picture in picture is not supported on "
- + "this device");
- }
- } else if (WindowConfiguration.isSplitScreenWindowingMode(windowingMode)) {
- if (!mService.mSupportsSplitScreenMultiWindow) {
- throw new UnsupportedOperationException("Split-screen is not supported on this "
- + "device");
- }
- } else if (windowingMode == WINDOWING_MODE_MULTI_WINDOW) {
- if (!mService.mSupportsMultiWindow) {
- throw new UnsupportedOperationException("Multi-window is not supported on this "
- + "device");
- }
- } else {
- throw new UnsupportedOperationException("As of now only Pinned/Split/Multiwindow"
- + " windowing modes are supported for registerTaskOrganizer");
- }
+ public void registerTaskOrganizer(ITaskOrganizer organizer) {
enforceStackPermission("registerTaskOrganizer()");
final int uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- if (getTaskOrganizer(windowingMode) != null) {
- Slog.w(TAG, "Task organizer already exists for windowing mode: "
- + windowingMode);
- }
-
- LinkedList<IBinder> orgs = mTaskOrganizersForWindowingMode.get(windowingMode);
- if (orgs == null) {
- orgs = new LinkedList<>();
- mTaskOrganizersForWindowingMode.put(windowingMode, orgs);
- }
- orgs.add(organizer.asBinder());
- if (!mTaskOrganizerStates.containsKey(organizer.asBinder())) {
- mTaskOrganizerStates.put(organizer.asBinder(),
- new TaskOrganizerState(organizer, uid));
- }
-
- mService.mRootWindowContainer.forAllTasks((task) -> {
- if (task.getWindowingMode() == windowingMode) {
- task.updateTaskOrganizerState(true /* forceUpdate */);
+ for (int winMode : SUPPORTED_WINDOWING_MODES) {
+ if (!mTaskOrganizerStates.containsKey(organizer.asBinder())) {
+ mTaskOrganizers.add(organizer);
+ mTaskOrganizerStates.put(organizer.asBinder(),
+ new TaskOrganizerState(organizer, uid));
}
- });
+ mService.mRootWindowContainer.forAllTasks((task) -> {
+ if (task.getWindowingMode() == winMode) {
+ task.updateTaskOrganizerState(true /* forceUpdate */);
+ }
+ });
+ }
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -362,17 +342,22 @@
}
}
+ /**
+ * @return the task organizer key for a given windowing mode.
+ */
ITaskOrganizer getTaskOrganizer(int windowingMode) {
- final IBinder organizer =
- mTaskOrganizersForWindowingMode.get(windowingMode, EMPTY_LIST).peekLast();
- if (organizer == null) {
- return null;
+ return isSupportedWindowingMode(windowingMode)
+ ? mTaskOrganizers.peekLast()
+ : null;
+ }
+
+ private boolean isSupportedWindowingMode(int winMode) {
+ for (int i = 0; i < SUPPORTED_WINDOWING_MODES.length; i++) {
+ if (SUPPORTED_WINDOWING_MODES[i] == winMode) {
+ return true;
+ }
}
- final TaskOrganizerState state = mTaskOrganizerStates.get(organizer);
- if (state == null) {
- return null;
- }
- return state.mOrganizer.mTaskOrganizer;
+ return false;
}
void onTaskAppeared(ITaskOrganizer organizer, Task task) {
@@ -458,6 +443,8 @@
|| mTmpTaskInfo.topActivityType != lastInfo.topActivityType
|| mTmpTaskInfo.isResizeable != lastInfo.isResizeable
|| mTmpTaskInfo.pictureInPictureParams != lastInfo.pictureInPictureParams
+ || mTmpTaskInfo.getConfiguration().windowConfiguration.getWindowingMode()
+ != lastInfo.getConfiguration().windowConfiguration.getWindowingMode()
|| !TaskDescription.equals(mTmpTaskInfo.taskDescription, lastInfo.taskDescription);
if (!changed) {
int cfgChanges = mTmpTaskInfo.configuration.diff(lastInfo.configuration);
@@ -655,18 +642,19 @@
final String innerPrefix = prefix + " ";
pw.print(prefix); pw.println("TaskOrganizerController:");
pw.print(innerPrefix); pw.println("Per windowing mode:");
- for (int i = 0; i < mTaskOrganizersForWindowingMode.size(); i++) {
- final int windowingMode = mTaskOrganizersForWindowingMode.keyAt(i);
- final List<IBinder> taskOrgs = mTaskOrganizersForWindowingMode.valueAt(i);
+ for (int i = 0; i < SUPPORTED_WINDOWING_MODES.length; i++) {
+ final int windowingMode = SUPPORTED_WINDOWING_MODES[i];
pw.println(innerPrefix + " "
+ WindowConfiguration.windowingModeToString(windowingMode) + ":");
- for (int j = 0; j < taskOrgs.size(); j++) {
- final TaskOrganizerState state = mTaskOrganizerStates.get(taskOrgs.get(j));
+ for (final TaskOrganizerState state : mTaskOrganizerStates.values()) {
final ArrayList<Task> tasks = state.mOrganizedTasks;
pw.print(innerPrefix + " ");
pw.println(state.mOrganizer.mTaskOrganizer + " uid=" + state.mUid + ":");
for (int k = 0; k < tasks.size(); k++) {
- pw.println(innerPrefix + " " + tasks.get(k));
+ final Task task = tasks.get(k);
+ if (windowingMode == task.getWindowingMode()) {
+ pw.println(innerPrefix + " " + task);
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index a66cd84..f32781a 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -242,8 +242,8 @@
mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
mDragWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
mDragWindowHandle.visible = true;
- mDragWindowHandle.canReceiveKeys = false;
- mDragWindowHandle.hasFocus = true;
+ // When dragging the window around, we do not want to steal focus for the window.
+ mDragWindowHandle.focusable = false;
mDragWindowHandle.hasWallpaper = false;
mDragWindowHandle.paused = false;
mDragWindowHandle.ownerPid = Process.myPid();
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index dbbb7ff..e3112ef 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 @@
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/UnknownAppVisibilityController.java b/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
index 61e9e50..5e81e40 100644
--- a/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
+++ b/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
@@ -24,8 +24,6 @@
import android.util.ArrayMap;
import android.util.Slog;
-import com.android.server.wm.WindowManagerService.H;
-
import java.io.PrintWriter;
/**
@@ -102,7 +100,13 @@
if (DEBUG_UNKNOWN_APP_VISIBILITY) {
Slog.d(TAG, "App launched activity=" + activity);
}
- mUnknownApps.put(activity, UNKNOWN_STATE_WAITING_RESUME);
+ // If the activity was started with launchTaskBehind, the lifecycle will goes to paused
+ // directly, and the process will pass onResume, so we don't need to waiting resume for it.
+ if (!activity.mLaunchTaskBehind) {
+ mUnknownApps.put(activity, UNKNOWN_STATE_WAITING_RESUME);
+ } else {
+ mUnknownApps.put(activity, UNKNOWN_STATE_WAITING_RELAYOUT);
+ }
}
/**
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 6e00ab4..ce13867 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 @@
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 @@
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 cd222a9..c45ccb6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
+import static android.Manifest.permission.INPUT_CONSUMER;
import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.MANAGE_APP_TOKENS;
@@ -929,7 +930,7 @@
private void setShadowRenderer() {
mRenderShadowsInCompositor = Settings.Global.getInt(mContext.getContentResolver(),
- DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 0) != 0;
+ DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 1) != 0;
}
PowerManager mPowerManager;
@@ -1847,7 +1848,7 @@
}
// 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();
@@ -2068,7 +2069,7 @@
outDisplayFrame.setEmpty();
return;
}
- outDisplayFrame.set(win.getDisplayFrameLw());
+ outDisplayFrame.set(win.getDisplayFrame());
if (win.inSizeCompatMode()) {
outDisplayFrame.scale(win.mInvGlobalScale);
}
@@ -2388,7 +2389,7 @@
if (displayPolicy.areSystemBarsForcedShownLw(win)) {
result |= WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS;
}
- if (!win.isGoneForLayoutLw()) {
+ if (!win.isGoneForLayout()) {
win.mResizedWhileGone = false;
}
@@ -2418,7 +2419,7 @@
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()
@@ -2882,11 +2883,6 @@
}
@Override
- public WindowManagerPolicy.WindowState getInputMethodWindowLw() {
- return mRoot.getCurrentInputMethodWindow();
- }
-
- @Override
public void notifyKeyguardTrustedChanged() {
mAtmInternal.notifyKeyguardTrustedChanged();
}
@@ -5480,7 +5476,7 @@
// 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);
@@ -5861,6 +5857,11 @@
@Override
public void createInputConsumer(IBinder token, String name, int displayId,
InputChannel inputChannel) {
+ if (!mAtmInternal.isCallerRecents(Binder.getCallingUid())
+ && mContext.checkCallingOrSelfPermission(INPUT_CONSUMER) != PERMISSION_GRANTED) {
+ throw new SecurityException("createInputConsumer requires INPUT_CONSUMER permission");
+ }
+
synchronized (mGlobalLock) {
DisplayContent display = mRoot.getDisplayContent(displayId);
if (display != null) {
@@ -5872,6 +5873,11 @@
@Override
public boolean destroyInputConsumer(String name, int displayId) {
+ if (!mAtmInternal.isCallerRecents(Binder.getCallingUid())
+ && mContext.checkCallingOrSelfPermission(INPUT_CONSUMER) != PERMISSION_GRANTED) {
+ throw new SecurityException("destroyInputConsumer requires INPUT_CONSUMER permission");
+ }
+
synchronized (mGlobalLock) {
DisplayContent display = mRoot.getDisplayContent(displayId);
if (display != null) {
@@ -7345,7 +7351,7 @@
synchronized (mGlobalLock) {
WindowState windowState = mWindowMap.get(token);
if (windowState != null) {
- outBounds.set(windowState.getFrameLw());
+ outBounds.set(windowState.getFrame());
} else {
outBounds.setEmpty();
}
@@ -8065,8 +8071,7 @@
h.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | sanitizedFlags;
h.layoutParamsType = type;
h.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
- h.canReceiveKeys = false;
- h.hasFocus = false;
+ h.focusable = false;
h.hasWallpaper = false;
h.paused = false;
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index c714eeb..bb9cf2e 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -941,7 +941,7 @@
final ActivityRecord r = candidates.remove(0);
if (DEBUG_RELEASE) Slog.v(TAG_RELEASE, "Destroying " + r
+ " in state " + r.getState() + " for reason " + reason);
- r.destroyImmediately(true /*removeFromApp*/, reason);
+ r.destroyImmediately(reason);
--maxRelease;
} while (maxRelease > 0);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 49e623d..9ff33b1 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -728,7 +728,8 @@
* @return The insets state as requested by the client, i.e. the dispatched insets state
* for which the visibilities are overridden with what the client requested.
*/
- InsetsState getRequestedInsetsState() {
+ @Override
+ public InsetsState getRequestedInsetsState() {
return mRequestedInsetsState;
}
@@ -1008,8 +1009,8 @@
getDisplayContent().reapplyMagnificationSpec();
}
- @Override
- public int getOwningUid() {
+ /** Returns the uid of the app that owns this window. */
+ int getOwningUid() {
return mOwnerUid;
}
@@ -1023,8 +1024,12 @@
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;
}
@@ -1045,7 +1050,7 @@
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) {
@@ -1053,8 +1058,10 @@
}
}
- @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
@@ -1282,32 +1289,41 @@
}
}
- @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;
}
@@ -1336,32 +1352,17 @@
}
@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;
}
@@ -1375,8 +1376,8 @@
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;
}
@@ -1390,7 +1391,7 @@
*/
void updateResizingWindowIfNeeded() {
final WindowStateAnimator winAnimator = mWinAnimator;
- if (!mHasSurface || getDisplayContent().mLayoutSeq != mLayoutSeq || isGoneForLayoutLw()) {
+ if (!mHasSurface || getDisplayContent().mLayoutSeq != mLayoutSeq || isGoneForLayout()) {
return;
}
@@ -1463,7 +1464,7 @@
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);
@@ -1638,9 +1639,16 @@
: 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) {
@@ -1662,7 +1670,7 @@
@Override
boolean hasContentToDisplay() {
- if (!mAppFreezing && isDrawnLw() && (mViewVisibility == View.VISIBLE
+ if (!mAppFreezing && isDrawn() && (mViewVisibility == View.VISIBLE
|| (isAnimating(TRANSITION | PARENTS)
&& !getDisplayContent().mAppTransition.isTransitionSet()))) {
return true;
@@ -1850,10 +1858,9 @@
* 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));
}
@@ -1866,8 +1873,8 @@
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
@@ -1894,11 +1901,11 @@
}
/**
- * 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);
}
@@ -1913,7 +1920,7 @@
// 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 */
@@ -1928,7 +1935,7 @@
return;
}
if (mAttrs.type == TYPE_APPLICATION_STARTING) {
- if (isDrawnLw()) {
+ if (isDrawn()) {
// Unnecessary to redraw a drawn starting window.
return;
}
@@ -2015,11 +2022,11 @@
@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;
}
@@ -2057,10 +2064,17 @@
// animating... let's do something.
final int left = mWindowFrames.mFrame.left;
final int top = mWindowFrames.mFrame.top;
+
+ // During the transition from pip to fullscreen, the activity windowing mode is set to
+ // fullscreen at the beginning while the task is kept in pinned mode. Skip the move
+ // animation in such case since the transition is handled in SysUI.
+ final boolean hasMovementAnimation = getTask() == null
+ ? getWindowConfiguration().hasMovementAnimations()
+ : getTask().getWindowConfiguration().hasMovementAnimations();
if (mToken.okToAnimate()
&& (mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
&& !isDragResizing()
- && getWindowConfiguration().hasMovementAnimations()
+ && hasMovementAnimation
&& !mWinAnimator.mLastHidden
&& !mSeamlesslyRotated) {
startMoveAnimation(left, top);
@@ -2506,7 +2520,7 @@
/** 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;
@@ -2740,7 +2754,7 @@
mLayoutNeeded = true;
}
- if (isDrawnLw() && mToken.okToAnimate()) {
+ if (isDrawn() && mToken.okToAnimate()) {
mWinAnimator.applyEnterAnimationLocked();
}
}
@@ -2865,8 +2879,8 @@
return getWindowConfiguration().keepVisibleDeadAppWindowOnScreen();
}
- @Override
- public boolean canReceiveKeys() {
+ /** Returns {@code true} if this window desires key events. */
+ boolean canReceiveKeys() {
return canReceiveKeys(false /* fromUserTouch */);
}
@@ -2915,8 +2929,13 @@
&& 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;
}
@@ -3150,8 +3169,8 @@
}
}
- @Override
- public boolean isAlive() {
+ /** Checks whether the process hosting this window is currently alive. */
+ boolean isAlive() {
return mClient.asBinder().isBinderAlive();
}
@@ -3331,16 +3350,6 @@
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() {
@@ -3400,10 +3409,10 @@
// 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;
}
@@ -3561,6 +3570,13 @@
}
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());
}
@@ -3766,11 +3782,11 @@
* 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;
@@ -3874,7 +3890,7 @@
// background.
return (getDisplayContent().mDividerControllerLocked.isResizing()
|| mActivityRecord != null && !mActivityRecord.mFrozenBounds.isEmpty()) &&
- !task.inFreeformWindowingMode() && !isGoneForLayoutLw();
+ !task.inFreeformWindowingMode() && !isGoneForLayout();
}
@@ -4290,7 +4306,7 @@
private boolean isParentWindowGoneForLayout() {
final WindowState parent = getParentWindow();
- return parent != null && parent.isGoneForLayoutLw();
+ return parent != null && parent.isGoneForLayout();
}
void setWillReplaceWindow(boolean animate) {
@@ -4403,8 +4419,7 @@
return null;
}
- @Override
- public int getRotationAnimationHint() {
+ int getRotationAnimationHint() {
if (mActivityRecord != null) {
return mActivityRecord.mRotationAnimationHint;
} else {
@@ -4860,7 +4875,7 @@
}
boolean hasVisibleNotDrawnWallpaper() {
- if (mWallpaperVisible && !isDrawnLw()) {
+ if (mWallpaperVisible && !isDrawn()) {
return true;
}
for (int j = mChildren.size() - 1; j >= 0; --j) {
@@ -4884,9 +4899,9 @@
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
@@ -4897,7 +4912,7 @@
}
results.numInteresting++;
- if (isDrawnLw()) {
+ if (isDrawn()) {
results.numDrawn++;
if (!isAnimating(TRANSITION | PARENTS)) {
results.numVisible++;
@@ -5033,7 +5048,7 @@
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="
@@ -5605,15 +5620,14 @@
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) {
@@ -5676,8 +5690,8 @@
return mWindowFrames.mVisibleInsets;
}
- @Override
- public WindowFrames getWindowFrames() {
+ /** Returns the {@link WindowFrames} associated with this {@link WindowState}. */
+ WindowFrames getWindowFrames() {
return mWindowFrames;
}
@@ -5785,7 +5799,7 @@
// 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 92177ab..1bd712c 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -38,6 +38,7 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
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.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
@@ -525,13 +526,13 @@
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);
}
@@ -659,80 +660,7 @@
}
void computeShownFrameLocked() {
- final ScreenRotationAnimation screenRotationAnimation =
- mWin.getDisplayContent().getRotationAnimation();
- final boolean windowParticipatesInScreenRotationAnimation =
- !mWin.mForceSeamlesslyRotate;
- final boolean screenAnimation = screenRotationAnimation != null
- && screenRotationAnimation.isAnimating()
- && windowParticipatesInScreenRotationAnimation;
-
- if (screenAnimation) {
- // cache often used attributes locally
- final Rect frame = mWin.getFrameLw();
- final float tmpFloats[] = mService.mTmpFloats;
- final Matrix tmpMatrix = mWin.mTmpMatrix;
-
- // Compute the desired transformation.
- if (screenRotationAnimation.isRotating()) {
- // If we are doing a screen animation, the global rotation
- // applied to windows can result in windows that are carefully
- // aligned with each other to slightly separate, allowing you
- // to see what is behind them. An unsightly mess. This...
- // thing... magically makes it call good: scale each window
- // slightly (two pixels larger in each dimension, from the
- // window's center).
- final float w = frame.width();
- final float h = frame.height();
- if (w>=1 && h>=1) {
- tmpMatrix.setScale(1 + 2/w, 1 + 2/h, w/2, h/2);
- } else {
- tmpMatrix.reset();
- }
- } else {
- tmpMatrix.reset();
- }
-
- tmpMatrix.postScale(mWin.mGlobalScale, mWin.mGlobalScale);
-
- // WindowState.prepareSurfaces expands for surface insets (in order they don't get
- // clipped by the WindowState surface), so we need to go into the other direction here.
- tmpMatrix.postTranslate(mWin.mAttrs.surfaceInsets.left,
- mWin.mAttrs.surfaceInsets.top);
-
-
- // "convert" it into SurfaceFlinger's format
- // (a 2x2 matrix + an offset)
- // Here we must not transform the position of the surface
- // since it is already included in the transformation.
- //Slog.i(TAG_WM, "Transform: " + matrix);
-
- mHaveMatrix = true;
- tmpMatrix.getValues(tmpFloats);
- mDsDx = tmpFloats[Matrix.MSCALE_X];
- mDtDx = tmpFloats[Matrix.MSKEW_Y];
- mDtDy = tmpFloats[Matrix.MSKEW_X];
- mDsDy = tmpFloats[Matrix.MSCALE_Y];
-
- // Now set the alpha... but because our current hardware
- // can't do alpha transformation on a non-opaque surface,
- // turn it off if we are running an animation that is also
- // transforming since it is more important to have that
- // animation be smooth.
- mShownAlpha = mAlpha;
- if (!mService.mLimitedAlphaCompositing
- || (!PixelFormat.formatHasAlpha(mWin.mAttrs.format)
- || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDtDy, mDsDy)))) {
- mShownAlpha *= screenRotationAnimation.getEnterTransformation().getAlpha();
- }
-
- if ((DEBUG_ANIM || DEBUG) && (mShownAlpha == 1.0 || mShownAlpha == 0.0)) {
- Slog.v(TAG, "computeShownFrameLocked: Animating " + this + " mAlpha=" + mAlpha
- + " screen=" + (screenAnimation
- ? screenRotationAnimation.getEnterTransformation().getAlpha() : "null"));
- }
- return;
- } else if (mIsWallpaper && mService.mRoot.mWallpaperActionPending) {
+ if (mIsWallpaper && mService.mRoot.mWallpaperActionPending) {
return;
} else if (mWin.isDragResizeChanged()) {
// This window is awaiting a relayout because user just started (or ended)
@@ -968,7 +896,7 @@
// 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);
}
@@ -992,7 +920,7 @@
// 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);
@@ -1070,7 +998,7 @@
}
if (w.getOrientationChanging()) {
- if (!w.isDrawnLw()) {
+ if (!w.isDrawn()) {
mAnimator.mBulkUpdateParams &= ~SET_ORIENTATION_CHANGE_COMPLETE;
mAnimator.mLastWindowFreezeSource = w;
ProtoLog.v(WM_DEBUG_ORIENTATION,
@@ -1327,7 +1255,7 @@
mWin.getDisplayContent().adjustForImeIfNeeded();
}
- return mWin.isAnimating(PARENTS);
+ return mWin.isAnimating(0 /* flags */, ANIMATION_TYPE_WINDOW_ANIMATION);
}
void dumpDebug(ProtoOutputStream proto, long fieldId) {
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index b3f3a5e..9aca848 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -40,14 +40,12 @@
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::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 @@
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 @@
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 @@
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 @@
{"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/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6154bef..22e309c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -302,7 +302,6 @@
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
@@ -322,7 +321,6 @@
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -575,13 +573,11 @@
private final CertificateMonitor mCertificateMonitor;
private final SecurityLogMonitor mSecurityLogMonitor;
+ private final RemoteBugreportManager mBugreportCollectionManager;
@GuardedBy("getLockObject()")
private NetworkLogger mNetworkLogger;
- private final AtomicBoolean mRemoteBugreportServiceIsActive = new AtomicBoolean();
- private final AtomicBoolean mRemoteBugreportSharingAccepted = new AtomicBoolean();
-
private final SetupContentObserver mSetupContentObserver;
private final DevicePolicyConstantsObserver mConstantsObserver;
@@ -633,44 +629,6 @@
@VisibleForTesting
final TransferOwnershipMetadataManager mTransferOwnershipMetadataManager;
- private final Runnable mRemoteBugreportTimeoutRunnable = new Runnable() {
- @Override
- public void run() {
- if(mRemoteBugreportServiceIsActive.get()) {
- onBugreportFailed();
- }
- }
- };
-
- /** Listens only if mHasFeature == true. */
- private final BroadcastReceiver mRemoteBugreportFinishedReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH.equals(intent.getAction())
- && mRemoteBugreportServiceIsActive.get()) {
- onBugreportFinished(intent);
- }
- }
- };
-
- /** Listens only if mHasFeature == true. */
- private final BroadcastReceiver mRemoteBugreportConsentReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- mInjector.getNotificationManager().cancel(LOG_TAG,
- RemoteBugreportUtils.NOTIFICATION_ID);
- if (DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED.equals(action)) {
- onBugreportSharingAccepted();
- } else if (DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED.equals(action)) {
- onBugreportSharingDeclined();
- }
- mContext.unregisterReceiver(mRemoteBugreportConsentReceiver);
- }
- };
-
public static final class Lifecycle extends SystemService {
private BaseIDevicePolicyManager mService;
@@ -748,17 +706,9 @@
}
}
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
- && userHandle == mOwners.getDeviceOwnerUserId()
- && getDeviceOwnerRemoteBugreportUri() != null) {
- IntentFilter filterConsent = new IntentFilter();
- filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED);
- filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED);
- mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
- mInjector.getNotificationManager().notifyAsUser(LOG_TAG,
- RemoteBugreportUtils.NOTIFICATION_ID,
- RemoteBugreportUtils.buildNotification(mContext,
- DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED),
- UserHandle.ALL);
+ && userHandle == mOwners.getDeviceOwnerUserId()) {
+ mBugreportCollectionManager.checkForPendingBugreportAfterBoot();
+
}
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
|| ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
@@ -1435,10 +1385,9 @@
mCertificateMonitor = new CertificateMonitor(this, mInjector, mBackgroundHandler);
mDeviceAdminServiceController = new DeviceAdminServiceController(this, mConstants);
-
mOverlayPackagesProvider = new OverlayPackagesProvider(mContext);
-
mTransferOwnershipMetadataManager = mInjector.newTransferOwnershipMetadataManager();
+ mBugreportCollectionManager = new RemoteBugreportManager(this, mInjector);
if (!mHasFeature) {
// Skip the rest of the initialization
@@ -1566,7 +1515,15 @@
/**
* Creates a new {@link CallerIdentity} object to represent the caller's identity.
*/
- private CallerIdentity getCallerIdentity(String callerPackage) {
+ private CallerIdentity getCallerIdentity() {
+ final int callerUid = mInjector.binderGetCallingUid();
+ return new CallerIdentity(callerUid, null, null);
+ }
+
+ /**
+ * Creates a new {@link CallerIdentity} object to represent the caller's identity.
+ */
+ private CallerIdentity getCallerIdentity(@NonNull String callerPackage) {
final int callerUid = mInjector.binderGetCallingUid();
if (!isCallingFromPackage(callerPackage, callerUid)) {
@@ -2127,6 +2084,81 @@
reqPolicy, /* permission= */ null);
}
+ @NonNull ActiveAdmin getDeviceOwnerOfCallerLocked(final CallerIdentity caller) {
+ ensureLocked();
+ ComponentName doComponent = mOwners.getDeviceOwnerComponent();
+ Preconditions.checkState(doComponent != null,
+ String.format("No device owner for user %d", caller.getUid()));
+
+ // Use the user ID of the caller instead of mOwners.getDeviceOwnerUserId() because
+ // secondary, affiliated users will have their own admin.
+ ActiveAdmin doAdmin = getUserData(caller.getUserId()).mAdminMap.get(doComponent);
+ Preconditions.checkState(doAdmin != null,
+ String.format("Device owner %s for user %d not found", doComponent,
+ caller.getUid()));
+
+ Preconditions.checkSecurity(doAdmin.getUid() == caller.getUid(),
+ String.format("Admin %s is not owned by uid %d, but uid %d", doComponent,
+ caller.getUid(), doAdmin.getUid()));
+
+ Preconditions.checkSecurity(doAdmin.info.getComponent().equals(caller.getComponentName()),
+ String.format("Caller component %s is not device owner",
+ caller.getComponentName()));
+
+ return doAdmin;
+ }
+
+ @NonNull ActiveAdmin getProfileOwnerOfCallerLocked(final CallerIdentity caller) {
+ ensureLocked();
+ final ComponentName poAdminComponent = mOwners.getProfileOwnerComponent(caller.getUserId());
+
+ Preconditions.checkState(poAdminComponent != null,
+ String.format("No profile owner for user %d", caller.getUid()));
+
+ ActiveAdmin poAdmin = getUserData(caller.getUserId()).mAdminMap.get(poAdminComponent);
+ Preconditions.checkState(poAdmin != null,
+ String.format("No device profile owner for caller %d", caller.getUid()));
+
+ Preconditions.checkSecurity(poAdmin.getUid() == caller.getUid(),
+ String.format("Admin %s is not owned by uid %d", poAdminComponent,
+ caller.getUid()));
+
+ Preconditions.checkSecurity(poAdmin.info.getComponent().equals(caller.getComponentName()),
+ String.format("Caller component %s is not profile owner",
+ caller.getComponentName()));
+
+ return poAdmin;
+ }
+
+ @NonNull ActiveAdmin getOrganizationOwnedProfileOwnerLocked(final CallerIdentity caller) {
+ final ActiveAdmin profileOwner = getProfileOwnerOfCallerLocked(caller);
+
+ Preconditions.checkSecurity(
+ mOwners.isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId()),
+ String.format("Admin %s is not of an org-owned device",
+ profileOwner.info.getComponent()));
+
+ return profileOwner;
+ }
+
+ @NonNull ActiveAdmin getProfileOwnerOrDeviceOwnerLocked(final CallerIdentity caller) {
+ ensureLocked();
+ // Try to find an admin which can use reqPolicy
+ final ComponentName poAdminComponent = mOwners.getProfileOwnerComponent(caller.getUserId());
+ final ComponentName doAdminComponent = mOwners.getDeviceOwnerComponent();
+
+ if (poAdminComponent == null && doAdminComponent == null) {
+ throw new IllegalStateException(
+ String.format("No profile or device owner for user %d", caller.getUid()));
+ }
+
+ if (poAdminComponent != null) {
+ return getProfileOwnerOfCallerLocked(caller);
+ }
+
+ return getDeviceOwnerOfCallerLocked(caller);
+ }
+
/**
* Finds an active admin for the caller then checks {@code permission} if admin check failed.
*
@@ -2145,9 +2177,7 @@
ActiveAdmin result = getActiveAdminWithPolicyForUidLocked(who, reqPolicy, callingUid);
if (result != null) {
return result;
- } else if (permission != null
- && (mContext.checkCallingPermission(permission)
- == PackageManager.PERMISSION_GRANTED)) {
+ } else if (permission != null && hasCallingPermission(permission)) {
return null;
}
@@ -2844,9 +2874,12 @@
private void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle,
Bundle onEnableData) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.MANAGE_DEVICE_ADMINS));
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
DevicePolicyData policy = getUserData(userHandle);
DeviceAdminInfo info = findAdmin(adminReceiver, userHandle,
@@ -2986,7 +3019,11 @@
if (!mHasFeature) {
return false;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;
}
@@ -2997,7 +3034,11 @@
if (!mHasFeature) {
return false;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
DevicePolicyData policyData = getUserData(userHandle);
return policyData.mRemovingAdmins.contains(adminReceiver);
@@ -3009,7 +3050,11 @@
if (!mHasFeature) {
return false;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity(adminReceiver);
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
if (administrator == null) {
@@ -3025,8 +3070,11 @@
if (!mHasFeature) {
return Collections.EMPTY_LIST;
}
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- enforceFullCrossUsersPermission(userHandle);
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
DevicePolicyData policy = getUserData(userHandle);
final int N = policy.mAdminList.size();
@@ -3046,7 +3094,11 @@
if (!mHasFeature) {
return false;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
DevicePolicyData policy = getUserData(userHandle);
final int N = policy.mAdminList.size();
@@ -3156,8 +3208,12 @@
if (!mHasFeature) {
return;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
enforceUserUnlocked(userHandle);
+
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
if (admin == null) {
@@ -3309,7 +3365,11 @@
if (!mHasFeature) {
return PASSWORD_QUALITY_UNSPECIFIED;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
int mode = PASSWORD_QUALITY_UNSPECIFIED;
@@ -3521,7 +3581,11 @@
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return 0L;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
long timeout = 0L;
@@ -3547,12 +3611,12 @@
@Override
public boolean addCrossProfileWidgetProvider(ComponentName admin, String packageName) {
- final int userId = UserHandle.getCallingUserId();
+ final CallerIdentity identity = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isProfileOwner(identity) || isDeviceOwner(identity));
List<String> changedProviders = null;
synchronized (getLockObject()) {
- ActiveAdmin activeAdmin = getActiveAdminForCallerLocked(admin,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin activeAdmin = getProfileOwnerOrDeviceOwnerLocked(identity);
if (activeAdmin.crossProfileWidgetProviders == null) {
activeAdmin.crossProfileWidgetProviders = new ArrayList<>();
}
@@ -3560,7 +3624,7 @@
if (!providers.contains(packageName)) {
providers.add(packageName);
changedProviders = new ArrayList<>(providers);
- saveSettingsLocked(userId);
+ saveSettingsLocked(identity.getUserId());
}
}
@@ -3570,7 +3634,8 @@
.write();
if (changedProviders != null) {
- mLocalService.notifyCrossProfileProvidersChanged(userId, changedProviders);
+ mLocalService.notifyCrossProfileProvidersChanged(identity.getUserId(),
+ changedProviders);
return true;
}
@@ -3579,12 +3644,12 @@
@Override
public boolean removeCrossProfileWidgetProvider(ComponentName admin, String packageName) {
- final int userId = UserHandle.getCallingUserId();
+ final CallerIdentity identity = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isProfileOwner(identity) || isDeviceOwner(identity));
List<String> changedProviders = null;
synchronized (getLockObject()) {
- ActiveAdmin activeAdmin = getActiveAdminForCallerLocked(admin,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin activeAdmin = getProfileOwnerOrDeviceOwnerLocked(identity);
if (activeAdmin.crossProfileWidgetProviders == null
|| activeAdmin.crossProfileWidgetProviders.isEmpty()) {
return false;
@@ -3592,7 +3657,7 @@
List<String> providers = activeAdmin.crossProfileWidgetProviders;
if (providers.remove(packageName)) {
changedProviders = new ArrayList<>(providers);
- saveSettingsLocked(userId);
+ saveSettingsLocked(identity.getUserId());
}
}
@@ -3602,7 +3667,8 @@
.write();
if (changedProviders != null) {
- mLocalService.notifyCrossProfileProvidersChanged(userId, changedProviders);
+ mLocalService.notifyCrossProfileProvidersChanged(identity.getUserId(),
+ changedProviders);
return true;
}
@@ -3611,9 +3677,11 @@
@Override
public List<String> getCrossProfileWidgetProviders(ComponentName admin) {
+ final CallerIdentity identity = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isProfileOwner(identity) || isDeviceOwner(identity));
+
synchronized (getLockObject()) {
- ActiveAdmin activeAdmin = getActiveAdminForCallerLocked(admin,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin activeAdmin = getProfileOwnerOrDeviceOwnerLocked(identity);
if (activeAdmin.crossProfileWidgetProviders == null
|| activeAdmin.crossProfileWidgetProviders.isEmpty()) {
return null;
@@ -3656,7 +3724,11 @@
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return 0L;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
return getPasswordExpirationLocked(who, userHandle, parent);
}
@@ -3862,7 +3934,11 @@
if (!mHasFeature) {
return 0;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
if (who != null) {
final ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
@@ -3902,7 +3978,11 @@
if (!mHasFeature) {
new PasswordMetrics(CREDENTIAL_TYPE_NONE);
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
ArrayList<PasswordMetrics> adminMetrics = new ArrayList<>();
synchronized (getLockObject()) {
List<ActiveAdmin> admins =
@@ -3919,7 +3999,10 @@
if (!mHasFeature) {
return true;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
enforceUserUnlocked(userHandle, parent);
synchronized (getLockObject()) {
@@ -3951,7 +4034,10 @@
if (!mHasFeature) {
return true;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
enforceManagedProfile(userHandle, "call APIs refering to the parent profile");
synchronized (getLockObject()) {
@@ -3970,7 +4056,10 @@
if (!mHasFeature) {
return true;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
enforceNotManagedProfile(userHandle, "check password sufficiency");
enforceUserUnlocked(userHandle);
@@ -4058,12 +4147,15 @@
if (!mLockPatternUtils.hasSecureLockScreen()) {
return 0;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
- if (!isCallerWithSystemUid()) {
+ if (!isSystemUid(identity)) {
// This API can be called by an active device admin or by keyguard code.
- if (mContext.checkCallingPermission(permission.ACCESS_KEYGUARD_SECURE_STORAGE)
- != PackageManager.PERMISSION_GRANTED) {
+ if (!hasCallingPermission(permission.ACCESS_KEYGUARD_SECURE_STORAGE)) {
getActiveAdminForCallerLocked(
null, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent);
}
@@ -4106,7 +4198,11 @@
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return 0;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
ActiveAdmin admin = (who != null)
? getActiveAdminUncheckedLocked(who, userHandle, parent)
@@ -4120,7 +4216,11 @@
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return UserHandle.USER_NULL;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
ActiveAdmin admin = getAdminWithMinimumFailedPasswordsForWipeLocked(
userHandle, parent);
@@ -4191,8 +4291,7 @@
// As of R, only privlleged caller holding RESET_PASSWORD can call resetPassword() to
// set password to an unsecured user.
- if (mContext.checkCallingPermission(permission.RESET_PASSWORD)
- == PackageManager.PERMISSION_GRANTED) {
+ if (hasCallingPermission(permission.RESET_PASSWORD)) {
return setPasswordPrivileged(password, flags, callingUid);
}
@@ -4392,7 +4491,11 @@
if (!mHasFeature) {
return 0;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
if (who != null) {
final ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
@@ -4465,12 +4568,16 @@
if (!mHasFeature) {
return DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
}
+ Preconditions.checkArgumentNonnegative(userId, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userId));
+
if (!mLockPatternUtils.hasSecureLockScreen()) {
// No strong auth timeout on devices not supporting the
// {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature
return 0;
}
- enforceFullCrossUsersPermission(userId);
synchronized (getLockObject()) {
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userId, parent);
@@ -4504,8 +4611,7 @@
@Override
public void lockNow(int flags, boolean parent) {
- if (!mHasFeature && mContext.checkCallingPermission(android.Manifest.permission.LOCK_DEVICE)
- != PackageManager.PERMISSION_GRANTED) {
+ if (!mHasFeature && !hasCallingPermission(permission.LOCK_DEVICE)) {
return;
}
@@ -4597,8 +4703,7 @@
}
private void enforceNetworkStackOrProfileOrDeviceOwner(ComponentName who) {
- if (mContext.checkCallingPermission(PERMISSION_MAINLINE_NETWORK_STACK)
- == PackageManager.PERMISSION_GRANTED) {
+ if (hasCallingPermission(PERMISSION_MAINLINE_NETWORK_STACK)) {
return;
}
enforceProfileOrDeviceOwner(who);
@@ -5677,8 +5782,9 @@
if (!mHasFeature) {
return;
}
-
- enforceFullCrossUsersPermission(mInjector.userHandleGetCallingUserId());
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(isSystemUid(identity) || isRootUid(identity)
+ || hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS_FULL));
final ActiveAdmin admin;
synchronized (getLockObject()) {
@@ -5854,8 +5960,7 @@
synchronized (getLockObject()) {
if (who == null) {
if ((frpManagementAgentUid != mInjector.binderGetCallingUid())
- && (mContext.checkCallingPermission(permission.MASTER_CLEAR)
- != PackageManager.PERMISSION_GRANTED)) {
+ && !hasCallingPermission(permission.MASTER_CLEAR)) {
throw new SecurityException(
"Must be called by the FRP management agent on device");
}
@@ -5893,9 +5998,13 @@
if (!mHasFeature) {
return;
}
- enforceFullCrossUsersPermission(userHandle);
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = comp != null
+ ? getCallerIdentity(comp)
+ : getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(comp, userHandle);
@@ -5972,13 +6081,15 @@
@Override
public void reportFailedPasswordAttempt(int userHandle) {
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
if (!isSeparateProfileChallengeEnabled(userHandle)) {
enforceNotManagedProfile(userHandle,
"report failed password attempt if separate profile challenge is not in place");
}
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.BIND_DEVICE_ADMIN, null);
boolean wipeData = false;
ActiveAdmin strictestAdmin = null;
@@ -6051,9 +6162,11 @@
@Override
public void reportSuccessfulPasswordAttempt(int userHandle) {
- enforceFullCrossUsersPermission(userHandle);
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
synchronized (getLockObject()) {
DevicePolicyData policy = getUserData(userHandle);
@@ -6079,9 +6192,12 @@
@Override
public void reportFailedBiometricAttempt(int userHandle) {
- enforceFullCrossUsersPermission(userHandle);
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
+
if (mInjector.securityLogIsLoggingEnabled()) {
SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 0,
/*method strength*/ 0);
@@ -6090,9 +6206,12 @@
@Override
public void reportSuccessfulBiometricAttempt(int userHandle) {
- enforceFullCrossUsersPermission(userHandle);
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
+
if (mInjector.securityLogIsLoggingEnabled()) {
SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 1,
/*method strength*/ 0);
@@ -6101,9 +6220,11 @@
@Override
public void reportKeyguardDismissed(int userHandle) {
- enforceFullCrossUsersPermission(userHandle);
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
if (mInjector.securityLogIsLoggingEnabled()) {
SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISSED);
@@ -6112,9 +6233,11 @@
@Override
public void reportKeyguardSecured(int userHandle) {
- enforceFullCrossUsersPermission(userHandle);
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
if (mInjector.securityLogIsLoggingEnabled()) {
SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_SECURED);
@@ -6176,7 +6299,11 @@
if (!mHasFeature) {
return null;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
// Scan through active admins and find if anyone has already
@@ -6310,7 +6437,13 @@
if (!mHasFeature) {
return false;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = who != null
+ ? getCallerIdentity(who)
+ : getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
// Check for permissions if a particular caller is specified
if (who != null) {
@@ -6340,7 +6473,12 @@
if (!mHasFeature) {
// Ok to return current status.
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = callerPackage != null
+ ? getCallerIdentity(callerPackage)
+ : getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
// It's not critical here, but let's make sure the package name is correct, in case
// we start using it for different purposes.
@@ -6485,24 +6623,23 @@
return;
}
Objects.requireNonNull(who, "ComponentName is null");
- final int userHandle = UserHandle.getCallingUserId();
+ final CallerIdentity identity = getCallerIdentity(who);
+
boolean requireAutoTimeChanged = false;
synchronized (getLockObject()) {
- if (isManagedProfile(userHandle)) {
- throw new SecurityException("Managed profile cannot set auto time required");
- }
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ Preconditions.checkSecurity(!isManagedProfile(identity.getUserId()),
+ "Managed profile cannot set auto time required");
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
if (admin.requireAutoTime != required) {
admin.requireAutoTime = required;
- saveSettingsLocked(userHandle);
+ saveSettingsLocked(identity.getUserId());
requireAutoTimeChanged = true;
}
}
// requireAutoTime is now backed by DISALLOW_CONFIG_DATE_TIME restriction, so propagate
// updated restrictions to the framework.
if (requireAutoTimeChanged) {
- pushUserRestrictions(userHandle);
+ pushUserRestrictions(identity.getUserId());
}
// Turn AUTO_TIME on in settings if it is required
if (required) {
@@ -6679,45 +6816,24 @@
Preconditions.checkCallAuthorization(isDeviceOwner(identity));
ensureAllUsersAffiliated();
- if (mRemoteBugreportServiceIsActive.get()
- || (getDeviceOwnerRemoteBugreportUri() != null)) {
- Slog.d(LOG_TAG, "Remote bugreport wasn't started because there's already one running.");
- return false;
- }
-
- final long currentTime = System.currentTimeMillis();
- synchronized (getLockObject()) {
- DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM);
- if (currentTime > policyData.mLastBugReportRequestTime) {
- policyData.mLastBugReportRequestTime = currentTime;
- saveSettingsLocked(UserHandle.USER_SYSTEM);
- }
- }
-
- final long callingIdentity = mInjector.binderClearCallingIdentity();
- try {
- mInjector.getIActivityManager().requestRemoteBugReport();
-
- mRemoteBugreportServiceIsActive.set(true);
- mRemoteBugreportSharingAccepted.set(false);
- registerRemoteBugreportReceivers();
- mInjector.getNotificationManager().notifyAsUser(LOG_TAG,
- RemoteBugreportUtils.NOTIFICATION_ID,
- RemoteBugreportUtils.buildNotification(mContext,
- DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED), UserHandle.ALL);
- mHandler.postDelayed(mRemoteBugreportTimeoutRunnable,
- RemoteBugreportUtils.REMOTE_BUGREPORT_TIMEOUT_MILLIS);
+ if (mBugreportCollectionManager.requestBugreport()) {
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.REQUEST_BUGREPORT)
.setAdmin(who)
.write();
+
+ final long currentTime = System.currentTimeMillis();
+ synchronized (getLockObject()) {
+ DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM);
+ if (currentTime > policyData.mLastBugReportRequestTime) {
+ policyData.mLastBugReportRequestTime = currentTime;
+ saveSettingsLocked(UserHandle.USER_SYSTEM);
+ }
+ }
+
return true;
- } catch (RemoteException re) {
- // should never happen
- Slog.e(LOG_TAG, "Failed to make remote calls to start bugreportremote service", re);
+ } else {
return false;
- } finally {
- mInjector.binderRestoreCallingIdentity(callingIdentity);
}
}
@@ -6761,146 +6877,36 @@
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
}
- private String getDeviceOwnerRemoteBugreportUri() {
+ void sendBugreportToDeviceOwner(Uri bugreportUri, String bugreportHash) {
synchronized (getLockObject()) {
- return mOwners.getDeviceOwnerRemoteBugreportUri();
+ final Intent intent = new Intent(DeviceAdminReceiver.ACTION_BUGREPORT_SHARE);
+ intent.setComponent(mOwners.getDeviceOwnerComponent());
+ intent.setDataAndType(bugreportUri, RemoteBugreportManager.BUGREPORT_MIMETYPE);
+ intent.putExtra(DeviceAdminReceiver.EXTRA_BUGREPORT_HASH, bugreportHash);
+ intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+ final UriGrantsManagerInternal ugm = LocalServices
+ .getService(UriGrantsManagerInternal.class);
+ final NeededUriGrants needed = ugm.checkGrantUriPermissionFromIntent(intent,
+ Process.SHELL_UID, mOwners.getDeviceOwnerComponent().getPackageName(),
+ mOwners.getDeviceOwnerUserId());
+ ugm.grantUriPermissionUncheckedFromIntent(needed, null);
+
+ mContext.sendBroadcastAsUser(intent, UserHandle.of(mOwners.getDeviceOwnerUserId()));
}
}
- private void setDeviceOwnerRemoteBugreportUriAndHash(String bugreportUri,
- String bugreportHash) {
+ void setDeviceOwnerRemoteBugreportUriAndHash(String bugreportUri, String bugreportHash) {
synchronized (getLockObject()) {
mOwners.setDeviceOwnerRemoteBugreportUriAndHash(bugreportUri, bugreportHash);
}
}
- private void registerRemoteBugreportReceivers() {
- try {
- IntentFilter filterFinished = new IntentFilter(
- DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH,
- RemoteBugreportUtils.BUGREPORT_MIMETYPE);
- mContext.registerReceiver(mRemoteBugreportFinishedReceiver, filterFinished);
- } catch (IntentFilter.MalformedMimeTypeException e) {
- // should never happen, as setting a constant
- Slog.w(LOG_TAG, "Failed to set type " + RemoteBugreportUtils.BUGREPORT_MIMETYPE, e);
- }
- IntentFilter filterConsent = new IntentFilter();
- filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED);
- filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED);
- mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
- }
-
- private void onBugreportFinished(Intent intent) {
- mHandler.removeCallbacks(mRemoteBugreportTimeoutRunnable);
- mRemoteBugreportServiceIsActive.set(false);
- Uri bugreportUri = intent.getData();
- String bugreportUriString = null;
- if (bugreportUri != null) {
- bugreportUriString = bugreportUri.toString();
- }
- String bugreportHash = intent.getStringExtra(
- DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH);
- if (mRemoteBugreportSharingAccepted.get()) {
- shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
- mInjector.getNotificationManager().cancel(LOG_TAG,
- RemoteBugreportUtils.NOTIFICATION_ID);
- } else {
- setDeviceOwnerRemoteBugreportUriAndHash(bugreportUriString, bugreportHash);
- mInjector.getNotificationManager().notifyAsUser(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
- RemoteBugreportUtils.buildNotification(mContext,
- DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED),
- UserHandle.ALL);
- }
- mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
- }
-
- private void onBugreportFailed() {
- mRemoteBugreportServiceIsActive.set(false);
- mInjector.systemPropertiesSet(RemoteBugreportUtils.CTL_STOP,
- RemoteBugreportUtils.REMOTE_BUGREPORT_SERVICE);
- mRemoteBugreportSharingAccepted.set(false);
- setDeviceOwnerRemoteBugreportUriAndHash(null, null);
- mInjector.getNotificationManager().cancel(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID);
- Bundle extras = new Bundle();
- extras.putInt(DeviceAdminReceiver.EXTRA_BUGREPORT_FAILURE_REASON,
- DeviceAdminReceiver.BUGREPORT_FAILURE_FAILED_COMPLETING);
- sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_BUGREPORT_FAILED, extras);
- mContext.unregisterReceiver(mRemoteBugreportConsentReceiver);
- mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
- }
-
- private void onBugreportSharingAccepted() {
- mRemoteBugreportSharingAccepted.set(true);
- String bugreportUriString = null;
- String bugreportHash = null;
+ Pair<String, String> getDeviceOwnerRemoteBugreportUriAndHash() {
synchronized (getLockObject()) {
- bugreportUriString = getDeviceOwnerRemoteBugreportUri();
- bugreportHash = mOwners.getDeviceOwnerRemoteBugreportHash();
- }
- if (bugreportUriString != null) {
- shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
- } else if (mRemoteBugreportServiceIsActive.get()) {
- mInjector.getNotificationManager().notifyAsUser(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
- RemoteBugreportUtils.buildNotification(mContext,
- DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED),
- UserHandle.ALL);
- }
- }
-
- private void onBugreportSharingDeclined() {
- if (mRemoteBugreportServiceIsActive.get()) {
- mInjector.systemPropertiesSet(RemoteBugreportUtils.CTL_STOP,
- RemoteBugreportUtils.REMOTE_BUGREPORT_SERVICE);
- mRemoteBugreportServiceIsActive.set(false);
- mHandler.removeCallbacks(mRemoteBugreportTimeoutRunnable);
- mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
- }
- mRemoteBugreportSharingAccepted.set(false);
- setDeviceOwnerRemoteBugreportUriAndHash(null, null);
- sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_BUGREPORT_SHARING_DECLINED, null);
- }
-
- private void shareBugreportWithDeviceOwnerIfExists(String bugreportUriString,
- String bugreportHash) {
- ParcelFileDescriptor pfd = null;
- try {
- if (bugreportUriString == null) {
- throw new FileNotFoundException();
- }
- Uri bugreportUri = Uri.parse(bugreportUriString);
- pfd = mContext.getContentResolver().openFileDescriptor(bugreportUri, "r");
-
- synchronized (getLockObject()) {
- Intent intent = new Intent(DeviceAdminReceiver.ACTION_BUGREPORT_SHARE);
- intent.setComponent(mOwners.getDeviceOwnerComponent());
- intent.setDataAndType(bugreportUri, RemoteBugreportUtils.BUGREPORT_MIMETYPE);
- intent.putExtra(DeviceAdminReceiver.EXTRA_BUGREPORT_HASH, bugreportHash);
- intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-
- final UriGrantsManagerInternal ugm = LocalServices
- .getService(UriGrantsManagerInternal.class);
- final NeededUriGrants needed = ugm.checkGrantUriPermissionFromIntent(intent,
- Process.SHELL_UID, mOwners.getDeviceOwnerComponent().getPackageName(),
- mOwners.getDeviceOwnerUserId());
- ugm.grantUriPermissionUncheckedFromIntent(needed, null);
-
- mContext.sendBroadcastAsUser(intent, UserHandle.of(mOwners.getDeviceOwnerUserId()));
- }
- } catch (FileNotFoundException e) {
- Bundle extras = new Bundle();
- extras.putInt(DeviceAdminReceiver.EXTRA_BUGREPORT_FAILURE_REASON,
- DeviceAdminReceiver.BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE);
- sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_BUGREPORT_FAILED, extras);
- } finally {
- try {
- if (pfd != null) {
- pfd.close();
- }
- } catch (IOException ex) {
- // Ignore
- }
- mRemoteBugreportSharingAccepted.set(false);
- setDeviceOwnerRemoteBugreportUriAndHash(null, null);
+ final String uri = mOwners.getDeviceOwnerRemoteBugreportUri();
+ return uri == null ? null
+ : new Pair<>(uri, mOwners.getDeviceOwnerRemoteBugreportHash());
}
}
@@ -7033,7 +7039,11 @@
if (!mHasFeature) {
return 0;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
final long ident = mInjector.binderClearCallingIdentity();
try {
synchronized (getLockObject()) {
@@ -7229,6 +7239,16 @@
return who != null && who.equals(profileOwner);
}
+ /**
+ * Returns {@code true} if the provided caller identity is of a profile owner.
+ * @param identity identity of caller.
+ * @return true if {@code identity} is a profile owner, false otherwise.
+ */
+ public boolean isProfileOwner(CallerIdentity identity) {
+ final ComponentName profileOwner = getProfileOwner(identity.getUserId());
+ return profileOwner != null && profileOwner.equals(identity.getComponentName());
+ }
+
private boolean hasProfileOwner(int userId) {
synchronized (getLockObject()) {
return mOwners.hasProfileOwner(userId);
@@ -7783,7 +7803,10 @@
@Override
public ComponentName getProfileOwnerAsUser(int userHandle) {
- enforceCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasCrossUsersPermission(identity, userHandle));
return getProfileOwner(userHandle);
}
@@ -8140,56 +8163,31 @@
}
}
- private void enforceAcrossUsersPermissions() {
- final int callingUid = mInjector.binderGetCallingUid();
+ private boolean hasCallingPermission(String permission) {
+ return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED;
+ }
+
+ private boolean hasCallingOrSelfPermission(String permission) {
+ return mContext.checkCallingOrSelfPermission(permission)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ private boolean hasPermissionForPreflight(CallerIdentity identity, String permission) {
final int callingPid = mInjector.binderGetCallingPid();
final String packageName = mContext.getPackageName();
- if (isCallerWithSystemUid() || callingUid == Process.ROOT_UID) {
- return;
- }
- if (PermissionChecker.checkPermissionForPreflight(
- mContext, permission.INTERACT_ACROSS_PROFILES, callingPid, callingUid,
- packageName) == PermissionChecker.PERMISSION_GRANTED) {
- return;
- }
- if (mContext.checkCallingPermission(permission.INTERACT_ACROSS_USERS)
- == PackageManager.PERMISSION_GRANTED) {
- return;
- }
- if (mContext.checkCallingPermission(permission.INTERACT_ACROSS_USERS_FULL)
- == PackageManager.PERMISSION_GRANTED) {
- return;
- }
- throw new SecurityException("Calling user does not have INTERACT_ACROSS_PROFILES or"
- + "INTERACT_ACROSS_USERS or INTERACT_ACROSS_USERS_FULL permissions");
+ return PermissionChecker.checkPermissionForPreflight(mContext, permission, callingPid,
+ identity.getUid(), packageName) == PermissionChecker.PERMISSION_GRANTED;
}
- private void enforceFullCrossUsersPermission(int userHandle) {
- enforceSystemUserOrPermissionIfCrossUser(userHandle,
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+ private boolean hasFullCrossUsersPermission(CallerIdentity identity, int userHandle) {
+ return (userHandle == identity.getUserId()) || isSystemUid(identity) || isRootUid(identity)
+ || hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS_FULL);
}
- private void enforceCrossUsersPermission(int userHandle) {
- enforceSystemUserOrPermissionIfCrossUser(userHandle,
- android.Manifest.permission.INTERACT_ACROSS_USERS);
- }
-
- private void enforceSystemUserOrPermission(String permission) {
- if (!(isCallerWithSystemUid() || mInjector.binderGetCallingUid() == Process.ROOT_UID)) {
- mContext.enforceCallingOrSelfPermission(permission,
- "Must be system or have " + permission + " permission");
- }
- }
-
- private void enforceSystemUserOrPermissionIfCrossUser(int userHandle, String permission) {
- if (userHandle < 0) {
- throw new IllegalArgumentException("Invalid userId " + userHandle);
- }
- if (userHandle == mInjector.userHandleGetCallingUserId()) {
- return;
- }
- enforceSystemUserOrPermission(permission);
+ private boolean hasCrossUsersPermission(CallerIdentity identity, int userHandle) {
+ return (userHandle == identity.getUserId()) || isSystemUid(identity) || isRootUid(identity)
+ || hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS);
}
private void enforceManagedProfile(int userId, String message) {
@@ -8249,19 +8247,18 @@
throw new SecurityException("No active admin found");
}
- private void enforceProfileOwnerOrFullCrossUsersPermission(int userId) {
- if (userId == mInjector.userHandleGetCallingUserId()) {
+ private void enforceProfileOwnerOrFullCrossUsersPermission(CallerIdentity identity,
+ int userId) {
+ if (userId == identity.getUserId()) {
synchronized (getLockObject()) {
if (getActiveAdminWithPolicyForUidLocked(null,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, mInjector.binderGetCallingUid())
- != null) {
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, identity.getUid()) != null) {
// Device Owner/Profile Owner may access the user it runs on.
return;
}
}
}
- // Otherwise, INTERACT_ACROSS_USERS_FULL permission, system UID or root UID is required.
- enforceSystemUserOrPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userId));
}
private boolean canUserUseLockTaskLocked(int userId) {
@@ -8315,6 +8312,18 @@
return UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID);
}
+ private boolean isSystemUid(CallerIdentity identity) {
+ return UserHandle.isSameApp(identity.getUid(), Process.SYSTEM_UID);
+ }
+
+ private boolean isRootUid(CallerIdentity identity) {
+ return UserHandle.isSameApp(identity.getUid(), Process.ROOT_UID);
+ }
+
+ private boolean isShellUid(CallerIdentity identity) {
+ return UserHandle.isSameApp(identity.getUid(), Process.SHELL_UID);
+ }
+
protected int getProfileParentId(int userHandle) {
return mInjector.binderWithCleanCallingIdentity(() -> {
UserInfo parentUser = mUserManager.getProfileParent(userHandle);
@@ -8569,7 +8578,12 @@
return null;
}
Objects.requireNonNull(agent, "agent null");
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = admin != null
+ ? getCallerIdentity(admin)
+ : getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
synchronized (getLockObject()) {
final String componentName = agent.flattenToString();
@@ -8769,9 +8783,10 @@
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
if (packageList != null) {
- int userId = UserHandle.getCallingUserId();
+ int userId = identity.getUserId();
List<AccessibilityServiceInfo> enabledServices = null;
long id = mInjector.binderClearCallingIdentity();
try {
@@ -8801,8 +8816,7 @@
}
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
admin.permittedAccessiblityServices = packageList;
saveSettingsLocked(UserHandle.getCallingUserId());
}
@@ -8822,10 +8836,11 @@
return null;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(identity) || isProfileOwner(identity));
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.permittedAccessiblityServices;
}
}
@@ -8920,17 +8935,19 @@
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
- final int callingUserId = mInjector.userHandleGetCallingUserId();
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(identity) || isProfileOwner(identity));
+
if (packageList != null) {
List<InputMethodInfo> enabledImes = InputMethodManagerInternal.get()
- .getEnabledInputMethodListAsUser(callingUserId);
+ .getEnabledInputMethodListAsUser(identity.getUserId());
if (enabledImes != null) {
List<String> enabledPackages = new ArrayList<String>();
for (InputMethodInfo ime : enabledImes) {
enabledPackages.add(ime.getPackageName());
}
if (!checkPackagesInPermittedListOrSystem(enabledPackages, packageList,
- callingUserId)) {
+ identity.getUserId())) {
Slog.e(LOG_TAG, "Cannot set permitted input methods, "
+ "because it contains already enabled input method.");
return false;
@@ -8939,10 +8956,9 @@
}
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
admin.permittedInputMethods = packageList;
- saveSettingsLocked(callingUserId);
+ saveSettingsLocked(identity.getUserId());
}
final String[] packageArray =
packageList != null ? ((List<String>) packageList).toArray(new String[0]) : null;
@@ -8960,10 +8976,11 @@
return null;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(identity) || isProfileOwner(identity));
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.permittedInputMethods;
}
}
@@ -9037,17 +9054,16 @@
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
- final int callingUserId = mInjector.userHandleGetCallingUserId();
- if (!isManagedProfile(callingUserId)) {
+ if (!isManagedProfile(identity.getUserId())) {
return false;
}
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(
- who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
admin.permittedNotificationListeners = packageList;
- saveSettingsLocked(callingUserId);
+ saveSettingsLocked(identity.getUserId());
}
return true;
}
@@ -9058,10 +9074,12 @@
return null;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(
- who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ // API contract is to return null if there are no permitted cross-profile notification
+ // listeners, including in Device Owner mode.
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.permittedNotificationListeners;
}
}
@@ -9922,10 +9940,14 @@
@Override
public String[] getAccountTypesWithManagementDisabledAsUser(int userId, boolean parent) {
- enforceFullCrossUsersPermission(userId);
if (!mHasFeature) {
return null;
}
+ Preconditions.checkArgumentNonnegative(userId, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userId));
+
synchronized (getLockObject()) {
final ArraySet<String> resultSet = new ArraySet<>();
@@ -9992,10 +10014,12 @@
final int userId = UserHandle.getCallingUserId();
synchronized (getLockObject()) {
+ //TODO: This is a silly access control check. Remove.
if (who != null) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(
+ isProfileOwner(caller) || isDeviceOwner(caller));
}
-
long id = mInjector.binderClearCallingIdentity();
try {
return mIPackageManager.getBlockUninstallForUser(packageName, userId);
@@ -10015,12 +10039,14 @@
return;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isProfileOwner(identity) || isDeviceOwner(identity));
+
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
if (admin.disableCallerId != disabled) {
admin.disableCallerId = disabled;
- saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ saveSettingsLocked(identity.getUserId());
}
}
DevicePolicyEventLogger
@@ -10036,16 +10062,22 @@
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isProfileOwner(identity) || isDeviceOwner(identity));
+
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.disableCallerId;
}
}
@Override
public boolean getCrossProfileCallerIdDisabledForUser(int userId) {
- enforceCrossUsersPermission(userId);
+ Preconditions.checkArgumentNonnegative(userId, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasCrossUsersPermission(identity, userId));
+
synchronized (getLockObject()) {
ActiveAdmin admin = getProfileOwnerAdminLocked(userId);
return (admin != null) ? admin.disableCallerId : false;
@@ -10058,12 +10090,14 @@
return;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isProfileOwner(identity) || isDeviceOwner(identity));
+
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
if (admin.disableContactsSearch != disabled) {
admin.disableContactsSearch = disabled;
- saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ saveSettingsLocked(identity.getUserId());
}
}
DevicePolicyEventLogger
@@ -10079,16 +10113,22 @@
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isProfileOwner(identity) || isDeviceOwner(identity));
+
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.disableContactsSearch;
}
}
@Override
public boolean getCrossProfileContactsSearchDisabledForUser(int userId) {
- enforceCrossUsersPermission(userId);
+ Preconditions.checkArgumentNonnegative(userId, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasCrossUsersPermission(identity, userId));
+
synchronized (getLockObject()) {
ActiveAdmin admin = getProfileOwnerAdminLocked(userId);
return (admin != null) ? admin.disableContactsSearch : false;
@@ -10159,12 +10199,14 @@
return;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(identity) || isProfileOwner(identity));
+
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
if (admin.disableBluetoothContactSharing != disabled) {
admin.disableBluetoothContactSharing = disabled;
- saveSettingsLocked(UserHandle.getCallingUserId());
+ saveSettingsLocked(identity.getUserId());
}
}
DevicePolicyEventLogger
@@ -10180,9 +10222,11 @@
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(identity) || isProfileOwner(identity));
+
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.disableBluetoothContactSharing;
}
}
@@ -12138,13 +12182,12 @@
return;
}
Objects.requireNonNull(who, "ComponentName is null");
- final int userHandle = mInjector.userHandleGetCallingUserId();
- enforceManagedProfile(userHandle, "set organization color");
+ final CallerIdentity identity = getCallerIdentity(who);
+ enforceManagedProfile(identity.getUserId(), "set organization color");
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
admin.organizationColor = color;
- saveSettingsLocked(userHandle);
+ saveSettingsLocked(identity.getUserId());
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_ORGANIZATION_COLOR)
@@ -12157,7 +12200,11 @@
if (!mHasFeature) {
return;
}
- enforceFullCrossUsersPermission(userId);
+ Preconditions.checkArgumentNonnegative(userId, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userId));
+
enforceManageUsers();
enforceManagedProfile(userId, "set organization color");
synchronized (getLockObject()) {
@@ -12173,10 +12220,10 @@
return ActiveAdmin.DEF_ORGANIZATION_COLOR;
}
Objects.requireNonNull(who, "ComponentName is null");
- enforceManagedProfile(mInjector.userHandleGetCallingUserId(), "get organization color");
+ final CallerIdentity identity = getCallerIdentity(who);
+ enforceManagedProfile(identity.getUserId(), "get organization color");
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.organizationColor;
}
}
@@ -12186,7 +12233,11 @@
if (!mHasFeature) {
return ActiveAdmin.DEF_ORGANIZATION_COLOR;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
enforceManagedProfile(userHandle, "get organization color");
synchronized (getLockObject()) {
ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userHandle);
@@ -12202,15 +12253,14 @@
return;
}
Objects.requireNonNull(who, "ComponentName is null");
- final int userHandle = mInjector.userHandleGetCallingUserId();
+ final CallerIdentity identity = getCallerIdentity(who);
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
if (!TextUtils.equals(admin.organizationName, text)) {
admin.organizationName = (text == null || text.length() == 0)
? null : text.toString();
- saveSettingsLocked(userHandle);
+ saveSettingsLocked(identity.getUserId());
}
}
}
@@ -12221,10 +12271,10 @@
return null;
}
Objects.requireNonNull(who, "ComponentName is null");
- enforceManagedProfile(mInjector.userHandleGetCallingUserId(), "get organization name");
+ final CallerIdentity identity = getCallerIdentity(who);
+ enforceManagedProfile(identity.getUserId(), "get organization name");
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.organizationName;
}
}
@@ -12246,7 +12296,11 @@
if (!mHasFeature) {
return null;
}
- enforceFullCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+
enforceManagedProfile(userHandle, "get organization name");
synchronized (getLockObject()) {
ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userHandle);
@@ -12260,20 +12314,21 @@
public List<String> setMeteredDataDisabledPackages(ComponentName who, List<String> packageNames) {
Objects.requireNonNull(who);
Objects.requireNonNull(packageNames);
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkSecurity(isDeviceOwner(identity) || isProfileOwner(identity),
+ String.format("Admin %s does not own the profile", identity.getComponentName()));
if (!mHasFeature) {
return packageNames;
}
synchronized (getLockObject()) {
- final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- final int callingUserId = mInjector.userHandleGetCallingUserId();
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return mInjector.binderWithCleanCallingIdentity(() -> {
- final List<String> excludedPkgs
- = removeInvalidPkgsForMeteredDataRestriction(callingUserId, packageNames);
+ final List<String> excludedPkgs = removeInvalidPkgsForMeteredDataRestriction(
+ identity.getUserId(), packageNames);
admin.meteredDisabledPackages = packageNames;
- pushMeteredDisabledPackagesLocked(callingUserId);
- saveSettingsLocked(callingUserId);
+ pushMeteredDisabledPackagesLocked(identity.getUserId());
+ saveSettingsLocked(identity.getUserId());
return excludedPkgs;
});
}
@@ -12310,9 +12365,12 @@
if (!mHasFeature) {
return new ArrayList<>();
}
+ final CallerIdentity identity = getCallerIdentity(who);
+ Preconditions.checkSecurity(isDeviceOwner(identity) || isProfileOwner(identity),
+ String.format("Admin %s does not own the profile", identity.getComponentName()));
+
synchronized (getLockObject()) {
- final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.meteredDisabledPackages == null
? new ArrayList<>() : admin.meteredDisabledPackages;
}
@@ -12337,12 +12395,6 @@
return false;
}
- private boolean hasMarkProfileOwnerOnOrganizationOwnedDevicePermission() {
- return mContext.checkCallingPermission(
- permission.MARK_DEVICE_ORGANIZATION_OWNED)
- == PackageManager.PERMISSION_GRANTED;
- }
-
@Override
public void markProfileOwnerOnOrganizationOwnedDevice(ComponentName who, int userId) {
// As the caller is the system, it must specify the component name of the profile owner
@@ -12355,7 +12407,7 @@
// Only adb or system apps with the right permission can mark a profile owner on
// organization-owned device.
- if (!(isAdb() || hasMarkProfileOwnerOnOrganizationOwnedDevicePermission())) {
+ if (!(isAdb() || hasCallingPermission(permission.MARK_DEVICE_ORGANIZATION_OWNED))) {
throw new SecurityException(
"Only the system can mark a profile owner of organization-owned device.");
}
@@ -13483,7 +13535,8 @@
@Override
public StringParceledListSlice getOwnerInstalledCaCerts(@NonNull UserHandle user) {
final int userId = user.getIdentifier();
- enforceProfileOwnerOrFullCrossUsersPermission(userId);
+ final CallerIdentity identity = getCallerIdentity();
+ enforceProfileOwnerOrFullCrossUsersPermission(identity, userId);
synchronized (getLockObject()) {
return new StringParceledListSlice(
new ArrayList<>(getUserData(userId).mOwnerInstalledCaCerts));
@@ -14100,12 +14153,12 @@
return;
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
synchronized (getLockObject()) {
- final ActiveAdmin admin = getActiveAdminForCallerLocked(
- who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
admin.mCrossProfileCalendarPackages = packageNames;
- saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ saveSettingsLocked(identity.getUserId());
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_CROSS_PROFILE_CALENDAR_PACKAGES)
@@ -14121,10 +14174,10 @@
return Collections.emptyList();
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
synchronized (getLockObject()) {
- final ActiveAdmin admin = getActiveAdminForCallerLocked(
- who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.mCrossProfileCalendarPackages;
}
}
@@ -14136,8 +14189,11 @@
return false;
}
Preconditions.checkStringNotEmpty(packageName, "Package name is null or empty");
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- enforceCrossUsersPermission(userHandle);
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
if (mInjector.settingsSecureGetIntForUser(
Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED, 0, userHandle) == 0) {
@@ -14159,7 +14215,11 @@
if (!mHasFeature) {
return Collections.emptyList();
}
- enforceCrossUsersPermission(userHandle);
+ Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
+
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasCrossUsersPermission(identity, userHandle));
+
synchronized (getLockObject()) {
final ActiveAdmin admin = getProfileOwnerAdminLocked(userHandle);
if (admin != null) {
@@ -14176,16 +14236,17 @@
}
Objects.requireNonNull(who, "ComponentName is null");
Objects.requireNonNull(packageNames, "Package names is null");
+ final CallerIdentity identity = getCallerIdentity(who);
+
final List<String> previousCrossProfilePackages;
synchronized (getLockObject()) {
- final ActiveAdmin admin =
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
previousCrossProfilePackages = admin.mCrossProfilePackages;
if (packageNames.equals(previousCrossProfilePackages)) {
return;
}
admin.mCrossProfilePackages = packageNames;
- saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ saveSettingsLocked(identity.getUserId());
}
logSetCrossProfilePackages(who, packageNames);
final CrossProfileApps crossProfileApps = mContext.getSystemService(CrossProfileApps.class);
@@ -14208,10 +14269,10 @@
return Collections.emptyList();
}
Objects.requireNonNull(who, "ComponentName is null");
+ final CallerIdentity identity = getCallerIdentity(who);
synchronized (getLockObject()) {
- final ActiveAdmin admin = getActiveAdminForCallerLocked(
- who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
return admin.mCrossProfilePackages;
}
}
@@ -14221,7 +14282,12 @@
if (!mHasFeature) {
return Collections.emptyList();
}
- enforceAcrossUsersPermissions();
+ final CallerIdentity identity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(
+ isSystemUid(identity) || isRootUid(identity) || hasCallingPermission(
+ permission.INTERACT_ACROSS_USERS) || hasCallingPermission(
+ permission.INTERACT_ACROSS_USERS_FULL) || hasPermissionForPreflight(
+ identity, permission.INTERACT_ACROSS_PROFILES));
synchronized (getLockObject()) {
final List<ActiveAdmin> admins = getProfileOwnerAdminsForCurrentProfileGroup();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
new file mode 100644
index 0000000..46c9aab
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
@@ -0,0 +1,324 @@
+/*
+ * 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.devicepolicy;
+
+import static android.app.admin.DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED;
+import static android.app.admin.DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED;
+import static android.app.admin.DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH;
+import static android.app.admin.DevicePolicyManager.EXTRA_BUGREPORT_NOTIFICATION_TYPE;
+import static android.app.admin.DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH;
+import static android.app.admin.DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED;
+import static android.app.admin.DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED;
+import static android.app.admin.DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED;
+
+import android.annotation.IntDef;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.admin.DeviceAdminReceiver;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.format.DateUtils;
+import android.util.Pair;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.notification.SystemNotificationChannels;
+
+import java.io.FileNotFoundException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Class managing bugreport collection upon device owner's request.
+ */
+public class RemoteBugreportManager {
+ private static final String LOG_TAG = DevicePolicyManagerService.LOG_TAG;
+
+ static final String BUGREPORT_MIMETYPE = "application/vnd.android.bugreport";
+
+ private static final long REMOTE_BUGREPORT_TIMEOUT_MILLIS = 10 * DateUtils.MINUTE_IN_MILLIS;
+ private static final String CTL_STOP = "ctl.stop";
+ private static final String REMOTE_BUGREPORT_SERVICE = "bugreportd";
+ private static final int NOTIFICATION_ID = SystemMessage.NOTE_REMOTE_BUGREPORT;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ NOTIFICATION_BUGREPORT_STARTED,
+ NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED,
+ NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED
+ })
+ @interface RemoteBugreportNotificationType {}
+ private final DevicePolicyManagerService mService;
+ private final DevicePolicyManagerService.Injector mInjector;
+
+ private final AtomicBoolean mRemoteBugreportServiceIsActive = new AtomicBoolean();
+ private final AtomicBoolean mRemoteBugreportSharingAccepted = new AtomicBoolean();
+ private final Context mContext;
+
+ private final Handler mHandler;
+
+ private final Runnable mRemoteBugreportTimeoutRunnable = () -> {
+ if (mRemoteBugreportServiceIsActive.get()) {
+ onBugreportFailed();
+ }
+ };
+
+ private final BroadcastReceiver mRemoteBugreportFinishedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (ACTION_REMOTE_BUGREPORT_DISPATCH.equals(intent.getAction())
+ && mRemoteBugreportServiceIsActive.get()) {
+ onBugreportFinished(intent);
+ }
+ }
+ };
+
+ private final BroadcastReceiver mRemoteBugreportConsentReceiver = new BroadcastReceiver() {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ mInjector.getNotificationManager().cancel(LOG_TAG, NOTIFICATION_ID);
+ if (ACTION_BUGREPORT_SHARING_ACCEPTED.equals(action)) {
+ onBugreportSharingAccepted();
+ } else if (ACTION_BUGREPORT_SHARING_DECLINED.equals(action)) {
+ onBugreportSharingDeclined();
+ }
+ mContext.unregisterReceiver(mRemoteBugreportConsentReceiver);
+ }
+ };
+
+ public RemoteBugreportManager(
+ DevicePolicyManagerService service, DevicePolicyManagerService.Injector injector) {
+ mService = service;
+ mInjector = injector;
+ mContext = service.mContext;
+ mHandler = service.mHandler;
+ }
+
+ private Notification buildNotification(@RemoteBugreportNotificationType int type) {
+ final Intent dialogIntent = new Intent(Settings.ACTION_SHOW_REMOTE_BUGREPORT_DIALOG);
+ dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ dialogIntent.putExtra(EXTRA_BUGREPORT_NOTIFICATION_TYPE, type);
+
+ // Fill the component explicitly to prevent the PendingIntent from being intercepted
+ // and fired with crafted target. b/155183624
+ final ActivityInfo targetInfo = dialogIntent.resolveActivityInfo(
+ mContext.getPackageManager(), PackageManager.MATCH_SYSTEM_ONLY);
+ if (targetInfo != null) {
+ dialogIntent.setComponent(targetInfo.getComponentName());
+ } else {
+ Slog.wtf(LOG_TAG, "Failed to resolve intent for remote bugreport dialog");
+ }
+
+ final PendingIntent pendingDialogIntent = PendingIntent.getActivityAsUser(mContext, type,
+ dialogIntent, 0, null, UserHandle.CURRENT);
+
+ final Notification.Builder builder =
+ new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN)
+ .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+ .setOngoing(true)
+ .setLocalOnly(true)
+ .setContentIntent(pendingDialogIntent)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color));
+
+ if (type == NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED) {
+ builder.setContentTitle(mContext.getString(
+ R.string.sharing_remote_bugreport_notification_title))
+ .setProgress(0, 0, true);
+ } else if (type == NOTIFICATION_BUGREPORT_STARTED) {
+ builder.setContentTitle(mContext.getString(
+ R.string.taking_remote_bugreport_notification_title))
+ .setProgress(0, 0, true);
+ } else if (type == NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED) {
+ final PendingIntent pendingIntentAccept = PendingIntent.getBroadcast(mContext,
+ NOTIFICATION_ID, new Intent(ACTION_BUGREPORT_SHARING_ACCEPTED),
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ final PendingIntent pendingIntentDecline = PendingIntent.getBroadcast(mContext,
+ NOTIFICATION_ID, new Intent(ACTION_BUGREPORT_SHARING_DECLINED),
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ builder.addAction(new Notification.Action.Builder(null /* icon */, mContext.getString(
+ R.string.decline_remote_bugreport_action), pendingIntentDecline).build())
+ .addAction(new Notification.Action.Builder(null /* icon */, mContext.getString(
+ R.string.share_remote_bugreport_action), pendingIntentAccept).build())
+ .setContentTitle(mContext.getString(
+ R.string.share_remote_bugreport_notification_title))
+ .setContentText(mContext.getString(
+ R.string.share_remote_bugreport_notification_message_finished))
+ .setStyle(new Notification.BigTextStyle().bigText(mContext.getString(
+ R.string.share_remote_bugreport_notification_message_finished)));
+ }
+
+ return builder.build();
+ }
+
+ /**
+ * Initiates bugreport collection.
+ * @return whether collection was initiated successfully.
+ */
+ public boolean requestBugreport() {
+ if (mRemoteBugreportServiceIsActive.get()
+ || (mService.getDeviceOwnerRemoteBugreportUriAndHash() != null)) {
+ Slog.d(LOG_TAG, "Remote bugreport wasn't started because there's already one running.");
+ return false;
+ }
+
+ final long callingIdentity = mInjector.binderClearCallingIdentity();
+ try {
+ mInjector.getIActivityManager().requestRemoteBugReport();
+
+ mRemoteBugreportServiceIsActive.set(true);
+ mRemoteBugreportSharingAccepted.set(false);
+ registerRemoteBugreportReceivers();
+ mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
+ buildNotification(NOTIFICATION_BUGREPORT_STARTED), UserHandle.ALL);
+ mHandler.postDelayed(mRemoteBugreportTimeoutRunnable, REMOTE_BUGREPORT_TIMEOUT_MILLIS);
+ return true;
+ } catch (RemoteException re) {
+ // should never happen
+ Slog.e(LOG_TAG, "Failed to make remote calls to start bugreportremote service", re);
+ return false;
+ } finally {
+ mInjector.binderRestoreCallingIdentity(callingIdentity);
+ }
+ }
+
+ private void registerRemoteBugreportReceivers() {
+ try {
+ final IntentFilter filterFinished =
+ new IntentFilter(ACTION_REMOTE_BUGREPORT_DISPATCH, BUGREPORT_MIMETYPE);
+ mContext.registerReceiver(mRemoteBugreportFinishedReceiver, filterFinished);
+ } catch (IntentFilter.MalformedMimeTypeException e) {
+ // should never happen, as setting a constant
+ Slog.w(LOG_TAG, "Failed to set type " + BUGREPORT_MIMETYPE, e);
+ }
+ final IntentFilter filterConsent = new IntentFilter();
+ filterConsent.addAction(ACTION_BUGREPORT_SHARING_DECLINED);
+ filterConsent.addAction(ACTION_BUGREPORT_SHARING_ACCEPTED);
+ mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
+ }
+
+ private void onBugreportFinished(Intent intent) {
+ mHandler.removeCallbacks(mRemoteBugreportTimeoutRunnable);
+ mRemoteBugreportServiceIsActive.set(false);
+ final Uri bugreportUri = intent.getData();
+ String bugreportUriString = null;
+ if (bugreportUri != null) {
+ bugreportUriString = bugreportUri.toString();
+ }
+ final String bugreportHash = intent.getStringExtra(EXTRA_REMOTE_BUGREPORT_HASH);
+ if (mRemoteBugreportSharingAccepted.get()) {
+ shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
+ mInjector.getNotificationManager().cancel(LOG_TAG,
+ NOTIFICATION_ID);
+ } else {
+ mService.setDeviceOwnerRemoteBugreportUriAndHash(bugreportUriString, bugreportHash);
+ mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
+ buildNotification(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED),
+ UserHandle.ALL);
+ }
+ mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
+ }
+
+ private void onBugreportFailed() {
+ mRemoteBugreportServiceIsActive.set(false);
+ mInjector.systemPropertiesSet(CTL_STOP, REMOTE_BUGREPORT_SERVICE);
+ mRemoteBugreportSharingAccepted.set(false);
+ mService.setDeviceOwnerRemoteBugreportUriAndHash(null, null);
+ mInjector.getNotificationManager().cancel(LOG_TAG, NOTIFICATION_ID);
+ final Bundle extras = new Bundle();
+ extras.putInt(DeviceAdminReceiver.EXTRA_BUGREPORT_FAILURE_REASON,
+ DeviceAdminReceiver.BUGREPORT_FAILURE_FAILED_COMPLETING);
+ mService.sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_BUGREPORT_FAILED, extras);
+ mContext.unregisterReceiver(mRemoteBugreportConsentReceiver);
+ mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
+ }
+
+ private void onBugreportSharingAccepted() {
+ mRemoteBugreportSharingAccepted.set(true);
+ final Pair<String, String> uriAndHash = mService.getDeviceOwnerRemoteBugreportUriAndHash();
+ if (uriAndHash != null) {
+ shareBugreportWithDeviceOwnerIfExists(uriAndHash.first, uriAndHash.second);
+ } else if (mRemoteBugreportServiceIsActive.get()) {
+ mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
+ buildNotification(NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED),
+ UserHandle.ALL);
+ }
+ }
+
+ private void onBugreportSharingDeclined() {
+ if (mRemoteBugreportServiceIsActive.get()) {
+ mInjector.systemPropertiesSet(CTL_STOP,
+ REMOTE_BUGREPORT_SERVICE);
+ mRemoteBugreportServiceIsActive.set(false);
+ mHandler.removeCallbacks(mRemoteBugreportTimeoutRunnable);
+ mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
+ }
+ mRemoteBugreportSharingAccepted.set(false);
+ mService.setDeviceOwnerRemoteBugreportUriAndHash(null, null);
+ mService.sendDeviceOwnerCommand(
+ DeviceAdminReceiver.ACTION_BUGREPORT_SHARING_DECLINED, null);
+ }
+
+ private void shareBugreportWithDeviceOwnerIfExists(
+ String bugreportUriString, String bugreportHash) {
+ try {
+ if (bugreportUriString == null) {
+ throw new FileNotFoundException();
+ }
+ final Uri bugreportUri = Uri.parse(bugreportUriString);
+ mService.sendBugreportToDeviceOwner(bugreportUri, bugreportHash);
+ } catch (FileNotFoundException e) {
+ final Bundle extras = new Bundle();
+ extras.putInt(DeviceAdminReceiver.EXTRA_BUGREPORT_FAILURE_REASON,
+ DeviceAdminReceiver.BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE);
+ mService.sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_BUGREPORT_FAILED, extras);
+ } finally {
+ mRemoteBugreportSharingAccepted.set(false);
+ mService.setDeviceOwnerRemoteBugreportUriAndHash(null, null);
+ }
+ }
+
+ /**
+ * Check if a bugreport was collected but not shared before reboot because the user didn't act
+ * upon sharing notification.
+ */
+ public void checkForPendingBugreportAfterBoot() {
+ if (mService.getDeviceOwnerRemoteBugreportUriAndHash() == null) {
+ return;
+ }
+ final IntentFilter filterConsent = new IntentFilter();
+ filterConsent.addAction(ACTION_BUGREPORT_SHARING_DECLINED);
+ filterConsent.addAction(ACTION_BUGREPORT_SHARING_ACCEPTED);
+ mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
+ mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
+ buildNotification(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED), UserHandle.ALL);
+ }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
deleted file mode 100644
index 1630f27..0000000
--- a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2016 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.devicepolicy;
-
-import android.annotation.IntDef;
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.admin.DevicePolicyManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.text.format.DateUtils;
-import android.util.Slog;
-
-import com.android.internal.R;
-import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.internal.notification.SystemNotificationChannels;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Utilities class for the remote bugreport operation.
- */
-class RemoteBugreportUtils {
-
- private static final String TAG = "RemoteBugreportUtils";
- static final int NOTIFICATION_ID = SystemMessage.NOTE_REMOTE_BUGREPORT;
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED,
- DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED,
- DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED
- })
- @interface RemoteBugreportNotificationType {}
-
- static final long REMOTE_BUGREPORT_TIMEOUT_MILLIS = 10 * DateUtils.MINUTE_IN_MILLIS;
-
- static final String CTL_STOP = "ctl.stop";
- static final String REMOTE_BUGREPORT_SERVICE = "bugreportd";
-
- static final String BUGREPORT_MIMETYPE = "application/vnd.android.bugreport";
-
- static Notification buildNotification(Context context,
- @RemoteBugreportNotificationType int type) {
- Intent dialogIntent = new Intent(Settings.ACTION_SHOW_REMOTE_BUGREPORT_DIALOG);
- dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- dialogIntent.putExtra(DevicePolicyManager.EXTRA_BUGREPORT_NOTIFICATION_TYPE, type);
-
- // Fill the component explicitly to prevent the PendingIntent from being intercepted
- // and fired with crafted target. b/155183624
- ActivityInfo targetInfo = dialogIntent.resolveActivityInfo(
- context.getPackageManager(), PackageManager.MATCH_SYSTEM_ONLY);
- if (targetInfo != null) {
- dialogIntent.setComponent(targetInfo.getComponentName());
- } else {
- Slog.wtf(TAG, "Failed to resolve intent for remote bugreport dialog");
- }
-
- PendingIntent pendingDialogIntent = PendingIntent.getActivityAsUser(context, type,
- dialogIntent, 0, null, UserHandle.CURRENT);
-
- Notification.Builder builder =
- new Notification.Builder(context, SystemNotificationChannels.DEVICE_ADMIN)
- .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
- .setOngoing(true)
- .setLocalOnly(true)
- .setContentIntent(pendingDialogIntent)
- .setColor(context.getColor(
- com.android.internal.R.color.system_notification_accent_color));
-
- if (type == DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED) {
- builder.setContentTitle(context.getString(
- R.string.sharing_remote_bugreport_notification_title))
- .setProgress(0, 0, true);
- } else if (type == DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED) {
- builder.setContentTitle(context.getString(
- R.string.taking_remote_bugreport_notification_title))
- .setProgress(0, 0, true);
- } else if (type == DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED) {
- PendingIntent pendingIntentAccept = PendingIntent.getBroadcast(context, NOTIFICATION_ID,
- new Intent(DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED),
- PendingIntent.FLAG_CANCEL_CURRENT);
- PendingIntent pendingIntentDecline = PendingIntent.getBroadcast(context,
- NOTIFICATION_ID, new Intent(
- DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED),
- PendingIntent.FLAG_CANCEL_CURRENT);
- builder.addAction(new Notification.Action.Builder(null /* icon */, context.getString(
- R.string.decline_remote_bugreport_action), pendingIntentDecline).build())
- .addAction(new Notification.Action.Builder(null /* icon */, context.getString(
- R.string.share_remote_bugreport_action), pendingIntentAccept).build())
- .setContentTitle(context.getString(
- R.string.share_remote_bugreport_notification_title))
- .setContentText(context.getString(
- R.string.share_remote_bugreport_notification_message_finished))
- .setStyle(new Notification.BigTextStyle().bigText(context.getString(
- R.string.share_remote_bugreport_notification_message_finished)));
- }
-
- return builder.build();
- }
-}
-
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index 0ae10b6..41945a2 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -237,11 +237,9 @@
return ok();
}
-binder::Status BinderIncrementalService::isFileRangeLoaded(int32_t storageId,
- const std::string& path, int64_t start,
- int64_t end, bool* _aidl_return) {
- // TODO: implement
- *_aidl_return = false;
+binder::Status BinderIncrementalService::getLoadingProgress(int32_t storageId,
+ float* _aidl_return) {
+ *_aidl_return = mImpl.getLoadingProgress(storageId);
return ok();
}
diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h
index 1015494..8b40350 100644
--- a/services/incremental/BinderIncrementalService.h
+++ b/services/incremental/BinderIncrementalService.h
@@ -66,8 +66,7 @@
int32_t destStorageId, const std::string& destPath,
int32_t* _aidl_return) final;
binder::Status unlink(int32_t storageId, const std::string& path, int32_t* _aidl_return) final;
- binder::Status isFileRangeLoaded(int32_t storageId, const std::string& path, int64_t start,
- int64_t end, bool* _aidl_return) final;
+ binder::Status getLoadingProgress(int32_t storageId, float* _aidl_return) final;
binder::Status getMetadataByPath(int32_t storageId, const std::string& path,
std::vector<uint8_t>* _aidl_return) final;
binder::Status getMetadataById(int32_t storageId, const std::vector<uint8_t>& id,
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index f7082a9..ba6ae92 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -37,7 +37,6 @@
#include "Metadata.pb.h"
using namespace std::literals;
-namespace fs = std::filesystem;
constexpr const char* kDataUsageStats = "android.permission.LOADER_USAGE_STATS";
constexpr const char* kOpUsage = "android:loader_usage_stats";
@@ -276,6 +275,7 @@
mJni(sm.getJni()),
mLooper(sm.getLooper()),
mTimedQueue(sm.getTimedQueue()),
+ mFs(sm.getFs()),
mIncrementalDir(rootDir) {
CHECK(mVold) << "Vold service is unavailable";
CHECK(mDataLoaderManager) << "DataLoaderManagerService is unavailable";
@@ -283,6 +283,7 @@
CHECK(mJni) << "JNI is unavailable";
CHECK(mLooper) << "Looper is unavailable";
CHECK(mTimedQueue) << "TimedQueue is unavailable";
+ CHECK(mFs) << "Fs is unavailable";
mJobQueue.reserve(16);
mJobProcessor = std::thread([this]() {
@@ -344,7 +345,8 @@
}
dprintf(fd, " storages (%d): {\n", int(mnt.storages.size()));
for (auto&& [storageId, storage] : mnt.storages) {
- dprintf(fd, " [%d] -> [%s]\n", storageId, storage.name.c_str());
+ dprintf(fd, " [%d] -> [%s] (%d %% loaded) \n", storageId, storage.name.c_str(),
+ (int)(getLoadingProgressFromPath(mnt, storage.name.c_str()) * 100));
}
dprintf(fd, " }\n");
@@ -1671,6 +1673,45 @@
return mRunning;
}
+float IncrementalService::getLoadingProgress(StorageId storage) const {
+ std::unique_lock l(mLock);
+ const auto ifs = getIfsLocked(storage);
+ if (!ifs) {
+ LOG(ERROR) << "getLoadingProgress failed, invalid storageId: " << storage;
+ return -EINVAL;
+ }
+ const auto storageInfo = ifs->storages.find(storage);
+ if (storageInfo == ifs->storages.end()) {
+ LOG(ERROR) << "getLoadingProgress failed, no storage: " << storage;
+ return -EINVAL;
+ }
+ l.unlock();
+ return getLoadingProgressFromPath(*ifs, storageInfo->second.name);
+}
+
+float IncrementalService::getLoadingProgressFromPath(const IncFsMount& ifs,
+ std::string_view storagePath) const {
+ size_t totalBlocks = 0, filledBlocks = 0;
+ const auto filePaths = mFs->listFilesRecursive(storagePath);
+ for (const auto& filePath : filePaths) {
+ const auto [filledBlocksCount, totalBlocksCount] =
+ mIncFs->countFilledBlocks(ifs.control, filePath);
+ if (filledBlocksCount < 0) {
+ LOG(ERROR) << "getLoadingProgress failed to get filled blocks count for: " << filePath
+ << " errno: " << filledBlocksCount;
+ return filledBlocksCount;
+ }
+ totalBlocks += totalBlocksCount;
+ filledBlocks += filledBlocksCount;
+ }
+
+ if (totalBlocks == 0) {
+ LOG(ERROR) << "getLoadingProgress failed to get total num of blocks";
+ return -EINVAL;
+ }
+ return (float)filledBlocks / (float)totalBlocks;
+}
+
bool IncrementalService::perfLoggingEnabled() {
static const bool enabled = base::GetBoolProperty("incremental.perflogging", false);
return enabled;
@@ -2029,11 +2070,13 @@
// Healthcheck depends on timestamp of the oldest pending read.
// To get it, we need to re-open a pendingReads FD to get a full list of reads.
- // Additionally we need to re-register for epoll with fresh FDs in case there are no reads.
+ // Additionally we need to re-register for epoll with fresh FDs in case there are no
+ // reads.
const auto now = Clock::now();
const auto kernelTsUs = getOldestPendingReadTs();
if (baseline) {
- // Updating baseline only on looper/epoll callback, i.e. on new set of pending reads.
+ // Updating baseline only on looper/epoll callback, i.e. on new set of pending
+ // reads.
mHealthBase = {now, kernelTsUs};
}
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index a6cc946..cd6bfed 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -132,9 +132,7 @@
std::string_view newPath);
int unlink(StorageId storage, std::string_view path);
- bool isRangeLoaded(StorageId storage, FileId file, std::pair<BlockIndex, BlockIndex> range) {
- return false;
- }
+ float getLoadingProgress(StorageId storage) const;
RawMetadata getMetadata(StorageId storage, std::string_view path) const;
RawMetadata getMetadata(StorageId storage, FileId node) const;
@@ -341,6 +339,8 @@
int makeDirs(const IncFsMount& ifs, StorageId storageId, std::string_view path, int mode);
binder::Status applyStorageParams(IncFsMount& ifs, bool enableReadLogs);
+ float getLoadingProgressFromPath(const IncFsMount& ifs, std::string_view path) const;
+
void registerAppOpsCallback(const std::string& packageName);
bool unregisterAppOpsCallback(const std::string& packageName);
void onAppOpChanged(const std::string& packageName);
@@ -363,6 +363,7 @@
const std::unique_ptr<JniWrapper> mJni;
const std::unique_ptr<LooperWrapper> mLooper;
const std::unique_ptr<TimedQueueWrapper> mTimedQueue;
+ const std::unique_ptr<FsWrapper> mFs;
const std::string mIncrementalDir;
mutable std::mutex mLock;
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index 99a35ad..1ed46c4 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -25,6 +25,7 @@
#include <binder/AppOpsManager.h>
#include <utils/String16.h>
+#include <filesystem>
#include <thread>
#include "IncrementalServiceValidation.h"
@@ -165,6 +166,29 @@
FileId getFileId(const Control& control, std::string_view path) const final {
return incfs::getFileId(control, path);
}
+ std::pair<IncFsBlockIndex, IncFsBlockIndex> countFilledBlocks(
+ const Control& control, std::string_view path) const final {
+ const auto fileId = incfs::getFileId(control, path);
+ const auto fd = incfs::openForSpecialOps(control, fileId);
+ int res = fd.get();
+ if (!fd.ok()) {
+ return {res, res};
+ }
+ const auto ranges = incfs::getFilledRanges(res);
+ res = ranges.first;
+ if (res) {
+ return {res, res};
+ }
+ const auto totalBlocksCount = ranges.second.internalRawRanges().endIndex;
+ int filledBlockCount = 0;
+ for (const auto& dataRange : ranges.second.dataRanges()) {
+ filledBlockCount += dataRange.size();
+ }
+ for (const auto& hashRange : ranges.second.hashRanges()) {
+ filledBlockCount += hashRange.size();
+ }
+ return {filledBlockCount, totalBlocksCount};
+ }
ErrorCode link(const Control& control, std::string_view from, std::string_view to) const final {
return incfs::link(control, from, to);
}
@@ -265,6 +289,23 @@
std::thread mThread;
};
+class RealFsWrapper : public FsWrapper {
+public:
+ RealFsWrapper() = default;
+ ~RealFsWrapper() = default;
+
+ std::vector<std::string> listFilesRecursive(std::string_view directoryPath) const final {
+ std::vector<std::string> files;
+ for (const auto& entry : std::filesystem::recursive_directory_iterator(directoryPath)) {
+ if (!entry.is_regular_file()) {
+ continue;
+ }
+ files.push_back(entry.path().c_str());
+ }
+ return files;
+ }
+};
+
RealServiceManager::RealServiceManager(sp<IServiceManager> serviceManager, JNIEnv* env)
: mServiceManager(std::move(serviceManager)), mJvm(RealJniWrapper::getJvm(env)) {}
@@ -316,6 +357,10 @@
return std::make_unique<RealTimedQueueWrapper>(mJvm);
}
+std::unique_ptr<FsWrapper> RealServiceManager::getFs() {
+ return std::make_unique<RealFsWrapper>();
+}
+
static JavaVM* getJavaVm(JNIEnv* env) {
CHECK(env);
JavaVM* jvm = nullptr;
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index 8cd726fd..82a1704 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -91,6 +91,8 @@
virtual incfs::RawMetadata getMetadata(const Control& control, FileId fileid) const = 0;
virtual incfs::RawMetadata getMetadata(const Control& control, std::string_view path) const = 0;
virtual FileId getFileId(const Control& control, std::string_view path) const = 0;
+ virtual std::pair<IncFsBlockIndex, IncFsBlockIndex> countFilledBlocks(
+ const Control& control, std::string_view path) const = 0;
virtual ErrorCode link(const Control& control, std::string_view from,
std::string_view to) const = 0;
virtual ErrorCode unlink(const Control& control, std::string_view path) const = 0;
@@ -106,7 +108,8 @@
virtual ~AppOpsManagerWrapper() = default;
virtual binder::Status checkPermission(const char* permission, const char* operation,
const char* package) const = 0;
- virtual void startWatchingMode(int32_t op, const String16& packageName, const sp<IAppOpsCallback>& callback) = 0;
+ virtual void startWatchingMode(int32_t op, const String16& packageName,
+ const sp<IAppOpsCallback>& callback) = 0;
virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0;
};
@@ -134,6 +137,12 @@
virtual void stop() = 0;
};
+class FsWrapper {
+public:
+ virtual ~FsWrapper() = default;
+ virtual std::vector<std::string> listFilesRecursive(std::string_view directoryPath) const = 0;
+};
+
class ServiceManagerWrapper {
public:
virtual ~ServiceManagerWrapper() = default;
@@ -144,6 +153,7 @@
virtual std::unique_ptr<JniWrapper> getJni() = 0;
virtual std::unique_ptr<LooperWrapper> getLooper() = 0;
virtual std::unique_ptr<TimedQueueWrapper> getTimedQueue() = 0;
+ virtual std::unique_ptr<FsWrapper> getFs() = 0;
};
// --- Real stuff ---
@@ -159,6 +169,7 @@
std::unique_ptr<JniWrapper> getJni() final;
std::unique_ptr<LooperWrapper> getLooper() final;
std::unique_ptr<TimedQueueWrapper> getTimedQueue() final;
+ std::unique_ptr<FsWrapper> getFs() final;
private:
template <class INTERFACE>
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 1ae9e25..44cef49 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -54,8 +54,10 @@
MOCK_CONST_METHOD1(unmountIncFs, binder::Status(const std::string& dir));
MOCK_CONST_METHOD2(bindMount,
binder::Status(const std::string& sourceDir, const std::string& argetDir));
- MOCK_CONST_METHOD2(setIncFsMountOptions,
- binder::Status(const ::android::os::incremental::IncrementalFileSystemControlParcel&, bool));
+ MOCK_CONST_METHOD2(
+ setIncFsMountOptions,
+ binder::Status(const ::android::os::incremental::IncrementalFileSystemControlParcel&,
+ bool));
void mountIncFsFails() {
ON_CALL(*this, mountIncFs(_, _, _, _))
@@ -80,8 +82,8 @@
}
void setIncFsMountOptionsFails() const {
ON_CALL(*this, setIncFsMountOptions(_, _))
- .WillByDefault(
- Return(binder::Status::fromExceptionCode(1, String8("failed to set options"))));
+ .WillByDefault(Return(
+ binder::Status::fromExceptionCode(1, String8("failed to set options"))));
}
void setIncFsMountOptionsSuccess() {
ON_CALL(*this, setIncFsMountOptions(_, _)).WillByDefault(Return(binder::Status::ok()));
@@ -280,8 +282,12 @@
MOCK_CONST_METHOD2(getMetadata, RawMetadata(const Control& control, FileId fileid));
MOCK_CONST_METHOD2(getMetadata, RawMetadata(const Control& control, std::string_view path));
MOCK_CONST_METHOD2(getFileId, FileId(const Control& control, std::string_view path));
+ MOCK_CONST_METHOD2(countFilledBlocks,
+ std::pair<IncFsBlockIndex, IncFsBlockIndex>(const Control& control,
+ std::string_view path));
MOCK_CONST_METHOD3(link,
- ErrorCode(const Control& control, std::string_view from, std::string_view to));
+ ErrorCode(const Control& control, std::string_view from,
+ std::string_view to));
MOCK_CONST_METHOD2(unlink, ErrorCode(const Control& control, std::string_view path));
MOCK_CONST_METHOD2(openForSpecialOps, base::unique_fd(const Control& control, FileId id));
MOCK_CONST_METHOD1(writeBlocks, ErrorCode(std::span<const DataBlock> blocks));
@@ -293,6 +299,19 @@
void makeFileFails() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(-1)); }
void makeFileSuccess() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(0)); }
+
+ void countFilledBlocksSuccess() {
+ ON_CALL(*this, countFilledBlocks(_, _)).WillByDefault(Return(std::make_pair(1, 2)));
+ }
+
+ void countFilledBlocksFails() {
+ ON_CALL(*this, countFilledBlocks(_, _)).WillByDefault(Return(std::make_pair(-1, -1)));
+ }
+
+ void countFilledBlocksEmpty() {
+ ON_CALL(*this, countFilledBlocks(_, _)).WillByDefault(Return(std::make_pair(0, 0)));
+ }
+
void openMountSuccess() {
ON_CALL(*this, openMount(_)).WillByDefault(Invoke(this, &MockIncFs::openMountForHealth));
}
@@ -447,6 +466,21 @@
Job mWhat;
};
+class MockFsWrapper : public FsWrapper {
+public:
+ MOCK_CONST_METHOD1(listFilesRecursive, std::vector<std::string>(std::string_view));
+ void hasNoFile() {
+ ON_CALL(*this, listFilesRecursive(_)).WillByDefault(Return(std::vector<std::string>()));
+ }
+ void hasFiles() {
+ ON_CALL(*this, listFilesRecursive(_))
+ .WillByDefault(Invoke(this, &MockFsWrapper::fakeFiles));
+ }
+ std::vector<std::string> fakeFiles(std::string_view directoryPath) {
+ return {"base.apk", "split.apk", "lib/a.so"};
+ }
+};
+
class MockStorageHealthListener : public os::incremental::BnStorageHealthListener {
public:
MOCK_METHOD2(onHealthStatus, binder::Status(int32_t storageId, int32_t status));
@@ -474,23 +508,28 @@
std::unique_ptr<MockAppOpsManager> appOpsManager,
std::unique_ptr<MockJniWrapper> jni,
std::unique_ptr<MockLooperWrapper> looper,
- std::unique_ptr<MockTimedQueueWrapper> timedQueue)
+ std::unique_ptr<MockTimedQueueWrapper> timedQueue,
+ std::unique_ptr<MockFsWrapper> fs)
: mVold(std::move(vold)),
mDataLoaderManager(std::move(dataLoaderManager)),
mIncFs(std::move(incfs)),
mAppOpsManager(std::move(appOpsManager)),
mJni(std::move(jni)),
mLooper(std::move(looper)),
- mTimedQueue(std::move(timedQueue)) {}
+ mTimedQueue(std::move(timedQueue)),
+ mFs(std::move(fs)) {}
std::unique_ptr<VoldServiceWrapper> getVoldService() final { return std::move(mVold); }
std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final {
return std::move(mDataLoaderManager);
}
std::unique_ptr<IncFsWrapper> getIncFs() final { return std::move(mIncFs); }
- std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final { return std::move(mAppOpsManager); }
+ std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final {
+ return std::move(mAppOpsManager);
+ }
std::unique_ptr<JniWrapper> getJni() final { return std::move(mJni); }
std::unique_ptr<LooperWrapper> getLooper() final { return std::move(mLooper); }
std::unique_ptr<TimedQueueWrapper> getTimedQueue() final { return std::move(mTimedQueue); }
+ std::unique_ptr<FsWrapper> getFs() final { return std::move(mFs); }
private:
std::unique_ptr<MockVoldService> mVold;
@@ -500,6 +539,7 @@
std::unique_ptr<MockJniWrapper> mJni;
std::unique_ptr<MockLooperWrapper> mLooper;
std::unique_ptr<MockTimedQueueWrapper> mTimedQueue;
+ std::unique_ptr<MockFsWrapper> mFs;
};
// --- IncrementalServiceTest ---
@@ -523,6 +563,8 @@
mLooper = looper.get();
auto timedQueue = std::make_unique<NiceMock<MockTimedQueueWrapper>>();
mTimedQueue = timedQueue.get();
+ auto fs = std::make_unique<NiceMock<MockFsWrapper>>();
+ mFs = fs.get();
mIncrementalService =
std::make_unique<IncrementalService>(MockServiceManager(std::move(vold),
std::move(
@@ -531,12 +573,14 @@
std::move(appOps),
std::move(jni),
std::move(looper),
- std::move(timedQueue)),
+ std::move(timedQueue),
+ std::move(fs)),
mRootDir.path);
mDataLoaderParcel.packageName = "com.test";
mDataLoaderParcel.arguments = "uri";
mDataLoaderManager->unbindFromDataLoaderSuccess();
mIncrementalService->onSystemReady();
+ setupSuccess();
}
void setUpExistingMountDir(const std::string& rootDir) {
@@ -560,6 +604,14 @@
.WillByDefault(Invoke(mIncFs, &MockIncFs::getStorageMetadata));
}
+ void setupSuccess() {
+ mVold->mountIncFsSuccess();
+ mIncFs->makeFileSuccess();
+ mVold->bindMountSuccess();
+ mDataLoaderManager->bindToDataLoaderSuccess();
+ mDataLoaderManager->getDataLoaderSuccess();
+ }
+
protected:
NiceMock<MockVoldService>* mVold = nullptr;
NiceMock<MockIncFs>* mIncFs = nullptr;
@@ -568,6 +620,7 @@
NiceMock<MockJniWrapper>* mJni = nullptr;
NiceMock<MockLooperWrapper>* mLooper = nullptr;
NiceMock<MockTimedQueueWrapper>* mTimedQueue = nullptr;
+ NiceMock<MockFsWrapper>* mFs = nullptr;
NiceMock<MockDataLoader>* mDataLoader = nullptr;
std::unique_ptr<IncrementalService> mIncrementalService;
TemporaryDir mRootDir;
@@ -641,11 +694,6 @@
}
TEST_F(IncrementalServiceTest, testDeleteStorageSuccess) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
@@ -661,11 +709,6 @@
}
TEST_F(IncrementalServiceTest, testDataLoaderDestroyed) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(2);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(2);
@@ -682,12 +725,7 @@
}
TEST_F(IncrementalServiceTest, testStartDataLoaderCreate) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
mDataLoader->initializeCreateOkNoStatus();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
@@ -705,12 +743,7 @@
}
TEST_F(IncrementalServiceTest, testStartDataLoaderPendingStart) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
mDataLoader->initializeCreateOkNoStatus();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(2);
@@ -727,12 +760,7 @@
}
TEST_F(IncrementalServiceTest, testStartDataLoaderCreateUnavailable) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
mDataLoader->initializeCreateOkNoStatus();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
@@ -748,14 +776,10 @@
}
TEST_F(IncrementalServiceTest, testStartDataLoaderRecreateOnPendingReads) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mIncFs->openMountSuccess();
mIncFs->waitForPendingReadsSuccess();
- mVold->bindMountSuccess();
+ mIncFs->openMountSuccess();
mDataLoader->initializeCreateOkNoStatus();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
+
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(2);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(2);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(2);
@@ -776,12 +800,8 @@
}
TEST_F(IncrementalServiceTest, testStartDataLoaderUnhealthyStorage) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
mIncFs->openMountSuccess();
- mVold->bindMountSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
+
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
@@ -906,13 +926,9 @@
}
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
mVold->setIncFsMountOptionsSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
mAppOpsManager->checkPermissionSuccess();
+
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// We are calling setIncFsMountOptions(true).
@@ -930,13 +946,9 @@
}
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndDisabled) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
mVold->setIncFsMountOptionsSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
mAppOpsManager->checkPermissionSuccess();
+
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// Enabling and then disabling readlogs.
@@ -958,14 +970,10 @@
}
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndPermissionChanged) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
mVold->setIncFsMountOptionsSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
mAppOpsManager->checkPermissionSuccess();
mAppOpsManager->initializeStartWatchingMode();
+
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// We are calling setIncFsMountOptions(true).
@@ -987,12 +995,8 @@
}
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsCheckPermissionFails) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
mAppOpsManager->checkPermissionFails();
+
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// checkPermission fails, no calls to set opitions, start or stop WatchingMode.
@@ -1008,13 +1012,9 @@
}
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsFails) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
mVold->setIncFsMountOptionsFails();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
mAppOpsManager->checkPermissionSuccess();
+
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// We are calling setIncFsMountOptions.
@@ -1031,11 +1031,6 @@
}
TEST_F(IncrementalServiceTest, testMakeDirectory) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
TemporaryDir tempDir;
int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
IncrementalService::CreateOptions::CreateNew,
@@ -1055,11 +1050,6 @@
}
TEST_F(IncrementalServiceTest, testMakeDirectories) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
TemporaryDir tempDir;
int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
IncrementalService::CreateOptions::CreateNew,
@@ -1078,4 +1068,51 @@
auto res = mIncrementalService->makeDirs(storageId, dir_path, 0555);
ASSERT_EQ(res, 0);
}
+
+TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithNoFile) {
+ mIncFs->countFilledBlocksSuccess();
+ mFs->hasNoFile();
+
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
+ ASSERT_EQ(-EINVAL, mIncrementalService->getLoadingProgress(storageId));
+}
+
+TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithFailedRanges) {
+ mIncFs->countFilledBlocksFails();
+ mFs->hasFiles();
+
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
+ EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
+ ASSERT_EQ(-1, mIncrementalService->getLoadingProgress(storageId));
+}
+
+TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithEmptyRanges) {
+ mIncFs->countFilledBlocksEmpty();
+ mFs->hasFiles();
+
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
+ EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(3);
+ ASSERT_EQ(-EINVAL, mIncrementalService->getLoadingProgress(storageId));
+}
+
+TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccess) {
+ mIncFs->countFilledBlocksSuccess();
+ mFs->hasFiles();
+
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
+ EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(3);
+ ASSERT_EQ(0.5, mIncrementalService->getLoadingProgress(storageId));
+}
} // namespace android::os::incremental
diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
index 4b25890..5fa809f 100644
--- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
+++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
@@ -204,10 +204,10 @@
CROSS_PROFILE_APP_PACKAGE_NAME, PERSONAL_PROFILE_UID, PERSONAL_PROFILE_USER_ID);
ShadowApplicationPackageManager.setPackageUidAsUser(
CROSS_PROFILE_APP_PACKAGE_NAME, WORK_PROFILE_UID, WORK_PROFILE_USER_ID);
- when(mPackageManagerInternal.getPackageUidInternal(
+ when(mPackageManagerInternal.getPackageUid(
CROSS_PROFILE_APP_PACKAGE_NAME, /* flags= */ 0, PERSONAL_PROFILE_USER_ID))
.thenReturn(PERSONAL_PROFILE_UID);
- when(mPackageManagerInternal.getPackageUidInternal(
+ when(mPackageManagerInternal.getPackageUid(
CROSS_PROFILE_APP_PACKAGE_NAME, /* flags= */ 0, WORK_PROFILE_USER_ID))
.thenReturn(WORK_PROFILE_UID);
}
diff --git a/services/tests/servicestests/src/android/location/timezone/LocationTimeZoneEventTest.java b/services/tests/servicestests/src/android/location/timezone/LocationTimeZoneEventTest.java
index 80373ac..f9dd7dc 100644
--- a/services/tests/servicestests/src/android/location/timezone/LocationTimeZoneEventTest.java
+++ b/services/tests/servicestests/src/android/location/timezone/LocationTimeZoneEventTest.java
@@ -23,6 +23,8 @@
import static java.util.Collections.singletonList;
+import android.os.UserHandle;
+
import org.junit.Test;
import java.util.List;
@@ -33,6 +35,10 @@
private static final List<String> ARBITRARY_TIME_ZONE_IDS = singletonList("Europe/London");
+ private static final UserHandle ARBITRARY_USER_HANDLE = UserHandle.SYSTEM;
+ private static final UserHandle ARBITRARY_USER_HANDLE2 =
+ UserHandle.of(ARBITRARY_USER_HANDLE.getIdentifier() + 1);
+
@Test(expected = RuntimeException.class)
public void testSetInvalidEventType() {
new LocationTimeZoneEvent.Builder().setEventType(Integer.MAX_VALUE);
@@ -41,6 +47,7 @@
@Test(expected = RuntimeException.class)
public void testBuildUnsetEventType() {
new LocationTimeZoneEvent.Builder()
+ .setUserHandle(ARBITRARY_USER_HANDLE)
.setTimeZoneIds(ARBITRARY_TIME_ZONE_IDS)
.setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS)
.build();
@@ -49,6 +56,7 @@
@Test(expected = RuntimeException.class)
public void testInvalidTimeZoneIds() {
new LocationTimeZoneEvent.Builder()
+ .setUserHandle(ARBITRARY_USER_HANDLE)
.setEventType(LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN)
.setTimeZoneIds(ARBITRARY_TIME_ZONE_IDS)
.setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS)
@@ -58,6 +66,7 @@
@Test
public void testEquals() {
LocationTimeZoneEvent.Builder builder1 = new LocationTimeZoneEvent.Builder()
+ .setUserHandle(ARBITRARY_USER_HANDLE)
.setEventType(LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN)
.setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS);
{
@@ -66,6 +75,7 @@
}
LocationTimeZoneEvent.Builder builder2 = new LocationTimeZoneEvent.Builder()
+ .setUserHandle(ARBITRARY_USER_HANDLE)
.setEventType(LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN)
.setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS);
{
@@ -75,6 +85,22 @@
assertEquals(two, one);
}
+ builder1.setUserHandle(ARBITRARY_USER_HANDLE2);
+ {
+ LocationTimeZoneEvent one = builder1.build();
+ LocationTimeZoneEvent two = builder2.build();
+ assertNotEquals(one, two);
+ assertNotEquals(two, one);
+ }
+
+ builder2.setUserHandle(ARBITRARY_USER_HANDLE2);
+ {
+ LocationTimeZoneEvent one = builder1.build();
+ LocationTimeZoneEvent two = builder2.build();
+ assertEquals(one, two);
+ assertEquals(two, one);
+ }
+
builder1.setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS + 1);
{
LocationTimeZoneEvent one = builder1.build();
@@ -127,6 +153,7 @@
@Test
public void testParcelable() {
LocationTimeZoneEvent.Builder builder = new LocationTimeZoneEvent.Builder()
+ .setUserHandle(ARBITRARY_USER_HANDLE)
.setEventType(LocationTimeZoneEvent.EVENT_TYPE_PERMANENT_FAILURE)
.setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS);
assertRoundTripParcelable(builder.build());
diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
index b7a36f2..8d4f2aa 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.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 @@
@Test
public void createService_initializesNativeService() {
createService();
- verify(mNativeWrapperMock).vibratorInit();
+ verify(mNativeWrapperMock).vibratorInit(notNull());
verify(mNativeWrapperMock).vibratorOff();
}
@@ -294,7 +295,7 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
@Test
public void vibrate_withOneShotAndNativeCallbackTriggered_finishesVibration() {
- doAnswer(invocation -> {
- ((VibratorService.Vibration) invocation.getArgument(1)).onComplete();
- return null;
- }).when(mNativeWrapperMock).vibratorOn(anyLong(), any(VibratorService.Vibration.class));
VibratorService service = createService();
+ doAnswer(invocation -> {
+ service.onVibrationComplete(invocation.getArgument(1));
+ return null;
+ }).when(mNativeWrapperMock).vibratorOn(anyLong(), anyLong());
Mockito.clearInvocations(mNativeWrapperMock);
vibrate(service, VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE));
@@ -396,7 +395,7 @@
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 void vibrate_withPrebakedAndNativeCallbackTriggered_finishesVibration() {
when(mNativeWrapperMock.vibratorGetSupportedEffects())
.thenReturn(new int[]{VibrationEffect.EFFECT_CLICK});
- doAnswer(invocation -> {
- ((VibratorService.Vibration) invocation.getArgument(2)).onComplete();
- return 10_000L; // 10s
- }).when(mNativeWrapperMock).vibratorPerformEffect(
- anyLong(), anyLong(), any(VibratorService.Vibration.class));
VibratorService service = createService();
+ doAnswer(invocation -> {
+ service.onVibrationComplete(invocation.getArgument(2));
+ return 10_000L; // 10s
+ }).when(mNativeWrapperMock).vibratorPerformEffect(anyLong(), anyLong(), anyLong());
Mockito.clearInvocations(mNativeWrapperMock);
vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
@@ -419,7 +417,7 @@
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,20 +434,19 @@
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();
+ doAnswer(invocation -> {
+ service.onVibrationComplete(invocation.getArgument(1));
+ return null;
+ }).when(mNativeWrapperMock).vibratorPerformComposedEffect(any(), anyLong());
Mockito.clearInvocations(mNativeWrapperMock);
VibrationEffect effect = VibrationEffect.startComposition()
@@ -460,32 +457,7 @@
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();
- 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));
+ any(VibrationEffect.Composition.PrimitiveEffect[].class), gt(0L));
inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
}
@@ -513,12 +485,11 @@
@Test
public void registerVibratorStateListener_callbacksAreTriggered() throws Exception {
- doAnswer(invocation -> {
- ((VibratorService.Vibration) invocation.getArgument(1)).onComplete();
- return null;
- }).when(mNativeWrapperMock).vibratorOn(anyLong(), any(VibratorService.Vibration.class));
VibratorService service = createService();
-
+ doAnswer(invocation -> {
+ service.onVibrationComplete(invocation.getArgument(1));
+ return null;
+ }).when(mNativeWrapperMock).vibratorOn(anyLong(), anyLong());
service.registerVibratorStateListener(mVibratorStateListenerMock);
verify(mVibratorStateListenerMock).onVibrating(false);
Mockito.clearInvocations(mVibratorStateListenerMock);
@@ -569,15 +540,15 @@
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 @@
// 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/magnification/MockWindowMagnificationConnection.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java
index c29c510..42ba842f 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java
@@ -17,23 +17,33 @@
package com.android.server.accessibility.magnification;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.view.Display;
import android.view.accessibility.IWindowMagnificationConnection;
import android.view.accessibility.IWindowMagnificationConnectionCallback;
+/**
+ * Mocks the basic logic of window magnification in System UI. We assume the screen size is
+ * unlimited, so source bounds is always on the center of the mirror window bounds.
+ */
class MockWindowMagnificationConnection {
+ public static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY;
private final IWindowMagnificationConnection mConnection;
private final Binder mBinder;
private IBinder.DeathRecipient mDeathRecipient;
private IWindowMagnificationConnectionCallback mIMirrorWindowCallback;
+ private Rect mMirrorWindowFrame = new Rect(0, 0, 500, 500);
MockWindowMagnificationConnection() throws RemoteException {
mConnection = mock(IWindowMagnificationConnection.class);
@@ -50,6 +60,30 @@
return null;
}).when(mBinder).linkToDeath(
any(IBinder.DeathRecipient.class), eq(0));
+ stubConnection();
+ }
+
+ private void stubConnection() throws RemoteException {
+ doAnswer((invocation) -> {
+ final int displayId = invocation.getArgument(0);
+ if (displayId != TEST_DISPLAY) {
+ throw new IllegalArgumentException("only support default display :" + displayId);
+ }
+ computeMirrorWindowFrame(invocation.getArgument(1), invocation.getArgument(2));
+
+ mIMirrorWindowCallback.onWindowMagnifierBoundsChanged(TEST_DISPLAY,
+ mMirrorWindowFrame);
+ return null;
+ }).when(mConnection).enableWindowMagnification(anyInt(),
+ anyFloat(), anyFloat(), anyFloat());
+ }
+
+ private void computeMirrorWindowFrame(float centerX, float centerY) {
+ final float offsetX = Float.isNaN(centerX) ? 0
+ : centerX - mMirrorWindowFrame.exactCenterX();
+ final float offsetY = Float.isNaN(centerY) ? 0
+ : centerY - mMirrorWindowFrame.exactCenterY();
+ mMirrorWindowFrame.offset((int) offsetX, (int) offsetY);
}
IWindowMagnificationConnection getConnection() {
@@ -60,12 +94,16 @@
return mBinder;
}
- public IBinder.DeathRecipient getDeathRecipient() {
+ IBinder.DeathRecipient getDeathRecipient() {
return mDeathRecipient;
}
- public IWindowMagnificationConnectionCallback getConnectionCallback() {
+ IWindowMagnificationConnectionCallback getConnectionCallback() {
return mIMirrorWindowCallback;
}
+
+ public Rect getMirrorWindowFrame() {
+ return new Rect(mMirrorWindowFrame);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownTest.java
index 2b1bdc5..ed8dc4e 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownTest.java
@@ -87,15 +87,15 @@
secondPointerCoords.x = DEFAULT_X + 10;
secondPointerCoords.y = DEFAULT_Y + 10;
- final MotionEvent pointerDownEvent = TouchEventGenerator.pointerDownEvent(
+ final MotionEvent twoPointersDownEvent = TouchEventGenerator.twoPointersDownEvent(
Display.DEFAULT_DISPLAY, defPointerCoords, secondPointerCoords);
mGesturesObserver.onMotionEvent(downEvent, downEvent, 0);
- mGesturesObserver.onMotionEvent(pointerDownEvent, pointerDownEvent, 0);
+ mGesturesObserver.onMotionEvent(twoPointersDownEvent, twoPointersDownEvent, 0);
verify(mListener, timeout(sTimeoutMillis)).onGestureCompleted(
- MagnificationGestureMatcher.GESTURE_TWO_FINGER_DOWN, pointerDownEvent,
- pointerDownEvent, 0);
+ MagnificationGestureMatcher.GESTURE_TWO_FINGER_DOWN, twoPointersDownEvent,
+ twoPointersDownEvent, 0);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
index e580340..bec9f26 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
@@ -16,14 +16,9 @@
package com.android.server.accessibility.magnification;
-import static android.view.MotionEvent.ACTION_POINTER_DOWN;
-
import static com.android.server.testutils.TestUtils.strictMock;
import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.anyFloat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import android.content.Context;
@@ -63,11 +58,9 @@
public static final int LAST_STATE = STATE_SHOW_MAGNIFIER_TRIPLE_TAP;
// Co-prime x and y, to potentially catch x-y-swapped errors
- public static final float DEFAULT_X = 301;
- public static final float DEFAULT_Y = 299;
- //Assume first pointer position (DEFAULT_X,DEFAULT_Y) is in the window.
- public static Rect DEFAULT_WINDOW_FRAME = new Rect(0, 0, 500, 500);
- private static final int DISPLAY_0 = 0;
+ public static final float DEFAULT_TAP_X = 301;
+ public static final float DEFAULT_TAP_Y = 299;
+ private static final int DISPLAY_0 = MockWindowMagnificationConnection.TEST_DISPLAY;
private Context mContext;
private WindowMagnificationManager mWindowMagnificationManager;
@@ -83,14 +76,6 @@
mContext, mWindowMagnificationManager, mock(ScaleChangedListener.class),
/** detectTripleTap= */true, /** detectShortcutTrigger= */true, DISPLAY_0);
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mMockConnection.getConnectionCallback().onWindowMagnifierBoundsChanged(DISPLAY_0,
- DEFAULT_WINDOW_FRAME);
- doAnswer((invocation) -> {
- mMockConnection.getConnectionCallback().onWindowMagnifierBoundsChanged(DISPLAY_0,
- DEFAULT_WINDOW_FRAME);
- return null;
- }).when(mMockConnection.getConnection()).enableWindowMagnification(eq(DISPLAY_0),
- anyFloat(), anyFloat(), anyFloat());
mWindowMagnificationGestureHandler.setNext(strictMock(EventStreamTransformation.class));
}
@@ -208,10 +193,11 @@
break;
case STATE_TWO_FINGERS_DOWN: {
goFromStateIdleTo(STATE_SHOW_MAGNIFIER);
- send(downEvent());
+ final Rect frame = mMockConnection.getMirrorWindowFrame();
+ send(downEvent(frame.centerX(), frame.centerY()));
//Second finger is outside the window.
- send(pointerEvent(ACTION_POINTER_DOWN, DEFAULT_WINDOW_FRAME.right + 10,
- DEFAULT_WINDOW_FRAME.bottom + 10));
+ send(twoPointerDownEvent(new float[]{frame.centerX(), frame.centerX() + 10},
+ new float[]{frame.centerY(), frame.centerY() + 10}));
}
break;
case STATE_SHOW_MAGNIFIER_TRIPLE_TAP: {
@@ -243,7 +229,8 @@
}
break;
case STATE_TWO_FINGERS_DOWN: {
- send(upEvent());
+ final Rect frame = mMockConnection.getMirrorWindowFrame();
+ send(upEvent(frame.centerX(), frame.centerY()));
returnToNormalFrom(STATE_SHOW_MAGNIFIER);
}
break;
@@ -286,12 +273,8 @@
}
}
- private MotionEvent downEvent() {
- return TouchEventGenerator.downEvent(DISPLAY_0, DEFAULT_X, DEFAULT_Y);
- }
-
- private MotionEvent upEvent() {
- return upEvent(DEFAULT_X, DEFAULT_Y);
+ private MotionEvent downEvent(float x, float y) {
+ return TouchEventGenerator.downEvent(DISPLAY_0, x, y);
}
private MotionEvent upEvent(float x, float y) {
@@ -299,18 +282,18 @@
}
private void tap() {
- send(downEvent());
- send(upEvent());
+ send(downEvent(DEFAULT_TAP_X, DEFAULT_TAP_Y));
+ send(upEvent(DEFAULT_TAP_X, DEFAULT_TAP_Y));
}
- private MotionEvent pointerEvent(int action, float x, float y) {
+ private MotionEvent twoPointerDownEvent(float[] x, float[] y) {
final MotionEvent.PointerCoords defPointerCoords = new MotionEvent.PointerCoords();
- defPointerCoords.x = DEFAULT_X;
- defPointerCoords.y = DEFAULT_Y;
+ defPointerCoords.x = x[0];
+ defPointerCoords.y = y[0];
final MotionEvent.PointerCoords pointerCoords = new MotionEvent.PointerCoords();
- pointerCoords.x = x;
- pointerCoords.y = y;
- return TouchEventGenerator.pointerDownEvent(DISPLAY_0, defPointerCoords, pointerCoords);
+ pointerCoords.x = x[1];
+ pointerCoords.y = y[1];
+ return TouchEventGenerator.twoPointersDownEvent(DISPLAY_0, defPointerCoords, pointerCoords);
}
private String stateDump() {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java b/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java
index 7cbf3ee..a05881f 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java
@@ -43,9 +43,9 @@
return generateSingleTouchEvent(displayId, ACTION_UP, x, y);
}
- public static MotionEvent pointerDownEvent(int displayId, PointerCoords defPointerCoords,
+ public static MotionEvent twoPointersDownEvent(int displayId, PointerCoords defPointerCoords,
PointerCoords pointerCoords) {
- return generatePointerEvent(displayId, ACTION_POINTER_DOWN, defPointerCoords,
+ return generateTwoPointersEvent(displayId, ACTION_POINTER_DOWN, defPointerCoords,
pointerCoords);
}
@@ -59,7 +59,7 @@
return ev;
}
- private static MotionEvent generatePointerEvent(int displayId, int action,
+ private static MotionEvent generateTwoPointersEvent(int displayId, int action,
PointerCoords defPointerCoords, PointerCoords pointerCoords) {
final long downTime = SystemClock.uptimeMillis();
MotionEvent.PointerProperties defPointerProperties = new MotionEvent.PointerProperties();
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 32afe82..e6fc792 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4465,6 +4465,7 @@
final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436);
addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
+ mServiceContext.permissions.add(permission.INTERACT_ACROSS_USERS_FULL);
// Even if the caller is the managed profile, the current user is the user 0
when(getServices().iactivityManager.getCurrentUser())
@@ -5694,6 +5695,7 @@
final long ident = mServiceContext.binder.clearCallingIdentity();
configureContextForAccess(mServiceContext, true);
+ mServiceContext.permissions.add(permission.MARK_DEVICE_ORGANIZATION_OWNED);
mServiceContext.binder.callingUid =
UserHandle.getUid(CALLER_USER_HANDLE,
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index ce7ac9e..09b6d7b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -259,18 +259,7 @@
@Override
public int checkPermission(String permission, int pid, int uid) {
- if (UserHandle.isSameApp(binder.getCallingUid(), SYSTEM_UID)) {
- return PackageManager.PERMISSION_GRANTED; // Assume system has all permissions.
- }
- List<String> permissions = binder.callingPermissions.get(binder.getCallingUid());
- if (permissions == null) {
- permissions = callerPermissions;
- }
- if (permissions.contains(permission)) {
- return PackageManager.PERMISSION_GRANTED;
- } else {
- return PackageManager.PERMISSION_DENIED;
- }
+ return checkPermission(permission);
}
@Override
@@ -480,11 +469,32 @@
@Override
public int checkCallingPermission(String permission) {
- return spiedContext.checkCallingPermission(permission);
+ return checkPermission(permission);
+ }
+
+ @Override
+ public int checkCallingOrSelfPermission(String permission) {
+ return checkPermission(permission);
}
@Override
public void startActivityAsUser(Intent intent, UserHandle userHandle) {
spiedContext.startActivityAsUser(intent, userHandle);
}
+
+ private int checkPermission(String permission) {
+ if (UserHandle.isSameApp(binder.getCallingUid(), SYSTEM_UID)) {
+ return PackageManager.PERMISSION_GRANTED; // Assume system has all permissions.
+ }
+ List<String> permissions = binder.callingPermissions.get(binder.getCallingUid());
+ if (permissions == null) {
+ permissions = callerPermissions;
+ }
+ if (permissions.contains(permission)) {
+ return PackageManager.PERMISSION_GRANTED;
+ } else {
+ return PackageManager.PERMISSION_DENIED;
+ }
+ }
+
}
diff --git a/services/tests/servicestests/src/com/android/server/job/MaxJobCountsTest.java b/services/tests/servicestests/src/com/android/server/job/MaxJobCountsTest.java
index 0219f22..4c36747 100644
--- a/services/tests/servicestests/src/com/android/server/job/MaxJobCountsTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/MaxJobCountsTest.java
@@ -15,13 +15,15 @@
*/
package com.android.server.job;
-import android.util.KeyValueListParser;
+import android.annotation.Nullable;
+import android.provider.DeviceConfig;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.job.JobSchedulerService.MaxJobCounts;
+import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -29,19 +31,32 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
public class MaxJobCountsTest {
+ @After
+ public void tearDown() throws Exception {
+ resetConfig();
+ }
- private void check(String config,
+ private void resetConfig() {
+ // DeviceConfig.resetToDefaults() doesn't work here. Need to reset constants manually.
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, "total", "", false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, "maxbg", "", false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, "minbg", "", false);
+ }
+
+ private void check(@Nullable DeviceConfig.Properties config,
int defaultTotal, int defaultMaxBg, int defaultMinBg,
- int expectedTotal, int expectedMaxBg, int expectedMinBg) {
- final KeyValueListParser parser = new KeyValueListParser(',');
- parser.setString(config);
+ int expectedTotal, int expectedMaxBg, int expectedMinBg) throws Exception {
+ resetConfig();
+ if (config != null) {
+ DeviceConfig.setProperties(config);
+ }
final MaxJobCounts counts = new JobSchedulerService.MaxJobCounts(
defaultTotal, "total",
defaultMaxBg, "maxbg",
defaultMinBg, "minbg");
- counts.parse(parser);
+ counts.update();
Assert.assertEquals(expectedTotal, counts.getMaxTotal());
Assert.assertEquals(expectedMaxBg, counts.getMaxBg());
@@ -49,24 +64,35 @@
}
@Test
- public void test() {
+ public void test() throws Exception {
// Tests with various combinations.
- check("", /*default*/ 5, 1, 0, /*expected*/ 5, 1, 0);
- check("", /*default*/ 5, 0, 0, /*expected*/ 5, 1, 0);
- check("", /*default*/ 0, 0, 0, /*expected*/ 1, 1, 0);
- check("", /*default*/ -1, -1, -1, /*expected*/ 1, 1, 0);
- check("", /*default*/ 5, 5, 5, /*expected*/ 5, 5, 4);
- check("", /*default*/ 6, 5, 6, /*expected*/ 6, 5, 5);
- check("", /*default*/ 4, 5, 6, /*expected*/ 4, 4, 3);
- check("", /*default*/ 5, 1, 1, /*expected*/ 5, 1, 1);
- check("", /*default*/ 15, 15, 15, /*expected*/ 15, 15, 14);
- check("", /*default*/ 16, 16, 16, /*expected*/ 16, 16, 15);
- check("", /*default*/ 20, 20, 20, /*expected*/ 16, 16, 15);
+ check(null, /*default*/ 5, 1, 0, /*expected*/ 5, 1, 0);
+ check(null, /*default*/ 5, 0, 0, /*expected*/ 5, 1, 0);
+ check(null, /*default*/ 0, 0, 0, /*expected*/ 1, 1, 0);
+ check(null, /*default*/ -1, -1, -1, /*expected*/ 1, 1, 0);
+ check(null, /*default*/ 5, 5, 5, /*expected*/ 5, 5, 4);
+ check(null, /*default*/ 6, 5, 6, /*expected*/ 6, 5, 5);
+ check(null, /*default*/ 4, 5, 6, /*expected*/ 4, 4, 3);
+ check(null, /*default*/ 5, 1, 1, /*expected*/ 5, 1, 1);
+ check(null, /*default*/ 15, 15, 15, /*expected*/ 15, 15, 14);
+ check(null, /*default*/ 16, 16, 16, /*expected*/ 16, 16, 15);
+ check(null, /*default*/ 20, 20, 20, /*expected*/ 16, 16, 15);
// Test for overriding with a setting string.
- check("total=5,maxbg=4,minbg=3", /*default*/ 9, 9, 9, /*expected*/ 5, 4, 3);
- check("total=5", /*default*/ 9, 9, 9, /*expected*/ 5, 5, 4);
- check("maxbg=4", /*default*/ 9, 9, 9, /*expected*/ 9, 4, 4);
- check("minbg=3", /*default*/ 9, 9, 9, /*expected*/ 9, 9, 3);
+ check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
+ .setInt("total", 5)
+ .setInt("maxbg", 4)
+ .setInt("minbg", 3)
+ .build(),
+ /*default*/ 9, 9, 9, /*expected*/ 5, 4, 3);
+ check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
+ .setInt("total", 5).build(),
+ /*default*/ 9, 9, 9, /*expected*/ 5, 5, 4);
+ check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
+ .setInt("maxbg", 4).build(),
+ /*default*/ 9, 9, 9, /*expected*/ 9, 4, 4);
+ check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
+ .setInt("minbg", 3).build(),
+ /*default*/ 9, 9, 9, /*expected*/ 9, 9, 3);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
index 946f27e..d36dcce 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
@@ -20,7 +20,7 @@
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.PackageParser
-import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.Postsubmit
import com.android.server.pm.parsing.AndroidPackageInfoFlagBehaviorTest.Companion.Param.Companion.appInfo
import com.android.server.pm.parsing.AndroidPackageInfoFlagBehaviorTest.Companion.Param.Companion.pkgInfo
import com.android.server.pm.parsing.pkg.AndroidPackage
@@ -38,7 +38,7 @@
* This test has to be updated manually whenever the info generation behavior changes, since
* there's no single place where flag -> field is defined besides this test.
*/
-@Presubmit
+@Postsubmit
@RunWith(Parameterized::class)
class AndroidPackageInfoFlagBehaviorTest : AndroidPackageParsingTestBase() {
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
index f96ebda..574921c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
@@ -17,26 +17,20 @@
package com.android.server.pm.parsing
import android.content.pm.PackageManager
-import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.Postsubmit
import androidx.test.filters.LargeTest
import com.google.common.truth.Expect
-
import org.junit.Rule
import org.junit.Test
-import org.junit.rules.Timeout
-import java.util.concurrent.TimeUnit
/**
* Collects APKs from the device and verifies that the new parsing behavior outputs
* the same exposed Info object as the old parsing logic.
*/
-@Presubmit
+@Postsubmit
class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() {
@get:Rule
- val timeout = Timeout(4, TimeUnit.MINUTES)
-
- @get:Rule
val expect = Expect.create()
@Test
diff --git a/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java
index d5aee5d..2c719ff 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java
@@ -120,17 +120,17 @@
LocalServices.addService(PackageManagerInternal.class, mPmInternal);
for (int userId : new int[] { USER_PRIMARY, USER_SECONDARY }) {
- when(mPmInternal.getPackageUidInternal(eq(PKG_SOCIAL), anyInt(), eq(userId)))
+ when(mPmInternal.getPackageUid(eq(PKG_SOCIAL), anyInt(), eq(userId)))
.thenReturn(UserHandle.getUid(userId, UID_SOCIAL));
- when(mPmInternal.getPackageUidInternal(eq(PKG_CAMERA), anyInt(), eq(userId)))
+ when(mPmInternal.getPackageUid(eq(PKG_CAMERA), anyInt(), eq(userId)))
.thenReturn(UserHandle.getUid(userId, UID_CAMERA));
- when(mPmInternal.getPackageUidInternal(eq(PKG_PRIVATE), anyInt(), eq(userId)))
+ when(mPmInternal.getPackageUid(eq(PKG_PRIVATE), anyInt(), eq(userId)))
.thenReturn(UserHandle.getUid(userId, UID_PRIVATE));
- when(mPmInternal.getPackageUidInternal(eq(PKG_PUBLIC), anyInt(), eq(userId)))
+ when(mPmInternal.getPackageUid(eq(PKG_PUBLIC), anyInt(), eq(userId)))
.thenReturn(UserHandle.getUid(userId, UID_PUBLIC));
- when(mPmInternal.getPackageUidInternal(eq(PKG_FORCE), anyInt(), eq(userId)))
+ when(mPmInternal.getPackageUid(eq(PKG_FORCE), anyInt(), eq(userId)))
.thenReturn(UserHandle.getUid(userId, UID_FORCE));
- when(mPmInternal.getPackageUidInternal(eq(PKG_COMPLEX), anyInt(), eq(userId)))
+ when(mPmInternal.getPackageUid(eq(PKG_COMPLEX), anyInt(), eq(userId)))
.thenReturn(UserHandle.getUid(userId, UID_COMPLEX));
when(mPmInternal.resolveContentProvider(eq(PKG_CAMERA), anyInt(), eq(userId)))
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 f860e17..59f0a79 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -544,7 +544,7 @@
mActivity = new ActivityBuilder(mAtm)
.setTask(mTask)
.setLaunchTaskBehind(true)
- .setConfigChanges(CONFIG_ORIENTATION)
+ .setConfigChanges(CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT)
.build();
mActivity.setState(Task.ActivityState.STOPPED, "Testing");
@@ -1190,7 +1190,7 @@
assertEquals(DESTROYING, mActivity.getState());
assertTrue(mActivity.finishing);
- verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
+ verify(mActivity).destroyImmediately(anyString());
}
/**
@@ -1214,7 +1214,7 @@
// Verify that the activity was not actually destroyed, but waits for next one to come up
// instead.
- verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
+ verify(mActivity, never()).destroyImmediately(anyString());
assertEquals(FINISHING, mActivity.getState());
assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
}
@@ -1238,7 +1238,7 @@
mActivity.completeFinishing("test");
// Verify that the activity is not destroyed immediately, but waits for next one to come up.
- verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
+ verify(mActivity, never()).destroyImmediately(anyString());
assertEquals(FINISHING, mActivity.getState());
assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
}
@@ -1250,26 +1250,26 @@
@Test
public void testDestroyImmediately_hadApp_finishing() {
mActivity.finishing = true;
- mActivity.destroyImmediately(false /* removeFromApp */, "test");
+ mActivity.destroyImmediately("test");
assertEquals(DESTROYING, mActivity.getState());
}
/**
* Test that the activity will be moved to destroyed state immediately if it was not marked as
- * finishing before {@link ActivityRecord#destroyImmediately(boolean, String)}.
+ * finishing before {@link ActivityRecord#destroyImmediately(String)}.
*/
@Test
public void testDestroyImmediately_hadApp_notFinishing() {
mActivity.finishing = false;
- mActivity.destroyImmediately(false /* removeFromApp */, "test");
+ mActivity.destroyImmediately("test");
assertEquals(DESTROYED, mActivity.getState());
}
/**
* Test that an activity with no process attached and that is marked as finishing will be
- * removed from task when {@link ActivityRecord#destroyImmediately(boolean, String)} is called.
+ * removed from task when {@link ActivityRecord#destroyImmediately(String)} is called.
*/
@Test
public void testDestroyImmediately_noApp_finishing() {
@@ -1277,7 +1277,7 @@
mActivity.finishing = true;
final Task task = mActivity.getTask();
- mActivity.destroyImmediately(false /* removeFromApp */, "test");
+ mActivity.destroyImmediately("test");
assertEquals(DESTROYED, mActivity.getState());
assertNull(mActivity.getTask());
@@ -1294,7 +1294,7 @@
mActivity.finishing = false;
final Task task = mActivity.getTask();
- mActivity.destroyImmediately(false /* removeFromApp */, "test");
+ mActivity.destroyImmediately("test");
assertEquals(DESTROYED, mActivity.getState());
assertEquals(task, mActivity.getTask());
@@ -1310,7 +1310,7 @@
mActivity.safelyDestroy("test");
- verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
+ verify(mActivity, never()).destroyImmediately(anyString());
}
/**
@@ -1322,7 +1322,7 @@
mActivity.safelyDestroy("test");
- verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
+ verify(mActivity).destroyImmediately(anyString());
}
@Test
@@ -1655,13 +1655,13 @@
assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
.diff(wpc.getRequestedOverrideConfiguration()));
- secondActivity.destroyImmediately(true, "");
+ secondActivity.destroyImmediately("");
assertTrue(wpc.registeredForActivityConfigChanges());
assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
.diff(wpc.getRequestedOverrideConfiguration()));
- firstActivity.destroyImmediately(true, "");
+ firstActivity.destroyImmediately("");
assertTrue(wpc.registeredForActivityConfigChanges());
assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
@@ -1714,6 +1714,27 @@
}
+ @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 d54b4a0..f8baf84 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 @@
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 0675c6d..2d834ac 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 4483f8c..b50530e 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 @@
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 @@
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/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index 555906d..608305c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -43,7 +43,6 @@
import static org.mockito.Mockito.spy;
import android.platform.test.annotations.Presubmit;
-import android.util.IntArray;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.test.InsetsModeSession;
@@ -242,8 +241,7 @@
}).when(policy).startAnimation(anyBoolean(), any(), any());
policy.updateBarControlTarget(mAppWindow);
- policy.showTransient(
- IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
+ policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR});
waitUntilWindowAnimatorIdle();
final InsetsSourceControl[] controls =
mDisplayContent.getInsetsStateController().getControlsForDispatch(mAppWindow);
@@ -271,8 +269,7 @@
final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
doNothing().when(policy).startAnimation(anyBoolean(), any(), any());
policy.updateBarControlTarget(mAppWindow);
- policy.showTransient(
- IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
+ policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR});
waitUntilWindowAnimatorIdle();
final InsetsSourceControl[] controls =
mDisplayContent.getInsetsStateController().getControlsForDispatch(mAppWindow);
@@ -301,8 +298,7 @@
final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
doNothing().when(policy).startAnimation(anyBoolean(), any(), any());
policy.updateBarControlTarget(mAppWindow);
- policy.showTransient(
- IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
+ policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR});
waitUntilWindowAnimatorIdle();
InsetsSourceControl[] controls =
mDisplayContent.getInsetsStateController().getControlsForDispatch(mAppWindow);
@@ -340,8 +336,7 @@
final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
doNothing().when(policy).startAnimation(anyBoolean(), any(), any());
policy.updateBarControlTarget(app);
- policy.showTransient(
- IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
+ policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR});
final InsetsSourceControl[] controls =
mDisplayContent.getInsetsStateController().getControlsForDispatch(app);
policy.updateBarControlTarget(app2);
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 1d6dd0b..a0fa936 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 @@
@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 @@
@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 @@
@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 @@
@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 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 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 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 @@
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 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 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 @@
@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 @@
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/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index 085230d..59f8cc8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -346,8 +346,7 @@
assertTrue(rotatedState.getSource(ITYPE_STATUS_BAR).isVisible());
provider.getSource().setVisible(false);
- mDisplayContent.getInsetsPolicy().showTransient(
- IntArray.wrap(new int[] { ITYPE_STATUS_BAR }));
+ mDisplayContent.getInsetsPolicy().showTransient(new int[] { ITYPE_STATUS_BAR });
assertTrue(mDisplayContent.getInsetsPolicy().isTransient(ITYPE_STATUS_BAR));
assertFalse(app.getInsetsState().getSource(ITYPE_STATUS_BAR).isVisible());
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 72899e7..191c33c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -184,7 +184,7 @@
};
activities[0].detachFromProcess();
activities[1].finishing = true;
- activities[1].destroyImmediately(true /* removeFromApp */, "test");
+ activities[1].destroyImmediately("test");
spyOn(wpc);
doReturn(true).when(wpc).isRemoved();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index fc54e1d..08537a4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -50,6 +50,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@@ -245,17 +246,17 @@
final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920);
final DisplayContent display = new TestDisplayContent.Builder(mAtm,
fullScreenBounds.width(), fullScreenBounds.height()).setCanRotate(false).build();
- assertTrue(mRootWindowContainer.getDisplayContent(display.mDisplayId) != null);
+ assertNotNull(mRootWindowContainer.getDisplayContent(display.mDisplayId));
// Fix the display orientation to landscape which is the natural rotation (0) for the test
// display.
final DisplayRotation dr = display.mDisplayContent.getDisplayRotation();
dr.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
dr.setUserRotation(USER_ROTATION_FREE, ROTATION_0);
- Task stack = new StackBuilder(mRootWindowContainer)
+ final Task stack = new StackBuilder(mRootWindowContainer)
.setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
- Task task = stack.getBottomMostTask();
- ActivityRecord root = task.getTopNonFinishingActivity();
+ final Task task = stack.getBottomMostTask();
+ final ActivityRecord root = task.getTopNonFinishingActivity();
assertEquals(fullScreenBounds, task.getBounds());
@@ -267,7 +268,7 @@
assertEquals(fullScreenBounds.height(), task.getBounds().height());
// Top activity gets used
- ActivityRecord top = new ActivityBuilder(mAtm).setTask(task).setStack(stack).build();
+ final ActivityRecord top = new ActivityBuilder(mAtm).setTask(task).setStack(stack).build();
assertEquals(top, task.getTopNonFinishingActivity());
top.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height());
@@ -304,6 +305,33 @@
}
@Test
+ public void testReportsOrientationRequestInLetterboxForOrientation() {
+ final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
+ final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920);
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm,
+ fullScreenBounds.width(), fullScreenBounds.height()).setCanRotate(false).build();
+ assertNotNull(mRootWindowContainer.getDisplayContent(display.mDisplayId));
+ // Fix the display orientation to landscape which is the natural rotation (0) for the test
+ // display.
+ final DisplayRotation dr = display.mDisplayContent.getDisplayRotation();
+ dr.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
+ dr.setUserRotation(USER_ROTATION_FREE, ROTATION_0);
+
+ final Task stack = new StackBuilder(mRootWindowContainer)
+ .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
+ final Task task = stack.getBottomMostTask();
+ ActivityRecord root = task.getTopNonFinishingActivity();
+
+ assertEquals(fullScreenBounds, task.getBounds());
+
+ // Setting app to fixed portrait fits within parent
+ root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
+ assertThat(task.getBounds().width()).isLessThan(task.getBounds().height());
+
+ assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getOrientation());
+ }
+
+ @Test
public void testIgnoresForcedOrientationWhenParentHandles() {
final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
DisplayContent display = new TestDisplayContent.Builder(
@@ -404,6 +432,31 @@
}
@Test
+ public void testComputeConfigResourceLayoutOverrides() {
+ final Rect fullScreenBounds = new Rect(0, 0, 1000, 2500);
+ TestDisplayContent display = new TestDisplayContent.Builder(
+ mAtm, fullScreenBounds.width(), fullScreenBounds.height()).build();
+ final Task task = new TaskBuilder(mSupervisor).setDisplay(display).build();
+ final Configuration inOutConfig = new Configuration();
+ final Configuration parentConfig = new Configuration();
+ final Rect nonLongBounds = new Rect(0, 0, 1000, 1250);
+ parentConfig.windowConfiguration.setBounds(fullScreenBounds);
+ parentConfig.windowConfiguration.setAppBounds(fullScreenBounds);
+ parentConfig.densityDpi = 400;
+ parentConfig.screenHeightDp = (fullScreenBounds.bottom * 160) / parentConfig.densityDpi;
+ parentConfig.screenWidthDp = (fullScreenBounds.right * 160) / parentConfig.densityDpi;
+ parentConfig.windowConfiguration.setRotation(ROTATION_0);
+
+ // Set BOTH screenW/H to an override value
+ inOutConfig.screenWidthDp = nonLongBounds.width() * 160 / parentConfig.densityDpi;
+ inOutConfig.screenHeightDp = nonLongBounds.height() * 160 / parentConfig.densityDpi;
+ task.computeConfigResourceOverrides(inOutConfig, parentConfig);
+
+ // screenLayout should honor override when both screenW/H are set.
+ assertTrue((inOutConfig.screenLayout & Configuration.SCREENLAYOUT_LONG_NO) != 0);
+ }
+
+ @Test
public void testComputeNestedConfigResourceOverrides() {
final Task task = new TaskBuilder(mSupervisor).build();
assertTrue(task.getResolvedOverrideBounds().isEmpty());
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 4a8e8da..dc85904 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 @@
}
@Override
- public int getMaxWallpaperLayer() {
- return 0;
- }
-
- @Override
public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs) {
return attrs.type == TYPE_NOTIFICATION_SHADE;
}
@@ -377,11 +372,6 @@
}
@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/UnknownAppVisibilityControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
index 6ed7622..78dfd40 100644
--- a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
@@ -55,6 +55,18 @@
}
@Test
+ public void testSkipResume() {
+ final ActivityRecord activity = createTestActivityRecord(mDisplayContent);
+ activity.mLaunchTaskBehind = true;
+ mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity);
+ mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(activity);
+
+ // Make sure our handler processed the message.
+ waitHandlerIdle(mWm.mH);
+ assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
+ }
+
+ @Test
public void testMultiple() {
final ActivityRecord activity1 = createTestActivityRecord(mDisplayContent);
final ActivityRecord activity2 = createTestActivityRecord(mDisplayContent);
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 ed9e270..63367ac 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 @@
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 @@
// 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 eb2aa41..ca3626d 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 @@
}
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 @@
// 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 @@
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 @@
// 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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 9135297..289d54e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -88,20 +88,14 @@
@Presubmit
@RunWith(WindowTestRunner.class)
public class WindowOrganizerTests extends WindowTestsBase {
- private ITaskOrganizer registerMockOrganizer(int windowingMode) {
+ private ITaskOrganizer registerMockOrganizer() {
final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
when(organizer.asBinder()).thenReturn(new Binder());
- mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(
- organizer, windowingMode);
-
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(organizer);
return organizer;
}
- private ITaskOrganizer registerMockOrganizer() {
- return registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
- }
-
Task createTask(Task stack, boolean fakeDraw) {
final Task task = createTaskInStack(stack, 0);
@@ -133,11 +127,12 @@
final Task task = createTask(stack);
final ITaskOrganizer organizer = registerMockOrganizer();
- task.setTaskOrganizer(organizer);
+ stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ stack.setTaskOrganizer(organizer);
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- task.removeImmediately();
+ stack.removeImmediately();
verify(organizer).onTaskVanished(any());
}
@@ -147,16 +142,17 @@
final Task task = createTask(stack, false);
final ITaskOrganizer organizer = registerMockOrganizer();
- task.setTaskOrganizer(organizer);
+ stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ stack.setTaskOrganizer(organizer);
verify(organizer, never())
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- task.setHasBeenVisible(true);
+ stack.setHasBeenVisible(true);
assertTrue(stack.getHasBeenVisible());
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- task.removeImmediately();
+ stack.removeImmediately();
verify(organizer).onTaskVanished(any());
}
@@ -169,42 +165,14 @@
// In this test we skip making the Task visible, and verify
// that even though a TaskOrganizer is set remove doesn't emit
// a vanish callback, because we never emitted appear.
- task.setTaskOrganizer(organizer);
+ stack.setTaskOrganizer(organizer);
verify(organizer, never())
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- task.removeImmediately();
+ stack.removeImmediately();
verify(organizer, never()).onTaskVanished(any());
}
@Test
- public void testSwapOrganizer() throws RemoteException {
- final Task stack = createStack();
- final Task task = createTask(stack);
- final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
- final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_PINNED);
-
- task.setTaskOrganizer(organizer);
- verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- task.setTaskOrganizer(organizer2);
- verify(organizer).onTaskVanished(any());
- verify(organizer2).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- }
-
- @Test
- public void testSwapWindowingModes() throws RemoteException {
- final Task stack = createStack();
- final Task task = createTask(stack);
- final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
- final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_PINNED);
-
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- stack.setWindowingMode(WINDOWING_MODE_PINNED);
- verify(organizer).onTaskVanished(any());
- verify(organizer2).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- }
-
- @Test
public void testTaskNoDraw() throws RemoteException {
final Task stack = createStack();
final Task task = createTask(stack, false /* fakeDraw */);
@@ -226,6 +194,7 @@
final Task task = createTask(stack);
final ITaskOrganizer organizer = registerMockOrganizer();
+ stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
stack.setTaskOrganizer(organizer);
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
assertTrue(stack.isOrganized());
@@ -258,7 +227,7 @@
final Task task2 = createTask(stack2);
final Task stack3 = createStack();
final Task task3 = createTask(stack3);
- final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
+ final ITaskOrganizer organizer = registerMockOrganizer();
// First organizer is registered, verify a task appears when changing windowing mode
stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
@@ -268,7 +237,7 @@
// Now we replace the registration and1 verify the new organizer receives tasks
// newly entering the windowing mode.
- final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
+ final ITaskOrganizer organizer2 = registerMockOrganizer();
stack2.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
// One each for task and task2
verify(organizer2, times(2))
@@ -294,7 +263,7 @@
@Test
public void testRegisterTaskOrganizerStackWindowingModeChanges() throws RemoteException {
- final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_PINNED);
+ final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack);
@@ -313,7 +282,7 @@
final Task task = createTask(stack);
stack.setWindowingMode(WINDOWING_MODE_PINNED);
- final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_PINNED);
+ final ITaskOrganizer organizer = registerMockOrganizer();
verify(organizer, times(1))
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
}
@@ -483,8 +452,7 @@
public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
}
};
- mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener,
- WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener);
RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
@@ -542,8 +510,7 @@
public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
}
};
- mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener,
- WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener);
RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
lastReportedTiles.clear();
@@ -604,10 +571,7 @@
public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
}
};
- mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(
- listener, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
- mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(
- listener, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener);
RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
RunningTaskInfo info2 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
@@ -874,7 +838,7 @@
@Test
public void testEnterPipParams() {
final StubOrganizer o = new StubOrganizer();
- mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o, WINDOWING_MODE_PINNED);
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o);
final ActivityRecord record = makePipableActivity();
final PictureInPictureParams p = new PictureInPictureParams.Builder()
@@ -895,7 +859,7 @@
}
}
ChangeSavingOrganizer o = new ChangeSavingOrganizer();
- mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o, WINDOWING_MODE_PINNED);
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o);
final ActivityRecord record = makePipableActivity();
final PictureInPictureParams p = new PictureInPictureParams.Builder()
@@ -926,8 +890,7 @@
}
}
ChangeSavingOrganizer o = new ChangeSavingOrganizer();
- mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o,
- WINDOWING_MODE_MULTI_WINDOW);
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o);
final Task stack = createStack();
final Task task = createTask(stack);
@@ -942,22 +905,23 @@
@Test
public void testPreventDuplicateAppear() throws RemoteException {
final Task stack = createStack();
- final Task task = createTask(stack);
+ final Task task = createTask(stack, false /* fakeDraw */);
final ITaskOrganizer organizer = registerMockOrganizer();
- task.setTaskOrganizer(organizer);
+ stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ stack.setTaskOrganizer(organizer);
// setHasBeenVisible was already called once by the set-up code.
- task.setHasBeenVisible(true);
+ stack.setHasBeenVisible(true);
verify(organizer, times(1))
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- task.setTaskOrganizer(null);
+ stack.setTaskOrganizer(null);
verify(organizer, times(1)).onTaskVanished(any());
- task.setTaskOrganizer(organizer);
+ stack.setTaskOrganizer(organizer);
verify(organizer, times(2))
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- task.removeImmediately();
+ stack.removeImmediately();
verify(organizer, times(2)).onTaskVanished(any());
}
@@ -966,7 +930,7 @@
final Task stack = createStack();
final Task task = createTask(stack);
final ActivityRecord activity = createActivityRecordInTask(stack.mDisplayContent, task);
- final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
+ final ITaskOrganizer organizer = registerMockOrganizer();
// Setup the task to be controlled by the MW mode organizer
stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
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 f095fd4..9603d28 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 @@
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 @@
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 @@
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 @@
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 5ce61b4..38c4e0a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -1031,10 +1031,7 @@
TestSplitOrganizer(ActivityTaskManagerService service, int displayId) {
mService = service;
mDisplayId = displayId;
- mService.mTaskOrganizerController.registerTaskOrganizer(this,
- WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
- mService.mTaskOrganizerController.registerTaskOrganizer(this,
- WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ mService.mTaskOrganizerController.registerTaskOrganizer(this);
WindowContainerToken primary = mService.mTaskOrganizerController.createRootTask(
displayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).token;
mPrimary = WindowContainer.fromBinder(primary.asBinder()).asTask();
@@ -1134,7 +1131,7 @@
}
@Override
- public boolean isGoneForLayoutLw() {
+ public boolean isGoneForLayout() {
return false;
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 1e5d92b..81aad97 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1653,8 +1653,8 @@
// If the calling app is asking about itself, continue, else check for permission.
if (packageName.equals(callingPackage)) {
- final int actualCallingUid = mPackageManagerInternal.getPackageUidInternal(
- callingPackage, 0, userId);
+ final int actualCallingUid = mPackageManagerInternal.getPackageUid(
+ callingPackage, /* flags= */ 0, userId);
if (actualCallingUid != callingUid) {
return false;
}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
index 8f1d0ad..3104c7e 100644
--- a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
+++ b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
@@ -123,7 +123,7 @@
try {
iorap = IIorap.Stub.asInterface(ServiceManager.getServiceOrThrow("iorapd"));
} catch (ServiceManager.ServiceNotFoundException e) {
- handleRemoteError(e);
+ Log.w(TAG, e.getMessage());
return null;
}
diff --git a/telephony/api/system-current.txt b/telephony/api/system-current.txt
index 52e0953..944edd5 100644
--- a/telephony/api/system-current.txt
+++ b/telephony/api/system-current.txt
@@ -687,10 +687,8 @@
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAnyRadioPoweredOn();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApnMetered(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataConnectionAllowed();
method public boolean isDataConnectivityPossible();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataEnabledForApn(int);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabledWithReason(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean isIccLockEnabled();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
@@ -722,7 +720,6 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabledWithReason(int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunisticNetworkState(boolean);
@@ -760,10 +757,6 @@
field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
- field public static final int DATA_ENABLED_REASON_CARRIER = 2; // 0x2
- field public static final int DATA_ENABLED_REASON_POLICY = 1; // 0x1
- field public static final int DATA_ENABLED_REASON_THERMAL = 3; // 0x3
- field public static final int DATA_ENABLED_REASON_USER = 0; // 0x0
field public static final String EXTRA_ANOMALY_DESCRIPTION = "android.telephony.extra.ANOMALY_DESCRIPTION";
field public static final String EXTRA_ANOMALY_ID = "android.telephony.extra.ANOMALY_ID";
field public static final String EXTRA_PHONE_IN_ECM_STATE = "android.telephony.extra.PHONE_IN_ECM_STATE";
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index fa229fb..a229efb 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4406,7 +4406,7 @@
});
sDefaults.putBoolean(KEY_SUPPORT_WPS_OVER_IMS_BOOL, true);
sDefaults.putAll(Ims.getDefaults());
- sDefaults.putStringArray(KEY_CARRIER_CERTIFICATE_STRING_ARRAY, null);
+ sDefaults.putStringArray(KEY_CARRIER_CERTIFICATE_STRING_ARRAY, new String[0]);
sDefaults.putBoolean(KEY_FORMAT_INCOMING_NUMBER_TO_NATIONAL_FOR_JP_BOOL, false);
sDefaults.putIntArray(KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY,
new int[] {4 /* BUSY */});
diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java
index 06c34dc..905f908 100644
--- a/telephony/java/android/telephony/CellIdentityNr.java
+++ b/telephony/java/android/telephony/CellIdentityNr.java
@@ -50,6 +50,18 @@
// a list of additional PLMN-IDs reported for this cell
private final ArraySet<String> mAdditionalPlmns;
+ /** @hide */
+ public CellIdentityNr() {
+ super(TAG, CellInfo.TYPE_NR, null, null, null, null);
+ mNrArfcn = CellInfo.UNAVAILABLE;
+ mPci = CellInfo.UNAVAILABLE;
+ mTac = CellInfo.UNAVAILABLE;
+ mNci = CellInfo.UNAVAILABLE;
+ mBands = new int[] {};
+ mAdditionalPlmns = new ArraySet();
+ mGlobalCellId = null;
+ }
+
/**
*
* @param pci Physical Cell Id in range [0, 1007].
diff --git a/telephony/java/android/telephony/CellInfoNr.java b/telephony/java/android/telephony/CellInfoNr.java
index a7e79f9..e01e8f0 100644
--- a/telephony/java/android/telephony/CellInfoNr.java
+++ b/telephony/java/android/telephony/CellInfoNr.java
@@ -29,9 +29,16 @@
public final class CellInfoNr extends CellInfo {
private static final String TAG = "CellInfoNr";
- private final CellIdentityNr mCellIdentity;
+ private CellIdentityNr mCellIdentity;
private final CellSignalStrengthNr mCellSignalStrength;
+ /** @hide */
+ public CellInfoNr() {
+ super();
+ mCellIdentity = new CellIdentityNr();
+ mCellSignalStrength = new CellSignalStrengthNr();
+ }
+
private CellInfoNr(Parcel in) {
super(in);
mCellIdentity = CellIdentityNr.CREATOR.createFromParcel(in);
@@ -71,6 +78,11 @@
return mCellIdentity;
}
+ /** @hide */
+ public void setCellIdentity(CellIdentityNr cid) {
+ mCellIdentity = cid;
+ }
+
/**
* @return a {@link CellSignalStrengthNr} instance.
*/
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f9148d0..7a77922 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -9231,7 +9231,7 @@
* app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param enable Whether to enable mobile data.
- * @deprecated use setDataEnabledWithReason with reason DATA_ENABLED_REASON_USER instead.
+ * @deprecated use setDataEnabledForReason with reason DATA_ENABLED_REASON_USER instead.
*
*/
@Deprecated
@@ -9243,16 +9243,16 @@
/**
* @hide
- * @deprecated use {@link #setDataEnabledWithReason(int, boolean)} instead.
+ * @deprecated use {@link #setDataEnabledForReason(int, boolean)} instead.
*/
@SystemApi
@Deprecated
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void setDataEnabled(int subId, boolean enable) {
try {
- setDataEnabledWithReason(subId, DATA_ENABLED_REASON_USER, enable);
+ setDataEnabledForReason(subId, DATA_ENABLED_REASON_USER, enable);
} catch (RuntimeException e) {
- Log.e(TAG, "Error calling setDataEnabledWithReason e:" + e);
+ Log.e(TAG, "Error calling setDataEnabledForReason e:" + e);
}
}
@@ -9461,9 +9461,9 @@
@SystemApi
public boolean getDataEnabled(int subId) {
try {
- return isDataEnabledWithReason(DATA_ENABLED_REASON_USER);
+ return isDataEnabledForReason(DATA_ENABLED_REASON_USER);
} catch (RuntimeException e) {
- Log.e(TAG, "Error calling isDataEnabledWithReason e:" + e);
+ Log.e(TAG, "Error calling isDataEnabledForReason e:" + e);
}
return false;
}
@@ -11016,7 +11016,7 @@
*
* @param enabled control enable or disable carrier data.
* @see #resetAllCarrierActions()
- * @deprecated use {@link #setDataEnabledWithReason(int, boolean) with
+ * @deprecated use {@link #setDataEnabledForReason(int, boolean) with
* reason {@link #DATA_ENABLED_REASON_CARRIER}} instead.
* @hide
*/
@@ -11025,9 +11025,9 @@
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void setCarrierDataEnabled(boolean enabled) {
try {
- setDataEnabledWithReason(DATA_ENABLED_REASON_CARRIER, enabled);
+ setDataEnabledForReason(DATA_ENABLED_REASON_CARRIER, enabled);
} catch (RuntimeException e) {
- Log.e(TAG, "Error calling setDataEnabledWithReason e:" + e);
+ Log.e(TAG, "Error calling setDataEnabledForReason e:" + e);
}
}
@@ -11113,7 +11113,7 @@
/**
* Policy control of data connection. Usually used when data limit is passed.
* @param enabled True if enabling the data, otherwise disabling.
- * @deprecated use {@link #setDataEnabledWithReason(int, boolean) with
+ * @deprecated use {@link #setDataEnabledForReason(int, boolean) with
* reason {@link #DATA_ENABLED_REASON_POLICY}} instead.
* @hide
*/
@@ -11121,9 +11121,9 @@
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setPolicyDataEnabled(boolean enabled) {
try {
- setDataEnabledWithReason(DATA_ENABLED_REASON_POLICY, enabled);
+ setDataEnabledForReason(DATA_ENABLED_REASON_POLICY, enabled);
} catch (RuntimeException e) {
- Log.e(TAG, "Error calling setDataEnabledWithReason e:" + e);
+ Log.e(TAG, "Error calling setDataEnabledForReason e:" + e);
}
}
@@ -11139,36 +11139,28 @@
/**
* To indicate that user enabled or disabled data.
- * @hide
*/
- @SystemApi
public static final int DATA_ENABLED_REASON_USER = 0;
/**
* To indicate that data control due to policy. Usually used when data limit is passed.
* Policy data on/off won't affect user settings but will bypass the
* settings and turns off data internally if set to {@code false}.
- * @hide
*/
- @SystemApi
public static final int DATA_ENABLED_REASON_POLICY = 1;
/**
* To indicate enable or disable carrier data by the system based on carrier signalling or
* carrier privileged apps. Carrier data on/off won't affect user settings but will bypass the
* settings and turns off data internally if set to {@code false}.
- * @hide
*/
- @SystemApi
public static final int DATA_ENABLED_REASON_CARRIER = 2;
/**
* To indicate enable or disable data by thermal service.
* Thermal data on/off won't affect user settings but will bypass the
* settings and turns off data internally if set to {@code false}.
- * @hide
*/
- @SystemApi
public static final int DATA_ENABLED_REASON_THERMAL = 3;
/**
@@ -11197,25 +11189,23 @@
* has {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} irrespective of
* the reason.
* @throws IllegalStateException if the Telephony process is not currently available.
- * @hide
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
- @SystemApi
- public void setDataEnabledWithReason(@DataEnabledReason int reason, boolean enabled) {
- setDataEnabledWithReason(getSubId(), reason, enabled);
+ public void setDataEnabledForReason(@DataEnabledReason int reason, boolean enabled) {
+ setDataEnabledForReason(getSubId(), reason, enabled);
}
- private void setDataEnabledWithReason(int subId, @DataEnabledReason int reason,
+ private void setDataEnabledForReason(int subId, @DataEnabledReason int reason,
boolean enabled) {
try {
ITelephony service = getITelephony();
if (service != null) {
- service.setDataEnabledWithReason(subId, reason, enabled);
+ service.setDataEnabledForReason(subId, reason, enabled);
} else {
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- Log.e(TAG, "Telephony#setDataEnabledWithReason RemoteException", ex);
+ Log.e(TAG, "Telephony#setDataEnabledForReason RemoteException", ex);
ex.rethrowFromSystemServer();
}
}
@@ -11223,9 +11213,11 @@
/**
* Return whether data is enabled for certain reason .
*
- * If {@link #isDataEnabledWithReason} returns false, it means in data enablement for a
+ * If {@link #isDataEnabledForReason} returns false, it means in data enablement for a
* specific reason is turned off. If any of the reason is off, then it will result in
- * bypassing user preference and result in data to be turned off.
+ * bypassing user preference and result in data to be turned off. Call
+ * {@link #isDataConnectionAllowed} in order to know whether
+ * data connection is allowed on the device.
*
* <p>If this object has been created with {@link #createForSubscriptionId}, applies
* to the given subId. Otherwise, applies to
@@ -11234,27 +11226,26 @@
* @param reason the reason the data enable change is taking place
* @return whether data is enabled for a reason.
* <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} or
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}
* @throws IllegalStateException if the Telephony process is not currently available.
- * @hide
*/
@RequiresPermission(anyOf = {android.Manifest.permission.ACCESS_NETWORK_STATE,
android.Manifest.permission.READ_PHONE_STATE})
- @SystemApi
- public boolean isDataEnabledWithReason(@DataEnabledReason int reason) {
- return isDataEnabledWithReason(getSubId(), reason);
+ public boolean isDataEnabledForReason(@DataEnabledReason int reason) {
+ return isDataEnabledForReason(getSubId(), reason);
}
- private boolean isDataEnabledWithReason(int subId, @DataEnabledReason int reason) {
+ private boolean isDataEnabledForReason(int subId, @DataEnabledReason int reason) {
try {
ITelephony service = getITelephony();
if (service != null) {
- return service.isDataEnabledWithReason(subId, reason);
+ return service.isDataEnabledForReason(subId, reason);
} else {
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- Log.e(TAG, "Telephony#isDataEnabledWithReason RemoteException", ex);
+ Log.e(TAG, "Telephony#isDataEnabledForReason RemoteException", ex);
ex.rethrowFromSystemServer();
}
return false;
@@ -11395,10 +11386,14 @@
* <LI>And possibly others.</LI>
* </UL>
* @return {@code true} if the overall data connection is allowed; {@code false} if not.
- * @hide
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} or
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE} or
+ * android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE
*/
- @SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @RequiresPermission(anyOf = {android.Manifest.permission.ACCESS_NETWORK_STATE,
+ android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE})
public boolean isDataConnectionAllowed() {
boolean retVal = false;
try {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index e2de5c8..4021d0a 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1015,7 +1015,7 @@
* @param reason the reason the data enable change is taking place
* @param enable true to turn on, else false
*/
- void setDataEnabledWithReason(int subId, int reason, boolean enable);
+ void setDataEnabledForReason(int subId, int reason, boolean enable);
/**
* Return whether data is enabled for certain reason
@@ -1023,7 +1023,7 @@
* @param reason the reason the data enable change is taking place
* @return true on enabled
*/
- boolean isDataEnabledWithReason(int subId, int reason);
+ boolean isDataEnabledForReason(int subId, int reason);
/**
* Checks if manual network selection is allowed.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 9a8e37b..57d6127 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -88,7 +88,7 @@
noUncoveredRegions(Surface.ROTATION_0, rotation, bugId = 141361128)
navBarLayerRotatesAndScales(Surface.ROTATION_0, rotation)
statusBarLayerRotatesScales(Surface.ROTATION_0, rotation)
- navBarLayerIsAlwaysVisible()
+ navBarLayerIsAlwaysVisible(bugId = 140855415)
statusBarLayerIsAlwaysVisible(enabled = false)
wallpaperLayerBecomesInvisible()
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
index 91ec211..279092d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
@@ -87,9 +87,9 @@
}
layersTrace {
- navBarLayerIsAlwaysVisible()
+ navBarLayerIsAlwaysVisible(bugId = 140855415)
statusBarLayerIsAlwaysVisible()
- noUncoveredRegions(rotation)
+ noUncoveredRegions(rotation, enabled = false)
navBarLayerRotatesAndScales(rotation, bugId = 140855415)
statusBarLayerRotatesScales(rotation)
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 7790043..05a59ef 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -744,6 +744,15 @@
</intent-filter>
</activity>
+ <activity android:name="BlurActivity"
+ android:label="Shaders/Blur"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
<activity android:name="TextActivity"
android:label="Text/Simple Text"
android:theme="@android:style/Theme.NoTitleBar"
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java
new file mode 100644
index 0000000..033fb0e
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.BlurShader;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.Shader;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class BlurActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout layout = new LinearLayout(this);
+ layout.setClipChildren(false);
+ layout.setGravity(Gravity.CENTER);
+ layout.setOrientation(LinearLayout.VERTICAL);
+
+
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(500, 500);
+ params.bottomMargin = 100;
+
+ layout.addView(new BlurGradientView(this), params);
+ layout.addView(new BlurView(this), params);
+
+ setContentView(layout);
+ }
+
+ public static class BlurGradientView extends View {
+ private BlurShader mBlurShader = null;
+ private Paint mPaint;
+
+ public BlurGradientView(Context c) {
+ super(c);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (changed || mBlurShader == null) {
+ LinearGradient gradient = new LinearGradient(
+ 0f,
+ 0f,
+ right - left,
+ bottom - top,
+ Color.CYAN,
+ Color.YELLOW,
+ Shader.TileMode.CLAMP
+ );
+ mBlurShader = new BlurShader(30f, 40f, gradient);
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaint.setShader(mBlurShader);
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
+ }
+ }
+
+ public static class BlurView extends View {
+
+ private final BlurShader mBlurShader;
+ private final Paint mPaint;
+
+ public BlurView(Context c) {
+ super(c);
+
+ mBlurShader = new BlurShader(20f, 20f, null);
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaint.setShader(mBlurShader);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ mPaint.setColor(Color.BLUE);
+ canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
+
+ mPaint.setColor(Color.RED);
+ canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, 50f, mPaint);
+ }
+ }
+}
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index 76f8df0..f55d4d4 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -26,7 +26,7 @@
java_test_host {
name: "StagedInstallInternalTest",
srcs: ["src/**/*.java"],
- libs: ["tradefed"],
+ libs: ["tradefed", "cts-shim-host-lib"],
static_libs: [
"testng",
"compatibility-tradefed",
@@ -35,6 +35,7 @@
"cts-install-lib-host",
],
data: [
+ ":com.android.apex.apkrollback.test_v1",
":com.android.apex.cts.shim.v2_prebuilt",
":TestAppAv1",
],
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index 7817239..e5411de 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -47,11 +47,7 @@
@RunWith(JUnit4.class)
public class StagedInstallInternalTest {
-
- private static final String TAG = StagedInstallInternalTest.class.getSimpleName();
private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
- private static final TestApp TEST_APEX_WITH_APK_V1 = new TestApp("TestApexWithApkV1",
- APK_IN_APEX_TESTAPEX_NAME, 1, /*isApex*/true, APK_IN_APEX_TESTAPEX_NAME + "_v1.apex");
private static final TestApp TEST_APEX_WITH_APK_V2 = new TestApp("TestApexWithApkV2",
APK_IN_APEX_TESTAPEX_NAME, 2, /*isApex*/true, APK_IN_APEX_TESTAPEX_NAME + "_v2.apex");
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 d7b0796..f50d2e1 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 @@
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 @@
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/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
index 073ae30..ca723b8 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
@@ -157,7 +157,7 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mOrganizer.registerOrganizer(WINDOWING_MODE_MULTI_WINDOW);
+ mOrganizer.registerOrganizer();
mTaskView1 = new ResizingTaskView(this, makeSettingsIntent());
mTaskView2 = new ResizingTaskView(this, makeContactsIntent());
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
index 8fc5c5d..5ec9493 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
@@ -57,7 +57,7 @@
public void onCreate() {
super.onCreate();
- mOrganizer.registerOrganizer(WINDOWING_MODE_PINNED);
+ mOrganizer.registerOrganizer();
final WindowManager.LayoutParams wlp = new WindowManager.LayoutParams();
wlp.setTitle("TaskOrganizerPipTest");
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index ab12ac0..5a29c2c 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -26,19 +26,14 @@
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_OEM;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRODUCT;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR;
+import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
+import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_REQUIRED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
-import static android.net.INetd.PERMISSION_INTERNET;
-import static android.net.INetd.PERMISSION_NONE;
-import static android.net.INetd.PERMISSION_SYSTEM;
-import static android.net.INetd.PERMISSION_UNINSTALLED;
-import static android.net.INetd.PERMISSION_UPDATE_DEVICE_STATS;
-import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.os.Process.SYSTEM_UID;
import static com.android.server.connectivity.PermissionMonitor.NETWORK;
import static com.android.server.connectivity.PermissionMonitor.SYSTEM;
-import static com.android.server.connectivity.PermissionMonitor.UidNetdPermissionInfo;
import static junit.framework.Assert.fail;
@@ -69,7 +64,7 @@
import android.os.Build;
import android.os.UserHandle;
import android.os.UserManager;
-import android.util.SparseArray;
+import android.util.SparseIntArray;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -102,6 +97,7 @@
private static final int SYSTEM_UID1 = 1000;
private static final int SYSTEM_UID2 = 1008;
private static final int VPN_UID = 10002;
+ private static final String REAL_SYSTEM_PACKAGE_NAME = "android";
private static final String MOCK_PACKAGE1 = "appName1";
private static final String MOCK_PACKAGE2 = "appName2";
private static final String SYSTEM_PACKAGE1 = "sysName1";
@@ -132,7 +128,6 @@
new UserInfo(MOCK_USER1, "", 0),
new UserInfo(MOCK_USER2, "", 0),
}));
- doReturn(PackageManager.PERMISSION_DENIED).when(mDeps).uidPermission(anyString(), anyInt());
mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));
@@ -145,15 +140,35 @@
verify(mMockPmi).getPackageList(mPermissionMonitor);
}
- private boolean wouldBeCarryoverPackage(String partition, int targetSdkVersion, int uid) {
- final PackageInfo packageInfo = buildPackageInfo(partition, uid, MOCK_USER1);
+ private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid,
+ String... permissions) {
+ final PackageInfo packageInfo =
+ packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, permissions, partition);
packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
- return mPermissionMonitor.isCarryoverPackage(packageInfo.applicationInfo);
+ packageInfo.applicationInfo.uid = uid;
+ return mPermissionMonitor.hasRestrictedNetworkPermission(packageInfo);
}
- private static PackageInfo packageInfoWithPartition(String partition) {
+ private static PackageInfo systemPackageInfoWithPermissions(String... permissions) {
+ return packageInfoWithPermissions(
+ REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM);
+ }
+
+ private static PackageInfo vendorPackageInfoWithPermissions(String... permissions) {
+ return packageInfoWithPermissions(
+ REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_VENDOR);
+ }
+
+ private static PackageInfo packageInfoWithPermissions(int permissionsFlags,
+ String[] permissions, String partition) {
+ int[] requestedPermissionsFlags = new int[permissions.length];
+ for (int i = 0; i < permissions.length; i++) {
+ requestedPermissionsFlags[i] = permissionsFlags;
+ }
final PackageInfo packageInfo = new PackageInfo();
+ packageInfo.requestedPermissions = permissions;
packageInfo.applicationInfo = new ApplicationInfo();
+ packageInfo.requestedPermissionsFlags = requestedPermissionsFlags;
int privateFlags = 0;
switch (partition) {
case PARTITION_OEM:
@@ -170,145 +185,168 @@
return packageInfo;
}
- private static PackageInfo buildPackageInfo(String partition, int uid, int userId) {
- final PackageInfo pkgInfo = packageInfoWithPartition(partition);
+ private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid, int userId) {
+ final PackageInfo pkgInfo;
+ if (hasSystemPermission) {
+ pkgInfo = systemPackageInfoWithPermissions(
+ CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+ } else {
+ pkgInfo = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, new String[] {}, "");
+ }
pkgInfo.applicationInfo.uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
return pkgInfo;
}
- /** This will REMOVE all previously set permissions from given uid. */
- private void removeAllPermissions(int uid) {
- doReturn(PackageManager.PERMISSION_DENIED).when(mDeps).uidPermission(anyString(), eq(uid));
- }
-
- /** Set up mocks so that given UID has the requested permissions. */
- private void addPermissions(int uid, String... permissions) {
- for (String permission : permissions) {
- doReturn(PackageManager.PERMISSION_GRANTED)
- .when(mDeps).uidPermission(eq(permission), eq(uid));
- }
- }
-
@Test
public void testHasPermission() {
- addPermissions(MOCK_UID1);
- assertFalse(mPermissionMonitor.hasPermission(CHANGE_NETWORK_STATE, MOCK_UID1));
- assertFalse(mPermissionMonitor.hasPermission(NETWORK_STACK, MOCK_UID1));
- assertFalse(mPermissionMonitor.hasPermission(
- CONNECTIVITY_USE_RESTRICTED_NETWORKS, MOCK_UID1));
- assertFalse(mPermissionMonitor.hasPermission(CONNECTIVITY_INTERNAL, MOCK_UID1));
+ PackageInfo app = systemPackageInfoWithPermissions();
+ assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
+ assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
+ assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
- addPermissions(MOCK_UID1, CHANGE_NETWORK_STATE, NETWORK_STACK);
- assertTrue(mPermissionMonitor.hasPermission(CHANGE_NETWORK_STATE, MOCK_UID1));
- assertTrue(mPermissionMonitor.hasPermission(NETWORK_STACK, MOCK_UID1));
- assertFalse(mPermissionMonitor.hasPermission(
- CONNECTIVITY_USE_RESTRICTED_NETWORKS, MOCK_UID1));
- assertFalse(mPermissionMonitor.hasPermission(CONNECTIVITY_INTERNAL, MOCK_UID1));
- assertFalse(mPermissionMonitor.hasPermission(CHANGE_NETWORK_STATE, MOCK_UID2));
- assertFalse(mPermissionMonitor.hasPermission(NETWORK_STACK, MOCK_UID2));
+ app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE, NETWORK_STACK);
+ assertTrue(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
+ assertTrue(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
+ assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
- addPermissions(MOCK_UID2, CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL);
- assertFalse(mPermissionMonitor.hasPermission(
- CONNECTIVITY_USE_RESTRICTED_NETWORKS, MOCK_UID1));
- assertFalse(mPermissionMonitor.hasPermission(CONNECTIVITY_INTERNAL, MOCK_UID1));
- assertTrue(mPermissionMonitor.hasPermission(
- CONNECTIVITY_USE_RESTRICTED_NETWORKS, MOCK_UID2));
- assertTrue(mPermissionMonitor.hasPermission(CONNECTIVITY_INTERNAL, MOCK_UID2));
+ app = systemPackageInfoWithPermissions(
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL);
+ assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
+ assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
+ assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
+
+ app = packageInfoWithPermissions(REQUESTED_PERMISSION_REQUIRED, new String[] {
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL, NETWORK_STACK },
+ PARTITION_SYSTEM);
+ assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
+ assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
+ assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
+
+ app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
+ app.requestedPermissions = null;
+ assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
+
+ app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
+ app.requestedPermissionsFlags = null;
+ assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
}
@Test
public void testIsVendorApp() {
- PackageInfo app = packageInfoWithPartition(PARTITION_SYSTEM);
+ PackageInfo app = systemPackageInfoWithPermissions();
assertFalse(mPermissionMonitor.isVendorApp(app.applicationInfo));
- app = packageInfoWithPartition(PARTITION_OEM);
+ app = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED,
+ new String[] {}, PARTITION_OEM);
assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
- app = packageInfoWithPartition(PARTITION_PRODUCT);
+ app = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED,
+ new String[] {}, PARTITION_PRODUCT);
assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
- app = packageInfoWithPartition(PARTITION_VENDOR);
+ app = vendorPackageInfoWithPermissions();
assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
}
- /**
- * Remove all permissions from the uid then setup permissions to uid for checking restricted
- * network permission.
- */
- private void assertRestrictedNetworkPermission(boolean hasPermission, int uid,
- String... permissions) {
- removeAllPermissions(uid);
- addPermissions(uid, permissions);
- assertEquals(hasPermission, mPermissionMonitor.hasRestrictedNetworkPermission(uid));
+ @Test
+ public void testHasNetworkPermission() {
+ PackageInfo app = systemPackageInfoWithPermissions();
+ assertFalse(mPermissionMonitor.hasNetworkPermission(app));
+ app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
+ assertTrue(mPermissionMonitor.hasNetworkPermission(app));
+ app = systemPackageInfoWithPermissions(NETWORK_STACK);
+ assertFalse(mPermissionMonitor.hasNetworkPermission(app));
+ app = systemPackageInfoWithPermissions(CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+ assertFalse(mPermissionMonitor.hasNetworkPermission(app));
+ app = systemPackageInfoWithPermissions(CONNECTIVITY_INTERNAL);
+ assertFalse(mPermissionMonitor.hasNetworkPermission(app));
}
@Test
public void testHasRestrictedNetworkPermission() {
- assertRestrictedNetworkPermission(false, MOCK_UID1);
- assertRestrictedNetworkPermission(false, MOCK_UID1, CHANGE_NETWORK_STATE);
- assertRestrictedNetworkPermission(true, MOCK_UID1, NETWORK_STACK);
- assertRestrictedNetworkPermission(false, MOCK_UID1, CONNECTIVITY_INTERNAL);
- assertRestrictedNetworkPermission(true, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
- assertRestrictedNetworkPermission(false, MOCK_UID1, CHANGE_WIFI_STATE);
- assertRestrictedNetworkPermission(true, MOCK_UID1, PERMISSION_MAINLINE_NETWORK_STACK);
+ assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, MOCK_UID1, NETWORK_STACK));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
- assertFalse(mPermissionMonitor.hasRestrictedNetworkPermission(MOCK_UID2));
- assertFalse(mPermissionMonitor.hasRestrictedNetworkPermission(SYSTEM_UID));
+ assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_Q, MOCK_UID1, CONNECTIVITY_INTERNAL));
}
@Test
- public void testIsCarryoverPackage() {
+ public void testHasRestrictedNetworkPermissionSystemUid() {
doReturn(VERSION_P).when(mDeps).getDeviceFirstSdkInt();
- assertTrue(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
- assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, SYSTEM_UID));
- assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
- assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
- assertTrue(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
- assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, SYSTEM_UID));
- assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
- assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
+ assertTrue(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_INTERNAL));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt();
- assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
- assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, SYSTEM_UID));
- assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
- assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
- assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
- assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, SYSTEM_UID));
- assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
- assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
+ assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_INTERNAL));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ }
- assertFalse(wouldBeCarryoverPackage(PARTITION_OEM, VERSION_Q, SYSTEM_UID));
- assertFalse(wouldBeCarryoverPackage(PARTITION_PRODUCT, VERSION_Q, SYSTEM_UID));
- assertFalse(wouldBeCarryoverPackage(PARTITION_OEM, VERSION_Q, MOCK_UID1));
- assertFalse(wouldBeCarryoverPackage(PARTITION_PRODUCT, VERSION_Q, MOCK_UID1));
+ @Test
+ public void testHasRestrictedNetworkPermissionVendorApp() {
+ assertTrue(hasRestrictedNetworkPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_P, MOCK_UID1, NETWORK_STACK));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
+
+ assertFalse(hasRestrictedNetworkPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CONNECTIVITY_INTERNAL));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_NETWORK_STATE));
}
private void assertBackgroundPermission(boolean hasPermission, String name, int uid,
String... permissions) throws Exception {
when(mPackageManager.getPackageInfo(eq(name), anyInt()))
- .thenReturn(buildPackageInfo(PARTITION_SYSTEM, uid, MOCK_USER1));
- addPermissions(uid, permissions);
+ .thenReturn(packageInfoWithPermissions(
+ REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM));
mPermissionMonitor.onPackageAdded(name, uid);
assertEquals(hasPermission, mPermissionMonitor.hasUseBackgroundNetworksPermission(uid));
}
@Test
public void testHasUseBackgroundNetworksPermission() throws Exception {
- assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID1));
- assertBackgroundPermission(false, "mock1", MOCK_UID1);
- assertBackgroundPermission(false, "mock2", MOCK_UID1, CONNECTIVITY_INTERNAL);
- assertBackgroundPermission(true, "mock3", MOCK_UID1, NETWORK_STACK);
+ assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(SYSTEM_UID));
+ assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID);
+ assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID, CONNECTIVITY_INTERNAL);
+ assertBackgroundPermission(true, SYSTEM_PACKAGE1, SYSTEM_UID, CHANGE_NETWORK_STATE);
+ assertBackgroundPermission(true, SYSTEM_PACKAGE1, SYSTEM_UID, NETWORK_STACK);
- assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID2));
- assertBackgroundPermission(false, "mock4", MOCK_UID2);
- assertBackgroundPermission(true, "mock5", MOCK_UID2,
+ assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID1));
+ assertBackgroundPermission(false, MOCK_PACKAGE1, MOCK_UID1);
+ assertBackgroundPermission(true, MOCK_PACKAGE1, MOCK_UID1,
CONNECTIVITY_USE_RESTRICTED_NETWORKS);
- doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt();
- assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(SYSTEM_UID));
- assertBackgroundPermission(false, "system1", SYSTEM_UID);
- assertBackgroundPermission(true, "system2", SYSTEM_UID, CHANGE_NETWORK_STATE);
- doReturn(VERSION_P).when(mDeps).getDeviceFirstSdkInt();
- removeAllPermissions(SYSTEM_UID);
- assertBackgroundPermission(true, "system3", SYSTEM_UID);
+ assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID2));
+ assertBackgroundPermission(false, MOCK_PACKAGE2, MOCK_UID2);
+ assertBackgroundPermission(false, MOCK_PACKAGE2, MOCK_UID2,
+ CONNECTIVITY_INTERNAL);
+ assertBackgroundPermission(true, MOCK_PACKAGE2, MOCK_UID2, NETWORK_STACK);
}
private class NetdMonitor {
@@ -318,7 +356,7 @@
// Add hook to verify and track result of setPermission.
doAnswer((InvocationOnMock invocation) -> {
final Object[] args = invocation.getArguments();
- final Boolean isSystem = args[0].equals(PERMISSION_SYSTEM);
+ final Boolean isSystem = args[0].equals(INetd.PERMISSION_SYSTEM);
for (final int uid : (int[]) args[1]) {
// TODO: Currently, permission monitor will send duplicate commands for each uid
// corresponding to each user. Need to fix that and uncomment below test.
@@ -378,14 +416,13 @@
// MOCK_UID1: MOCK_PACKAGE1 only has network permission.
// SYSTEM_UID: SYSTEM_PACKAGE1 has system permission.
// SYSTEM_UID: SYSTEM_PACKAGE2 only has network permission.
- doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(eq(SYSTEM),
- anyString(), anyInt());
+ doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(eq(SYSTEM), anyString());
doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(any(),
- eq(SYSTEM_PACKAGE1), anyInt());
+ eq(SYSTEM_PACKAGE1));
doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
- eq(SYSTEM_PACKAGE2), anyInt());
+ eq(SYSTEM_PACKAGE2));
doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
- eq(MOCK_PACKAGE1), anyInt());
+ eq(MOCK_PACKAGE1));
// Add SYSTEM_PACKAGE2, expect only have network permission.
mPermissionMonitor.onUserAdded(MOCK_USER1);
@@ -436,15 +473,13 @@
public void testUidFilteringDuringVpnConnectDisconnectAndUidUpdates() throws Exception {
when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
Arrays.asList(new PackageInfo[] {
- buildPackageInfo(PARTITION_SYSTEM, SYSTEM_UID1, MOCK_USER1),
- buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1),
- buildPackageInfo(PARTITION_SYSTEM, MOCK_UID2, MOCK_USER1),
- buildPackageInfo(PARTITION_SYSTEM, VPN_UID, MOCK_USER1)
+ buildPackageInfo(/* SYSTEM */ true, SYSTEM_UID1, MOCK_USER1),
+ buildPackageInfo(/* SYSTEM */ false, MOCK_UID1, MOCK_USER1),
+ buildPackageInfo(/* SYSTEM */ false, MOCK_UID2, MOCK_USER1),
+ buildPackageInfo(/* SYSTEM */ false, VPN_UID, MOCK_USER1)
}));
when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn(
- buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1));
- addPermissions(SYSTEM_UID,
- CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+ buildPackageInfo(false, MOCK_UID1, MOCK_USER1));
mPermissionMonitor.startMonitoring();
// Every app on user 0 except MOCK_UID2 are under VPN.
final Set<UidRange> vpnRange1 = new HashSet<>(Arrays.asList(new UidRange[] {
@@ -489,11 +524,11 @@
public void testUidFilteringDuringPackageInstallAndUninstall() throws Exception {
when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
Arrays.asList(new PackageInfo[] {
- buildPackageInfo(PARTITION_SYSTEM, SYSTEM_UID1, MOCK_USER1),
- buildPackageInfo(PARTITION_SYSTEM, VPN_UID, MOCK_USER1)
+ buildPackageInfo(true, SYSTEM_UID1, MOCK_USER1),
+ buildPackageInfo(false, VPN_UID, MOCK_USER1)
}));
when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn(
- buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1));
+ buildPackageInfo(false, MOCK_UID1, MOCK_USER1));
mPermissionMonitor.startMonitoring();
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(MOCK_USER1));
@@ -561,48 +596,47 @@
// SYSTEM_UID1: SYSTEM_PACKAGE1 has internet permission and update device stats permission.
// SYSTEM_UID2: SYSTEM_PACKAGE2 has only update device stats permission.
- final SparseArray<UidNetdPermissionInfo> uidsPermInfo = new SparseArray<>();
- uidsPermInfo.put(MOCK_UID1, new UidNetdPermissionInfo(PERMISSION_INTERNET));
- uidsPermInfo.put(MOCK_UID2, new UidNetdPermissionInfo(PERMISSION_NONE));
- uidsPermInfo.put(SYSTEM_UID1, new UidNetdPermissionInfo(
- PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS));
- uidsPermInfo.put(SYSTEM_UID2, new UidNetdPermissionInfo(PERMISSION_UPDATE_DEVICE_STATS));
+ SparseIntArray netdPermissionsAppIds = new SparseIntArray();
+ netdPermissionsAppIds.put(MOCK_UID1, INetd.PERMISSION_INTERNET);
+ netdPermissionsAppIds.put(MOCK_UID2, INetd.PERMISSION_NONE);
+ netdPermissionsAppIds.put(SYSTEM_UID1, INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS);
+ netdPermissionsAppIds.put(SYSTEM_UID2, INetd.PERMISSION_UPDATE_DEVICE_STATS);
// Send the permission information to netd, expect permission updated.
- mPermissionMonitor.sendPackagePermissionsToNetd(uidsPermInfo);
+ mPermissionMonitor.sendPackagePermissionsToNetd(netdPermissionsAppIds);
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET,
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET,
new int[]{MOCK_UID1});
- mNetdServiceMonitor.expectPermission(PERMISSION_NONE, new int[]{MOCK_UID2});
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
- | PERMISSION_UPDATE_DEVICE_STATS, new int[]{SYSTEM_UID1});
- mNetdServiceMonitor.expectPermission(PERMISSION_UPDATE_DEVICE_STATS,
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID2});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{SYSTEM_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UPDATE_DEVICE_STATS,
new int[]{SYSTEM_UID2});
// Update permission of MOCK_UID1, expect new permission show up.
- mPermissionMonitor.sendPackagePermissionsForUid(MOCK_UID1, new UidNetdPermissionInfo(
- PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS));
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
- | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ mPermissionMonitor.sendPackagePermissionsForUid(MOCK_UID1,
+ INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
// Change permissions of SYSTEM_UID2, expect new permission show up and old permission
// revoked.
- mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID2, new UidNetdPermissionInfo(
- PERMISSION_INTERNET));
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{SYSTEM_UID2});
+ mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID2,
+ INetd.PERMISSION_INTERNET);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{SYSTEM_UID2});
// Revoke permission from SYSTEM_UID1, expect no permission stored.
- mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, new UidNetdPermissionInfo(
- PERMISSION_NONE));
- mNetdServiceMonitor.expectPermission(PERMISSION_NONE, new int[]{SYSTEM_UID1});
+ mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, INetd.PERMISSION_NONE);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{SYSTEM_UID1});
}
private PackageInfo setPackagePermissions(String packageName, int uid, String[] permissions)
throws Exception {
- final PackageInfo packageInfo = buildPackageInfo(PARTITION_SYSTEM, uid, MOCK_USER1);
+ PackageInfo packageInfo = packageInfoWithPermissions(
+ REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM);
when(mPackageManager.getPackageInfo(eq(packageName), anyInt())).thenReturn(packageInfo);
when(mPackageManager.getPackagesForUid(eq(uid))).thenReturn(new String[]{packageName});
- addPermissions(uid, permissions);
return packageInfo;
}
@@ -618,30 +652,31 @@
final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
- | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
addPackage(MOCK_PACKAGE2, MOCK_UID2, new String[] {INTERNET});
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID2});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID2});
}
@Test
public void testPackageInstallSharedUid() throws Exception {
final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
- | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ PackageInfo packageInfo1 = addPackage(MOCK_PACKAGE1, MOCK_UID1,
+ new String[] {INTERNET, UPDATE_DEVICE_STATS});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
// Install another package with the same uid and no permissions should not cause the UID to
// lose permissions.
- final PackageInfo packageInfo2 = buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1);
+ PackageInfo packageInfo2 = systemPackageInfoWithPermissions();
when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
when(mPackageManager.getPackagesForUid(MOCK_UID1))
.thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
mPermissionMonitor.onPackageAdded(MOCK_PACKAGE2, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
- | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
}
@Test
@@ -649,12 +684,12 @@
final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
- | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
}
@Test
@@ -662,16 +697,15 @@
final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
- | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
- removeAllPermissions(MOCK_UID1);
mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
}
@Test
@@ -679,10 +713,10 @@
final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {});
- mNetdServiceMonitor.expectPermission(PERMISSION_NONE, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID1});
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
}
@Test
@@ -690,19 +724,17 @@
final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
- | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
// Mock another package with the same uid but different permissions.
- final PackageInfo packageInfo2 = buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1);
+ PackageInfo packageInfo2 = systemPackageInfoWithPermissions(INTERNET);
when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{
MOCK_PACKAGE2});
- removeAllPermissions(MOCK_UID1);
- addPermissions(MOCK_UID1, INTERNET);
mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
}
@Test
@@ -711,6 +743,9 @@
// necessary permission.
final Context realContext = InstrumentationRegistry.getContext();
final PermissionMonitor monitor = new PermissionMonitor(realContext, mNetdService);
- assertTrue(monitor.hasPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, SYSTEM_UID));
+ final PackageManager manager = realContext.getPackageManager();
+ final PackageInfo systemInfo = manager.getPackageInfo(REAL_SYSTEM_PACKAGE_NAME,
+ GET_PERMISSIONS | MATCH_ANY_USER);
+ assertTrue(monitor.hasPermission(systemInfo, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
}
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
index 6dc4fce..8f09377 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
@@ -30,6 +30,7 @@
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.net.NetworkTemplate;
import android.os.test.TestLooper;
@@ -135,6 +136,11 @@
mMonitor.onSubscriptionsChanged();
}
+ private void updateSubscriberIdForTestSub(int subId, @Nullable final String subscriberId) {
+ when(mTelephonyManager.getSubscriberId(subId)).thenReturn(subscriberId);
+ mMonitor.onSubscriptionsChanged();
+ }
+
private void removeTestSub(int subId) {
// Remove subId from TestSubList.
mTestSubList.removeIf(it -> it == subId);
@@ -268,4 +274,54 @@
listener.onServiceStateChanged(serviceState);
assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_NR);
}
+
+ @Test
+ public void testSubscriberIdUnavailable() {
+ final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor =
+ ArgumentCaptor.forClass(RatTypeListener.class);
+
+ mMonitor.start();
+ // Insert sim1, set subscriberId to null which is normal in SIM PIN locked case.
+ // Verify RAT type is NETWORK_TYPE_UNKNOWN and service will not perform listener
+ // registration.
+ addTestSub(TEST_SUBID1, null);
+ verify(mTelephonyManager, never()).listen(any(), anyInt());
+ assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+
+ // Set IMSI for sim1, verify the listener will be registered.
+ updateSubscriberIdForTestSub(TEST_SUBID1, TEST_IMSI1);
+ verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor.capture(),
+ eq(PhoneStateListener.LISTEN_SERVICE_STATE));
+ reset(mTelephonyManager);
+ when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
+
+ // Set RAT type of sim1 to UMTS. Verify RAT type of sim1 is changed.
+ setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
+ TelephonyManager.NETWORK_TYPE_UMTS);
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
+ reset(mDelegate);
+
+ // Set IMSI to null again to simulate somehow IMSI is not available, such as
+ // modem crash. Verify service should not unregister listener.
+ updateSubscriberIdForTestSub(TEST_SUBID1, null);
+ verify(mTelephonyManager, never()).listen(any(), anyInt());
+ assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
+ reset(mDelegate);
+
+ // Set RAT type of sim1 to LTE. Verify RAT type of sim1 is still changed even if the IMSI
+ // is not available. The monitor keeps the listener even if the IMSI disappears because
+ // the IMSI can never change for any given subId, therefore even if the IMSI is updated
+ // to null, the monitor should continue accepting updates of the RAT type. However,
+ // telephony is never actually supposed to do this, if the IMSI disappears there should
+ // not be updates, but it's still the right thing to do theoretically.
+ setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
+ TelephonyManager.NETWORK_TYPE_LTE);
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_LTE);
+ reset(mDelegate);
+
+ mMonitor.stop();
+ verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()),
+ eq(PhoneStateListener.LISTEN_NONE));
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ }
}
diff --git a/tools/preload-check/Android.bp b/tools/preload-check/Android.bp
index 87b31d2..aaa6d76 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 00fd414e3..3d85153 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 @@
}
/**
- * 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();
diff --git a/wifi/api/current.txt b/wifi/api/current.txt
index 53c3b33..ee7320f 100644
--- a/wifi/api/current.txt
+++ b/wifi/api/current.txt
@@ -487,6 +487,7 @@
method @Nullable public String getPassphrase();
method @Nullable public android.net.wifi.hotspot2.PasspointConfiguration getPasspointConfig();
method @IntRange(from=0) public int getPriority();
+ method public int getPriorityGroup();
method @Nullable public String getSsid();
method public boolean isAppInteractionRequired();
method public boolean isCredentialSharedWithUser();
@@ -513,6 +514,7 @@
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsUserInteractionRequired(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPasspointConfig(@NonNull android.net.wifi.hotspot2.PasspointConfiguration);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriority(@IntRange(from=0) int);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriorityGroup(int);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setSsid(@NonNull String);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setUntrusted(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWapiEnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 68eb1bb..a3c4ae7 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -102,10 +102,15 @@
*/
private int mMeteredOverride;
/**
- * Priority of this network among other network suggestions provided by the app.
+ * Priority of this network among other network suggestions from same priority group
+ * provided by the app.
* The lower the number, the higher the priority (i.e value of 0 = highest priority).
*/
private int mPriority;
+ /**
+ * Priority group ID, while suggestion priority will only effect inside the priority group.
+ */
+ private int mPriorityGroup;
/**
* The carrier ID identifies the operator who provides this network configuration.
@@ -165,6 +170,7 @@
mWapiPskPassphrase = null;
mWapiEnterpriseConfig = null;
mIsNetworkUntrusted = false;
+ mPriorityGroup = 0;
}
/**
@@ -329,6 +335,18 @@
}
/**
+ * Set the priority group ID, {@link #setPriority(int)} will only impact the network
+ * suggestions from the same priority group within the same app.
+ *
+ * @param priorityGroup priority group id, if not set default is 0.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setPriorityGroup(int priorityGroup) {
+ mPriorityGroup = priorityGroup;
+ return this;
+ }
+
+ /**
* Set the ASCII WAPI passphrase for this network. Needed for authenticating to
* WAPI-PSK networks.
*
@@ -411,8 +429,9 @@
/**
* Specify the priority of this network among other network suggestions provided by the same
- * app (priorities have no impact on suggestions by different apps). The higher the number,
- * the higher the priority (i.e value of 0 = lowest priority).
+ * app (priorities have no impact on suggestions by different apps) and within the same
+ * priority group, see {@link #setPriorityGroup(int)}.
+ * The higher the number, the higher the priority (i.e value of 0 = lowest priority).
* <p>
* <li>If not set, defaults a lower priority than any assigned priority.</li>
*
@@ -696,7 +715,8 @@
mIsAppInteractionRequired,
mIsUserInteractionRequired,
mIsSharedWithUser,
- mIsInitialAutojoinEnabled);
+ mIsInitialAutojoinEnabled,
+ mPriorityGroup);
}
}
@@ -739,6 +759,12 @@
*/
public final boolean isInitialAutoJoinEnabled;
+ /**
+ * Priority group ID.
+ * @hide
+ */
+ public final int priorityGroup;
+
/** @hide */
public WifiNetworkSuggestion() {
this.wifiConfiguration = new WifiConfiguration();
@@ -747,6 +773,7 @@
this.isUserInteractionRequired = false;
this.isUserAllowedToManuallyConnect = true;
this.isInitialAutoJoinEnabled = true;
+ this.priorityGroup = 0;
}
/** @hide */
@@ -755,7 +782,7 @@
boolean isAppInteractionRequired,
boolean isUserInteractionRequired,
boolean isUserAllowedToManuallyConnect,
- boolean isInitialAutoJoinEnabled) {
+ boolean isInitialAutoJoinEnabled, int priorityGroup) {
checkNotNull(networkConfiguration);
this.wifiConfiguration = networkConfiguration;
this.passpointConfiguration = passpointConfiguration;
@@ -764,6 +791,7 @@
this.isUserInteractionRequired = isUserInteractionRequired;
this.isUserAllowedToManuallyConnect = isUserAllowedToManuallyConnect;
this.isInitialAutoJoinEnabled = isInitialAutoJoinEnabled;
+ this.priorityGroup = priorityGroup;
}
public static final @NonNull Creator<WifiNetworkSuggestion> CREATOR =
@@ -776,7 +804,8 @@
in.readBoolean(), // isAppInteractionRequired
in.readBoolean(), // isUserInteractionRequired
in.readBoolean(), // isSharedCredentialWithUser
- in.readBoolean() // isAutojoinEnabled
+ in.readBoolean(), // isAutojoinEnabled
+ in.readInt() // priorityGroup
);
}
@@ -799,6 +828,7 @@
dest.writeBoolean(isUserInteractionRequired);
dest.writeBoolean(isUserAllowedToManuallyConnect);
dest.writeBoolean(isInitialAutoJoinEnabled);
+ dest.writeInt(priorityGroup);
}
@Override
@@ -842,6 +872,7 @@
.append(", isCredentialSharedWithUser=").append(isUserAllowedToManuallyConnect)
.append(", isInitialAutoJoinEnabled=").append(isInitialAutoJoinEnabled)
.append(", isUnTrusted=").append(!wifiConfiguration.trusted)
+ .append(", priorityGroup=").append(priorityGroup)
.append(" ]");
return sb.toString();
}
@@ -962,4 +993,11 @@
}
return WifiInfo.removeDoubleQuotes(wifiConfiguration.preSharedKey);
}
+
+ /**
+ * @see Builder#setPriorityGroup(int)
+ */
+ public int getPriorityGroup() {
+ return priorityGroup;
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index f0839e9..3744a51 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -16,7 +16,12 @@
package android.net.wifi;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import android.net.MacAddress;
import android.net.wifi.hotspot2.PasspointConfiguration;
@@ -39,6 +44,8 @@
private static final String TEST_FQDN = "fqdn";
private static final String TEST_WAPI_CERT_SUITE = "suite";
private static final String TEST_DOMAIN_SUFFIX_MATCH = "domainSuffixMatch";
+ private static final int DEFAULT_PRIORITY_GROUP = 0;
+ private static final int TEST_PRIORITY_GROUP = 1;
/**
* Validate correctness of WifiNetworkSuggestion object created by
@@ -612,7 +619,7 @@
configuration.BSSID = TEST_BSSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion(
- configuration, null, false, true, true, true);
+ configuration, null, false, true, true, true, TEST_PRIORITY_GROUP);
Parcel parcelW = Parcel.obtain();
suggestion.writeToParcel(parcelW, 0);
@@ -683,14 +690,16 @@
configuration.BSSID = TEST_BSSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, true, false, true, true);
+ new WifiNetworkSuggestion(configuration, null, true, false, true, true,
+ TEST_PRIORITY_GROUP);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID;
configuration1.BSSID = TEST_BSSID;
configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, true, true, true);
+ new WifiNetworkSuggestion(configuration1, null, false, true, true, true,
+ DEFAULT_PRIORITY_GROUP);
assertEquals(suggestion, suggestion1);
assertEquals(suggestion.hashCode(), suggestion1.hashCode());
@@ -706,13 +715,15 @@
configuration.SSID = TEST_SSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, false, false, true, true);
+ new WifiNetworkSuggestion(configuration, null, false, false, true, true,
+ DEFAULT_PRIORITY_GROUP);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID_1;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
+ new WifiNetworkSuggestion(configuration1, null, false, false, true, true,
+ DEFAULT_PRIORITY_GROUP);
assertNotEquals(suggestion, suggestion1);
}
@@ -728,13 +739,15 @@
configuration.BSSID = TEST_BSSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, false, false, true, true);
+ new WifiNetworkSuggestion(configuration, null, false, false, true, true,
+ DEFAULT_PRIORITY_GROUP);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID;
configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
+ new WifiNetworkSuggestion(configuration1, null, false, false, true, true,
+ DEFAULT_PRIORITY_GROUP);
assertNotEquals(suggestion, suggestion1);
}
@@ -749,13 +762,15 @@
configuration.SSID = TEST_SSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, false, false, true, true);
+ new WifiNetworkSuggestion(configuration, null, false, false, true, true,
+ DEFAULT_PRIORITY_GROUP);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID;
configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
+ new WifiNetworkSuggestion(configuration1, null, false, false, true, true,
+ DEFAULT_PRIORITY_GROUP);
assertNotEquals(suggestion, suggestion1);
}