Merge "DarkMode Tile affects all users"
diff --git a/ApiDocs.bp b/ApiDocs.bp
index 029699e..ca921ff 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -150,12 +150,10 @@
":current-support-api",
":current-androidx-api",
],
- create_stubs: false,
}
doc_defaults {
name: "framework-dokka-docs-default",
- create_stubs: false,
}
droiddoc {
diff --git a/apct-tests/perftests/autofill/Android.bp b/apct-tests/perftests/autofill/Android.bp
index 9ac8c87..4f6c21a 100644
--- a/apct-tests/perftests/autofill/Android.bp
+++ b/apct-tests/perftests/autofill/Android.bp
@@ -20,8 +20,9 @@
"androidx.test.rules",
"androidx.annotation_annotation",
"apct-perftests-utils",
- "collector-device-lib-platform",
+ "collector-device-lib",
],
platform_apis: true,
test_suites: ["device-tests"],
+ data: [":perfetto_artifacts"],
}
diff --git a/apct-tests/perftests/autofill/AndroidManifest.xml b/apct-tests/perftests/autofill/AndroidManifest.xml
index 51f6a76..57595a2 100644
--- a/apct-tests/perftests/autofill/AndroidManifest.xml
+++ b/apct-tests/perftests/autofill/AndroidManifest.xml
@@ -16,11 +16,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.perftests.autofill">
- <uses-sdk android:targetSdkVersion="28" />
-
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.REAL_GET_TASKS" />
-
<application>
<uses-library android:name="android.test.runner" />
<activity android:name="android.perftests.utils.PerfTestActivity"
diff --git a/apct-tests/perftests/autofill/AndroidTest.xml b/apct-tests/perftests/autofill/AndroidTest.xml
index 29f9f94..eee7bdc 100644
--- a/apct-tests/perftests/autofill/AndroidTest.xml
+++ b/apct-tests/perftests/autofill/AndroidTest.xml
@@ -21,8 +21,40 @@
<option name="test-file-name" value="AutofillPerfTests.apk" />
</target_preparer>
+ <!-- Needed for pushing the trace config file -->
+ <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" />
+ </target_preparer>
+
+ <!-- Needed for pulling the collected trace config on to the host -->
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="pull-pattern-keys" value="perfetto_file_path" />
+ </metrics_collector>
+
+ <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+ <option name="isolated-storage" value="false" />
+
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.perftests.autofill" />
<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.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" />
+
+ <!-- ProcLoadListener related arguments -->
+ <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
+ <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+ <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+ <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+ <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
+
+ <!-- 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>
</configuration>
diff --git a/apct-tests/perftests/multiuser/Android.bp b/apct-tests/perftests/multiuser/Android.bp
index 04432f2..fc45d4a 100644
--- a/apct-tests/perftests/multiuser/Android.bp
+++ b/apct-tests/perftests/multiuser/Android.bp
@@ -22,5 +22,6 @@
],
platform_apis: true,
test_suites: ["device-tests"],
+ data: [":perfetto_artifacts"],
certificate: "platform",
}
diff --git a/apct-tests/perftests/multiuser/AndroidManifest.xml b/apct-tests/perftests/multiuser/AndroidManifest.xml
index e4196dd..cb05651 100644
--- a/apct-tests/perftests/multiuser/AndroidManifest.xml
+++ b/apct-tests/perftests/multiuser/AndroidManifest.xml
@@ -17,7 +17,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.perftests.multiuser">
- <uses-sdk android:targetSdkVersion="28" />
<uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
<uses-permission android:name="android.permission.MANAGE_USERS" />
@@ -25,8 +24,6 @@
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.REAL_GET_TASKS" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/apct-tests/perftests/multiuser/AndroidTest.xml b/apct-tests/perftests/multiuser/AndroidTest.xml
index 9117561..c7929af 100644
--- a/apct-tests/perftests/multiuser/AndroidTest.xml
+++ b/apct-tests/perftests/multiuser/AndroidTest.xml
@@ -16,14 +16,48 @@
<configuration description="Runs MultiUserPerfTests metric instrumentation.">
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="apct-metric-instrumentation" />
+
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="MultiUserPerfTests.apk" />
<option name="test-file-name" value="MultiUserPerfDummyApp.apk" />
</target_preparer>
+ <!-- Needed for pushing the trace config file -->
+ <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" />
+ </target_preparer>
+
+ <!-- Needed for pulling the collected trace config on to the host -->
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="pull-pattern-keys" value="perfetto_file_path" />
+ </metrics_collector>
+
+ <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+ <option name="isolated-storage" value="false" />
+
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.perftests.multiuser" />
<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.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" />
+
+ <!-- ProcLoadListener related arguments -->
+ <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
+ <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+ <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+ <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+ <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
+
+ <!-- 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>
</configuration>
diff --git a/apct-tests/perftests/textclassifier/Android.bp b/apct-tests/perftests/textclassifier/Android.bp
index 49952dc..9f795a7 100644
--- a/apct-tests/perftests/textclassifier/Android.bp
+++ b/apct-tests/perftests/textclassifier/Android.bp
@@ -19,7 +19,9 @@
"androidx.test.rules",
"androidx.annotation_annotation",
"apct-perftests-utils",
+ "collector-device-lib-platform",
],
+ data: [":perfetto_artifacts"],
platform_apis: true,
test_suites: ["device-tests"],
}
diff --git a/apct-tests/perftests/textclassifier/AndroidTest.xml b/apct-tests/perftests/textclassifier/AndroidTest.xml
index 3df51b8..3fac462 100644
--- a/apct-tests/perftests/textclassifier/AndroidTest.xml
+++ b/apct-tests/perftests/textclassifier/AndroidTest.xml
@@ -21,8 +21,40 @@
<option name="test-file-name" value="TextClassifierPerfTests.apk" />
</target_preparer>
+ <!-- Needed for pushing the trace config file -->
+ <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" />
+ </target_preparer>
+
+ <!-- Needed for pulling the collected trace config on to the host -->
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="pull-pattern-keys" value="perfetto_file_path" />
+ </metrics_collector>
+
+ <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+ <option name="isolated-storage" value="false" />
+
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.perftests.textclassifier" />
<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.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" />
+
+ <!-- ProcLoadListener related arguments -->
+ <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
+ <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+ <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+ <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+ <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
+
+ <!-- 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>
</configuration>
diff --git a/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassifierPerfTest.java b/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassifierPerfTest.java
index 14a121d..324def8 100644
--- a/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassifierPerfTest.java
+++ b/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassifierPerfTest.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
+import android.service.textclassifier.TextClassifierService;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
@@ -25,48 +26,73 @@
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
-import java.util.Random;
-@RunWith(Parameterized.class)
@LargeTest
public class TextClassifierPerfTest {
- /** Request contains meaning text, rather than garbled text. */
- private static final int ACTUAL_REQUEST = 0;
- private static final String RANDOM_CHAR_SET = "abcdefghijklmnopqrstuvwxyz0123456789";
+ private static final String TEXT = " Oh hi Mark, the number is (323) 654-6192.\n"
+ + "Anyway, I'll meet you at 1600 Pennsylvania Avenue NW.\n"
+ + "My flight is LX 38 and I'll arrive at 8:00pm.\n"
+ + "Also, check out www.google.com.\n";
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
- @Parameterized.Parameters(name = "size{0}")
- public static Collection<Object[]> data() {
- return Arrays.asList(new Object[][]{{ACTUAL_REQUEST}, {10}, {100}, {1000}});
- }
-
private TextClassifier mTextClassifier;
- private final int mSize;
-
- public TextClassifierPerfTest(int size) {
- mSize = size;
- }
@Before
public void setUp() {
Context context = InstrumentationRegistry.getTargetContext();
- TextClassificationManager textClassificationManager =
- context.getSystemService(TextClassificationManager.class);
- mTextClassifier = textClassificationManager.getTextClassifier(TextClassifier.LOCAL);
+ mTextClassifier = TextClassifierService.getDefaultTextClassifierImplementation(context);
+ }
+
+ @Test
+ public void testClassifyText() {
+ TextClassification.Request request =
+ new TextClassification.Request.Builder(TEXT, 0, TEXT.length()).build();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mTextClassifier.classifyText(request);
+ }
+ }
+
+ @Test
+ public void testSuggestSelection() {
+ // Trying to select the phone number.
+ TextSelection.Request request =
+ new TextSelection.Request.Builder(
+ TEXT,
+ /* startIndex= */ 28,
+ /* endIndex= */29)
+ .build();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mTextClassifier.suggestSelection(request);
+ }
+ }
+
+ @Test
+ public void testGenerateLinks() {
+ TextLinks.Request request =
+ new TextLinks.Request.Builder(TEXT).build();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mTextClassifier.generateLinks(request);
+ }
}
@Test
public void testSuggestConversationActions() {
- String text = mSize == ACTUAL_REQUEST ? "Where are you?" : generateRandomString(mSize);
- ConversationActions.Request request = createConversationActionsRequest(text);
+ ConversationActions.Message message =
+ new ConversationActions.Message.Builder(
+ ConversationActions.Message.PERSON_USER_OTHERS)
+ .setText(TEXT)
+ .build();
+ ConversationActions.Request request = new ConversationActions.Request.Builder(
+ Collections.singletonList(message))
+ .build();
+
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mTextClassifier.suggestConversationActions(request);
@@ -75,36 +101,10 @@
@Test
public void testDetectLanguage() {
- String text = mSize == ACTUAL_REQUEST
- ? "これは日本語のテキストです" : generateRandomString(mSize);
- TextLanguage.Request request = createTextLanguageRequest(text);
+ TextLanguage.Request request = new TextLanguage.Request.Builder(TEXT).build();
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
mTextClassifier.detectLanguage(request);
}
}
-
- private static ConversationActions.Request createConversationActionsRequest(CharSequence text) {
- ConversationActions.Message message =
- new ConversationActions.Message.Builder(
- ConversationActions.Message.PERSON_USER_OTHERS)
- .setText(text)
- .build();
- return new ConversationActions.Request.Builder(Collections.singletonList(message))
- .build();
- }
-
- private static TextLanguage.Request createTextLanguageRequest(CharSequence text) {
- return new TextLanguage.Request.Builder(text).build();
- }
-
- private static String generateRandomString(int length) {
- Random random = new Random();
- StringBuilder stringBuilder = new StringBuilder(length);
- for (int i = 0; i < length; i++) {
- int index = random.nextInt(RANDOM_CHAR_SET.length());
- stringBuilder.append(RANDOM_CHAR_SET.charAt(index));
- }
- return stringBuilder.toString();
- }
}
diff --git a/api/current.txt b/api/current.txt
index a59c7b8..b70103b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11900,6 +11900,7 @@
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_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
}
@@ -24207,6 +24208,7 @@
method @NonNull public java.util.List<android.media.AudioPlaybackConfiguration> getActivePlaybackConfigurations();
method @NonNull public java.util.List<android.media.AudioRecordingConfiguration> getActiveRecordingConfigurations();
method public int getAllowedCapturePolicy();
+ method public int getAudioHwSyncForSession(int);
method public android.media.AudioDeviceInfo[] getDevices(int);
method public java.util.List<android.media.MicrophoneInfo> getMicrophones() throws java.io.IOException;
method public int getMode();
@@ -47864,6 +47866,7 @@
method @Nullable public android.net.LinkProperties getLinkProperties();
method public int getNetworkType();
method public int getState();
+ method public int getTransportType();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PreciseDataConnectionState> CREATOR;
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 11db781..56059dd 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4201,6 +4201,7 @@
method @IntRange(from=0) public long getAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioProductStrategy> getAudioProductStrategies();
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioVolumeGroup> getAudioVolumeGroups();
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getDevicesForAttributes(@NonNull android.media.AudioAttributes);
method @IntRange(from=0) public long getMaxAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
@@ -4219,6 +4220,7 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int requestAudioFocus(@NonNull android.media.AudioFocusRequest, @Nullable android.media.audiopolicy.AudioPolicy);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo, @IntRange(from=0) long);
method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setSupportedSystemUsages(@NonNull int[]);
@@ -4229,6 +4231,11 @@
field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1
field public static final int AUDIOFOCUS_FLAG_LOCK = 4; // 0x4
field public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 2; // 0x2
+ field public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3; // 0x3
+ field public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4; // 0x4
+ field public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2; // 0x2
+ field public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1; // 0x1
+ field public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0; // 0x0
field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int STREAM_ASSISTANT = 11; // 0xb
field public static final int SUCCESS = 0; // 0x0
}
@@ -10838,6 +10845,7 @@
method @Deprecated public int getDataConnectionApnTypeBitMask();
method @Deprecated public int getDataConnectionFailCause();
method @Deprecated public int getDataConnectionState();
+ method public int getId();
}
public final class PreciseDisconnectCause {
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 36ff20f..9c79612 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -417,7 +417,7 @@
// this guest property specifies multi-display IDs to show the boot animation
// multiple ids can be set with comma (,) as separator, for example:
// setprop persist.boot.animation.displays 19260422155234049,19261083906282754
- Vector<uint64_t> physicalDisplayIds;
+ Vector<PhysicalDisplayId> physicalDisplayIds;
char displayValue[PROPERTY_VALUE_MAX] = "";
property_get(DISPLAYS_PROP_NAME, displayValue, "");
bool isValid = displayValue[0] != '\0';
@@ -435,7 +435,7 @@
}
if (isValid) {
std::istringstream stream(displayValue);
- for (PhysicalDisplayId id; stream >> id; ) {
+ for (PhysicalDisplayId id; stream >> id.value; ) {
physicalDisplayIds.add(id);
if (stream.peek() == ',')
stream.ignore();
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index c1d8399..dec4a56 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -51,12 +51,11 @@
"usage: %s [-hp] [-d display-id] [FILENAME]\n"
" -h: this message\n"
" -p: save the file as a png.\n"
- " -d: specify the physical display ID to capture (default: %"
- ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ")\n"
+ " -d: specify the physical display ID to capture (default: %s)\n"
" see \"dumpsys SurfaceFlinger --display-id\" for valid display IDs.\n"
"If FILENAME ends with .png it will be saved as a png.\n"
"If FILENAME is not given, the results will be printed to stdout.\n",
- pname, displayId);
+ pname, to_string(displayId).c_str());
}
static int32_t flinger2bitmapFormat(PixelFormat f)
@@ -137,7 +136,7 @@
png = true;
break;
case 'd':
- displayId = atoll(optarg);
+ displayId = PhysicalDisplayId(atoll(optarg));
break;
case '?':
case 'h':
@@ -182,16 +181,17 @@
ProcessState::self()->setThreadPoolMaxThreadCount(0);
ProcessState::self()->startThreadPool();
- ui::Dataspace outDataspace;
- sp<GraphicBuffer> outBuffer;
-
- status_t result = ScreenshotClient::capture(*displayId, &outDataspace, &outBuffer);
+ ScreenCaptureResults captureResults;
+ status_t result = ScreenshotClient::captureDisplay(displayId->value, captureResults);
if (result != NO_ERROR) {
close(fd);
return 1;
}
- result = outBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base);
+ ui::Dataspace dataspace = captureResults.capturedDataspace;
+ sp<GraphicBuffer> buffer = captureResults.buffer;
+
+ result = buffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base);
if (base == nullptr || result != NO_ERROR) {
String8 reason;
@@ -207,13 +207,13 @@
if (png) {
AndroidBitmapInfo info;
- info.format = flinger2bitmapFormat(outBuffer->getPixelFormat());
+ info.format = flinger2bitmapFormat(buffer->getPixelFormat());
info.flags = ANDROID_BITMAP_FLAGS_ALPHA_PREMUL;
- info.width = outBuffer->getWidth();
- info.height = outBuffer->getHeight();
- info.stride = outBuffer->getStride() * bytesPerPixel(outBuffer->getPixelFormat());
+ info.width = buffer->getWidth();
+ info.height = buffer->getHeight();
+ info.stride = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat());
- int result = AndroidBitmap_compress(&info, static_cast<int32_t>(outDataspace), base,
+ int result = AndroidBitmap_compress(&info, static_cast<int32_t>(dataspace), base,
ANDROID_BITMAP_COMPRESS_FORMAT_PNG, 100, &fd,
[](void* fdPtr, const void* data, size_t size) -> bool {
int bytesWritten = write(*static_cast<int*>(fdPtr),
@@ -229,11 +229,11 @@
notifyMediaScanner(fn);
}
} else {
- uint32_t w = outBuffer->getWidth();
- uint32_t h = outBuffer->getHeight();
- uint32_t s = outBuffer->getStride();
- uint32_t f = outBuffer->getPixelFormat();
- uint32_t c = dataSpaceToInt(outDataspace);
+ uint32_t w = buffer->getWidth();
+ uint32_t h = buffer->getHeight();
+ uint32_t s = buffer->getStride();
+ uint32_t f = buffer->getPixelFormat();
+ uint32_t c = dataSpaceToInt(dataspace);
write(fd, &w, 4);
write(fd, &h, 4);
diff --git a/cmds/uiautomator/library/Android.bp b/cmds/uiautomator/library/Android.bp
index 04b00cb..14b74da 100644
--- a/cmds/uiautomator/library/Android.bp
+++ b/cmds/uiautomator/library/Android.bp
@@ -54,7 +54,6 @@
],
installable: false,
custom_template: "droiddoc-templates-sdk",
- create_stubs: false,
}
java_library_static {
@@ -66,6 +65,7 @@
"android.test.runner",
"junit",
],
+ java_version: "1.8",
}
java_library_static {
diff --git a/config/hiddenapi-force-blacklist.txt b/config/hiddenapi-force-blocked.txt
similarity index 100%
rename from config/hiddenapi-force-blacklist.txt
rename to config/hiddenapi-force-blocked.txt
diff --git a/config/hiddenapi-greylist-max-o.txt b/config/hiddenapi-max-target-o.txt
similarity index 100%
rename from config/hiddenapi-greylist-max-o.txt
rename to config/hiddenapi-max-target-o.txt
diff --git a/config/hiddenapi-greylist-max-p.txt b/config/hiddenapi-max-target-p.txt
similarity index 100%
rename from config/hiddenapi-greylist-max-p.txt
rename to config/hiddenapi-max-target-p.txt
diff --git a/config/hiddenapi-greylist-max-q.txt b/config/hiddenapi-max-target-q.txt
similarity index 100%
rename from config/hiddenapi-greylist-max-q.txt
rename to config/hiddenapi-max-target-q.txt
diff --git a/config/hiddenapi-greylist-packages.txt b/config/hiddenapi-unsupported-packages.txt
similarity index 100%
rename from config/hiddenapi-greylist-packages.txt
rename to config/hiddenapi-unsupported-packages.txt
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-unsupported.txt
similarity index 100%
rename from config/hiddenapi-greylist.txt
rename to config/hiddenapi-unsupported.txt
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index a9239b4..bc8db02 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -183,7 +183,7 @@
// This is to work around a bug in b/34736819. This needs to be removed once app team
// fixes their side.
- private AnimatorListenerAdapter mAnimationEndingListener = new AnimatorListenerAdapter() {
+ private AnimatorListenerAdapter mAnimationEndListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (mNodeMap.get(animation) == null) {
@@ -1186,7 +1186,7 @@
}
private void startAnimation() {
- addAnimationEndingListener();
+ addAnimationEndListener();
// Register animation callback
addAnimationCallback(0);
@@ -1243,15 +1243,15 @@
// This is to work around the issue in b/34736819, as the old behavior in AnimatorSet had
// masked a real bug in play movies. TODO: remove this and below once the root cause is fixed.
- private void addAnimationEndingListener() {
+ private void addAnimationEndListener() {
for (int i = 1; i < mNodes.size(); i++) {
- mNodes.get(i).mAnimation.addListener(mAnimationEndingListener);
+ mNodes.get(i).mAnimation.addListener(mAnimationEndListener);
}
}
- private void removeAnimationEndingListener() {
+ private void removeAnimationEndListener() {
for (int i = 1; i < mNodes.size(); i++) {
- mNodes.get(i).mAnimation.removeListener(mAnimationEndingListener);
+ mNodes.get(i).mAnimation.removeListener(mAnimationEndListener);
}
}
@@ -1301,7 +1301,7 @@
tmpListeners.get(i).onAnimationEnd(this, mReversing);
}
}
- removeAnimationEndingListener();
+ removeAnimationEndListener();
mSelfPulse = true;
mReversing = false;
}
@@ -1346,7 +1346,7 @@
anim.mNodeMap = new ArrayMap<Animator, Node>();
anim.mNodes = new ArrayList<Node>(nodeCount);
anim.mEvents = new ArrayList<AnimationEvent>();
- anim.mAnimationEndingListener = new AnimatorListenerAdapter() {
+ anim.mAnimationEndListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (anim.mNodeMap.get(animation) == null) {
@@ -1369,7 +1369,7 @@
final Node node = mNodes.get(n);
Node nodeClone = node.clone();
// Remove the old internal listener from the cloned child
- nodeClone.mAnimation.removeListener(mAnimationEndingListener);
+ nodeClone.mAnimation.removeListener(mAnimationEndListener);
clonesMap.put(node, nodeClone);
anim.mNodes.add(nodeClone);
anim.mNodeMap.put(nodeClone.mAnimation, nodeClone);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 2be9282..522b8cc 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2880,7 +2880,7 @@
* Return the number of actions that will be displayed in the picture-in-picture UI when the
* user interacts with the activity currently in picture-in-picture mode. This number may change
* if the global configuration changes (ie. if the device is plugged into an external display),
- * but will always be larger than three.
+ * but will always be at least three.
*/
public int getMaxNumPictureInPictureActions() {
try {
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 7fe567b..1f8cf8a 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -52,23 +52,14 @@
* if in the same profile group.
* Otherwise, {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required.
*/
- public static final int ALLOW_NON_FULL_IN_PROFILE_OR_FULL = 1;
+ public static final int ALLOW_NON_FULL_IN_PROFILE = 1;
public static final int ALLOW_FULL_ONLY = 2;
/**
* Allows access to a caller with {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES}
* or {@link android.Manifest.permission#INTERACT_ACROSS_USERS} if in the same profile group.
* Otherwise, {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required.
*/
- public static final int ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL = 3;
- /**
- * Requires {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES},
- * {@link android.Manifest.permission#INTERACT_ACROSS_USERS}, or
- * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} if in same profile group,
- * otherwise {@link android.Manifest.permission#INTERACT_ACROSS_USERS} or
- * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}. (so this is an extension
- * to {@link #ALLOW_NON_FULL})
- */
- public static final int ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL = 4;
+ public static final int ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE = 3;
/**
* Verify that calling app has access to the given provider.
@@ -350,7 +341,8 @@
/** @see com.android.server.am.ActivityManagerService#monitor */
public abstract void monitor();
- /** Input dispatch timeout to a window, start the ANR process. */
+ /** Input dispatch timeout to a window, start the ANR process. Return the timeout extension,
+ * in milliseconds, or 0 to abort dispatch. */
public abstract long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason);
public abstract boolean inputDispatchingTimedOut(Object proc, String activityShortComponentName,
ApplicationInfo aInfo, String parentShortComponentName, Object parentProc,
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index bca6f39..54f3f10 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -215,7 +215,7 @@
private long mMisses = 0;
@GuardedBy("mLock")
- private long mMissDisabled[] = new long[]{ 0, 0, 0 };
+ private long mSkips[] = new long[]{ 0, 0, 0 };
@GuardedBy("mLock")
private long mMissOverflow = 0;
@@ -223,6 +223,9 @@
@GuardedBy("mLock")
private long mHighWaterMark = 0;
+ @GuardedBy("mLock")
+ private long mClears = 0;
+
// Most invalidation is done in a static context, so the counters need to be accessible.
@GuardedBy("sCorkLock")
private static final HashMap<String, Long> sInvalidates = new HashMap<>();
@@ -273,6 +276,13 @@
*/
private volatile SystemProperties.Handle mPropertyHandle;
+ /**
+ * The name by which this cache is known. This should normally be the
+ * binder call that is being cached, but the constructors default it to
+ * the property name.
+ */
+ private final String mCacheName;
+
@GuardedBy("mLock")
private final LinkedHashMap<Query, Result> mCache;
@@ -297,9 +307,23 @@
*
* @param maxEntries Maximum number of entries to cache; LRU discard
* @param propertyName Name of the system property holding the cache invalidation nonce
+ * Defaults the cache name to the property name.
*/
public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName) {
+ this(maxEntries, propertyName, propertyName);
+ }
+
+ /**
+ * Make a new property invalidated cache.
+ *
+ * @param maxEntries Maximum number of entries to cache; LRU discard
+ * @param propertyName Name of the system property holding the cache invalidation nonce
+ * @param cacheName Name of this cache in debug and dumpsys
+ */
+ public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName,
+ @NonNull String cacheName) {
mPropertyName = propertyName;
+ mCacheName = cacheName;
mMaxEntries = maxEntries;
mCache = new LinkedHashMap<Query, Result>(
2 /* start small */,
@@ -320,7 +344,6 @@
};
synchronized (sCorkLock) {
sCaches.put(this, null);
- sInvalidates.put(propertyName, (long) 0);
}
}
@@ -333,6 +356,7 @@
Log.d(TAG, "clearing cache for " + mPropertyName);
}
mCache.clear();
+ mClears++;
}
}
@@ -413,7 +437,7 @@
// Do not bother collecting statistics if the cache is
// locally disabled.
synchronized (mLock) {
- mMissDisabled[(int) currentNonce]++;
+ mSkips[(int) currentNonce]++;
}
}
@@ -742,12 +766,16 @@
boolean alreadyQueued = mUncorkDeadlineMs >= 0;
if (DEBUG) {
Log.w(TAG, String.format(
- "autoCork mUncorkDeadlineMs=%s", mUncorkDeadlineMs));
+ "autoCork %s mUncorkDeadlineMs=%s", mPropertyName,
+ mUncorkDeadlineMs));
}
mUncorkDeadlineMs = SystemClock.uptimeMillis() + mAutoCorkDelayMs;
if (!alreadyQueued) {
getHandlerLocked().sendEmptyMessageAtTime(0, mUncorkDeadlineMs);
PropertyInvalidatedCache.corkInvalidations(mPropertyName);
+ } else {
+ final long count = sCorkedInvalidates.getOrDefault(mPropertyName, (long) 0);
+ sCorkedInvalidates.put(mPropertyName, count + 1);
}
}
}
@@ -756,7 +784,8 @@
synchronized (mLock) {
if (DEBUG) {
Log.w(TAG, String.format(
- "handleMsesage mUncorkDeadlineMs=%s", mUncorkDeadlineMs));
+ "handleMsesage %s mUncorkDeadlineMs=%s",
+ mPropertyName, mUncorkDeadlineMs));
}
if (mUncorkDeadlineMs < 0) {
@@ -816,7 +845,7 @@
* method is public so clients can use it.
*/
public String cacheName() {
- return mPropertyName;
+ return mCacheName;
}
/**
@@ -864,16 +893,20 @@
}
synchronized (mLock) {
- pw.println(String.format(" Cache Property Name: %s", cacheName()));
- pw.println(String.format(" Hits: %d, Misses: %d, Invalidates: %d, Overflows: %d",
- mHits, mMisses, invalidateCount, mMissOverflow));
- pw.println(String.format(" Miss-corked: %d, Miss-unset: %d, Miss-other: %d," +
- " CorkedInvalidates: %d",
- mMissDisabled[NONCE_CORKED], mMissDisabled[NONCE_UNSET],
- mMissDisabled[NONCE_DISABLED], corkedInvalidates));
- pw.println(String.format(" Last Observed Nonce: %d", mLastSeenNonce));
- pw.println(String.format(" Current Size: %d, Max Size: %d, HW Mark: %d",
- mCache.size(), mMaxEntries, mHighWaterMark));
+ pw.println(String.format(" Cache Name: %s", cacheName()));
+ pw.println(String.format(" Property: %s", mPropertyName));
+ final long skips = mSkips[NONCE_CORKED] + mSkips[NONCE_UNSET] + mSkips[NONCE_DISABLED];
+ pw.println(String.format(" Hits: %d, Misses: %d, Skips: %d, Clears: %d",
+ mHits, mMisses, skips, mClears));
+ pw.println(String.format(" Skip-corked: %d, Skip-unset: %d, Skip-other: %d",
+ mSkips[NONCE_CORKED], mSkips[NONCE_UNSET],
+ mSkips[NONCE_DISABLED]));
+ pw.println(String.format(
+ " Nonce: 0x%016x, Invalidates: %d, CorkedInvalidates: %d",
+ mLastSeenNonce, invalidateCount, corkedInvalidates));
+ pw.println(String.format(
+ " Current Size: %d, Max Size: %d, HW Mark: %d, Overflows: %d",
+ mCache.size(), mMaxEntries, mHighWaterMark, mMissOverflow));
pw.println(String.format(" Enabled: %s", mDisabled ? "false" : "true"));
Set<Map.Entry<Query, Result>> cacheEntries = mCache.entrySet();
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
index 6bd365f..0770aff 100644
--- a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
+++ b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
@@ -117,7 +117,7 @@
}
private void notifyConfigurationListeners(@NonNull TimeZoneConfiguration configuration) {
- ArraySet<TimeZoneConfigurationListener> configurationListeners;
+ final ArraySet<TimeZoneConfigurationListener> configurationListeners;
synchronized (this) {
configurationListeners = new ArraySet<>(mConfigurationListeners);
}
diff --git a/core/java/android/companion/BluetoothDeviceFilter.java b/core/java/android/companion/BluetoothDeviceFilter.java
index 2649fbe..cf9eeca 100644
--- a/core/java/android/companion/BluetoothDeviceFilter.java
+++ b/core/java/android/companion/BluetoothDeviceFilter.java
@@ -142,6 +142,16 @@
}
@Override
+ public String toString() {
+ return "BluetoothDeviceFilter{"
+ + "mNamePattern=" + mNamePattern
+ + ", mAddress='" + mAddress + '\''
+ + ", mServiceUuids=" + mServiceUuids
+ + ", mServiceUuidMasks=" + mServiceUuidMasks
+ + '}';
+ }
+
+ @Override
public int describeContents() {
return 0;
}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index bd02210..31c77ee 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -963,7 +963,7 @@
/** @hide */
public static final int LOCK_TASK_LAUNCH_MODE_ALWAYS = 2;
/** @hide */
- public static final int LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED = 3;
+ public static final int LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED = 3;
/** @hide */
public static final String lockTaskLaunchModeToString(int lockTaskLaunchMode) {
@@ -974,8 +974,8 @@
return "LOCK_TASK_LAUNCH_MODE_NEVER";
case LOCK_TASK_LAUNCH_MODE_ALWAYS:
return "LOCK_TASK_LAUNCH_MODE_ALWAYS";
- case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
- return "LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED";
+ case LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED:
+ return "LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED";
default:
return "unknown=" + lockTaskLaunchMode;
}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index df9db27..bed7b26 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2075,7 +2075,8 @@
STAGED_SESSION_NO_ERROR,
STAGED_SESSION_VERIFICATION_FAILED,
STAGED_SESSION_ACTIVATION_FAILED,
- STAGED_SESSION_UNKNOWN})
+ STAGED_SESSION_UNKNOWN,
+ STAGED_SESSION_OTHER_ERROR})
@Retention(RetentionPolicy.SOURCE)
public @interface StagedSessionErrorCode{}
/**
@@ -2101,6 +2102,12 @@
*/
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.
+ */
+ public static final int STAGED_SESSION_OTHER_ERROR = 4;
+
/** {@hide} */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int sessionId;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 42a6107..e08af55 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -8089,7 +8089,8 @@
private static final PropertyInvalidatedCache<ApplicationInfoQuery, ApplicationInfo>
sApplicationInfoCache =
new PropertyInvalidatedCache<ApplicationInfoQuery, ApplicationInfo>(
- 16, PermissionManager.CACHE_KEY_PACKAGE_INFO) {
+ 16, PermissionManager.CACHE_KEY_PACKAGE_INFO,
+ "getApplicationInfo") {
@Override
protected ApplicationInfo recompute(ApplicationInfoQuery query) {
return getApplicationInfoAsUserUncached(
@@ -8190,7 +8191,8 @@
private static final PropertyInvalidatedCache<PackageInfoQuery, PackageInfo>
sPackageInfoCache =
new PropertyInvalidatedCache<PackageInfoQuery, PackageInfo>(
- 32, PermissionManager.CACHE_KEY_PACKAGE_INFO) {
+ 32, PermissionManager.CACHE_KEY_PACKAGE_INFO,
+ "getPackageInfo") {
@Override
protected PackageInfo recompute(PackageInfoQuery query) {
return getPackageInfoAsUserUncached(
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index fbe6a50..b0d4497 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -743,6 +743,12 @@
@UnsupportedAppUsage
public abstract ArrayMap<String, ? extends Pkg> getPackageStats();
+ /**
+ * Returns the proportion of power consumed by the System Service
+ * calls made by this UID.
+ */
+ public abstract double getProportionalSystemServiceUsage();
+
public abstract ControllerActivityCounter getWifiControllerActivity();
public abstract ControllerActivityCounter getBluetoothControllerActivity();
public abstract ControllerActivityCounter getModemControllerActivity();
@@ -2882,6 +2888,17 @@
public abstract int getDischargeAmountScreenDozeSinceCharge();
/**
+ * Returns the approximate CPU time (in microseconds) spent by the system server handling
+ * incoming service calls from apps.
+ *
+ * @param cluster the index of the CPU cluster.
+ * @param step the index of the CPU speed. This is not the actual speed of the CPU.
+ * @see com.android.internal.os.PowerProfile#getNumCpuClusters()
+ * @see com.android.internal.os.PowerProfile#getNumSpeedStepsInCpuCluster(int)
+ */
+ public abstract long getSystemServiceTimeAtCpuSpeed(int cluster, int step);
+
+ /**
* Returns the total, last, or current battery uptime in microseconds.
*
* @param curTime the elapsed realtime in microseconds.
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index bf3d46f..0c19071 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -608,7 +608,7 @@
/** @hide */
private static final PropertyInvalidatedCache<PermissionQuery, Integer> sPermissionCache =
new PropertyInvalidatedCache<PermissionQuery, Integer>(
- 16, CACHE_KEY_PACKAGE_INFO) {
+ 16, CACHE_KEY_PACKAGE_INFO, "checkPermission") {
@Override
protected Integer recompute(PermissionQuery query) {
return checkPermissionUncached(query.permission, query.pid, query.uid);
@@ -689,7 +689,7 @@
private static PropertyInvalidatedCache<PackageNamePermissionQuery, Integer>
sPackageNamePermissionCache =
new PropertyInvalidatedCache<PackageNamePermissionQuery, Integer>(
- 16, CACHE_KEY_PACKAGE_INFO) {
+ 16, CACHE_KEY_PACKAGE_INFO, "checkPackageNamePermission") {
@Override
protected Integer recompute(PackageNamePermissionQuery query) {
return checkPackageNamePermissionUncached(
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7ee41b9..660455e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7912,6 +7912,13 @@
public static final String TAPS_APP_TO_EXIT = "taps_app_to_exit";
/**
+ * Internal use, one handed mode tutorial showed times.
+ * @hide
+ */
+ public static final String ONE_HANDED_TUTORIAL_SHOW_COUNT =
+ "one_handed_tutorial_show_count";
+
+ /**
* The current night mode that has been selected by the user. Owned
* and controlled by UiModeManagerService. Constants are as per
* UiModeManager.
@@ -8728,16 +8735,6 @@
= "bubble_important_conversations";
/**
- * When enabled, notifications the notification assistant service has modified will show an
- * indicator. When tapped, this indicator will describe the adjustment made and solicit
- * feedback. This flag will also add a "automatic" option to the long press menu.
- *
- * The value 1 - enable, 0 - disable
- * @hide
- */
- public static final String NOTIFICATION_FEEDBACK_ENABLED = "notification_feedback_enabled";
-
- /**
* Whether notifications are dismissed by a right-to-left swipe (instead of a left-to-right
* swipe).
*
@@ -14047,6 +14044,16 @@
"notification_snooze_options";
/**
+ * When enabled, notifications the notification assistant service has modified will show an
+ * indicator. When tapped, this indicator will describe the adjustment made and solicit
+ * feedback. This flag will also add a "automatic" option to the long press menu.
+ *
+ * The value 1 - enable, 0 - disable
+ * @hide
+ */
+ public static final String NOTIFICATION_FEEDBACK_ENABLED = "notification_feedback_enabled";
+
+ /**
* Settings key for the ratio of notification dismissals to notification views - one of the
* criteria for showing the notification blocking helper.
*
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 0a47032..a720601 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -26,10 +26,8 @@
import android.os.Build;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.telephony.Annotation.ApnType;
import android.telephony.Annotation.CallState;
import android.telephony.Annotation.DataActivityType;
-import android.telephony.Annotation.DataFailureCause;
import android.telephony.Annotation.DisconnectCauses;
import android.telephony.Annotation.NetworkType;
import android.telephony.Annotation.PreciseCallStates;
@@ -37,7 +35,6 @@
import android.telephony.Annotation.RadioPowerState;
import android.telephony.Annotation.SimActivationState;
import android.telephony.Annotation.SrvccState;
-import android.telephony.data.ApnSetting;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsReasonInfo;
import android.util.Log;
@@ -402,17 +399,16 @@
* @param subId for which data connection state changed.
* @param slotIndex for which data connections state changed. Can be derived from subId except
* when subId is invalid.
- * @param apnType the apn type bitmask, defined with {@code ApnSetting#TYPE_*} flags.
* @param preciseState the PreciseDataConnectionState
*
- * @see android.telephony.PreciseDataConnection
+ * @see PreciseDataConnectionState
* @see TelephonyManager#DATA_DISCONNECTED
*/
public void notifyDataConnectionForSubscriber(int slotIndex, int subId,
- @ApnType int apnType, @Nullable PreciseDataConnectionState preciseState) {
+ @NonNull PreciseDataConnectionState preciseState) {
try {
sRegistry.notifyDataConnectionForSubscriber(
- slotIndex, subId, apnType, preciseState);
+ slotIndex, subId, preciseState);
} catch (RemoteException ex) {
// system process is dead
}
@@ -612,25 +608,6 @@
}
/**
- * Notify precise data connection failed cause on certain subscription.
- *
- * @param subId for which data connection failed.
- * @param slotIndex for which data conenction failed. Can be derived from subId except when
- * subId is invalid.
- * @param apnType the apn type bitmask, defined with {@code ApnSetting#TYPE_*} flags.
- * @param apn the APN {@link ApnSetting#getApnName()} of this data connection.
- * @param failCause data fail cause.
- */
- public void notifyPreciseDataConnectionFailed(int subId, int slotIndex, @ApnType int apnType,
- @Nullable String apn, @DataFailureCause int failCause) {
- try {
- sRegistry.notifyPreciseDataConnectionFailed(slotIndex, subId, apnType, apn, failCause);
- } catch (RemoteException ex) {
- // system process is dead
- }
- }
-
- /**
* Notify single Radio Voice Call Continuity (SRVCC) state change for the currently active call
* on certain subscription.
*
diff --git a/core/java/android/view/InputApplicationHandle.java b/core/java/android/view/InputApplicationHandle.java
index 3d05e2a..108345e 100644
--- a/core/java/android/view/InputApplicationHandle.java
+++ b/core/java/android/view/InputApplicationHandle.java
@@ -34,7 +34,7 @@
public String name;
// Dispatching timeout.
- public long dispatchingTimeoutNanos;
+ public long dispatchingTimeoutMillis;
public final IBinder token;
@@ -46,7 +46,7 @@
public InputApplicationHandle(InputApplicationHandle handle) {
this.token = handle.token;
- this.dispatchingTimeoutNanos = handle.dispatchingTimeoutNanos;
+ this.dispatchingTimeoutMillis = handle.dispatchingTimeoutMillis;
this.name = handle.name;
}
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index a7e0305..e341845 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -50,7 +50,7 @@
public int layoutParamsType;
// Dispatching timeout.
- public long dispatchingTimeoutNanos;
+ public long dispatchingTimeoutMillis;
// Window frame.
public int frameLeft;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index eaa7eaf..50ed00c 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -89,13 +89,10 @@
private static native void nativeWriteToParcel(long nativeObject, Parcel out);
private static native void nativeRelease(long nativeObject);
private static native void nativeDisconnect(long nativeObject);
-
- private static native ScreenshotHardwareBuffer nativeScreenshot(IBinder displayToken,
- Rect sourceCrop, int width, int height, boolean useIdentityTransform, int rotation,
- boolean captureSecureLayers);
- private static native ScreenshotHardwareBuffer nativeCaptureLayers(IBinder displayToken,
- long layerObject, Rect sourceCrop, float frameScale, long[] excludeLayerObjects,
- int format);
+ private static native ScreenshotHardwareBuffer nativeCaptureDisplay(
+ DisplayCaptureArgs captureArgs);
+ private static native ScreenshotHardwareBuffer nativeCaptureLayers(
+ LayerCaptureArgs captureArgs);
private static native long nativeMirrorSurface(long mirrorOfObject);
private static native long nativeCreateTransaction();
private static native long nativeGetNativeTransactionFinalizer();
@@ -572,7 +569,8 @@
* Create ScreenshotHardwareBuffer from an existing HardwareBuffer object.
* @param hardwareBuffer The existing HardwareBuffer object
* @param namedColorSpace Integer value of a named color space {@link ColorSpace.Named}
- * @param containsSecureLayer Indicates whether this graphic buffer contains captured contents
+ * @param containsSecureLayers Indicates whether this graphic buffer contains captured
+ * contents
* of secure layers, in which case the screenshot should not be persisted.
*/
private static ScreenshotHardwareBuffer createFromNative(HardwareBuffer hardwareBuffer,
@@ -662,14 +660,14 @@
/**
* Each sub class should return itself to allow the builder to chain properly
*/
- public abstract T getThis();
+ abstract T getThis();
}
}
/**
* The arguments class used to make display capture requests.
*
- * @see #nativeScreenshot(IBinder, Rect, int, int, boolean, int, boolean)
+ * @see #nativeCaptureDisplay(DisplayCaptureArgs)
* @hide
*/
public static class DisplayCaptureArgs extends CaptureArgs {
@@ -759,7 +757,7 @@
}
@Override
- public Builder getThis() {
+ Builder getThis() {
return this;
}
}
@@ -768,7 +766,7 @@
/**
* The arguments class used to make layer capture requests.
*
- * @see #nativeCaptureLayers(IBinder, long, Rect, float, long[], int)
+ * @see #nativeCaptureLayers(LayerCaptureArgs)
* @hide
*/
public static class LayerCaptureArgs extends CaptureArgs {
@@ -780,9 +778,13 @@
super(builder);
mChildrenOnly = builder.mChildrenOnly;
mNativeLayer = builder.mLayer.mNativeObject;
- mNativeExcludeLayers = new long[builder.mExcludeLayers.length];
- for (int i = 0; i < builder.mExcludeLayers.length; i++) {
- mNativeExcludeLayers[i] = builder.mExcludeLayers[i].mNativeObject;
+ if (builder.mExcludeLayers != null) {
+ mNativeExcludeLayers = new long[builder.mExcludeLayers.length];
+ for (int i = 0; i < builder.mExcludeLayers.length; i++) {
+ mNativeExcludeLayers[i] = builder.mExcludeLayers[i].mNativeObject;
+ }
+ } else {
+ mNativeExcludeLayers = null;
}
}
@@ -837,7 +839,7 @@
}
@Override
- public Builder getThis() {
+ Builder getThis() {
return this;
}
@@ -2293,8 +2295,14 @@
throw new IllegalArgumentException("displayToken must not be null");
}
- return nativeScreenshot(display, sourceCrop, width, height, useIdentityTransform, rotation,
- false /* captureSecureLayers */);
+ DisplayCaptureArgs captureArgs = new DisplayCaptureArgs.Builder(display)
+ .setSourceCrop(sourceCrop)
+ .setSize(width, height)
+ .setUseIdentityTransform(useIdentityTransform)
+ .setRotation(rotation)
+ .build();
+
+ return nativeCaptureDisplay(captureArgs);
}
/**
@@ -2314,8 +2322,15 @@
throw new IllegalArgumentException("displayToken must not be null");
}
- return nativeScreenshot(display, sourceCrop, width, height, useIdentityTransform, rotation,
- true /* captureSecureLayers */);
+ DisplayCaptureArgs captureArgs = new DisplayCaptureArgs.Builder(display)
+ .setSourceCrop(sourceCrop)
+ .setSize(width, height)
+ .setUseIdentityTransform(useIdentityTransform)
+ .setRotation(rotation)
+ .setCaptureSecureLayers(true)
+ .build();
+
+ return nativeCaptureDisplay(captureArgs);
}
private static void rotateCropForSF(Rect crop, int rot) {
@@ -2365,24 +2380,30 @@
*/
public static ScreenshotHardwareBuffer captureLayers(SurfaceControl layer, Rect sourceCrop,
float frameScale, int format) {
- final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
- return nativeCaptureLayers(displayToken, layer.mNativeObject, sourceCrop, frameScale, null,
- format);
+ LayerCaptureArgs captureArgs = new LayerCaptureArgs.Builder(layer)
+ .setSourceCrop(sourceCrop)
+ .setFrameScale(frameScale)
+ .setPixelFormat(format)
+ .build();
+
+ return nativeCaptureLayers(captureArgs);
}
/**
- * Like {@link captureLayers} but with an array of layer handles to exclude.
+ * Like {@link #captureLayers(SurfaceControl, Rect, float, int)} but with an array of layer
+ * handles to exclude.
* @hide
*/
public static ScreenshotHardwareBuffer captureLayersExcluding(SurfaceControl layer,
Rect sourceCrop, float frameScale, int format, SurfaceControl[] exclude) {
- final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
- long[] nativeExcludeObjects = new long[exclude.length];
- for (int i = 0; i < exclude.length; i++) {
- nativeExcludeObjects[i] = exclude[i].mNativeObject;
- }
- return nativeCaptureLayers(displayToken, layer.mNativeObject, sourceCrop, frameScale,
- nativeExcludeObjects, PixelFormat.RGBA_8888);
+ LayerCaptureArgs captureArgs = new LayerCaptureArgs.Builder(layer)
+ .setSourceCrop(sourceCrop)
+ .setFrameScale(frameScale)
+ .setPixelFormat(format)
+ .setExcludeLayers(exclude)
+ .build();
+
+ return nativeCaptureLayers(captureArgs);
}
/**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0818abe..8917821 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -23358,7 +23358,7 @@
* displaying, else return the result of calling through to the
* super class.
*
- * @return boolean If true than the Drawable is being displayed in the
+ * @return boolean If true then the Drawable is being displayed in the
* view; else false and it is not allowed to animate.
*
* @see #unscheduleDrawable(android.graphics.drawable.Drawable)
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 64ddb2f..3f02d70 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1814,19 +1814,13 @@
/**
* Called after window layout to update the bounds surface. If the surface insets have changed
* or the surface has resized, update the bounds surface.
- *
- * @param shouldReparent Whether it should reparent the bounds layer to the main SurfaceControl.
*/
- private void updateBoundsLayer(boolean shouldReparent) {
+ private void updateBoundsLayer() {
if (mBoundsLayer != null) {
setBoundsLayerCrop();
- mTransaction.deferTransactionUntil(mBoundsLayer, getRenderSurfaceControl(),
- mSurface.getNextFrameNumber());
-
- if (shouldReparent) {
- mTransaction.reparent(mBoundsLayer, getRenderSurfaceControl());
- }
- mTransaction.apply();
+ mTransaction.deferTransactionUntil(mBoundsLayer,
+ getRenderSurfaceControl(), mSurface.getNextFrameNumber())
+ .apply();
}
}
@@ -2905,16 +2899,7 @@
}
if (surfaceSizeChanged || surfaceReplaced || surfaceCreated || windowAttributesChanged) {
- // If the surface has been replaced, there's a chance the bounds layer is not parented
- // to the new layer. When updating bounds layer, also reparent to the main VRI
- // SurfaceControl to ensure it's correctly placed in the hierarchy.
- //
- // This needs to be done on the client side since WMS won't reparent the children to the
- // new surface if it thinks the app is closing. WMS gets the signal that the app is
- // stopping, but on the client side it doesn't get stopped since it's restarted quick
- // enough. WMS doesn't want to keep around old children since they will leak when the
- // client creates new children.
- updateBoundsLayer(surfaceReplaced);
+ updateBoundsLayer();
}
final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 708e277..2d0f05e 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -1768,7 +1768,7 @@
* <strong>Note:</strong> The primary usage of this API is for UI test automation
* and in order to report the fully qualified view id if an {@link AccessibilityNodeInfo}
* the client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
- * flag when configuring their {@link android.accessibilityservice.AccessibilityService}.
+ * flag when configuring the {@link android.accessibilityservice.AccessibilityService}.
* </p>
* <p>
* <strong>Note:</strong> If this view hierarchy has a {@link SurfaceView} embedding another
@@ -3206,7 +3206,7 @@
* <strong>Note:</strong> The primary usage of this API is for UI test automation
* and in order to report the source view id of an {@link AccessibilityNodeInfo} the
* client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
- * flag when configuring their {@link android.accessibilityservice.AccessibilityService}.
+ * flag when configuring the {@link android.accessibilityservice.AccessibilityService}.
* </p>
* @return The id resource name.
diff --git a/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl b/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl
index e814ec6..eb67191 100644
--- a/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl
+++ b/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl
@@ -29,7 +29,7 @@
oneway interface IWindowMagnificationConnection {
/**
- * Enables window magnification on specifed display with specified center and scale.
+ * Enables window magnification on specified display with given center and scale and animation.
*
* @param displayId The logical display id.
* @param scale magnification scale.
@@ -41,7 +41,7 @@
void enableWindowMagnification(int displayId, float scale, float centerX, float centerY);
/**
- * Sets the scale of the window magnifier on specifed display.
+ * Sets the scale of the window magnifier on specified display.
*
* @param displayId The logical display id.
* @param scale magnification scale.
@@ -49,14 +49,14 @@
void setScale(int displayId, float scale);
/**
- * Disables window magnification on specifed display.
+ * Disables window magnification on specified display with animation.
*
* @param displayId The logical display id.
*/
void disableWindowMagnification(int displayId);
/**
- * Moves the window magnifier on the specifed display.
+ * Moves the window magnifier on the specified display. It has no effect while animating.
*
* @param offsetX the amount in pixels to offset the window magnifier in the X direction, in
* current screen pixels.
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index c4eb396..7683067 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -385,6 +385,7 @@
private final SuggestionHelper mSuggestionHelper = new SuggestionHelper();
private boolean mFlagCursorDragFromAnywhereEnabled;
+ private float mCursorDragDirectionMinXYRatio;
private boolean mFlagInsertionHandleGesturesEnabled;
// Specifies whether the new magnifier (with fish-eye effect) is enabled.
@@ -425,6 +426,11 @@
mFlagCursorDragFromAnywhereEnabled = AppGlobals.getIntCoreSetting(
WidgetFlags.KEY_ENABLE_CURSOR_DRAG_FROM_ANYWHERE,
WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT ? 1 : 0) != 0;
+ final int cursorDragMinAngleFromVertical = AppGlobals.getIntCoreSetting(
+ WidgetFlags.KEY_CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL,
+ WidgetFlags.CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL_DEFAULT);
+ mCursorDragDirectionMinXYRatio = EditorTouchState.getXYRatio(
+ cursorDragMinAngleFromVertical);
mFlagInsertionHandleGesturesEnabled = AppGlobals.getIntCoreSetting(
WidgetFlags.KEY_ENABLE_INSERTION_HANDLE_GESTURES,
WidgetFlags.ENABLE_INSERTION_HANDLE_GESTURES_DEFAULT ? 1 : 0) != 0;
@@ -437,6 +443,8 @@
if (TextView.DEBUG_CURSOR) {
logCursor("Editor", "Cursor drag from anywhere is %s.",
mFlagCursorDragFromAnywhereEnabled ? "enabled" : "disabled");
+ logCursor("Editor", "Cursor drag min angle from vertical is %d (= %f x/y ratio)",
+ cursorDragMinAngleFromVertical, mCursorDragDirectionMinXYRatio);
logCursor("Editor", "Insertion handle gestures is %s.",
mFlagInsertionHandleGesturesEnabled ? "enabled" : "disabled");
logCursor("Editor", "New magnifier is %s.",
@@ -463,6 +471,11 @@
}
@VisibleForTesting
+ public void setCursorDragMinAngleFromVertical(int degreesFromVertical) {
+ mCursorDragDirectionMinXYRatio = EditorTouchState.getXYRatio(degreesFromVertical);
+ }
+
+ @VisibleForTesting
public boolean getFlagInsertionHandleGesturesEnabled() {
return mFlagInsertionHandleGesturesEnabled;
}
@@ -6127,10 +6140,11 @@
if (mIsDraggingCursor) {
performCursorDrag(event);
} else if (mFlagCursorDragFromAnywhereEnabled
- && mTextView.getLayout() != null
- && mTextView.isFocused()
- && mTouchState.isMovedEnoughForDrag()
- && !mTouchState.isDragCloseToVertical()) {
+ && mTextView.getLayout() != null
+ && mTextView.isFocused()
+ && mTouchState.isMovedEnoughForDrag()
+ && (mTouchState.getInitialDragDirectionXYRatio()
+ > mCursorDragDirectionMinXYRatio || mTouchState.isOnHandle())) {
startCursorDrag(event);
}
break;
diff --git a/core/java/android/widget/EditorTouchState.java b/core/java/android/widget/EditorTouchState.java
index 9eb63087..7514368 100644
--- a/core/java/android/widget/EditorTouchState.java
+++ b/core/java/android/widget/EditorTouchState.java
@@ -59,7 +59,7 @@
private boolean mMultiTapInSameArea;
private boolean mMovedEnoughForDrag;
- private boolean mIsDragCloseToVertical;
+ private float mInitialDragDirectionXYRatio;
public float getLastDownX() {
return mLastDownX;
@@ -98,8 +98,23 @@
return mMovedEnoughForDrag;
}
- public boolean isDragCloseToVertical() {
- return mIsDragCloseToVertical && !mIsOnHandle;
+ /**
+ * When {@link #isMovedEnoughForDrag()} is {@code true}, this function returns the x/y ratio for
+ * the initial drag direction. Smaller values indicate that the direction is closer to vertical,
+ * while larger values indicate that the direction is closer to horizontal. For example:
+ * <ul>
+ * <li>if the drag direction is exactly vertical, this returns 0
+ * <li>if the drag direction is exactly horizontal, this returns {@link Float#MAX_VALUE}
+ * <li>if the drag direction is 45 deg from vertical, this returns 1
+ * <li>if the drag direction is 30 deg from vertical, this returns 0.58 (x delta is smaller
+ * than y delta)
+ * <li>if the drag direction is 60 deg from vertical, this returns 1.73 (x delta is bigger
+ * than y delta)
+ * </ul>
+ * This function never returns negative values, regardless of the direction of the drag.
+ */
+ public float getInitialDragDirectionXYRatio() {
+ return mInitialDragDirectionXYRatio;
}
public void setIsOnHandle(boolean onHandle) {
@@ -155,7 +170,7 @@
mLastDownY = event.getY();
mLastDownMillis = event.getEventTime();
mMovedEnoughForDrag = false;
- mIsDragCloseToVertical = false;
+ mInitialDragDirectionXYRatio = 0.0f;
} else if (action == MotionEvent.ACTION_UP) {
if (TextView.DEBUG_CURSOR) {
logCursor("EditorTouchState", "ACTION_UP");
@@ -164,7 +179,7 @@
mLastUpY = event.getY();
mLastUpMillis = event.getEventTime();
mMovedEnoughForDrag = false;
- mIsDragCloseToVertical = false;
+ mInitialDragDirectionXYRatio = 0.0f;
} else if (action == MotionEvent.ACTION_MOVE) {
if (!mMovedEnoughForDrag) {
float deltaX = event.getX() - mLastDownX;
@@ -174,9 +189,8 @@
int touchSlop = config.getScaledTouchSlop();
mMovedEnoughForDrag = distanceSquared > touchSlop * touchSlop;
if (mMovedEnoughForDrag) {
- // If the direction of the swipe motion is within 45 degrees of vertical, it is
- // considered a vertical drag.
- mIsDragCloseToVertical = Math.abs(deltaX) <= Math.abs(deltaY);
+ mInitialDragDirectionXYRatio = (deltaY == 0) ? Float.MAX_VALUE :
+ Math.abs(deltaX / deltaY);
}
}
} else if (action == MotionEvent.ACTION_CANCEL) {
@@ -185,7 +199,7 @@
mMultiTapStatus = MultiTapStatus.NONE;
mMultiTapInSameArea = false;
mMovedEnoughForDrag = false;
- mIsDragCloseToVertical = false;
+ mInitialDragDirectionXYRatio = 0.0f;
}
}
@@ -201,4 +215,27 @@
float distanceSquared = (deltaX * deltaX) + (deltaY * deltaY);
return distanceSquared <= maxDistance * maxDistance;
}
+
+ /**
+ * Returns the x/y ratio corresponding to the given angle relative to vertical. Smaller angle
+ * values (ie, closer to vertical) will result in a smaller x/y ratio. For example:
+ * <ul>
+ * <li>if the angle is 45 deg, the ratio is 1
+ * <li>if the angle is 30 deg, the ratio is 0.58 (x delta is smaller than y delta)
+ * <li>if the angle is 60 deg, the ratio is 1.73 (x delta is bigger than y delta)
+ * </ul>
+ * If the passed-in value is <= 0, this function returns 0. If the passed-in value is >= 90,
+ * this function returns {@link Float#MAX_VALUE}.
+ *
+ * @see #getInitialDragDirectionXYRatio()
+ */
+ public static float getXYRatio(int angleFromVerticalInDegrees) {
+ if (angleFromVerticalInDegrees <= 0) {
+ return 0.0f;
+ }
+ if (angleFromVerticalInDegrees >= 90) {
+ return Float.MAX_VALUE;
+ }
+ return (float) Math.tan(Math.toRadians(angleFromVerticalInDegrees));
+ }
}
diff --git a/core/java/android/widget/WidgetFlags.java b/core/java/android/widget/WidgetFlags.java
index 832dd51..1a49365 100644
--- a/core/java/android/widget/WidgetFlags.java
+++ b/core/java/android/widget/WidgetFlags.java
@@ -41,6 +41,28 @@
public static final boolean ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT = true;
/**
+ * Threshold for the direction of a swipe gesture in order for it to be handled as a cursor drag
+ * rather than a scroll. The direction angle of the swipe gesture must exceed this value in
+ * order to trigger cursor drag; otherwise, the swipe will be assumed to be a scroll gesture.
+ * The value units for this flag is degrees and the valid range is [0,90] inclusive. If a value
+ * < 0 is set, 0 will be used instead; if a value > 90 is set, 90 will be used instead.
+ */
+ public static final String CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL =
+ "CursorControlFeature__min_angle_from_vertical_to_start_cursor_drag";
+
+ /**
+ * The key used in app core settings for the flag
+ * {@link #CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL}.
+ */
+ public static final String KEY_CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL =
+ "widget__min_angle_from_vertical_to_start_cursor_drag";
+
+ /**
+ * Default value for the flag {@link #CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL}.
+ */
+ public static final int CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL_DEFAULT = 45;
+
+ /**
* The flag of finger-to-cursor distance in DP for cursor dragging.
* The value unit is DP and the range is {0..100}. If the value is out of range, the legacy
* value, which is based on handle size, will be used.
diff --git a/core/java/android/widget/inline/InlineContentView.java b/core/java/android/widget/inline/InlineContentView.java
index 699a7735..9712311 100644
--- a/core/java/android/widget/inline/InlineContentView.java
+++ b/core/java/android/widget/inline/InlineContentView.java
@@ -59,7 +59,7 @@
*/
public class InlineContentView extends ViewGroup {
- private static final String TAG = "InlineContentView_test2";
+ private static final String TAG = "InlineContentView";
private static final boolean DEBUG = false;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 3a89dcd..49ad81b 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -3134,7 +3134,9 @@
// ends up disabled. That's because at some point the old tab's vertical scrolling is
// disabled and the new tab's is enabled. For context, see b/159997845
setVerticalScrollEnabled(true);
- mResolverDrawerLayout.scrollNestedScrollableChildBackToTop();
+ if (mResolverDrawerLayout != null) {
+ mResolverDrawerLayout.scrollNestedScrollableChildBackToTop();
+ }
}
@Override
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index ea3d2de..eb59f0f 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -123,10 +123,15 @@
// Flag related to Privacy Indicators
/**
- * Whether the Permissions Hub is showing.
+ * Whether to show the complete ongoing app ops chip.
*/
public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_2_enabled";
+ /**
+ * Whether to show app ops chip for just microphone + camera.
+ */
+ public static final String PROPERTY_MIC_CAMERA_ENABLED = "camera_mic_icons_enabled";
+
// Flags related to Assistant
/**
diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java
index b3ea118..2620ba0 100644
--- a/core/java/com/android/internal/os/BatterySipper.java
+++ b/core/java/com/android/internal/os/BatterySipper.java
@@ -129,6 +129,7 @@
public double videoPowerMah;
public double wakeLockPowerMah;
public double wifiPowerMah;
+ public double systemServiceCpuPowerMah;
// ****************
// This list must be kept current with atoms.proto (frameworks/base/cmds/statsd/src/atoms.proto)
@@ -242,6 +243,7 @@
videoPowerMah += other.videoPowerMah;
proportionalSmearMah += other.proportionalSmearMah;
totalSmearedPowerMah += other.totalSmearedPowerMah;
+ systemServiceCpuPowerMah += other.systemServiceCpuPowerMah;
}
/**
@@ -253,7 +255,8 @@
public double sumPower() {
totalPowerMah = usagePowerMah + wifiPowerMah + gpsPowerMah + cpuPowerMah +
sensorPowerMah + mobileRadioPowerMah + wakeLockPowerMah + cameraPowerMah +
- flashlightPowerMah + bluetoothPowerMah + audioPowerMah + videoPowerMah;
+ flashlightPowerMah + bluetoothPowerMah + audioPowerMah + videoPowerMah
+ + systemServiceCpuPowerMah;
totalSmearedPowerMah = totalPowerMah + screenPowerMah + proportionalSmearMah;
return totalPowerMah;
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index b131ab8..3dfa3c3 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -133,6 +133,7 @@
private double mMaxDrainedPower;
PowerCalculator mCpuPowerCalculator;
+ SystemServicePowerCalculator mSystemServicePowerCalculator;
PowerCalculator mWakelockPowerCalculator;
MobileRadioPowerCalculator mMobileRadioPowerCalculator;
PowerCalculator mWifiPowerCalculator;
@@ -396,6 +397,11 @@
}
mCpuPowerCalculator.reset();
+ if (mSystemServicePowerCalculator == null) {
+ mSystemServicePowerCalculator = new SystemServicePowerCalculator(mPowerProfile, mStats);
+ }
+ mSystemServicePowerCalculator.reset();
+
if (mMemoryPowerCalculator == null) {
mMemoryPowerCalculator = new MemoryPowerCalculator(mPowerProfile);
}
@@ -588,6 +594,8 @@
mFlashlightPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs,
mStatsType);
mMediaPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+ mSystemServicePowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs,
+ mStatsType);
final double totalPower = app.sumPower();
if (DEBUG && totalPower != 0) {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 58ba16b..8498151 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -144,6 +144,7 @@
private static final boolean DEBUG = false;
public static final boolean DEBUG_ENERGY = false;
private static final boolean DEBUG_ENERGY_CPU = DEBUG_ENERGY;
+ private static final boolean DEBUG_BINDER_STATS = true;
private static final boolean DEBUG_MEMORY = false;
private static final boolean DEBUG_HISTORY = false;
private static final boolean USE_OLD_HISTORY = false; // for debugging.
@@ -154,7 +155,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- static final int VERSION = 186 + (USE_OLD_HISTORY ? 1000 : 0);
+ static final int VERSION = 187 + (USE_OLD_HISTORY ? 1000 : 0);
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -218,10 +219,13 @@
new KernelCpuUidClusterTimeReader(true);
@VisibleForTesting
protected KernelSingleUidTimeReader mKernelSingleUidTimeReader;
+ @VisibleForTesting
+ protected SystemServerCpuThreadReader mSystemServerCpuThreadReader;
private final KernelMemoryBandwidthStats mKernelMemoryBandwidthStats
= new KernelMemoryBandwidthStats();
private final LongSparseArray<SamplingTimer> mKernelMemoryStats = new LongSparseArray<>();
+
public LongSparseArray<SamplingTimer> getKernelMemoryStats() {
return mKernelMemoryStats;
}
@@ -267,6 +271,7 @@
/** Container for Rail Energy Data stats. */
private final RailStats mTmpRailStats = new RailStats();
+
/**
* Use a queue to delay removing UIDs from {@link KernelCpuUidUserSysTimeReader},
* {@link KernelCpuUidActiveTimeReader}, {@link KernelCpuUidClusterTimeReader},
@@ -1007,6 +1012,16 @@
private long[] mCpuFreqs;
+ /**
+ * Times spent by the system server threads grouped by cluster and CPU speed.
+ */
+ private LongSamplingCounter[][] mSystemServerThreadCpuTimesUs;
+
+ /**
+ * Times spent by the system server threads handling incoming binder requests.
+ */
+ private LongSamplingCounter[][] mBinderThreadCpuTimesUs;
+
@VisibleForTesting
protected PowerProfile mPowerProfile;
@@ -6131,10 +6146,77 @@
* the power consumption to the calling app.
*/
public void noteBinderCallStats(int workSourceUid, long incrementalCallCount,
- Collection<BinderCallsStats.CallStat> callStats) {
+ Collection<BinderCallsStats.CallStat> callStats, int[] binderThreadNativeTids) {
synchronized (this) {
getUidStatsLocked(workSourceUid).noteBinderCallStatsLocked(incrementalCallCount,
callStats);
+ mSystemServerCpuThreadReader.setBinderThreadNativeTids(binderThreadNativeTids);
+ }
+ }
+
+ /**
+ * Estimates the proportion of system server CPU activity handling incoming binder calls
+ * that can be attributed to each app
+ */
+ @VisibleForTesting
+ public void updateSystemServiceCallStats() {
+ // Start off by computing the average duration of recorded binder calls,
+ // regardless of which binder or transaction. We will use this as a fallback
+ // for calls that were not sampled at all.
+ int totalRecordedCallCount = 0;
+ long totalRecordedCallTimeMicros = 0;
+ for (int i = 0; i < mUidStats.size(); i++) {
+ Uid uid = mUidStats.valueAt(i);
+ ArraySet<BinderCallStats> binderCallStats = uid.mBinderCallStats;
+ for (int j = binderCallStats.size() - 1; j >= 0; j--) {
+ BinderCallStats stats = binderCallStats.valueAt(j);
+ totalRecordedCallCount += stats.recordedCallCount;
+ totalRecordedCallTimeMicros += stats.recordedCpuTimeMicros;
+ }
+ }
+
+ long totalSystemServiceTimeMicros = 0;
+
+ // For every UID, use recorded durations of sampled binder calls to estimate
+ // the total time the system server spent handling requests from this UID.
+ for (int i = 0; i < mUidStats.size(); i++) {
+ Uid uid = mUidStats.valueAt(i);
+
+ long totalTimeForUid = 0;
+ int totalCallCountForUid = 0;
+ ArraySet<BinderCallStats> binderCallStats = uid.mBinderCallStats;
+ for (int j = binderCallStats.size() - 1; j >= 0; j--) {
+ BinderCallStats stats = binderCallStats.valueAt(j);
+ totalCallCountForUid += stats.callCount;
+ if (stats.recordedCallCount > 0) {
+ totalTimeForUid +=
+ stats.callCount * stats.recordedCpuTimeMicros / stats.recordedCallCount;
+ } else if (totalRecordedCallCount > 0) {
+ totalTimeForUid +=
+ stats.callCount * totalRecordedCallTimeMicros / totalRecordedCallCount;
+ }
+ }
+
+ if (totalCallCountForUid < uid.mBinderCallCount && totalRecordedCallCount > 0) {
+ // Estimate remaining calls, which were not tracked because of binder call
+ // stats sampling
+ totalTimeForUid +=
+ (uid.mBinderCallCount - totalCallCountForUid) * totalRecordedCallTimeMicros
+ / totalRecordedCallCount;
+ }
+
+ uid.mSystemServiceTimeUs = totalTimeForUid;
+ totalSystemServiceTimeMicros += totalTimeForUid;
+ }
+
+ for (int i = 0; i < mUidStats.size(); i++) {
+ Uid uid = mUidStats.valueAt(i);
+ if (totalSystemServiceTimeMicros > 0) {
+ uid.mProportionalSystemServiceUsage =
+ (double) uid.mSystemServiceTimeUs / totalSystemServiceTimeMicros;
+ } else {
+ uid.mProportionalSystemServiceUsage = 0;
+ }
}
}
@@ -6583,7 +6665,7 @@
/**
* Accumulates stats for a specific binder transaction.
*/
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ @VisibleForTesting
protected static class BinderCallStats {
static final Comparator<BinderCallStats> COMPARATOR =
Comparator.comparing(BinderCallStats::getClassName)
@@ -6822,6 +6904,16 @@
*/
private final ArraySet<BinderCallStats> mBinderCallStats = new ArraySet<>();
+ /**
+ * Estimated total time spent by the system server handling requests from this uid.
+ */
+ private long mSystemServiceTimeUs;
+
+ /**
+ * Estimated proportion of system server binder call CPU cost for this uid.
+ */
+ private double mProportionalSystemServiceUsage;
+
public Uid(BatteryStatsImpl bsi, int uid) {
mBsi = bsi;
mUid = uid;
@@ -6899,7 +6991,6 @@
return nullIfAllZeros(mCpuClusterTimesMs, STATS_SINCE_CHARGED);
}
-
@Override
public long[] getCpuFreqTimes(int which, int procState) {
if (which < 0 || which >= NUM_PROCESS_STATE) {
@@ -6934,10 +7025,16 @@
return mBinderCallCount;
}
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
public ArraySet<BinderCallStats> getBinderCallStats() {
return mBinderCallStats;
}
+ @Override
+ public double getProportionalSystemServiceUsage() {
+ return mProportionalSystemServiceUsage;
+ }
+
public void addIsolatedUid(int isolatedUid) {
if (mChildUids == null) {
mChildUids = new IntArray();
@@ -8029,9 +8126,12 @@
mBinderCallCount = 0;
mBinderCallStats.clear();
+ mProportionalSystemServiceUsage = 0;
+
mLastStepUserTime = mLastStepSystemTime = 0;
mCurStepUserTime = mCurStepSystemTime = 0;
+
return !active;
}
@@ -8373,28 +8473,7 @@
mUserCpuTime.writeToParcel(out);
mSystemCpuTime.writeToParcel(out);
- if (mCpuClusterSpeedTimesUs != null) {
- out.writeInt(1);
- out.writeInt(mCpuClusterSpeedTimesUs.length);
- for (LongSamplingCounter[] cpuSpeeds : mCpuClusterSpeedTimesUs) {
- if (cpuSpeeds != null) {
- out.writeInt(1);
- out.writeInt(cpuSpeeds.length);
- for (LongSamplingCounter c : cpuSpeeds) {
- if (c != null) {
- out.writeInt(1);
- c.writeToParcel(out);
- } else {
- out.writeInt(0);
- }
- }
- } else {
- out.writeInt(0);
- }
- }
- } else {
- out.writeInt(0);
- }
+ mBsi.writeCpuSpeedCountersToParcel(out, mCpuClusterSpeedTimesUs);
LongSamplingCounterArray.writeToParcel(out, mCpuFreqTimeMs);
LongSamplingCounterArray.writeToParcel(out, mScreenOffCpuFreqTimeMs);
@@ -8432,6 +8511,7 @@
} else {
out.writeInt(0);
}
+ out.writeDouble(mProportionalSystemServiceUsage);
}
void readJobCompletionsFromParcelLocked(Parcel in) {
@@ -8692,36 +8772,7 @@
mUserCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
mSystemCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
- if (in.readInt() != 0) {
- int numCpuClusters = in.readInt();
- if (mBsi.mPowerProfile != null && mBsi.mPowerProfile.getNumCpuClusters() != numCpuClusters) {
- throw new ParcelFormatException("Incompatible number of cpu clusters");
- }
-
- mCpuClusterSpeedTimesUs = new LongSamplingCounter[numCpuClusters][];
- for (int cluster = 0; cluster < numCpuClusters; cluster++) {
- if (in.readInt() != 0) {
- int numSpeeds = in.readInt();
- if (mBsi.mPowerProfile != null &&
- mBsi.mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != numSpeeds) {
- throw new ParcelFormatException("Incompatible number of cpu speeds");
- }
-
- final LongSamplingCounter[] cpuSpeeds = new LongSamplingCounter[numSpeeds];
- mCpuClusterSpeedTimesUs[cluster] = cpuSpeeds;
- for (int speed = 0; speed < numSpeeds; speed++) {
- if (in.readInt() != 0) {
- cpuSpeeds[speed] = new LongSamplingCounter(
- mBsi.mOnBatteryTimeBase, in);
- }
- }
- } else {
- mCpuClusterSpeedTimesUs[cluster] = null;
- }
- }
- } else {
- mCpuClusterSpeedTimesUs = null;
- }
+ mCpuClusterSpeedTimesUs = mBsi.readCpuSpeedCountersFromParcel(in);
mCpuFreqTimeMs = LongSamplingCounterArray.readFromParcel(in, mBsi.mOnBatteryTimeBase);
mScreenOffCpuFreqTimeMs = LongSamplingCounterArray.readFromParcel(
@@ -8762,6 +8813,8 @@
} else {
mWifiRadioApWakeupCount = null;
}
+
+ mProportionalSystemServiceUsage = in.readDouble();
}
public void noteJobsDeferredLocked(int numDeferred, long sinceLast) {
@@ -9904,7 +9957,6 @@
UserInfoProvider userInfoProvider) {
init(clocks);
-
if (systemDir == null) {
mStatsFile = null;
mBatteryStatsHistory = new BatteryStatsHistory(this, mHistoryBuffer);
@@ -10046,6 +10098,8 @@
firstCpuOfCluster += mPowerProfile.getNumCoresInCpuCluster(i);
}
+ mSystemServerCpuThreadReader = SystemServerCpuThreadReader.create();
+
if (mEstimatedBatteryCapacity == -1) {
// Initialize the estimated battery capacity to a known preset one.
mEstimatedBatteryCapacity = (int) mPowerProfile.getBatteryCapacity();
@@ -10726,6 +10780,9 @@
mTmpRailStats.reset();
+ resetIfNotNull(mSystemServerThreadCpuTimesUs, false);
+ resetIfNotNull(mBinderThreadCpuTimesUs, false);
+
mLastHistoryStepDetails = null;
mLastStepCpuUserTime = mLastStepCpuSystemTime = 0;
mCurStepCpuUserTime = mCurStepCpuSystemTime = 0;
@@ -10853,7 +10910,7 @@
return null;
}
- /**
+ /**
* Distribute WiFi energy info and network traffic to apps.
* @param info The energy information from the WiFi controller.
*/
@@ -11772,6 +11829,7 @@
for (int cluster = mKernelCpuSpeedReaders.length - 1; cluster >= 0; --cluster) {
mKernelCpuSpeedReaders[cluster].readDelta();
}
+ mSystemServerCpuThreadReader.readDelta();
return;
}
@@ -11791,6 +11849,87 @@
readKernelUidCpuClusterTimesLocked(onBattery);
mNumAllUidCpuTimeReads += 2;
}
+
+ updateSystemServerThreadStats();
+ }
+
+ /**
+ * Estimates the proportion of the System Server CPU activity (per cluster per speed)
+ * spent on handling incoming binder calls.
+ */
+ @VisibleForTesting
+ public void updateSystemServerThreadStats() {
+ // There are some simplifying assumptions made in this algorithm
+ // 1) We assume that if a thread handles incoming binder calls, all of its activity
+ // is spent doing that. Most incoming calls are handled by threads allocated
+ // by the native layer in the binder thread pool, so this assumption is reasonable.
+ // 2) We use the aggregate CPU time spent in different threads as a proxy for the CPU
+ // cost. In reality, in multi-core CPUs, the CPU cost may not be linearly
+ // affected by additional threads.
+
+ SystemServerCpuThreadReader.SystemServiceCpuThreadTimes systemServiceCpuThreadTimes =
+ mSystemServerCpuThreadReader.readDelta();
+
+ int index = 0;
+ int numCpuClusters = mPowerProfile.getNumCpuClusters();
+ if (mSystemServerThreadCpuTimesUs == null) {
+ mSystemServerThreadCpuTimesUs = new LongSamplingCounter[numCpuClusters][];
+ mBinderThreadCpuTimesUs = new LongSamplingCounter[numCpuClusters][];
+ }
+ for (int cluster = 0; cluster < numCpuClusters; cluster++) {
+ int numSpeeds = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster);
+ if (mSystemServerThreadCpuTimesUs[cluster] == null) {
+ mSystemServerThreadCpuTimesUs[cluster] = new LongSamplingCounter[numSpeeds];
+ mBinderThreadCpuTimesUs[cluster] = new LongSamplingCounter[numSpeeds];
+ for (int speed = 0; speed < numSpeeds; speed++) {
+ mSystemServerThreadCpuTimesUs[cluster][speed] =
+ new LongSamplingCounter(mOnBatteryTimeBase);
+ mBinderThreadCpuTimesUs[cluster][speed] =
+ new LongSamplingCounter(mOnBatteryTimeBase);
+ }
+ }
+ for (int speed = 0; speed < numSpeeds; speed++) {
+ mSystemServerThreadCpuTimesUs[cluster][speed].addCountLocked(
+ systemServiceCpuThreadTimes.threadCpuTimesUs[index]);
+ mBinderThreadCpuTimesUs[cluster][speed].addCountLocked(
+ systemServiceCpuThreadTimes.binderThreadCpuTimesUs[index]);
+ index++;
+ }
+ }
+ if (DEBUG_BINDER_STATS) {
+ Slog.d(TAG, "System server threads per CPU cluster (binder threads/total threads/%)");
+ long binderThreadTime = 0;
+ long totalThreadTime = 0;
+ int cpuIndex = 0;
+ for (int cluster = 0; cluster < numCpuClusters; cluster++) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("cpu").append(cpuIndex).append(": [");
+ int numSpeeds = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster);
+ for (int speed = 0; speed < numSpeeds; speed++) {
+ if (speed != 0) {
+ sb.append(", ");
+ }
+ long totalCount = mSystemServerThreadCpuTimesUs[cluster][speed].getCountLocked(
+ 0) / 1000;
+ long binderCount = mBinderThreadCpuTimesUs[cluster][speed].getCountLocked(0)
+ / 1000;
+ sb.append(String.format("%d/%d(%.1f%%)",
+ binderCount,
+ totalCount,
+ totalCount != 0 ? (double) binderCount * 100 / totalCount : 0));
+
+ totalThreadTime += totalCount;
+ binderThreadTime += binderCount;
+ index++;
+ }
+ cpuIndex += mPowerProfile.getNumCoresInCpuCluster(cluster);
+ Slog.d(TAG, sb.toString());
+ }
+ Slog.d(TAG, "Total system server thread time (ms): " + totalThreadTime);
+ Slog.d(TAG, String.format("Total Binder thread time (ms): %d (%.1f%%)",
+ binderThreadTime,
+ binderThreadTime != 0 ? (double) binderThreadTime * 100 / totalThreadTime : 0));
+ }
}
/**
@@ -12998,6 +13137,75 @@
}
}
+
+ @Override
+ public long getSystemServiceTimeAtCpuSpeed(int cluster, int step) {
+ // Estimates the time spent by the system server handling incoming binder requests.
+ //
+ // The data that we can get from the kernel is this:
+ // - CPU duration for a (thread - cluster - CPU speed) combination
+ // - CPU duration for a (UID - cluster - CPU speed) combination
+ //
+ // The configuration we have in the Power Profile is this:
+ // - Average CPU power for a (cluster - CPU speed) combination.
+ //
+ // The model used by BatteryStats can be illustrated with this example:
+ //
+ // - Let's say the system server has 10 threads.
+ // - These 10 threads spent 1000 ms of CPU time in aggregate
+ // - Of the 10 threads 4 were execute exclusively incoming binder calls.
+ // - These 4 "binder" threads consumed 600 ms of CPU time in aggregate
+ // - The real time spent by the system server UID doing all of this is, say, 200 ms.
+ //
+ // We will assume that power consumption is proportional to the time spent by the CPU
+ // across all threads. This is a crude assumption, but we don't have more detailed data.
+ // Thus,
+ // binderRealTime = realTime * aggregateBinderThreadTime / aggregateAllThreadTime
+ //
+ // In our example,
+ // binderRealTime = 200 * 600 / 1000 = 120ms
+ //
+ // We can then multiply this estimated time by the average power to obtain an estimate
+ // of the total power consumed by incoming binder calls for the given cluster/speed
+ // combination.
+
+ if (mSystemServerThreadCpuTimesUs == null) {
+ return 0;
+ }
+
+ if (cluster < 0 || cluster >= mSystemServerThreadCpuTimesUs.length) {
+ return 0;
+ }
+
+ final LongSamplingCounter[] threadTimesForCluster = mSystemServerThreadCpuTimesUs[cluster];
+
+ if (step < 0 || step >= threadTimesForCluster.length) {
+ return 0;
+ }
+
+ Uid systemUid = mUidStats.get(Process.SYSTEM_UID);
+ if (systemUid == null) {
+ return 0;
+ }
+
+ final long uidTimeAtCpuSpeed = systemUid.getTimeAtCpuSpeed(cluster, step,
+ BatteryStats.STATS_SINCE_CHARGED);
+ if (uidTimeAtCpuSpeed == 0) {
+ return 0;
+ }
+
+ final long uidThreadTime =
+ threadTimesForCluster[step].getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
+
+ if (uidThreadTime == 0) {
+ return 0;
+ }
+
+ final long binderThreadTime = mBinderThreadCpuTimesUs[cluster][step].getCountLocked(
+ BatteryStats.STATS_SINCE_CHARGED);
+ return uidTimeAtCpuSpeed * binderThreadTime / uidThreadTime;
+ }
+
/**
* Retrieve the statistics object for a particular uid, creating if needed.
*/
@@ -13327,45 +13535,7 @@
pw.print(uid.getUserCpuTimeUs(STATS_SINCE_CHARGED) / 1000); pw.print(" ");
pw.println(uid.getSystemCpuTimeUs(STATS_SINCE_CHARGED) / 1000);
}
- pw.println("Per UID system service calls:");
- BinderTransactionNameResolver nameResolver = new BinderTransactionNameResolver();
- for (int i = 0; i < size; i++) {
- int u = mUidStats.keyAt(i);
- Uid uid = mUidStats.get(u);
- long binderCallCount = uid.getBinderCallCount();
- if (binderCallCount != 0) {
- pw.print(" ");
- pw.print(u);
- pw.print(" system service calls: ");
- pw.print(binderCallCount);
- ArraySet<BinderCallStats> binderCallStats = uid.getBinderCallStats();
- if (!binderCallStats.isEmpty()) {
- pw.println(", including");
- BinderCallStats[] bcss = new BinderCallStats[binderCallStats.size()];
- binderCallStats.toArray(bcss);
- for (BinderCallStats bcs : bcss) {
- bcs.ensureMethodName(nameResolver);
- }
- Arrays.sort(bcss, BinderCallStats.COMPARATOR);
- for (BinderCallStats callStats : bcss) {
- pw.print(" ");
- pw.print(callStats.getClassName());
- pw.print('#');
- pw.print(callStats.getMethodName());
- pw.print(" calls: ");
- pw.print(callStats.callCount);
- if (callStats.recordedCallCount != 0) {
- pw.print(" time: ");
- pw.print(callStats.callCount * callStats.recordedCpuTimeMicros
- / callStats.recordedCallCount / 1000);
- }
- pw.println();
- }
- } else {
- pw.println();
- }
- }
- }
+
pw.println("Per UID CPU active time in ms:");
for (int i = 0; i < size; i++) {
int u = mUidStats.keyAt(i);
@@ -13390,6 +13560,30 @@
pw.print(" "); pw.print(u); pw.print(": "); pw.println(Arrays.toString(times));
}
}
+
+ updateSystemServiceCallStats();
+ if (mSystemServerThreadCpuTimesUs != null) {
+ pw.println("Per UID System server binder time in ms:");
+ for (int i = 0; i < size; i++) {
+ int u = mUidStats.keyAt(i);
+ Uid uid = mUidStats.get(u);
+ double proportionalSystemServiceUsage = uid.getProportionalSystemServiceUsage();
+
+ long time = 0;
+ for (int cluster = 0; cluster < mSystemServerThreadCpuTimesUs.length; cluster++) {
+ int numSpeeds = mSystemServerThreadCpuTimesUs[cluster].length;
+ for (int speed = 0; speed < numSpeeds; speed++) {
+ time += getSystemServiceTimeAtCpuSpeed(cluster, speed)
+ * proportionalSystemServiceUsage;
+ }
+ }
+
+ pw.print(" ");
+ pw.print(u);
+ pw.print(": ");
+ pw.println(time);
+ }
+ }
}
final ReentrantLock mWriteLock = new ReentrantLock();
@@ -14908,6 +15102,9 @@
u.readFromParcelLocked(mOnBatteryTimeBase, mOnBatteryScreenOffTimeBase, in);
mUidStats.append(uid, u);
}
+
+ mSystemServerThreadCpuTimesUs = readCpuSpeedCountersFromParcel(in);
+ mBinderThreadCpuTimesUs = readCpuSpeedCountersFromParcel(in);
}
public void writeToParcel(Parcel out, int flags) {
@@ -14923,6 +15120,8 @@
// Need to update with current kernel wake lock counts.
pullPendingStateUpdatesLocked();
+ updateSystemServiceCallStats();
+
// Pull the clock time. This may update the time and make a new history entry
// if we had originally pulled a time before the RTC was set.
getStartClockTime();
@@ -15105,6 +15304,73 @@
} else {
out.writeInt(0);
}
+ writeCpuSpeedCountersToParcel(out, mSystemServerThreadCpuTimesUs);
+ writeCpuSpeedCountersToParcel(out, mBinderThreadCpuTimesUs);
+ }
+
+ private void writeCpuSpeedCountersToParcel(Parcel out, LongSamplingCounter[][] counters) {
+ if (counters == null) {
+ out.writeInt(0);
+ return;
+ }
+
+ out.writeInt(1);
+ out.writeInt(counters.length);
+ for (int i = 0; i < counters.length; i++) {
+ LongSamplingCounter[] counterArray = counters[i];
+ if (counterArray == null) {
+ out.writeInt(0);
+ continue;
+ }
+
+ out.writeInt(1);
+ out.writeInt(counterArray.length);
+ for (int j = 0; j < counterArray.length; j++) {
+ LongSamplingCounter c = counterArray[j];
+ if (c != null) {
+ out.writeInt(1);
+ c.writeToParcel(out);
+ } else {
+ out.writeInt(0);
+ }
+ }
+ }
+ }
+
+ private LongSamplingCounter[][] readCpuSpeedCountersFromParcel(Parcel in) {
+ LongSamplingCounter[][] counters;
+ if (in.readInt() != 0) {
+ int numCpuClusters = in.readInt();
+ if (mPowerProfile != null
+ && mPowerProfile.getNumCpuClusters() != numCpuClusters) {
+ throw new ParcelFormatException("Incompatible number of cpu clusters");
+ }
+
+ counters = new LongSamplingCounter[numCpuClusters][];
+ for (int cluster = 0; cluster < numCpuClusters; cluster++) {
+ if (in.readInt() != 0) {
+ int numSpeeds = in.readInt();
+ if (mPowerProfile != null
+ && mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != numSpeeds) {
+ throw new ParcelFormatException("Incompatible number of cpu speeds");
+ }
+
+ final LongSamplingCounter[] cpuSpeeds = new LongSamplingCounter[numSpeeds];
+ counters[cluster] = cpuSpeeds;
+ for (int speed = 0; speed < numSpeeds; speed++) {
+ if (in.readInt() != 0) {
+ cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ }
+ }
+ } else {
+ counters[cluster] = null;
+ }
+ }
+ } else {
+ counters = null;
+ }
+
+ return counters;
}
@UnsupportedAppUsage
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index e09ef49..201626a 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -115,7 +115,8 @@
if (uidEntry != null) {
ArrayMap<CallStatKey, CallStat> callStats = uidEntry.mCallStats;
mCallStatsObserver.noteCallStats(uidEntry.workSourceUid,
- uidEntry.incrementalCallCount, callStats.values());
+ uidEntry.incrementalCallCount, callStats.values(),
+ mNativeTids.toArray());
uidEntry.incrementalCallCount = 0;
for (int j = callStats.size() - 1; j >= 0; j--) {
callStats.valueAt(j).incrementalCallCount = 0;
diff --git a/core/java/com/android/internal/os/BinderInternal.java b/core/java/com/android/internal/os/BinderInternal.java
index feb5aab..f14d5f2 100644
--- a/core/java/com/android/internal/os/BinderInternal.java
+++ b/core/java/com/android/internal/os/BinderInternal.java
@@ -142,7 +142,8 @@
* Notes incoming binder call stats associated with this work source UID.
*/
void noteCallStats(int workSourceUid, long incrementalCallCount,
- Collection<BinderCallsStats.CallStat> callStats);
+ Collection<BinderCallsStats.CallStat> callStats,
+ int[] binderThreadNativeTids);
}
/**
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReader.java b/core/java/com/android/internal/os/KernelCpuThreadReader.java
index 3407670..2ba372a 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReader.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReader.java
@@ -225,19 +225,22 @@
/** Set the number of frequency buckets to use */
void setNumBuckets(int numBuckets) {
- if (numBuckets < 1) {
- Slog.w(TAG, "Number of buckets must be at least 1, but was " + numBuckets);
- return;
- }
// If `numBuckets` hasn't changed since the last set, do nothing
if (mFrequenciesKhz != null && mFrequenciesKhz.length == numBuckets) {
return;
}
- mFrequencyBucketCreator =
- new FrequencyBucketCreator(mProcTimeInStateReader.getFrequenciesKhz(), numBuckets);
- mFrequenciesKhz =
- mFrequencyBucketCreator.bucketFrequencies(
- mProcTimeInStateReader.getFrequenciesKhz());
+
+ final long[] frequenciesKhz = mProcTimeInStateReader.getFrequenciesKhz();
+ if (numBuckets != 0) {
+ mFrequencyBucketCreator = new FrequencyBucketCreator(frequenciesKhz, numBuckets);
+ mFrequenciesKhz = mFrequencyBucketCreator.bucketFrequencies(frequenciesKhz);
+ } else {
+ mFrequencyBucketCreator = null;
+ mFrequenciesKhz = new int[frequenciesKhz.length];
+ for (int i = 0; i < frequenciesKhz.length; i++) {
+ mFrequenciesKhz[i] = (int) frequenciesKhz[i];
+ }
+ }
}
/** Set the UID predicate for {@link #getProcessCpuUsage} */
@@ -320,8 +323,15 @@
if (cpuUsagesLong == null) {
return null;
}
- int[] cpuUsages = mFrequencyBucketCreator.bucketValues(cpuUsagesLong);
-
+ final int[] cpuUsages;
+ if (mFrequencyBucketCreator != null) {
+ cpuUsages = mFrequencyBucketCreator.bucketValues(cpuUsagesLong);
+ } else {
+ cpuUsages = new int[cpuUsagesLong.length];
+ for (int i = 0; i < cpuUsagesLong.length; i++) {
+ cpuUsages[i] = (int) cpuUsagesLong[i];
+ }
+ }
return new ThreadCpuUsage(threadId, threadName, cpuUsages);
}
diff --git a/core/java/com/android/internal/os/SystemServerCpuThreadReader.java b/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
new file mode 100644
index 0000000..1cdd42c
--- /dev/null
+++ b/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.os.Process;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Reads /proc/UID/task/TID/time_in_state files to obtain statistics on CPU usage
+ * by various threads of the System Server.
+ */
+public class SystemServerCpuThreadReader {
+ private KernelCpuThreadReader mKernelCpuThreadReader;
+ private int[] mBinderThreadNativeTids;
+
+ private int[] mThreadCpuTimesUs;
+ private int[] mBinderThreadCpuTimesUs;
+ private long[] mLastThreadCpuTimesUs;
+ private long[] mLastBinderThreadCpuTimesUs;
+
+ /**
+ * Times (in microseconds) spent by the system server UID.
+ */
+ public static class SystemServiceCpuThreadTimes {
+ // All threads
+ public long[] threadCpuTimesUs;
+ // Just the threads handling incoming binder calls
+ public long[] binderThreadCpuTimesUs;
+ }
+
+ private SystemServiceCpuThreadTimes mDeltaCpuThreadTimes = new SystemServiceCpuThreadTimes();
+
+ /**
+ * Creates a configured instance of SystemServerCpuThreadReader.
+ */
+ public static SystemServerCpuThreadReader create() {
+ return new SystemServerCpuThreadReader(
+ KernelCpuThreadReader.create(0, uid -> uid == Process.myUid()));
+ }
+
+ @VisibleForTesting
+ public SystemServerCpuThreadReader(Path procPath, int systemServerUid) throws IOException {
+ this(new KernelCpuThreadReader(0, uid -> uid == systemServerUid, null, null,
+ new KernelCpuThreadReader.Injector() {
+ @Override
+ public int getUidForPid(int pid) {
+ return systemServerUid;
+ }
+ }));
+ }
+
+ @VisibleForTesting
+ public SystemServerCpuThreadReader(KernelCpuThreadReader kernelCpuThreadReader) {
+ mKernelCpuThreadReader = kernelCpuThreadReader;
+ }
+
+ public void setBinderThreadNativeTids(int[] nativeTids) {
+ mBinderThreadNativeTids = nativeTids;
+ }
+
+ /**
+ * Returns delta of CPU times, per thread, since the previous call to this method.
+ */
+ public SystemServiceCpuThreadTimes readDelta() {
+ if (mBinderThreadCpuTimesUs == null) {
+ int numCpuFrequencies = mKernelCpuThreadReader.getCpuFrequenciesKhz().length;
+ mThreadCpuTimesUs = new int[numCpuFrequencies];
+ mBinderThreadCpuTimesUs = new int[numCpuFrequencies];
+
+ mLastThreadCpuTimesUs = new long[numCpuFrequencies];
+ mLastBinderThreadCpuTimesUs = new long[numCpuFrequencies];
+
+ mDeltaCpuThreadTimes.threadCpuTimesUs = new long[numCpuFrequencies];
+ mDeltaCpuThreadTimes.binderThreadCpuTimesUs = new long[numCpuFrequencies];
+ }
+
+ Arrays.fill(mThreadCpuTimesUs, 0);
+ Arrays.fill(mBinderThreadCpuTimesUs, 0);
+
+ ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsage =
+ mKernelCpuThreadReader.getProcessCpuUsage();
+ int processCpuUsageSize = processCpuUsage.size();
+ for (int i = 0; i < processCpuUsageSize; i++) {
+ KernelCpuThreadReader.ProcessCpuUsage pcu = processCpuUsage.get(i);
+ ArrayList<KernelCpuThreadReader.ThreadCpuUsage> threadCpuUsages = pcu.threadCpuUsages;
+ if (threadCpuUsages != null) {
+ int threadCpuUsagesSize = threadCpuUsages.size();
+ for (int j = 0; j < threadCpuUsagesSize; j++) {
+ KernelCpuThreadReader.ThreadCpuUsage tcu = threadCpuUsages.get(j);
+ boolean isBinderThread = isBinderThread(tcu.threadId);
+
+ final int len = Math.min(tcu.usageTimesMillis.length, mThreadCpuTimesUs.length);
+ for (int k = 0; k < len; k++) {
+ int usageTimeUs = tcu.usageTimesMillis[k] * 1000;
+ mThreadCpuTimesUs[k] += usageTimeUs;
+ if (isBinderThread) {
+ mBinderThreadCpuTimesUs[k] += usageTimeUs;
+ }
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < mThreadCpuTimesUs.length; i++) {
+ if (mThreadCpuTimesUs[i] < mLastThreadCpuTimesUs[i]) {
+ mDeltaCpuThreadTimes.threadCpuTimesUs[i] = mThreadCpuTimesUs[i];
+ mDeltaCpuThreadTimes.binderThreadCpuTimesUs[i] = mBinderThreadCpuTimesUs[i];
+ } else {
+ mDeltaCpuThreadTimes.threadCpuTimesUs[i] =
+ mThreadCpuTimesUs[i] - mLastThreadCpuTimesUs[i];
+ mDeltaCpuThreadTimes.binderThreadCpuTimesUs[i] =
+ mBinderThreadCpuTimesUs[i] - mLastBinderThreadCpuTimesUs[i];
+ }
+ mLastThreadCpuTimesUs[i] = mThreadCpuTimesUs[i];
+ mLastBinderThreadCpuTimesUs[i] = mBinderThreadCpuTimesUs[i];
+ }
+
+ return mDeltaCpuThreadTimes;
+ }
+
+ private boolean isBinderThread(int threadId) {
+ if (mBinderThreadNativeTids != null) {
+ for (int i = 0; i < mBinderThreadNativeTids.length; i++) {
+ if (threadId == mBinderThreadNativeTids[i]) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/core/java/com/android/internal/os/SystemServicePowerCalculator.java b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
new file mode 100644
index 0000000..481b901
--- /dev/null
+++ b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.os.BatteryStats;
+import android.util.Log;
+
+import java.util.Arrays;
+
+/**
+ * Estimates the amount of power consumed by the System Server handling requests from
+ * a given app.
+ */
+public class SystemServicePowerCalculator extends PowerCalculator {
+ private static final boolean DEBUG = false;
+ private static final String TAG = "SystemServicePowerCalc";
+
+ private static final long MICROSEC_IN_HR = (long) 60 * 60 * 1000 * 1000;
+
+ private final PowerProfile mPowerProfile;
+ private final BatteryStats mBatteryStats;
+ // Tracks system server CPU [cluster][speed] power in milliAmp-microseconds
+ private double[][] mSystemServicePowerMaUs;
+
+ public SystemServicePowerCalculator(PowerProfile powerProfile, BatteryStats batteryStats) {
+ mPowerProfile = powerProfile;
+ mBatteryStats = batteryStats;
+ }
+
+ @Override
+ public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
+ long rawUptimeUs, int statsType) {
+ final double proportionalUsage = u.getProportionalSystemServiceUsage();
+ if (proportionalUsage > 0) {
+ if (mSystemServicePowerMaUs == null) {
+ updateSystemServicePower();
+ }
+
+ double cpuPowerMaUs = 0;
+ int numCpuClusters = mPowerProfile.getNumCpuClusters();
+ for (int cluster = 0; cluster < numCpuClusters; cluster++) {
+ final int numSpeeds = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster);
+ for (int speed = 0; speed < numSpeeds; speed++) {
+ cpuPowerMaUs += mSystemServicePowerMaUs[cluster][speed] * proportionalUsage;
+ }
+ }
+
+ app.systemServiceCpuPowerMah = cpuPowerMaUs / MICROSEC_IN_HR;
+ }
+ }
+
+ private void updateSystemServicePower() {
+ final int numCpuClusters = mPowerProfile.getNumCpuClusters();
+ mSystemServicePowerMaUs = new double[numCpuClusters][];
+ for (int cluster = 0; cluster < numCpuClusters; cluster++) {
+ final int numSpeeds = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster);
+ mSystemServicePowerMaUs[cluster] = new double[numSpeeds];
+ for (int speed = 0; speed < numSpeeds; speed++) {
+ mSystemServicePowerMaUs[cluster][speed] =
+ mBatteryStats.getSystemServiceTimeAtCpuSpeed(cluster, speed)
+ * mPowerProfile.getAveragePowerForCpuCore(cluster, speed);
+ }
+ }
+ if (DEBUG) {
+ Log.d(TAG, "System service power per CPU cluster and frequency");
+ for (int cluster = 0; cluster < numCpuClusters; cluster++) {
+ Log.d(TAG, "Cluster[" + cluster + "]: "
+ + Arrays.toString(mSystemServicePowerMaUs[cluster]));
+ }
+ }
+ }
+
+ @Override
+ public void reset() {
+ mSystemServicePowerMaUs = null;
+ }
+}
diff --git a/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java b/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java
index ba60fa5..b42ea7d 100644
--- a/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java
+++ b/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java
@@ -16,14 +16,8 @@
package com.android.internal.os.logging;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.util.Pair;
import android.view.WindowManager.LayoutParams;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.FrameworkStatsLog;
/**
@@ -32,81 +26,6 @@
*/
public class MetricsLoggerWrapper {
- private static final int METRIC_VALUE_DISMISSED_BY_TAP = 0;
- private static final int METRIC_VALUE_DISMISSED_BY_DRAG = 1;
-
- public static void logPictureInPictureDismissByTap(Context context,
- Pair<ComponentName, Integer> topActivityInfo) {
- MetricsLogger.action(context, MetricsEvent.ACTION_PICTURE_IN_PICTURE_DISMISSED,
- METRIC_VALUE_DISMISSED_BY_TAP);
- FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED,
- getUid(context, topActivityInfo.first, topActivityInfo.second),
- topActivityInfo.first.flattenToString(),
- FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__DISMISSED);
- }
-
- public static void logPictureInPictureDismissByDrag(Context context,
- Pair<ComponentName, Integer> topActivityInfo) {
- MetricsLogger.action(context,
- MetricsEvent.ACTION_PICTURE_IN_PICTURE_DISMISSED,
- METRIC_VALUE_DISMISSED_BY_DRAG);
- FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED,
- getUid(context, topActivityInfo.first, topActivityInfo.second),
- topActivityInfo.first.flattenToString(),
- FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__DISMISSED);
- }
-
- public static void logPictureInPictureMinimize(Context context, boolean isMinimized,
- Pair<ComponentName, Integer> topActivityInfo) {
- MetricsLogger.action(context, MetricsEvent.ACTION_PICTURE_IN_PICTURE_MINIMIZED,
- isMinimized);
- FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED,
- getUid(context, topActivityInfo.first, topActivityInfo.second),
- topActivityInfo.first.flattenToString(),
- FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__MINIMIZED);
- }
-
- /**
- * Get uid from component name and user Id
- * @return uid. -1 if not found.
- */
- private static int getUid(Context context, ComponentName componentName, int userId) {
- int uid = -1;
- if (componentName == null) {
- return uid;
- }
- try {
- uid = context.getPackageManager().getApplicationInfoAsUser(
- componentName.getPackageName(), 0, userId).uid;
- } catch (NameNotFoundException e) {
- }
- return uid;
- }
-
- public static void logPictureInPictureMenuVisible(Context context, boolean menuStateFull) {
- MetricsLogger.visibility(context, MetricsEvent.ACTION_PICTURE_IN_PICTURE_MENU,
- menuStateFull);
- }
-
- public static void logPictureInPictureEnter(Context context,
- int uid, String shortComponentName, boolean supportsEnterPipOnTaskSwitch) {
- MetricsLogger.action(context, MetricsEvent.ACTION_PICTURE_IN_PICTURE_ENTERED,
- supportsEnterPipOnTaskSwitch);
- FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED, uid,
- shortComponentName,
- FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__ENTERED);
- }
-
- public static void logPictureInPictureFullScreen(Context context, int uid,
- String shortComponentName) {
- MetricsLogger.action(context,
- MetricsEvent.ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN);
- FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED,
- uid,
- shortComponentName,
- FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__EXPANDED_TO_FULL_SCREEN);
- }
-
public static void logAppOverlayEnter(int uid, String packageName, boolean changed, int type, boolean usingAlertWindow) {
if (changed) {
if (type != LayoutParams.TYPE_APPLICATION_OVERLAY) {
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 5a04992..ea09fc8 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -65,9 +65,7 @@
void notifyDataActivity(int state);
void notifyDataActivityForSubscriber(in int subId, int state);
void notifyDataConnectionForSubscriber(
- int phoneId, int subId, int apnType, in PreciseDataConnectionState preciseState);
- @UnsupportedAppUsage
- void notifyDataConnectionFailed(String apnType);
+ int phoneId, int subId, in PreciseDataConnectionState preciseState);
// Uses CellIdentity which is Parcelable here; will convert to CellLocation in client.
void notifyCellLocation(in CellIdentity cellLocation);
void notifyCellLocationForSubscriber(in int subId, in CellIdentity cellLocation);
@@ -77,8 +75,6 @@
int foregroundCallState, int backgroundCallState);
void notifyDisconnectCause(int phoneId, int subId, int disconnectCause,
int preciseDisconnectCause);
- void notifyPreciseDataConnectionFailed(int phoneId, int subId, int apnType, String apn,
- int failCause);
void notifyCellInfoForSubscriber(in int subId, in List<CellInfo> cellInfo);
void notifySrvccStateChanged(in int subId, in int lteState);
void notifySimActivationStateChangedForPhoneId(in int phoneId, in int subId,
diff --git a/core/jni/android_hardware_input_InputApplicationHandle.cpp b/core/jni/android_hardware_input_InputApplicationHandle.cpp
index ff73c74..7756a62 100644
--- a/core/jni/android_hardware_input_InputApplicationHandle.cpp
+++ b/core/jni/android_hardware_input_InputApplicationHandle.cpp
@@ -30,7 +30,7 @@
static struct {
jfieldID ptr;
jfieldID name;
- jfieldID dispatchingTimeoutNanos;
+ jfieldID dispatchingTimeoutMillis;
jfieldID token;
} gInputApplicationHandleClassInfo;
@@ -61,8 +61,8 @@
mInfo.name = getStringField(env, obj, gInputApplicationHandleClassInfo.name, "<null>");
- mInfo.dispatchingTimeoutNanos =
- env->GetLongField(obj, gInputApplicationHandleClassInfo.dispatchingTimeoutNanos);
+ mInfo.dispatchingTimeoutMillis =
+ env->GetLongField(obj, gInputApplicationHandleClassInfo.dispatchingTimeoutMillis);
jobject tokenObj = env->GetObjectField(obj,
gInputApplicationHandleClassInfo.token);
@@ -144,9 +144,8 @@
GET_FIELD_ID(gInputApplicationHandleClassInfo.name, clazz,
"name", "Ljava/lang/String;");
- GET_FIELD_ID(gInputApplicationHandleClassInfo.dispatchingTimeoutNanos,
- clazz,
- "dispatchingTimeoutNanos", "J");
+ GET_FIELD_ID(gInputApplicationHandleClassInfo.dispatchingTimeoutMillis, clazz,
+ "dispatchingTimeoutMillis", "J");
GET_FIELD_ID(gInputApplicationHandleClassInfo.token, clazz,
"token", "Landroid/os/IBinder;");
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index 796c5c4..ecdba3f 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -47,7 +47,7 @@
jfieldID name;
jfieldID layoutParamsFlags;
jfieldID layoutParamsType;
- jfieldID dispatchingTimeoutNanos;
+ jfieldID dispatchingTimeoutMillis;
jfieldID frameLeft;
jfieldID frameTop;
jfieldID frameRight;
@@ -118,8 +118,8 @@
env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsFlags));
mInfo.type = static_cast<InputWindowInfo::Type>(
env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsType));
- mInfo.dispatchingTimeout = decltype(mInfo.dispatchingTimeout)(
- env->GetLongField(obj, gInputWindowHandleClassInfo.dispatchingTimeoutNanos));
+ mInfo.dispatchingTimeout = std::chrono::milliseconds(
+ env->GetLongField(obj, gInputWindowHandleClassInfo.dispatchingTimeoutMillis));
mInfo.frameLeft = env->GetIntField(obj,
gInputWindowHandleClassInfo.frameLeft);
mInfo.frameTop = env->GetIntField(obj,
@@ -293,8 +293,8 @@
GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsType, clazz,
"layoutParamsType", "I");
- GET_FIELD_ID(gInputWindowHandleClassInfo.dispatchingTimeoutNanos, clazz,
- "dispatchingTimeoutNanos", "J");
+ GET_FIELD_ID(gInputWindowHandleClassInfo.dispatchingTimeoutMillis, clazz,
+ "dispatchingTimeoutMillis", "J");
GET_FIELD_ID(gInputWindowHandleClassInfo.frameLeft, clazz,
"frameLeft", "I");
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 7daefd3..e715be2 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -95,8 +95,8 @@
ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
if (receiverObj.get()) {
ALOGV("receiver %p ~ Invoking vsync handler.", this);
- env->CallVoidMethod(receiverObj.get(),
- gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, displayId, count);
+ env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync,
+ timestamp, displayId.value, count);
ALOGV("receiver %p ~ Returned from vsync handler.", this);
}
@@ -110,8 +110,8 @@
ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
if (receiverObj.get()) {
ALOGV("receiver %p ~ Invoking hotplug handler.", this);
- env->CallVoidMethod(receiverObj.get(),
- gDisplayEventReceiverClassInfo.dispatchHotplug, timestamp, displayId, connected);
+ env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchHotplug,
+ timestamp, displayId.value, connected);
ALOGV("receiver %p ~ Returned from hotplug handler.", this);
}
@@ -126,9 +126,8 @@
jniGetReferent(env, mReceiverWeakGlobal));
if (receiverObj.get()) {
ALOGV("receiver %p ~ Invoking config changed handler.", this);
- env->CallVoidMethod(receiverObj.get(),
- gDisplayEventReceiverClassInfo.dispatchConfigChanged,
- timestamp, displayId, configId);
+ env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchConfigChanged,
+ timestamp, displayId.value, configId);
ALOGV("receiver %p ~ Returned from config changed handler.", this);
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index a965ab3..d6a773f 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -104,6 +104,27 @@
jfieldID top;
} gRectClassInfo;
+static struct {
+ jfieldID pixelFormat;
+ jfieldID sourceCrop;
+ jfieldID frameScale;
+ jfieldID captureSecureLayers;
+} gCaptureArgsClassInfo;
+
+static struct {
+ jfieldID displayToken;
+ jfieldID width;
+ jfieldID height;
+ jfieldID useIdentityTransform;
+ jfieldID rotation;
+} gDisplayCaptureArgsClassInfo;
+
+static struct {
+ jfieldID layer;
+ jfieldID excludeLayers;
+ jfieldID childrenOnly;
+} gLayerCaptureArgsClassInfo;
+
// Implements SkMallocPixelRef::ReleaseProc, to delete the screenshot on unref.
void DeleteScreenshot(void* addr, void* context) {
delete ((ScreenshotClient*) context);
@@ -276,55 +297,79 @@
return Rect(left, top, right, bottom);
}
-static jobject nativeScreenshot(JNIEnv* env, jclass clazz,
- jobject displayTokenObj, jobject sourceCropObj, jint width, jint height,
- bool useIdentityTransform, int rotation, bool captureSecureLayers) {
- sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
- if (displayToken == NULL) {
+static void getCaptureArgs(JNIEnv* env, jobject captureArgsObject, CaptureArgs& captureArgs) {
+ captureArgs.pixelFormat = static_cast<ui::PixelFormat>(
+ env->GetIntField(captureArgsObject, gCaptureArgsClassInfo.pixelFormat));
+ captureArgs.sourceCrop =
+ rectFromObj(env,
+ env->GetObjectField(captureArgsObject, gCaptureArgsClassInfo.sourceCrop));
+ captureArgs.frameScale =
+ env->GetFloatField(captureArgsObject, gCaptureArgsClassInfo.frameScale);
+ captureArgs.captureSecureLayers =
+ env->GetBooleanField(captureArgsObject, gCaptureArgsClassInfo.captureSecureLayers);
+}
+
+static DisplayCaptureArgs displayCaptureArgsFromObject(JNIEnv* env,
+ jobject displayCaptureArgsObject) {
+ DisplayCaptureArgs captureArgs;
+ getCaptureArgs(env, displayCaptureArgsObject, captureArgs);
+
+ captureArgs.displayToken =
+ ibinderForJavaObject(env,
+ env->GetObjectField(displayCaptureArgsObject,
+ gDisplayCaptureArgsClassInfo.displayToken));
+ captureArgs.width =
+ env->GetIntField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.width);
+ captureArgs.height =
+ env->GetIntField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.height);
+ captureArgs.useIdentityTransform =
+ env->GetBooleanField(displayCaptureArgsObject,
+ gDisplayCaptureArgsClassInfo.useIdentityTransform);
+ captureArgs.rotation = ui::toRotation(
+ env->GetIntField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.rotation));
+ return captureArgs;
+}
+
+static jobject nativeCaptureDisplay(JNIEnv* env, jclass clazz, jobject displayCaptureArgsObject) {
+ const DisplayCaptureArgs captureArgs =
+ displayCaptureArgsFromObject(env, displayCaptureArgsObject);
+
+ if (captureArgs.displayToken == NULL) {
return NULL;
}
- const ui::ColorMode colorMode = SurfaceComposerClient::getActiveColorMode(displayToken);
- const ui::Dataspace dataspace = pickDataspaceFromColorMode(colorMode);
- Rect sourceCrop = rectFromObj(env, sourceCropObj);
- sp<GraphicBuffer> buffer;
- bool capturedSecureLayers = false;
- status_t res = ScreenshotClient::capture(displayToken, dataspace,
- ui::PixelFormat::RGBA_8888,
- sourceCrop, width, height,
- useIdentityTransform, ui::toRotation(rotation),
- captureSecureLayers, &buffer, capturedSecureLayers);
+ ScreenCaptureResults captureResults;
+ status_t res = ScreenshotClient::captureDisplay(captureArgs, captureResults);
if (res != NO_ERROR) {
return NULL;
}
- jobject jhardwareBuffer =
- android_hardware_HardwareBuffer_createFromAHardwareBuffer(env,
- buffer->toAHardwareBuffer());
- const jint namedColorSpace = fromDataspaceToNamedColorSpaceValue(dataspace);
+ jobject jhardwareBuffer = android_hardware_HardwareBuffer_createFromAHardwareBuffer(
+ env, captureResults.buffer->toAHardwareBuffer());
+ const jint namedColorSpace =
+ fromDataspaceToNamedColorSpaceValue(captureResults.capturedDataspace);
return env->CallStaticObjectMethod(gScreenshotHardwareBufferClassInfo.clazz,
gScreenshotHardwareBufferClassInfo.builder, jhardwareBuffer,
- namedColorSpace, capturedSecureLayers);
+ namedColorSpace, captureResults.capturedSecureLayers);
}
-static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject displayTokenObj,
- jlong layerObject, jobject sourceCropObj, jfloat frameScale,
- jlongArray excludeObjectArray, jint format) {
-
- auto layer = reinterpret_cast<SurfaceControl *>(layerObject);
- if (layer == NULL) {
- return NULL;
+static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerCaptureArgsObject) {
+ LayerCaptureArgs captureArgs;
+ getCaptureArgs(env, layerCaptureArgsObject, captureArgs);
+ SurfaceControl* layer = reinterpret_cast<SurfaceControl*>(
+ env->GetLongField(layerCaptureArgsObject, gLayerCaptureArgsClassInfo.layer));
+ if (layer == nullptr) {
+ return nullptr;
}
- Rect sourceCrop;
- if (sourceCropObj != NULL) {
- sourceCrop = rectFromObj(env, sourceCropObj);
- }
-
- std::unordered_set<sp<IBinder>,ISurfaceComposer::SpHash<IBinder>> excludeHandles;
+ captureArgs.layerHandle = layer->getHandle();
+ captureArgs.childrenOnly =
+ env->GetBooleanField(layerCaptureArgsObject, gLayerCaptureArgsClassInfo.childrenOnly);
+ jlongArray excludeObjectArray = reinterpret_cast<jlongArray>(
+ env->GetObjectField(layerCaptureArgsObject, gLayerCaptureArgsClassInfo.excludeLayers));
if (excludeObjectArray != NULL) {
const jsize len = env->GetArrayLength(excludeObjectArray);
- excludeHandles.reserve(len);
+ captureArgs.excludeHandles.reserve(len);
const jlong* objects = env->GetLongArrayElements(excludeObjectArray, nullptr);
for (jsize i = 0; i < len; i++) {
@@ -333,33 +378,24 @@
jniThrowNullPointerException(env, "Exclude layer is null");
return NULL;
}
- excludeHandles.emplace(excludeObject->getHandle());
+ captureArgs.excludeHandles.emplace(excludeObject->getHandle());
}
env->ReleaseLongArrayElements(excludeObjectArray, const_cast<jlong*>(objects), JNI_ABORT);
}
- sp<GraphicBuffer> buffer;
- ui::Dataspace dataspace = ui::Dataspace::V0_SRGB;
- sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
- if (displayToken != nullptr) {
- const ui::ColorMode colorMode = SurfaceComposerClient::getActiveColorMode(displayToken);
- dataspace = pickDataspaceFromColorMode(colorMode);
- }
- status_t res = ScreenshotClient::captureChildLayers(layer->getHandle(), dataspace,
- static_cast<ui::PixelFormat>(format),
- sourceCrop, excludeHandles, frameScale,
- &buffer);
+ ScreenCaptureResults captureResults;
+ status_t res = ScreenshotClient::captureLayers(captureArgs, captureResults);
if (res != NO_ERROR) {
return NULL;
}
- jobject jhardwareBuffer =
- android_hardware_HardwareBuffer_createFromAHardwareBuffer(env,
- buffer->toAHardwareBuffer());
- const jint namedColorSpace = fromDataspaceToNamedColorSpaceValue(dataspace);
+ jobject jhardwareBuffer = android_hardware_HardwareBuffer_createFromAHardwareBuffer(
+ env, captureResults.buffer->toAHardwareBuffer());
+ const jint namedColorSpace =
+ fromDataspaceToNamedColorSpaceValue(captureResults.capturedDataspace);
return env->CallStaticObjectMethod(gScreenshotHardwareBufferClassInfo.clazz,
gScreenshotHardwareBufferClassInfo.builder, jhardwareBuffer,
- namedColorSpace, false /* capturedSecureLayers */);
+ namedColorSpace, captureResults.capturedSecureLayers);
}
static void nativeApplyTransaction(JNIEnv* env, jclass clazz, jlong transactionObj, jboolean sync) {
@@ -667,7 +703,7 @@
jlong* values = env->GetLongArrayElements(array, 0);
for (size_t i = 0; i < displayIds.size(); ++i) {
- values[i] = static_cast<jlong>(displayIds[i]);
+ values[i] = static_cast<jlong>(displayIds[i].value);
}
env->ReleaseLongArrayElements(array, values, 0);
@@ -675,7 +711,8 @@
}
static jobject nativeGetPhysicalDisplayToken(JNIEnv* env, jclass clazz, jlong physicalDisplayId) {
- sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(physicalDisplayId);
+ sp<IBinder> token =
+ SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId(physicalDisplayId));
return javaObjectForIBinder(env, token);
}
@@ -1614,13 +1651,12 @@
(void*)nativeSeverChildren } ,
{"nativeSetOverrideScalingMode", "(JJI)V",
(void*)nativeSetOverrideScalingMode },
- {"nativeScreenshot",
- "(Landroid/os/IBinder;Landroid/graphics/Rect;IIZIZ)"
+ {"nativeCaptureDisplay",
+ "(Landroid/view/SurfaceControl$DisplayCaptureArgs;)"
"Landroid/view/SurfaceControl$ScreenshotHardwareBuffer;",
- (void*)nativeScreenshot },
+ (void*)nativeCaptureDisplay },
{"nativeCaptureLayers",
- "(Landroid/os/IBinder;JLandroid/graphics/Rect;"
- "F[JI)"
+ "(Landroid/view/SurfaceControl$LayerCaptureArgs;)"
"Landroid/view/SurfaceControl$ScreenshotHardwareBuffer;",
(void*)nativeCaptureLayers },
{"nativeSetInputWindowInfo", "(JJLandroid/view/InputWindowHandle;)V",
@@ -1795,6 +1831,36 @@
gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMax =
GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "appRequestRefreshRateMax", "F");
+ jclass captureArgsClazz = FindClassOrDie(env, "android/view/SurfaceControl$CaptureArgs");
+ gCaptureArgsClassInfo.pixelFormat = GetFieldIDOrDie(env, captureArgsClazz, "mPixelFormat", "I");
+ gCaptureArgsClassInfo.sourceCrop =
+ GetFieldIDOrDie(env, captureArgsClazz, "mSourceCrop", "Landroid/graphics/Rect;");
+ gCaptureArgsClassInfo.frameScale = GetFieldIDOrDie(env, captureArgsClazz, "mFrameScale", "F");
+ gCaptureArgsClassInfo.captureSecureLayers =
+ GetFieldIDOrDie(env, captureArgsClazz, "mCaptureSecureLayers", "Z");
+
+ jclass displayCaptureArgsClazz =
+ FindClassOrDie(env, "android/view/SurfaceControl$DisplayCaptureArgs");
+ gDisplayCaptureArgsClassInfo.displayToken =
+ GetFieldIDOrDie(env, displayCaptureArgsClazz, "mDisplayToken", "Landroid/os/IBinder;");
+ gDisplayCaptureArgsClassInfo.width =
+ GetFieldIDOrDie(env, displayCaptureArgsClazz, "mWidth", "I");
+ gDisplayCaptureArgsClassInfo.height =
+ GetFieldIDOrDie(env, displayCaptureArgsClazz, "mHeight", "I");
+ gDisplayCaptureArgsClassInfo.useIdentityTransform =
+ GetFieldIDOrDie(env, displayCaptureArgsClazz, "mUseIdentityTransform", "Z");
+ gDisplayCaptureArgsClassInfo.rotation =
+ GetFieldIDOrDie(env, displayCaptureArgsClazz, "mRotation", "I");
+
+ jclass layerCaptureArgsClazz =
+ FindClassOrDie(env, "android/view/SurfaceControl$LayerCaptureArgs");
+ gLayerCaptureArgsClassInfo.layer =
+ GetFieldIDOrDie(env, layerCaptureArgsClazz, "mNativeLayer", "J");
+ gLayerCaptureArgsClassInfo.excludeLayers =
+ GetFieldIDOrDie(env, layerCaptureArgsClazz, "mNativeExcludeLayers", "[J");
+ gLayerCaptureArgsClassInfo.childrenOnly =
+ GetFieldIDOrDie(env, layerCaptureArgsClazz, "mChildrenOnly", "Z");
+
return err;
}
diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
index df2946c..c37a34a 100644
--- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
+++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
@@ -201,6 +201,38 @@
}
@Test
+ public void testCursorDrag_diagonal_thresholdConfig() throws Throwable {
+ TextView tv = mActivity.findViewById(R.id.textview);
+ Editor editor = tv.getEditorForTesting();
+
+ StringBuilder sb = new StringBuilder();
+ for (int i = 1; i <= 9; i++) {
+ sb.append("here is some text").append(i).append("\n");
+ }
+ sb.append(Strings.repeat("abcdefghij\n", 400)).append("Last");
+ String text = sb.toString();
+ onView(withId(R.id.textview)).perform(replaceText(text));
+
+ int index = text.indexOf("text9");
+ onView(withId(R.id.textview)).perform(clickOnTextAtIndex(index));
+ onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(index));
+
+ // Configure the drag direction threshold to require the drag to be exactly horizontal. With
+ // this set, a swipe that is slightly off horizontal should not trigger cursor drag.
+ editor.setCursorDragMinAngleFromVertical(90);
+ int startIdx = text.indexOf("5");
+ int endIdx = text.indexOf("here is some text3");
+ onView(withId(R.id.textview)).perform(dragOnText(startIdx, endIdx));
+ onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(index));
+
+ // Configure the drag direction threshold to require the drag to be 45 degrees or more from
+ // vertical. With this set, the same swipe gesture as above should now trigger cursor drag.
+ editor.setCursorDragMinAngleFromVertical(45);
+ onView(withId(R.id.textview)).perform(dragOnText(startIdx, endIdx));
+ onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(endIdx));
+ }
+
+ @Test
public void testCursorDrag_vertical_whenTextViewContentsFitOnScreen() throws Throwable {
String text = "012345_aaa\n"
+ "0123456789\n"
diff --git a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
index 35fd4bd..94f43de 100644
--- a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
+++ b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
@@ -165,7 +165,7 @@
long event2Time = 1001;
MotionEvent event2 = moveEvent(event1Time, event2Time, 200f, 31f);
mTouchState.update(event2, mConfig);
- assertDrag(mTouchState, 20f, 30f, 0, 0, false);
+ assertDrag(mTouchState, 20f, 30f, 0, 0, 180f);
// Simulate an ACTION_UP event with a delay that's longer than the double-tap timeout.
long event3Time = 5000;
@@ -280,7 +280,7 @@
long event3Time = 1002;
MotionEvent event3 = moveEvent(event3Time, event3Time, newX, newY);
mTouchState.update(event3, mConfig);
- assertDrag(mTouchState, 20f, 30f, 0, 0, false);
+ assertDrag(mTouchState, 20f, 30f, 0, 0, Float.MAX_VALUE);
// Simulate an ACTION_UP event.
long event4Time = 1003;
@@ -301,15 +301,15 @@
long event2Time = 1002;
MotionEvent event2 = moveEvent(event1Time, event2Time, 100f, 174f);
mTouchState.update(event2, mConfig);
- assertDrag(mTouchState, 0f, 0f, 0, 0, true);
+ assertDrag(mTouchState, 0f, 0f, 0, 0, 100f / 174f);
// Simulate another ACTION_MOVE event that is horizontal from the original down event.
- // The value of `isDragCloseToVertical` should NOT change since it should only reflect the
- // initial direction of movement.
+ // The drag direction ratio should NOT change since it should only reflect the initial
+ // direction of movement.
long event3Time = 1003;
MotionEvent event3 = moveEvent(event1Time, event3Time, 200f, 0f);
mTouchState.update(event3, mConfig);
- assertDrag(mTouchState, 0f, 0f, 0, 0, true);
+ assertDrag(mTouchState, 0f, 0f, 0, 0, 100f / 174f);
// Simulate an ACTION_UP event.
long event4Time = 1004;
@@ -330,15 +330,15 @@
long event2Time = 1002;
MotionEvent event2 = moveEvent(event1Time, event2Time, 100f, 90f);
mTouchState.update(event2, mConfig);
- assertDrag(mTouchState, 0f, 0f, 0, 0, false);
+ assertDrag(mTouchState, 0f, 0f, 0, 0, 100f / 90f);
// Simulate another ACTION_MOVE event that is vertical from the original down event.
- // The value of `isDragCloseToVertical` should NOT change since it should only reflect the
- // initial direction of movement.
+ // The drag direction ratio should NOT change since it should only reflect the initial
+ // direction of movement.
long event3Time = 1003;
MotionEvent event3 = moveEvent(event1Time, event3Time, 0f, 200f);
mTouchState.update(event3, mConfig);
- assertDrag(mTouchState, 0f, 0f, 0, 0, false);
+ assertDrag(mTouchState, 0f, 0f, 0, 0, 100f / 90f);
// Simulate an ACTION_UP event.
long event4Time = 1004;
@@ -374,7 +374,7 @@
long event2Time = 1002;
MotionEvent event2 = moveEvent(event2Time, event2Time, 200f, 30f);
mTouchState.update(event2, mConfig);
- assertDrag(mTouchState, 20f, 30f, 0, 0, false);
+ assertDrag(mTouchState, 20f, 30f, 0, 0, Float.MAX_VALUE);
// Simulate an ACTION_CANCEL event.
long event3Time = 1003;
@@ -411,6 +411,84 @@
assertSingleTap(mTouchState, 22f, 33f, 20f, 30f);
}
+ @Test
+ public void testGetXYRatio() throws Exception {
+ doTestGetXYRatio(-1, 0.0f);
+ doTestGetXYRatio(0, 0.0f);
+ doTestGetXYRatio(30, 0.58f);
+ doTestGetXYRatio(45, 1.0f);
+ doTestGetXYRatio(60, 1.73f);
+ doTestGetXYRatio(90, Float.MAX_VALUE);
+ doTestGetXYRatio(91, Float.MAX_VALUE);
+ }
+
+ private void doTestGetXYRatio(int angleFromVerticalInDegrees, float expectedXYRatioRounded) {
+ float result = EditorTouchState.getXYRatio(angleFromVerticalInDegrees);
+ String msg = String.format(
+ "%d deg should give an x/y ratio of %f; actual unrounded result is %f",
+ angleFromVerticalInDegrees, expectedXYRatioRounded, result);
+ float roundedResult = (result == 0.0f || result == Float.MAX_VALUE) ? result :
+ Math.round(result * 100) / 100f;
+ assertThat(msg, roundedResult, is(expectedXYRatioRounded));
+ }
+
+ @Test
+ public void testUpdate_dragDirection() throws Exception {
+ // Simulate moving straight up.
+ doTestDragDirection(100f, 100f, 100f, 50f, 0f);
+
+ // Simulate moving straight down.
+ doTestDragDirection(100f, 100f, 100f, 150f, 0f);
+
+ // Simulate moving straight left.
+ doTestDragDirection(100f, 100f, 50f, 100f, Float.MAX_VALUE);
+
+ // Simulate moving straight right.
+ doTestDragDirection(100f, 100f, 150f, 100f, Float.MAX_VALUE);
+
+ // Simulate moving up and right, < 45 deg from vertical.
+ doTestDragDirection(100f, 100f, 110f, 50f, 10f / 50f);
+
+ // Simulate moving up and right, > 45 deg from vertical.
+ doTestDragDirection(100f, 100f, 150f, 90f, 50f / 10f);
+
+ // Simulate moving down and right, < 45 deg from vertical.
+ doTestDragDirection(100f, 100f, 110f, 150f, 10f / 50f);
+
+ // Simulate moving down and right, > 45 deg from vertical.
+ doTestDragDirection(100f, 100f, 150f, 110f, 50f / 10f);
+
+ // Simulate moving down and left, < 45 deg from vertical.
+ doTestDragDirection(100f, 100f, 90f, 150f, 10f / 50f);
+
+ // Simulate moving down and left, > 45 deg from vertical.
+ doTestDragDirection(100f, 100f, 50f, 110f, 50f / 10f);
+
+ // Simulate moving up and left, < 45 deg from vertical.
+ doTestDragDirection(100f, 100f, 90f, 50f, 10f / 50f);
+
+ // Simulate moving up and left, > 45 deg from vertical.
+ doTestDragDirection(100f, 100f, 50f, 90f, 50f / 10f);
+ }
+
+ private void doTestDragDirection(float downX, float downY, float moveX, float moveY,
+ float expectedInitialDragDirectionXYRatio) {
+ EditorTouchState touchState = new EditorTouchState();
+
+ // Simulate an ACTION_DOWN event.
+ long event1Time = 1001;
+ MotionEvent event1 = downEvent(event1Time, event1Time, downX, downY);
+ touchState.update(event1, mConfig);
+
+ // Simulate an ACTION_MOVE event.
+ long event2Time = 1002;
+ MotionEvent event2 = moveEvent(event1Time, event2Time, moveX, moveY);
+ touchState.update(event2, mConfig);
+ String msg = String.format("(%.0f,%.0f)=>(%.0f,%.0f)", downX, downY, moveX, moveY);
+ assertThat(msg, touchState.getInitialDragDirectionXYRatio(),
+ is(expectedInitialDragDirectionXYRatio));
+ }
+
private static MotionEvent downEvent(long downTime, long eventTime, float x, float y) {
return MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
}
@@ -441,7 +519,7 @@
}
private static void assertDrag(EditorTouchState touchState, float lastDownX,
- float lastDownY, float lastUpX, float lastUpY, boolean isDragCloseToVertical) {
+ float lastDownY, float lastUpX, float lastUpY, float initialDragDirectionXYRatio) {
assertThat(touchState.getLastDownX(), is(lastDownX));
assertThat(touchState.getLastDownY(), is(lastDownY));
assertThat(touchState.getLastUpX(), is(lastUpX));
@@ -451,7 +529,7 @@
assertThat(touchState.isMultiTap(), is(false));
assertThat(touchState.isMultiTapInSameArea(), is(false));
assertThat(touchState.isMovedEnoughForDrag(), is(true));
- assertThat(touchState.isDragCloseToVertical(), is(isDragCloseToVertical));
+ assertThat(touchState.getInitialDragDirectionXYRatio(), is(initialDragDirectionXYRatio));
}
private static void assertMultiTap(EditorTouchState touchState,
@@ -467,6 +545,5 @@
|| multiTapStatus == MultiTapStatus.TRIPLE_CLICK));
assertThat(touchState.isMultiTapInSameArea(), is(isMultiTapInSameArea));
assertThat(touchState.isMovedEnoughForDrag(), is(false));
- assertThat(touchState.isDragCloseToVertical(), is(false));
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java
index 3e67b8b..22c41f3 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java
@@ -38,7 +38,8 @@
@SmallTest
public class BatteryStatsBinderCallStatsTest extends TestCase {
- private static final int TRANSACTION_CODE = 100;
+ private static final int TRANSACTION_CODE1 = 100;
+ private static final int TRANSACTION_CODE2 = 101;
/**
* Test BatteryStatsImpl.Uid.noteBinderCallStats.
@@ -53,23 +54,23 @@
Collection<BinderCallsStats.CallStat> callStats = new ArrayList<>();
BinderCallsStats.CallStat stat1 = new BinderCallsStats.CallStat(callingUid,
- MockBinder.class, TRANSACTION_CODE, true /*screenInteractive */);
+ MockBinder.class, TRANSACTION_CODE1, true /*screenInteractive */);
stat1.incrementalCallCount = 21;
stat1.recordedCallCount = 5;
stat1.cpuTimeMicros = 1000;
callStats.add(stat1);
- bi.noteBinderCallStats(workSourceUid, 42, callStats);
+ bi.noteBinderCallStats(workSourceUid, 42, callStats, null);
callStats.clear();
BinderCallsStats.CallStat stat2 = new BinderCallsStats.CallStat(callingUid,
- MockBinder.class, TRANSACTION_CODE, true /*screenInteractive */);
+ MockBinder.class, TRANSACTION_CODE1, true /*screenInteractive */);
stat2.incrementalCallCount = 9;
stat2.recordedCallCount = 8;
stat2.cpuTimeMicros = 500;
callStats.add(stat2);
- bi.noteBinderCallStats(workSourceUid, 8, callStats);
+ bi.noteBinderCallStats(workSourceUid, 8, callStats, null);
BatteryStatsImpl.Uid uid = bi.getUidStatsLocked(workSourceUid);
assertEquals(42 + 8, uid.getBinderCallCount());
@@ -85,9 +86,62 @@
assertEquals(500, value.recordedCpuTimeMicros);
}
+
+ @Test
+ public void testProportionalSystemServiceUsage_noStatsForSomeMethods() throws Exception {
+ final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+
+ int callingUid = Process.FIRST_APPLICATION_UID + 1;
+ int workSourceUid1 = Process.FIRST_APPLICATION_UID + 1;
+ int workSourceUid2 = Process.FIRST_APPLICATION_UID + 2;
+ int workSourceUid3 = Process.FIRST_APPLICATION_UID + 3;
+
+ Collection<BinderCallsStats.CallStat> callStats = new ArrayList<>();
+ BinderCallsStats.CallStat stat1a = new BinderCallsStats.CallStat(callingUid,
+ MockBinder.class, TRANSACTION_CODE1, true /*screenInteractive */);
+ stat1a.incrementalCallCount = 10;
+ stat1a.recordedCallCount = 5;
+ stat1a.cpuTimeMicros = 1000;
+ callStats.add(stat1a);
+
+ BinderCallsStats.CallStat stat1b = new BinderCallsStats.CallStat(callingUid,
+ MockBinder.class, TRANSACTION_CODE2, true /*screenInteractive */);
+ stat1b.incrementalCallCount = 30;
+ stat1b.recordedCallCount = 15;
+ stat1b.cpuTimeMicros = 1500;
+ callStats.add(stat1b);
+
+ bi.noteBinderCallStats(workSourceUid1, 65, callStats, null);
+
+ // No recorded stats for some methods. Must use the global average.
+ callStats.clear();
+ BinderCallsStats.CallStat stat2 = new BinderCallsStats.CallStat(callingUid,
+ MockBinder.class, TRANSACTION_CODE1, true /*screenInteractive */);
+ stat2.incrementalCallCount = 10;
+ callStats.add(stat2);
+
+ bi.noteBinderCallStats(workSourceUid2, 40, callStats, null);
+
+ // No stats for any calls. Must use the global average
+ callStats.clear();
+ bi.noteBinderCallStats(workSourceUid3, 50, callStats, null);
+
+ bi.updateSystemServiceCallStats();
+
+ double prop1 = bi.getUidStatsLocked(workSourceUid1).getProportionalSystemServiceUsage();
+ double prop2 = bi.getUidStatsLocked(workSourceUid2).getProportionalSystemServiceUsage();
+ double prop3 = bi.getUidStatsLocked(workSourceUid3).getProportionalSystemServiceUsage();
+
+ assertEquals(0.419, prop1, 0.01);
+ assertEquals(0.258, prop2, 0.01);
+ assertEquals(0.323, prop3, 0.01);
+ assertEquals(1.000, prop1 + prop2 + prop3, 0.01);
+ }
+
private static class MockBinder extends Binder {
public static String getDefaultTransactionName(int txCode) {
- return txCode == TRANSACTION_CODE ? "testMethod" : "unknown";
+ return txCode == TRANSACTION_CODE1 ? "testMethod" : "unknown";
}
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
index a5117a3..188ba9e 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
@@ -768,8 +768,8 @@
final ArrayList<BinderCallsStats.CallStat> callStatsList = new ArrayList<>();
bcs.setCallStatsObserver(
- (workSourceUid, incrementalCallCount, callStats) -> callStatsList.addAll(
- callStats));
+ (workSourceUid, incrementalCallCount, callStats, binderThreadIds) ->
+ callStatsList.addAll(callStats));
Binder binder = new Binder();
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index bc0e0a4..75dd7fb 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -133,6 +133,12 @@
return this;
}
+ public MockBatteryStatsImpl setSystemServerCpuThreadReader(
+ SystemServerCpuThreadReader systemServerCpuThreadReader) {
+ mSystemServerCpuThreadReader = systemServerCpuThreadReader;
+ return this;
+ }
+
public MockBatteryStatsImpl setUserInfoProvider(UserInfoProvider provider) {
mUserInfoProvider = provider;
return this;
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java
new file mode 100644
index 0000000..10ba548
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.os.FileUtils;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SystemServerCpuThreadReaderTest {
+ private File mProcDirectory;
+
+ @Before
+ public void setUp() {
+ Context context = InstrumentationRegistry.getContext();
+ mProcDirectory = context.getDir("proc", Context.MODE_PRIVATE);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ FileUtils.deleteContents(mProcDirectory);
+ }
+
+ @Test
+ public void testReaderDelta_firstTime() throws IOException {
+ int uid = 42;
+ setupDirectory(
+ mProcDirectory.toPath().resolve(String.valueOf(uid)),
+ new int[]{42, 1, 2, 3},
+ new int[]{1000, 2000},
+ // Units are 10ms aka 10000Us
+ new int[][]{{100, 200}, {0, 200}, {0, 300}, {0, 400}});
+
+ SystemServerCpuThreadReader reader = new SystemServerCpuThreadReader(
+ mProcDirectory.toPath(), uid);
+ reader.setBinderThreadNativeTids(new int[]{1, 3});
+ SystemServerCpuThreadReader.SystemServiceCpuThreadTimes systemServiceCpuThreadTimes =
+ reader.readDelta();
+ assertArrayEquals(new long[]{100 * 10000, 1100 * 10000},
+ systemServiceCpuThreadTimes.threadCpuTimesUs);
+ assertArrayEquals(new long[]{0, 600 * 10000},
+ systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
+ }
+
+ @Test
+ public void testReaderDelta_nextTime() throws IOException {
+ int uid = 42;
+ setupDirectory(
+ mProcDirectory.toPath().resolve(String.valueOf(uid)),
+ new int[]{42, 1, 2, 3},
+ new int[]{1000, 2000},
+ new int[][]{{100, 200}, {0, 200}, {0, 300}, {0, 400}});
+
+ SystemServerCpuThreadReader reader = new SystemServerCpuThreadReader(
+ mProcDirectory.toPath(), uid);
+ reader.setBinderThreadNativeTids(new int[]{1, 3});
+
+ // First time, populate "last" snapshot
+ reader.readDelta();
+
+ FileUtils.deleteContents(mProcDirectory);
+ setupDirectory(
+ mProcDirectory.toPath().resolve(String.valueOf(uid)),
+ new int[]{42, 1, 2, 3},
+ new int[]{1000, 2000},
+ new int[][]{{500, 600}, {700, 800}, {900, 1000}, {1100, 1200}});
+
+ // Second time, get the actual delta
+ SystemServerCpuThreadReader.SystemServiceCpuThreadTimes systemServiceCpuThreadTimes =
+ reader.readDelta();
+
+ assertArrayEquals(new long[]{3100 * 10000, 2500 * 10000},
+ systemServiceCpuThreadTimes.threadCpuTimesUs);
+ assertArrayEquals(new long[]{1800 * 10000, 1400 * 10000},
+ systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
+ }
+
+ private void setupDirectory(Path processPath, int[] threadIds, int[] cpuFrequencies,
+ int[][] cpuTimes) throws IOException {
+ // Make /proc/$PID
+ assertTrue(processPath.toFile().mkdirs());
+
+ // Make /proc/$PID/task
+ final Path selfThreadsPath = processPath.resolve("task");
+ assertTrue(selfThreadsPath.toFile().mkdirs());
+
+ // Make thread directories in reverse order, as they are read in order of creation by
+ // CpuThreadProcReader
+ for (int i = 0; i < threadIds.length; i++) {
+ // Make /proc/$PID/task/$TID
+ final Path threadPath = selfThreadsPath.resolve(String.valueOf(threadIds[i]));
+ assertTrue(threadPath.toFile().mkdirs());
+
+ // Make /proc/$PID/task/$TID/time_in_state
+ final OutputStream timeInStateStream =
+ Files.newOutputStream(threadPath.resolve("time_in_state"));
+ for (int j = 0; j < cpuFrequencies.length; j++) {
+ final String line = cpuFrequencies[j] + " " + cpuTimes[i][j] + "\n";
+ timeInStateStream.write(line.getBytes());
+ }
+ timeInStateStream.close();
+ }
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
new file mode 100644
index 0000000..ac5443e
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.os.BatteryStats;
+import android.os.Binder;
+import android.os.Process;
+
+import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SystemServicePowerCalculatorTest {
+
+ private PowerProfile mProfile;
+ private MockBatteryStatsImpl mMockBatteryStats;
+ private MockKernelCpuUidFreqTimeReader mMockCpuUidFreqTimeReader;
+ private MockServerCpuThreadReader mMockServerCpuThreadReader;
+ private SystemServicePowerCalculator mSystemServicePowerCalculator;
+
+ @Before
+ public void setUp() throws IOException {
+ Context context = InstrumentationRegistry.getContext();
+ mProfile = new PowerProfile(context, true /* forTest */);
+ mMockServerCpuThreadReader = new MockServerCpuThreadReader();
+ mMockCpuUidFreqTimeReader = new MockKernelCpuUidFreqTimeReader();
+ mMockBatteryStats = new MockBatteryStatsImpl(new MockClocks())
+ .setPowerProfile(mProfile)
+ .setSystemServerCpuThreadReader(mMockServerCpuThreadReader)
+ .setKernelCpuUidFreqTimeReader(mMockCpuUidFreqTimeReader)
+ .setUserInfoProvider(new MockUserInfoProvider());
+ mMockBatteryStats.getOnBatteryTimeBase().setRunning(true, 0, 0);
+ mSystemServicePowerCalculator =
+ new SystemServicePowerCalculator(mProfile, mMockBatteryStats);
+ }
+
+ @Test
+ public void testCalculateApp() {
+ // Test Power Profile has two CPU clusters with 3 and 4 speeds, thus 7 freq times total
+ mMockServerCpuThreadReader.setThreadTimes(
+ new long[]{30000, 40000, 50000, 60000, 70000, 80000, 90000},
+ new long[]{20000, 30000, 40000, 50000, 60000, 70000, 80000});
+
+ mMockCpuUidFreqTimeReader.setSystemServerCpuTimes(
+ new long[]{10000, 20000, 30000, 40000, 50000, 60000, 70000}
+ );
+
+ mMockBatteryStats.readKernelUidCpuFreqTimesLocked(null, true, false);
+
+ int workSourceUid1 = 100;
+ int workSourceUid2 = 200;
+ int transactionCode = 42;
+
+ Collection<BinderCallsStats.CallStat> callStats = new ArrayList<>();
+ BinderCallsStats.CallStat stat1 = new BinderCallsStats.CallStat(workSourceUid1,
+ Binder.class, transactionCode, true /*screenInteractive */);
+ stat1.incrementalCallCount = 100;
+ stat1.recordedCallCount = 100;
+ stat1.cpuTimeMicros = 1000000;
+ callStats.add(stat1);
+
+ mMockBatteryStats.noteBinderCallStats(workSourceUid1, 100, callStats, null);
+
+ callStats.clear();
+ BinderCallsStats.CallStat stat2 = new BinderCallsStats.CallStat(workSourceUid2,
+ Binder.class, transactionCode, true /*screenInteractive */);
+ stat2.incrementalCallCount = 100;
+ stat2.recordedCallCount = 100;
+ stat2.cpuTimeMicros = 9000000;
+ callStats.add(stat2);
+
+ mMockBatteryStats.noteBinderCallStats(workSourceUid2, 100, callStats, null);
+
+ mMockBatteryStats.updateSystemServiceCallStats();
+ mMockBatteryStats.updateSystemServerThreadStats();
+
+ BatterySipper app1 = new BatterySipper(BatterySipper.DrainType.APP,
+ mMockBatteryStats.getUidStatsLocked(workSourceUid1), 0);
+ mSystemServicePowerCalculator.calculateApp(app1, app1.uidObj, 0, 0,
+ BatteryStats.STATS_SINCE_CHARGED);
+ assertEquals(0.27162, app1.systemServiceCpuPowerMah, 0.00001);
+
+ BatterySipper app2 = new BatterySipper(BatterySipper.DrainType.APP,
+ mMockBatteryStats.getUidStatsLocked(workSourceUid2), 0);
+ mSystemServicePowerCalculator.calculateApp(app2, app2.uidObj, 0, 0,
+ BatteryStats.STATS_SINCE_CHARGED);
+ assertEquals(2.44458, app2.systemServiceCpuPowerMah, 0.00001);
+ }
+
+ private static class MockKernelCpuUidFreqTimeReader extends
+ KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader {
+ private long[] mSystemServerCpuTimes;
+
+ MockKernelCpuUidFreqTimeReader() {
+ super(/*throttle */false);
+ }
+
+ void setSystemServerCpuTimes(long[] systemServerCpuTimes) {
+ mSystemServerCpuTimes = systemServerCpuTimes;
+ }
+
+ @Override
+ public boolean perClusterTimesAvailable() {
+ return true;
+ }
+
+ @Override
+ public void readDelta(@Nullable Callback<long[]> cb) {
+ if (cb != null) {
+ cb.onUidCpuTime(Process.SYSTEM_UID, mSystemServerCpuTimes);
+ }
+ }
+ }
+
+ private static class MockServerCpuThreadReader extends SystemServerCpuThreadReader {
+ private SystemServiceCpuThreadTimes mThreadTimes = new SystemServiceCpuThreadTimes();
+
+ MockServerCpuThreadReader() {
+ super(null);
+ }
+
+ public void setThreadTimes(long[] threadCpuTimesUs, long[] binderThreadCpuTimesUs) {
+ mThreadTimes.threadCpuTimesUs = threadCpuTimesUs;
+ mThreadTimes.binderThreadCpuTimesUs = binderThreadCpuTimesUs;
+ }
+
+ @Override
+ public SystemServiceCpuThreadTimes readDelta() {
+ return mThreadTimes;
+ }
+ }
+
+ private static class MockUserInfoProvider extends BatteryStatsImpl.UserInfoProvider {
+ @Nullable
+ @Override
+ protected int[] getUserIds() {
+ return new int[0];
+ }
+
+ @Override
+ public boolean exists(int userId) {
+ return true;
+ }
+ }
+}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index f834ce7..b3c8263 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -432,18 +432,6 @@
<permission name="android.permission.CAPTURE_AUDIO_OUTPUT" />
<!-- Permissions required for CTS test - AdbManagerTest -->
<permission name="android.permission.MANAGE_DEBUGGING" />
- <!-- Permissions required for ATS tests - AtsCarHostTestCases, AtsCarDeviceApp -->
- <permission name="android.car.permission.CAR_DRIVING_STATE" />
- <!-- Permissions required for ATS tests - AtsDeviceInfo, AtsAudioDeviceTestCases -->
- <permission name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME" />
- <!-- Permissions required for ATS tests - AtsDeviceInfo -->
- <permission name="android.car.permission.CAR_DIAGNOSTICS" />
- <!-- Permissions required for ATS tests - AtsDeviceInfo -->
- <permission name="android.car.permission.CLEAR_CAR_DIAGNOSTICS" />
- <!-- Permissions required for ATS tests - AtsCarHostTestCases -->
- <permission name="android.car.permission.CONTROL_APP_BLOCKING" />
- <!-- Permissions required for ATS tests - AtsCarHostTestCases -->
- <permission name="android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION" />
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index 4cdfbb8..5711f98 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -415,6 +415,7 @@
key usage 0x0c0067 WINDOW
key usage 0x0c006F BRIGHTNESS_UP
key usage 0x0c0070 BRIGHTNESS_DOWN
+key usage 0x0c0173 MEDIA_AUDIO_TRACK
# Joystick and game controller axes.
# Axes that are not mapped will be assigned generic axis numbers by the input subsystem.
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/UidChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/UidChecker.java
index 3ffb8ea..a2ee065 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/UidChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/UidChecker.java
@@ -23,12 +23,15 @@
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
+import com.google.errorprone.bugpatterns.BugChecker.NewClassTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.MethodInvocationTree;
+import com.sun.source.tree.NewClassTree;
+import com.sun.source.tree.Tree;
import com.sun.tools.javac.code.Symbol.VarSymbol;
import java.util.List;
@@ -44,11 +47,20 @@
name = "AndroidFrameworkUid",
summary = "Verifies that PID, UID and user ID arguments aren't crossed",
severity = WARNING)
-public final class UidChecker extends BugChecker implements MethodInvocationTreeMatcher {
+public final class UidChecker extends BugChecker implements MethodInvocationTreeMatcher,
+ NewClassTreeMatcher {
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
- final List<VarSymbol> vars = ASTHelpers.getSymbol(tree).params();
- final List<? extends ExpressionTree> args = tree.getArguments();
+ return matchArguments(ASTHelpers.getSymbol(tree).params(), tree.getArguments(), tree);
+ }
+
+ @Override
+ public Description matchNewClass(NewClassTree tree, VisitorState state) {
+ return matchArguments(ASTHelpers.getSymbol(tree).params(), tree.getArguments(), tree);
+ }
+
+ private Description matchArguments(List<VarSymbol> vars,
+ List<? extends ExpressionTree> args, Tree tree) {
for (int i = 0; i < Math.min(vars.size(), args.size()); i++) {
final Flavor varFlavor = getFlavor(vars.get(i));
final Flavor argFlavor = getFlavor(args.get(i));
diff --git a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/UidCheckerTest.java b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/UidCheckerTest.java
index 74da947..75341fd 100644
--- a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/UidCheckerTest.java
+++ b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/UidCheckerTest.java
@@ -34,7 +34,7 @@
}
@Test
- public void testTypical() {
+ public void testTypical_methodInvocation() {
compilationHelper
.addSourceLines("Example.java",
"public abstract class Example {",
@@ -57,7 +57,30 @@
}
@Test
- public void testCallingUid() {
+ public void testTypical_newClass() {
+ compilationHelper
+ .addSourceLines("Example.java",
+ "public abstract class Example {",
+ " class Bar { Bar(int pid, int uid, int userId) {} }",
+ " abstract int getUserId();",
+ " void foo(int pid, int uid, int userId, int unrelated) {",
+ " new Bar(0, 0, 0);",
+ " new Bar(pid, uid, userId);",
+ " new Bar(pid, uid, getUserId());",
+ " new Bar(unrelated, unrelated, unrelated);",
+ " // BUG: Diagnostic contains:",
+ " new Bar(uid, pid, userId);",
+ " // BUG: Diagnostic contains:",
+ " new Bar(pid, userId, uid);",
+ " // BUG: Diagnostic contains:",
+ " new Bar(getUserId(), 0, 0);",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testCallingUid_methodInvocation() {
compilationHelper
.addSourceFile("/android/os/Binder.java")
.addSourceFile("/android/os/UserHandle.java")
@@ -98,4 +121,48 @@
"}")
.doTest();
}
+
+
+ @Test
+ public void testCallingUid_newClass() {
+ compilationHelper
+ .addSourceFile("/android/os/Binder.java")
+ .addSourceFile("/android/os/UserHandle.java")
+ .addSourceLines("Example.java",
+ "import android.os.Binder;",
+ "import android.os.UserHandle;",
+ "public abstract class Example {",
+ " int callingUserId;",
+ " int callingUid;",
+ " class Foo { Foo(int callingUserId) {} }",
+ " class Bar { Bar(int callingUid) {} }",
+ " void doUserId(int callingUserId) {",
+ " new Foo(UserHandle.getUserId(Binder.getCallingUid()));",
+ " new Foo(this.callingUserId);",
+ " new Foo(callingUserId);",
+ " // BUG: Diagnostic contains:",
+ " new Foo(Binder.getCallingUid());",
+ " // BUG: Diagnostic contains:",
+ " new Foo(this.callingUid);",
+ " // BUG: Diagnostic contains:",
+ " new Foo(callingUid);",
+ " }",
+ " void doUid(int callingUserId) {",
+ " new Bar(Binder.getCallingUid());",
+ " new Bar(this.callingUid);",
+ " new Bar(callingUid);",
+ " // BUG: Diagnostic contains:",
+ " new Bar(UserHandle.getUserId(Binder.getCallingUid()));",
+ " // BUG: Diagnostic contains:",
+ " new Bar(this.callingUserId);",
+ " // BUG: Diagnostic contains:",
+ " new Bar(callingUserId);",
+ " }",
+ " void doInner() {",
+ " // BUG: Diagnostic contains:",
+ " new Foo(UserHandle.getUserId(callingUserId));",
+ " }",
+ "}")
+ .doTest();
+ }
}
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index 0f68376..e76aace 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -228,9 +228,12 @@
static jlong RuntimeShader_createShaderFactory(JNIEnv* env, jobject, jstring sksl) {
ScopedUtfChars strSksl(env, sksl);
- sk_sp<SkRuntimeEffect> effect = std::get<0>(SkRuntimeEffect::Make(SkString(strSksl.c_str())));
- ThrowIAE_IfNull(env, effect);
-
+ auto result = SkRuntimeEffect::Make(SkString(strSksl.c_str()));
+ sk_sp<SkRuntimeEffect> effect = std::get<0>(result);
+ if (!effect) {
+ const auto& err = std::get<1>(result);
+ doThrowIAE(env, err.c_str());
+ }
return reinterpret_cast<jlong>(effect.release());
}
diff --git a/location/java/android/location/GnssAntennaInfo.java b/location/java/android/location/GnssAntennaInfo.java
index b2f9a0f..23977f1 100644
--- a/location/java/android/location/GnssAntennaInfo.java
+++ b/location/java/android/location/GnssAntennaInfo.java
@@ -53,7 +53,7 @@
* Class containing information about the antenna phase center offset (PCO). PCO is defined with
* respect to the origin of the Android sensor coordinate system, e.g., center of primary screen
* for mobiles - see sensor or form factor documents for details. Uncertainties are reported
- * to 1-sigma.
+ * to 1-sigma.
*/
public static final class PhaseCenterOffset implements Parcelable {
private final double mOffsetXMm;
@@ -95,31 +95,55 @@
}
};
+ /**
+ * Returns the x-axis offset of the phase center from the origin of the Android sensor
+ * coordinate system, in millimeters.
+ */
@FloatRange()
public double getXOffsetMm() {
return mOffsetXMm;
}
+ /**
+ * Returns the 1-sigma uncertainty of the x-axis offset of the phase center from the origin
+ * of the Android sensor coordinate system, in millimeters.
+ */
@FloatRange()
public double getXOffsetUncertaintyMm() {
return mOffsetXUncertaintyMm;
}
+ /**
+ * Returns the y-axis offset of the phase center from the origin of the Android sensor
+ * coordinate system, in millimeters.
+ */
@FloatRange()
public double getYOffsetMm() {
return mOffsetYMm;
}
+ /**
+ * Returns the 1-sigma uncertainty of the y-axis offset of the phase center from the origin
+ * of the Android sensor coordinate system, in millimeters.
+ */
@FloatRange()
public double getYOffsetUncertaintyMm() {
return mOffsetYUncertaintyMm;
}
+ /**
+ * Returns the z-axis offset of the phase center from the origin of the Android sensor
+ * coordinate system, in millimeters.
+ */
@FloatRange()
public double getZOffsetMm() {
return mOffsetZMm;
}
+ /**
+ * Returns the 1-sigma uncertainty of the z-axis offset of the phase center from the origin
+ * of the Android sensor coordinate system, in millimeters.
+ */
@FloatRange()
public double getZOffsetUncertaintyMm() {
return mOffsetZUncertaintyMm;
@@ -165,7 +189,7 @@
* at 180 degrees. They are separated by deltaPhi, the regular spacing between zenith angles,
* i.e., deltaPhi = 180 / (number of columns - 1).
*/
- public static final class SphericalCorrections implements Parcelable{
+ public static final class SphericalCorrections implements Parcelable {
private final double[][] mCorrections;
private final double[][] mCorrectionUncertainties;
private final double mDeltaTheta;
@@ -296,10 +320,10 @@
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mNumRows);
dest.writeInt(mNumColumns);
- for (double[] row: mCorrections) {
+ for (double[] row : mCorrections) {
dest.writeDoubleArray(row);
}
- for (double[] row: mCorrectionUncertainties) {
+ for (double[] row : mCorrectionUncertainties) {
dest.writeDoubleArray(row);
}
}
@@ -340,6 +364,7 @@
/**
* Set antenna carrier frequency (MHz).
+ *
* @param carrierFrequencyMHz antenna carrier frequency (MHz)
* @return Builder builder object
*/
@@ -351,6 +376,7 @@
/**
* Set antenna phase center offset.
+ *
* @param phaseCenterOffset phase center offset object
* @return Builder builder object
*/
@@ -362,6 +388,7 @@
/**
* Set phase center variation corrections.
+ *
* @param phaseCenterVariationCorrections phase center variation corrections object
* @return Builder builder object
*/
@@ -374,6 +401,7 @@
/**
* Set signal gain corrections.
+ *
* @param signalGainCorrections signal gain corrections object
* @return Builder builder object
*/
@@ -386,6 +414,7 @@
/**
* Build GnssAntennaInfo object.
+ *
* @return instance of GnssAntennaInfo
*/
@NonNull
@@ -400,47 +429,65 @@
return mCarrierFrequencyMHz;
}
+ /**
+ * Returns a {@link PhaseCenterOffset} object encapsulating the phase center offset and
+ * corresponding uncertainties in millimeters.
+ *
+ * @return {@link PhaseCenterOffset}
+ */
@NonNull
public PhaseCenterOffset getPhaseCenterOffset() {
return mPhaseCenterOffset;
}
+ /**
+ * Returns a {@link SphericalCorrections} object encapsulating the phase center variation
+ * corrections and corresponding uncertainties in millimeters.
+ *
+ * @return phase center variation corrections as {@link SphericalCorrections}
+ */
@Nullable
public SphericalCorrections getPhaseCenterVariationCorrections() {
return mPhaseCenterVariationCorrections;
}
+ /**
+ * Returns a {@link SphericalCorrections} object encapsulating the signal gain
+ * corrections and corresponding uncertainties in dBi.
+ *
+ * @return signal gain corrections as {@link SphericalCorrections}
+ */
@Nullable
public SphericalCorrections getSignalGainCorrections() {
return mSignalGainCorrections;
}
- public static final @android.annotation.NonNull
- Creator<GnssAntennaInfo> CREATOR = new Creator<GnssAntennaInfo>() {
- @Override
- public GnssAntennaInfo createFromParcel(Parcel in) {
- double carrierFrequencyMHz = in.readDouble();
+ public static final @android.annotation.NonNull Creator<GnssAntennaInfo> CREATOR =
+ new Creator<GnssAntennaInfo>() {
+ @Override
+ public GnssAntennaInfo createFromParcel(Parcel in) {
+ double carrierFrequencyMHz = in.readDouble();
- ClassLoader classLoader = getClass().getClassLoader();
- PhaseCenterOffset phaseCenterOffset =
- in.readParcelable(classLoader);
- SphericalCorrections phaseCenterVariationCorrections =
- in.readParcelable(classLoader);
- SphericalCorrections signalGainCorrections =
- in.readParcelable(classLoader);
+ ClassLoader classLoader = getClass().getClassLoader();
+ PhaseCenterOffset phaseCenterOffset =
+ in.readParcelable(classLoader);
+ SphericalCorrections phaseCenterVariationCorrections =
+ in.readParcelable(classLoader);
+ SphericalCorrections signalGainCorrections =
+ in.readParcelable(classLoader);
- return new GnssAntennaInfo(
- carrierFrequencyMHz,
- phaseCenterOffset,
- phaseCenterVariationCorrections,
- signalGainCorrections);
- }
+ return new GnssAntennaInfo(
+ carrierFrequencyMHz,
+ phaseCenterOffset,
+ phaseCenterVariationCorrections,
+ signalGainCorrections);
+ }
- @Override
- public GnssAntennaInfo[] newArray(int size) {
- return new GnssAntennaInfo[size];
- }
- };
+ @Override
+ public GnssAntennaInfo[] newArray(int size) {
+ return new GnssAntennaInfo[size];
+ }
+ };
@Override
public int describeContents() {
diff --git a/location/java/android/location/LocationManagerInternal.java b/location/java/android/location/LocationManagerInternal.java
index 542737b4..ef68814 100644
--- a/location/java/android/location/LocationManagerInternal.java
+++ b/location/java/android/location/LocationManagerInternal.java
@@ -21,6 +21,8 @@
import android.annotation.Nullable;
import android.location.util.identity.CallerIdentity;
+import java.util.List;
+
/**
* Location manager local system service interface.
*
@@ -29,6 +31,16 @@
public abstract class LocationManagerInternal {
/**
+ * Listener for changes in provider enabled state.
+ */
+ public interface ProviderEnabledListener {
+ /**
+ * Called when the provider enabled state changes for a particular user.
+ */
+ void onProviderEnabledChanged(String provider, int userId, boolean enabled);
+ }
+
+ /**
* Returns true if the given provider is enabled for the given user.
*
* @param provider A location provider as listed by {@link LocationManager#getAllProviders()}
@@ -38,6 +50,24 @@
public abstract boolean isProviderEnabledForUser(@NonNull String provider, int userId);
/**
+ * Adds a provider enabled listener. The given provider must exist.
+ *
+ * @param provider The provider to listen for changes
+ * @param listener The listener
+ */
+ public abstract void addProviderEnabledListener(String provider,
+ ProviderEnabledListener listener);
+
+ /**
+ * Removes a provider enabled listener. The given provider must exist.
+ *
+ * @param provider The provider to listen for changes
+ * @param listener The listener
+ */
+ public abstract void removeProviderEnabledListener(String provider,
+ ProviderEnabledListener listener);
+
+ /**
* Returns true if the given identity is a location provider.
*
* @param provider The provider to check, or null to check every provider
@@ -52,4 +82,10 @@
*/
// TODO: there is no reason for this to exist as part of any API. move all the logic into gnss
public abstract void sendNiResponse(int notifId, int userResponse);
+
+ /**
+ * Should only be used by GNSS code.
+ */
+ // TODO: there is no reason for this to exist as part of any API. create a real batching API
+ public abstract void reportGnssBatchLocations(List<Location> locations);
}
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index bb36c2a..280bd05 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -32,6 +32,8 @@
import com.android.internal.util.Preconditions;
+import java.util.Objects;
+
/**
* A data object that contains quality of service parameters for requests
@@ -150,8 +152,6 @@
@UnsupportedAppUsage
private String mProvider;
- // if true, client requests coarse location, if false, client requests fine location
- private boolean mCoarseLocation;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mQuality;
@UnsupportedAppUsage
@@ -257,7 +257,6 @@
public LocationRequest() {
this(
/* provider= */ LocationManager.FUSED_PROVIDER,
- /* coarseLocation= */ false,
/* quality= */ POWER_LOW,
/* interval= */ DEFAULT_INTERVAL_MS,
/* fastestInterval= */ (long) (DEFAULT_INTERVAL_MS / FASTEST_INTERVAL_FACTOR),
@@ -276,7 +275,6 @@
public LocationRequest(LocationRequest src) {
this(
src.mProvider,
- src.mCoarseLocation,
src.mQuality,
src.mInterval,
src.mFastestInterval,
@@ -293,7 +291,6 @@
private LocationRequest(
@NonNull String provider,
- boolean coarseLocation,
int quality,
long intervalMs,
long fastestIntervalMs,
@@ -310,7 +307,6 @@
checkQuality(quality);
mProvider = provider;
- mCoarseLocation = coarseLocation;
mQuality = quality;
mInterval = intervalMs;
mFastestInterval = fastestIntervalMs;
@@ -327,20 +323,6 @@
}
/**
- * @hide
- */
- public boolean isCoarse() {
- return mCoarseLocation;
- }
-
- /**
- * @hide
- */
- public void setCoarse(boolean coarse) {
- mCoarseLocation = coarse;
- }
-
- /**
* Set the quality of the request.
*
* <p>Use with a accuracy constant such as {@link #ACCURACY_FINE}, or a power
@@ -720,7 +702,6 @@
public LocationRequest createFromParcel(Parcel in) {
return new LocationRequest(
/* provider= */ in.readString(),
- /* coarseLocation= */ in.readBoolean(),
/* quality= */ in.readInt(),
/* interval= */ in.readLong(),
/* fastestInterval= */ in.readLong(),
@@ -749,7 +730,6 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(mProvider);
- parcel.writeBoolean(mCoarseLocation);
parcel.writeInt(mQuality);
parcel.writeLong(mInterval);
parcel.writeLong(mFastestInterval);
@@ -784,6 +764,36 @@
}
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ LocationRequest that = (LocationRequest) o;
+ return mQuality == that.mQuality
+ && mInterval == that.mInterval
+ && mFastestInterval == that.mFastestInterval
+ && mExplicitFastestInterval == that.mExplicitFastestInterval
+ && mExpireAt == that.mExpireAt
+ && mExpireIn == that.mExpireIn
+ && mNumUpdates == that.mNumUpdates
+ && Float.compare(that.mSmallestDisplacement, mSmallestDisplacement) == 0
+ && mHideFromAppOps == that.mHideFromAppOps
+ && mLocationSettingsIgnored == that.mLocationSettingsIgnored
+ && mLowPowerMode == that.mLowPowerMode
+ && mProvider.equals(that.mProvider)
+ && Objects.equals(mWorkSource, that.mWorkSource);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mProvider, mInterval, mWorkSource);
+ }
+
@NonNull
@Override
public String toString() {
@@ -794,7 +804,7 @@
if (mQuality != POWER_NONE) {
s.append(" interval=");
TimeUtils.formatDuration(mInterval, s);
- if (mExplicitFastestInterval) {
+ if (mExplicitFastestInterval && mFastestInterval != mInterval) {
s.append(" fastestInterval=");
TimeUtils.formatDuration(mFastestInterval, s);
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 4c03fd1..408f34b 100755
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4601,36 +4601,41 @@
/**
* @hide
* Volume behavior for an audio device that has no particular volume behavior set. Invalid as
- * an argument to {@link #setDeviceVolumeBehavior(int, String, int)}.
+ * an argument to {@link #setDeviceVolumeBehavior(AudioDeviceAttributes, int)} and should not
+ * be returned by {@link #getDeviceVolumeBehavior(AudioDeviceAttributes)}.
*/
public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1;
/**
* @hide
* Volume behavior for an audio device where a software attenuation is applied
- * @see #setDeviceVolumeBehavior(int, String, int)
+ * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
*/
+ @SystemApi
public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0;
/**
* @hide
* Volume behavior for an audio device where the volume is always set to provide no attenuation
* nor gain (e.g. unit gain).
- * @see #setDeviceVolumeBehavior(int, String, int)
+ * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
*/
+ @SystemApi
public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1;
/**
* @hide
* Volume behavior for an audio device where the volume is either set to muted, or to provide
* no attenuation nor gain (e.g. unit gain).
- * @see #setDeviceVolumeBehavior(int, String, int)
+ * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
*/
+ @SystemApi
public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2;
/**
* @hide
* Volume behavior for an audio device where no software attenuation is applied, and
* the volume is kept synchronized between the host and the device itself through a
* device-specific protocol such as BT AVRCP.
- * @see #setDeviceVolumeBehavior(int, String, int)
+ * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
*/
+ @SystemApi
public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3;
/**
* @hide
@@ -4639,8 +4644,9 @@
* device-specific protocol (such as for hearing aids), based on the audio mode (e.g.
* normal vs in phone call).
* @see #setMode(int)
- * @see #setDeviceVolumeBehavior(int, String, int)
+ * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
*/
+ @SystemApi
public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4;
/** @hide */
@@ -4687,27 +4693,15 @@
/**
* @hide
* Sets the volume behavior for an audio output device.
- * @param deviceType the type of audio device to be affected. Currently only supports
- * {@link AudioDeviceInfo#TYPE_HDMI}, {@link AudioDeviceInfo#TYPE_HDMI_ARC},
- * {@link AudioDeviceInfo#TYPE_LINE_DIGITAL} and {@link AudioDeviceInfo#TYPE_AUX_LINE}
- * @param deviceAddress the address of the device, if any
+ * @see #DEVICE_VOLUME_BEHAVIOR_VARIABLE
+ * @see #DEVICE_VOLUME_BEHAVIOR_FULL
+ * @see #DEVICE_VOLUME_BEHAVIOR_FIXED
+ * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE
+ * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE
+ * @param device the device to be affected
* @param deviceVolumeBehavior one of the device behaviors
*/
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
- public void setDeviceVolumeBehavior(int deviceType, @Nullable String deviceAddress,
- @DeviceVolumeBehavior int deviceVolumeBehavior) {
- setDeviceVolumeBehavior(new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_OUTPUT,
- deviceType, deviceAddress), deviceVolumeBehavior);
- }
-
- /**
- * @hide
- * Sets the volume behavior for an audio output device.
- * @param device the device to be affected. Currently only supports devices of type
- * {@link AudioDeviceInfo#TYPE_HDMI}, {@link AudioDeviceInfo#TYPE_HDMI_ARC},
- * {@link AudioDeviceInfo#TYPE_LINE_DIGITAL} and {@link AudioDeviceInfo#TYPE_AUX_LINE}
- * @param deviceVolumeBehavior one of the device behaviors
- */
+ @SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
@DeviceVolumeBehavior int deviceVolumeBehavior) {
@@ -4726,29 +4720,14 @@
/**
* @hide
- * Returns the volume device behavior for the given device type and address
- * @param deviceType an audio output device type, as defined in {@link AudioDeviceInfo}
- * @param deviceAddress the address of the audio device, if any.
- * @return the volume behavior for the device
- */
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
- public @DeviceVolumeBehaviorState int getDeviceVolumeBehavior(int deviceType,
- @Nullable String deviceAddress) {
- // verify arguments
- AudioDeviceInfo.enforceValidAudioDeviceTypeOut(deviceType);
- return getDeviceVolumeBehavior(new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_OUTPUT,
- deviceType, deviceAddress));
- }
-
- /**
- * @hide
* Returns the volume device behavior for the given audio device
* @param device the audio device
* @return the volume behavior for the device
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
- public @DeviceVolumeBehaviorState int getDeviceVolumeBehavior(
- @NonNull AudioDeviceAttributes device) {
+ public @DeviceVolumeBehavior
+ int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
// verify arguments (validity of device type is enforced in server)
Objects.requireNonNull(device);
// communicate with service
@@ -6201,6 +6180,24 @@
}
}
+
+ /**
+ * Retrieves the Hardware A/V synchronization ID corresponding to the given audio session ID.
+ * For more details on Hardware A/V synchronization please refer to
+ * <a href="https://source.android.com/devices/tv/multimedia-tunneling/">
+ * media tunneling documentation</a>.
+ * @param sessionId the audio session ID for which the HW A/V sync ID is retrieved.
+ * @return the HW A/V sync ID for this audio session (an integer different from 0).
+ * @throws UnsupportedOperationException if HW A/V synchronization is not supported.
+ */
+ public int getAudioHwSyncForSession(int sessionId) {
+ int hwSyncId = AudioSystem.getAudioHwSyncForSession(sessionId);
+ if (hwSyncId == AudioSystem.AUDIO_HW_SYNC_INVALID) {
+ throw new UnsupportedOperationException("HW A/V synchronization is not supported.");
+ }
+ return hwSyncId;
+ }
+
//---------------------------------------------------------
// Inner classes
//--------------------
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 3cd4081..5770c67 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -291,8 +291,9 @@
C2DataIdInfo::C2DataIdInfo(uint32_t index, uint64_t value) : C2Param(kParamSize, index) {
CHECK(isGlobal());
CHECK_EQ(C2Param::INFO, kind());
- DummyInfo info{value};
- memcpy(this + 1, static_cast<C2Param *>(&info) + 1, kParamSize - sizeof(C2Param));
+ mInfo = StubInfo(value);
+ memcpy(static_cast<C2Param *>(this) + 1, static_cast<C2Param *>(&mInfo) + 1,
+ kParamSize - sizeof(C2Param));
}
/////////////// MediaEvent ///////////////////////
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 83e9db7..fd29959 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -250,8 +250,9 @@
public:
C2DataIdInfo(uint32_t index, uint64_t value);
private:
- typedef C2GlobalParam<C2Info, C2Int64Value, 0> DummyInfo;
- static const size_t kParamSize = sizeof(DummyInfo);
+ typedef C2GlobalParam<C2Info, C2Int64Value, 0> StubInfo;
+ StubInfo mInfo;
+ static const size_t kParamSize = sizeof(StubInfo);
};
} // namespace android
diff --git a/media/jni/audioeffect/Visualizer.cpp b/media/jni/audioeffect/Visualizer.cpp
index f4d65d0..a74ae53 100644
--- a/media/jni/audioeffect/Visualizer.cpp
+++ b/media/jni/audioeffect/Visualizer.cpp
@@ -34,21 +34,9 @@
// ---------------------------------------------------------------------------
-Visualizer::Visualizer (const String16& opPackageName,
- int32_t priority,
- effect_callback_t cbf,
- void* user,
- audio_session_t sessionId)
- : AudioEffect(SL_IID_VISUALIZATION, opPackageName, NULL, priority, cbf, user, sessionId),
- mCaptureRate(CAPTURE_RATE_DEF),
- mCaptureSize(CAPTURE_SIZE_DEF),
- mSampleRate(44100000),
- mScalingMode(VISUALIZER_SCALING_MODE_NORMALIZED),
- mMeasurementMode(MEASUREMENT_MODE_NONE),
- mCaptureCallBack(NULL),
- mCaptureCbkUser(NULL)
+Visualizer::Visualizer (const String16& opPackageName)
+ : AudioEffect(opPackageName)
{
- initCaptureSize();
}
Visualizer::~Visualizer()
@@ -58,6 +46,23 @@
setCaptureCallBack(NULL, NULL, 0, 0);
}
+status_t Visualizer::set(int32_t priority,
+ effect_callback_t cbf,
+ void* user,
+ audio_session_t sessionId,
+ audio_io_handle_t io,
+ const AudioDeviceTypeAddr& device,
+ bool probe)
+{
+ status_t status = AudioEffect::set(
+ SL_IID_VISUALIZATION, nullptr, priority, cbf, user, sessionId, io, device, probe);
+ if (status == NO_ERROR || status == ALREADY_EXISTS) {
+ initCaptureSize();
+ }
+ return status;
+}
+
+
void Visualizer::release()
{
ALOGV("Visualizer::release()");
diff --git a/media/jni/audioeffect/Visualizer.h b/media/jni/audioeffect/Visualizer.h
index d4672a9..8b6a62f 100644
--- a/media/jni/audioeffect/Visualizer.h
+++ b/media/jni/audioeffect/Visualizer.h
@@ -65,14 +65,22 @@
/* Constructor.
* See AudioEffect constructor for details on parameters.
*/
- Visualizer(const String16& opPackageName,
- int32_t priority = 0,
- effect_callback_t cbf = NULL,
- void* user = NULL,
- audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX);
+ explicit Visualizer(const String16& opPackageName);
~Visualizer();
+ /**
+ * Initialize an uninitialized Visualizer.
+ * See AudioEffect 'set' function for details on parameters.
+ */
+ status_t set(int32_t priority = 0,
+ effect_callback_t cbf = NULL,
+ void* user = NULL,
+ audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
+ audio_io_handle_t io = AUDIO_IO_HANDLE_NONE,
+ const AudioDeviceTypeAddr& device = {},
+ bool probe = false);
+
// Declared 'final' because we call this in ~Visualizer().
status_t setEnabled(bool enabled) final;
@@ -163,15 +171,15 @@
uint32_t initCaptureSize();
Mutex mCaptureLock;
- uint32_t mCaptureRate;
- uint32_t mCaptureSize;
- uint32_t mSampleRate;
- uint32_t mScalingMode;
- uint32_t mMeasurementMode;
- capture_cbk_t mCaptureCallBack;
- void *mCaptureCbkUser;
+ uint32_t mCaptureRate = CAPTURE_RATE_DEF;
+ uint32_t mCaptureSize = CAPTURE_SIZE_DEF;
+ uint32_t mSampleRate = 44100000;
+ uint32_t mScalingMode = VISUALIZER_SCALING_MODE_NORMALIZED;
+ uint32_t mMeasurementMode = MEASUREMENT_MODE_NONE;
+ capture_cbk_t mCaptureCallBack = nullptr;
+ void *mCaptureCbkUser = nullptr;
sp<CaptureThread> mCaptureThread;
- uint32_t mCaptureFlags;
+ uint32_t mCaptureFlags = 0;
};
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index dbe7b4b..96961ac2 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -337,22 +337,21 @@
}
// create the native AudioEffect object
- lpAudioEffect = new AudioEffect(typeStr,
- String16(opPackageNameStr.c_str()),
- uuidStr,
- priority,
- effectCallback,
- &lpJniStorage->mCallbackData,
- (audio_session_t) sessionId,
- AUDIO_IO_HANDLE_NONE,
- device,
- probe);
+ lpAudioEffect = new AudioEffect(String16(opPackageNameStr.c_str()));
if (lpAudioEffect == 0) {
ALOGE("Error creating AudioEffect");
goto setup_failure;
}
-
+ lpAudioEffect->set(typeStr,
+ uuidStr,
+ priority,
+ effectCallback,
+ &lpJniStorage->mCallbackData,
+ (audio_session_t) sessionId,
+ AUDIO_IO_HANDLE_NONE,
+ device,
+ probe);
lStatus = AudioEffectJni::translateNativeErrorToJava(lpAudioEffect->initCheck());
if (lStatus != AUDIOEFFECT_SUCCESS && lStatus != AUDIOEFFECT_ERROR_ALREADY_EXISTS) {
ALOGE("AudioEffect initCheck failed %d", lStatus);
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index f9a77f4..4c5970a 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -382,15 +382,15 @@
}
// create the native Visualizer object
- lpVisualizer = new Visualizer(String16(opPackageNameStr.c_str()),
- 0,
- android_media_visualizer_effect_callback,
- lpJniStorage,
- (audio_session_t) sessionId);
+ lpVisualizer = new Visualizer(String16(opPackageNameStr.c_str()));
if (lpVisualizer == 0) {
ALOGE("Error creating Visualizer");
goto setup_failure;
}
+ lpVisualizer->set(0,
+ android_media_visualizer_effect_callback,
+ lpJniStorage,
+ (audio_session_t) sessionId);
lStatus = translateError(lpVisualizer->initCheck());
if (lStatus != VISUALIZER_SUCCESS && lStatus != VISUALIZER_ERROR_ALREADY_EXISTS) {
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index 5aaca43..70ef69d 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -11900,6 +11900,7 @@
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_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
}
@@ -24189,6 +24190,7 @@
method @NonNull public java.util.List<android.media.AudioPlaybackConfiguration> getActivePlaybackConfigurations();
method @NonNull public java.util.List<android.media.AudioRecordingConfiguration> getActiveRecordingConfigurations();
method public int getAllowedCapturePolicy();
+ method public int getAudioHwSyncForSession(int);
method public android.media.AudioDeviceInfo[] getDevices(int);
method public java.util.List<android.media.MicrophoneInfo> getMicrophones() throws java.io.IOException;
method public int getMode();
@@ -46014,6 +46016,7 @@
method @Nullable public android.net.LinkProperties getLinkProperties();
method public int getNetworkType();
method public int getState();
+ method public int getTransportType();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PreciseDataConnectionState> CREATOR;
}
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index 222e563..844e929 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -4141,6 +4141,7 @@
method @IntRange(from=0) public long getAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioProductStrategy> getAudioProductStrategies();
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioVolumeGroup> getAudioVolumeGroups();
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getDevicesForAttributes(@NonNull android.media.AudioAttributes);
method @IntRange(from=0) public long getMaxAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
@@ -4159,6 +4160,7 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int requestAudioFocus(@NonNull android.media.AudioFocusRequest, @Nullable android.media.audiopolicy.AudioPolicy);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo, @IntRange(from=0) long);
method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setSupportedSystemUsages(@NonNull int[]);
@@ -4169,6 +4171,11 @@
field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1
field public static final int AUDIOFOCUS_FLAG_LOCK = 4; // 0x4
field public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 2; // 0x2
+ field public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3; // 0x3
+ field public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4; // 0x4
+ field public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2; // 0x2
+ field public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1; // 0x1
+ field public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0; // 0x0
field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int STREAM_ASSISTANT = 11; // 0xb
field public static final int SUCCESS = 0; // 0x0
}
@@ -9706,6 +9713,7 @@
method @Deprecated public int getDataConnectionApnTypeBitMask();
method @Deprecated public int getDataConnectionFailCause();
method @Deprecated public int getDataConnectionState();
+ method public int getId();
}
public final class PreciseDisconnectCause {
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index 995a3ec..f4e704e 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -38,6 +38,8 @@
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerImpl;
import com.android.systemui.doze.DozeHost;
+import com.android.systemui.pip.phone.PipMenuActivity;
+import com.android.systemui.pip.phone.dagger.PipMenuActivityClass;
import com.android.systemui.plugins.qs.QSFactory;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.power.EnhancedEstimates;
@@ -142,6 +144,13 @@
mainHandler, transactionPool).build();
}
+ @Singleton
+ @PipMenuActivityClass
+ @Provides
+ static Class<?> providePipMenuActivityClass() {
+ return PipMenuActivity.class;
+ }
+
@Binds
abstract HeadsUpManager bindHeadsUpManagerPhone(HeadsUpManagerPhone headsUpManagerPhone);
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppDetector.java b/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppDetector.java
index 5dcb9de..a2cd044 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppDetector.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppDetector.java
@@ -39,7 +39,7 @@
/**
* A class that detects unsafe apps.
- * An app is considered safe if is a system app or installed through whitelisted sources.
+ * An app is considered safe if is a system app or installed through allowed sources.
*/
@Singleton
public class SideLoadedAppDetector {
diff --git a/packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java b/packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java
index 5f9665f..0452b83 100644
--- a/packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java
+++ b/packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java
@@ -172,32 +172,32 @@
private static class Filter {
private static final String ALL = "*";
- private final ArraySet<String> mWhitelist;
- private final ArraySet<String> mBlacklist;
+ private final ArraySet<String> mToInclude;
+ private final ArraySet<String> mToExclude;
- private Filter(ArraySet<String> whitelist, ArraySet<String> blacklist) {
- mWhitelist = whitelist;
- mBlacklist = blacklist;
+ private Filter(ArraySet<String> toInclude, ArraySet<String> toExclude) {
+ mToInclude = toInclude;
+ mToExclude = toExclude;
}
boolean matches(String packageName) {
if (packageName == null) return false;
- if (onBlacklist(packageName)) return false;
- return onWhitelist(packageName);
+ if (toExclude(packageName)) return false;
+ return toInclude(packageName);
}
- private boolean onBlacklist(String packageName) {
- return mBlacklist.contains(packageName) || mBlacklist.contains(ALL);
+ private boolean toExclude(String packageName) {
+ return mToExclude.contains(packageName) || mToExclude.contains(ALL);
}
- private boolean onWhitelist(String packageName) {
- return mWhitelist.contains(ALL) || mWhitelist.contains(packageName);
+ private boolean toInclude(String packageName) {
+ return mToInclude.contains(ALL) || mToInclude.contains(packageName);
}
void dump(PrintWriter pw) {
pw.print("Filter[");
- dump("whitelist", mWhitelist, pw); pw.print(',');
- dump("blacklist", mBlacklist, pw); pw.print(']');
+ dump("toInclude", mToInclude, pw); pw.print(',');
+ dump("toExclude", mToExclude, pw); pw.print(']');
}
private void dump(String name, ArraySet<String> set, PrintWriter pw) {
@@ -221,18 +221,18 @@
// e.g. "com.package1", or "com.android.systemui, com.android.keyguard" or "*"
static Filter parse(String value) {
if (value == null) return null;
- ArraySet<String> whitelist = new ArraySet<String>();
- ArraySet<String> blacklist = new ArraySet<String>();
+ ArraySet<String> toInclude = new ArraySet<String>();
+ ArraySet<String> toExclude = new ArraySet<String>();
for (String token : value.split(",")) {
token = token.trim();
if (token.startsWith("-") && token.length() > 1) {
token = token.substring(1);
- blacklist.add(token);
+ toExclude.add(token);
} else {
- whitelist.add(token);
+ toInclude.add(token);
}
}
- return new Filter(whitelist, blacklist);
+ return new Filter(toInclude, toExclude);
}
}
diff --git a/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java b/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
index d769cac..86b86d4 100644
--- a/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
@@ -63,7 +63,7 @@
private static final String TAG = "AAA++VerifyTest";
- private static final Class[] BASE_CLS_WHITELIST = {
+ private static final Class[] BASE_CLS_TO_INCLUDE = {
SysuiTestCase.class,
SysuiBaseFragmentTest.class,
};
@@ -85,7 +85,7 @@
if (!isTestClass(cls)) continue;
boolean hasParent = false;
- for (Class<?> parent : BASE_CLS_WHITELIST) {
+ for (Class<?> parent : BASE_CLS_TO_INCLUDE) {
if (parent.isAssignableFrom(cls)) {
hasParent = true;
break;
@@ -129,7 +129,7 @@
}
private String getClsStr() {
- return TextUtils.join(",", Arrays.asList(BASE_CLS_WHITELIST)
+ return TextUtils.join(",", Arrays.asList(BASE_CLS_TO_INCLUDE)
.stream().map(cls -> cls.getSimpleName()).toArray());
}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
index 31f1170..f77294e 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
@@ -19,6 +19,8 @@
import static com.android.systemui.car.voicerecognition.ConnectedDeviceVoiceRecognitionNotifier.INVALID_VALUE;
import static com.android.systemui.car.voicerecognition.ConnectedDeviceVoiceRecognitionNotifier.VOICE_RECOGNITION_STARTED;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -40,11 +42,13 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
+// TODO(b/162866441): Refactor to use the Executor pattern instead.
public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase {
private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
@@ -52,13 +56,15 @@
private ConnectedDeviceVoiceRecognitionNotifier mVoiceRecognitionNotifier;
private TestableLooper mTestableLooper;
+ private Handler mHandler;
private Handler mTestHandler;
private BluetoothDevice mBluetoothDevice;
@Before
public void setUp() throws Exception {
mTestableLooper = TestableLooper.get(this);
- mTestHandler = spy(new Handler(mTestableLooper.getLooper()));
+ mHandler = new Handler(mTestableLooper.getLooper());
+ mTestHandler = spy(mHandler);
mBluetoothDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(
BLUETOOTH_REMOTE_ADDRESS);
mVoiceRecognitionNotifier = new ConnectedDeviceVoiceRecognitionNotifier(
@@ -74,8 +80,14 @@
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
mTestableLooper.processAllMessages();
+ waitForIdleSync();
- verify(mTestHandler).post(any());
+ mHandler.post(() -> {
+ ArgumentCaptor<Runnable> argumentCaptor = ArgumentCaptor.forClass(Runnable.class);
+ verify(mTestHandler).post(argumentCaptor.capture());
+ assertThat(argumentCaptor.getValue()).isNotNull();
+ assertThat(argumentCaptor.getValue()).isNotEqualTo(this);
+ });
}
@Test
@@ -86,8 +98,11 @@
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
mTestableLooper.processAllMessages();
+ waitForIdleSync();
- verify(mTestHandler, never()).post(any());
+ mHandler.post(() -> {
+ verify(mTestHandler, never()).post(any());
+ });
}
@Test
@@ -97,8 +112,11 @@
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
mTestableLooper.processAllMessages();
+ waitForIdleSync();
- verify(mTestHandler, never()).post(any());
+ mHandler.post(() -> {
+ verify(mTestHandler, never()).post(any());
+ });
}
@Test
@@ -108,7 +126,10 @@
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
mTestableLooper.processAllMessages();
+ waitForIdleSync();
- verify(mTestHandler, never()).post(any());
+ mHandler.post(() -> {
+ verify(mTestHandler, never()).post(any());
+ });
}
}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index bcaee36..f108e06 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -259,18 +259,19 @@
private void onDeviceFound(@Nullable DeviceFilterPair device) {
if (device == null) return;
- if (mDevicesFound.contains(device)) {
- return;
- }
-
- if (DEBUG) Log.i(LOG_TAG, "Found device " + device);
-
Handler.getMain().sendMessage(obtainMessage(
DeviceDiscoveryService::onDeviceFoundMainThread, this, device));
}
@MainThread
void onDeviceFoundMainThread(@NonNull DeviceFilterPair device) {
+ if (mDevicesFound.contains(device)) {
+ Log.i(LOG_TAG, "Skipping device " + device + " - already among found devices");
+ return;
+ }
+
+ Log.i(LOG_TAG, "Found device " + device);
+
if (mDevicesFound.isEmpty()) {
onReadyToShowUI();
}
@@ -428,10 +429,10 @@
@Override
public String toString() {
- return "DeviceFilterPair{" +
- "device=" + device +
- ", filter=" + filter +
- '}';
+ return "DeviceFilterPair{"
+ + "device=" + device + " " + getDisplayName()
+ + ", filter=" + filter
+ + '}';
}
}
diff --git a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeView.java b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeView.java
index 276d55ee..9fe7ab65 100644
--- a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeView.java
+++ b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeView.java
@@ -26,7 +26,7 @@
import android.view.View;
/**
- * Dummy view to emulate stuff an OEM may want to do.
+ * Fake view to emulate stuff an OEM may want to do.
*/
public class FakeView extends View {
static final long TICK_DELAY = 30*1000; // 30 seconds
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/MasterSwitchController.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/PrimarySwitchController.java
similarity index 87%
rename from packages/SettingsLib/Tile/src/com/android/settingslib/drawer/MasterSwitchController.java
rename to packages/SettingsLib/Tile/src/com/android/settingslib/drawer/PrimarySwitchController.java
index a12aa83..a08f566 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/MasterSwitchController.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/PrimarySwitchController.java
@@ -19,9 +19,9 @@
import android.os.Bundle;
/**
- * A controller that manages event for master switch.
+ * A controller that manages event for Primary switch.
*/
-public abstract class MasterSwitchController extends SwitchController {
+public abstract class PrimarySwitchController extends SwitchController {
@Override
protected final MetaData getMetaData() {
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java
index 73f1a90..f2b3e30 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java
@@ -88,7 +88,7 @@
controller.setAuthority(mAuthority);
mControllerMap.put(key, controller);
- if (!(controller instanceof MasterSwitchController)) {
+ if (!(controller instanceof PrimarySwitchController)) {
mSwitchDataList.add(controller.getBundle());
}
});
@@ -116,7 +116,7 @@
switch (method) {
case METHOD_GET_SWITCH_DATA:
- if (!(controller instanceof MasterSwitchController)) {
+ if (!(controller instanceof PrimarySwitchController)) {
return controller.getBundle();
}
break;
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 704d264..6751fa4 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Wys Bluetooth-toestelle sonder name"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Deaktiveer absolute volume"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Aktiveer Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Verbeterde konnektiwiteit"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP-weergawe"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Kies Bluetooth AVRCP-weergawe"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP-weergawe"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 585924d..470e780 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"የብሉቱዝ መሣሪያዎችን ያለ ስሞች አሳይ"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ፍጹማዊ ድምፅን አሰናክል"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorscheን አንቃ"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"የተሻሻለ ተገናኝነት"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"የብሉቱዝ AVRCP ስሪት"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"የብሉቱዝ AVRCP ስሪት ይምረጡ"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"የብሉቱዝ MAP ስሪት"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 39777cd..9acfa0d 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -152,7 +152,7 @@
<string name="user_guest" msgid="6939192779649870792">"ضيف"</string>
<string name="unknown" msgid="3544487229740637809">"غير معروف"</string>
<string name="running_process_item_user_label" msgid="3988506293099805796">"المستخدم: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
- <string name="launch_defaults_some" msgid="3631650616557252926">"تم تعيين بعض الإعدادات التلقائية"</string>
+ <string name="launch_defaults_some" msgid="3631650616557252926">"تم ضبط بعض الإعدادات التلقائية"</string>
<string name="launch_defaults_none" msgid="8049374306261262709">"لم يتم تعيين إعدادات تلقائية"</string>
<string name="tts_settings" msgid="8130616705989351312">"إعدادات تحويل النص إلى كلام"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"تحويل النص إلى كلام"</string>
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"عرض أجهزة البلوتوث بدون أسماء"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"إيقاف مستوى الصوت المطلق"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"تفعيل Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"إمكانية اتصال محسّن"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"إصدار Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"اختيار إصدار Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"إصدار Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index e0455cb..f993dba 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"নামবিহীন ব্লুটুথ ডিভাইচসমূহ দেখুৱাওক"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"পূৰ্ণ মাত্ৰাৰ ভলিউম অক্ষম কৰক"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche সক্ষম কৰক"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"উন্নত সংযোগ"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ব্লুটুথ AVRCP সংস্কৰণ"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ব্লুটুথ AVRCP সংস্কৰণ বাছনি কৰক"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ব্লুটুথ MAP সংস্কৰণ"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 6565d53..6a50661 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth cihazlarını adsız göstərin"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Mütləq səs həcmi deaktiv edin"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche\'ni aktiv edin"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Təkmilləşdirilmiş Bağlantı"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP Versiya"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP Versiyasını seçin"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP Versiyası"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 3ced29b..cf988ab 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži Bluetooth uređaje bez naziva"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Onemogući glavno podešavanje jačine zvuka"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Omogući Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Poboljšano povezivanje"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Verzija Bluetooth AVRCP-a"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Izaberite verziju Bluetooth AVRCP-a"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Verzija Bluetooth MAP-a"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 01d7682..8f71509 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Паказваць прылады Bluetooth без назваў"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Адключыць абсалютны гук"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Уключыць Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Палепшанае падключэнне"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Версія Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Выбраць версію Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Версія Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index d042c0f..747cb26 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Показване на устройствата с Bluetooth без имена"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Деактивиране на пълната сила на звука"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Активиране на Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Подобрена свързаност"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Версия на AVRCP за Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Избиране на версия на AVRCP за Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"MAP версия за Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 2db23f7..87f3b7a 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"নামহীন ব্লুটুথ ডিভাইসগুলি দেখুন"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"চূড়ান্ত ভলিউম অক্ষম করুন"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche ফিচার চালু করুন"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"কানেক্টিভিটি উন্নত করা হয়েছে"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ব্লুটুথ AVRCP ভার্সন"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ব্লুটুথ AVRCP ভার্সন বেছে নিন"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ব্লুটুথ MAP ভার্সন"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index f26fe9d..e329c99 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži Bluetooth uređaje bez naziva"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Onemogući apsolutnu jačinu zvuka"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Omogući Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Poboljšana povezivost"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP verzija"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Odaberite Bluetooth AVRCP verziju"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP verzija"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 3ca9d52..5ffdacd 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostra els dispositius Bluetooth sense el nom"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Desactiva el volum absolut"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Activa Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Connectivitat millorada"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versió AVRCP de Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecciona la versió AVRCP de Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versió MAP de Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index a5532e0..0aef99f 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Zobrazovat zařízení Bluetooth bez názvů"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Zakázat absolutní hlasitost"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Zapnout funkci Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Lepší připojování"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Verze profilu Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Vyberte verzi profilu Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Verze MAP pro Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 8ca22d7..98068cb 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Vis Bluetooth-enheder uden navne"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Deaktiver absolut lydstyrke"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Aktivér Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Enhanced Connectivity"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"AVRCP-version for Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Vælg AVRCP-version for Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"MAP-version for Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 6b0ae2e2..0837ad3 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth-Geräte ohne Namen anzeigen"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Absolute Lautstärkeregelung deaktivieren"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Bluetooth-Gabeldorsche aktivieren"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Verbesserte Konnektivität"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP-Version"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP-Version auswählen"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP-Version"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 4d7c882..1f9d977 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Εμφάνιση συσκευών Bluetooth χωρίς ονόματα"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Απενεργοποίηση απόλυτης έντασης"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Ενεργοποίηση Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Βελτιωμένη συνδεσιμότητα"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Έκδοση AVRCP Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Επιλογή έκδοσης AVRCP Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Έκδοση MAP Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index cc3b2aa..abe61a9 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Disable absolute volume"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Enable Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Enhanced connectivity"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP version"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Select Bluetooth AVRCP Version"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP version"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index a9f039a..959ad46 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Disable absolute volume"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Enable Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Enhanced connectivity"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP version"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Select Bluetooth AVRCP Version"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP version"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index cc3b2aa..abe61a9 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Disable absolute volume"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Enable Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Enhanced connectivity"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP version"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Select Bluetooth AVRCP Version"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP version"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index cc3b2aa..abe61a9 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Disable absolute volume"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Enable Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Enhanced connectivity"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP version"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Select Bluetooth AVRCP Version"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP version"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 41c20e0..738dd2a 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Disable absolute volume"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Enable Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Enhanced Connectivity"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP Version"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Select Bluetooth AVRCP Version"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP Version"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 287a1ac..d1e4fb5 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sin nombre"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Inhabilitar volumen absoluto"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Habilitar Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Conectividad mejorada"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versión de AVRCP del Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecciona la versión de AVRCP del Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versión de MAP de Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 9d34557..9ad71e2 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sin nombre"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Inhabilitar volumen absoluto"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Habilitar Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Conectividad mejorada"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versión AVRCP de Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecciona la versión AVRCP de Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versión de MAP de Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index d003ef0..14d3b57 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Kuva ilma nimedeta Bluetoothi seadmed"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Keela absoluutne helitugevus"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Luba Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Täiustatud ühenduvus"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetoothi AVRCP versioon"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Valige Bluetoothi AVRCP versioon"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetoothi MAP-i versioon"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 0042321..dcdadbd 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Erakutsi Bluetooth bidezko gailuak izenik gabe"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Desgaitu bolumen absolutua"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gaitu Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Konexio hobeak"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP bertsioa"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Hautatu Bluetooth AVRCP bertsioa"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAParen bertsioa"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 1c08815..f3b22d3 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"نمایش دستگاههای بلوتوث بدون نام"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"غیرفعال کردن میزان صدای مطلق"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"فعال کردن Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"اتصال بهبودیافته"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"نسخه AVRCP بلوتوث"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"انتخاب نسخه AVRCP بلوتوث"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"نسخه MAP بلوتوث"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 3945e55..3d28f1d 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Näytä nimettömät Bluetooth-laitteet"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Poista yleinen äänenvoimakkuuden säätö käytöstä"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Ota Gabeldorsche käyttöön"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Parannetut yhteydet"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetoothin AVRCP-versio"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Valitse Bluetoothin AVRCP-versio"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetoothin MAP-versio"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 140d4ce..87d3de1 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Afficher les appareils Bluetooth sans nom"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Désactiver le volume absolu"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Activer le Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Connectivité améliorée"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Version du profil Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Sélectionner la version du profil Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Version du profil Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 1b1ae8e..ddf2bc0 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -251,13 +251,12 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certification affichage sans fil"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Autoriser l\'enregistrement d\'infos Wi-Fi détaillées"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Limiter la recherche Wi‑Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Chgt aléatoire d\'adresse MAC sur Wi-Fi"</string>
+ <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Chgt aléatoire d\'adresse MAC en Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Données mobiles toujours actives"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Accélération matérielle pour le partage de connexion"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Afficher les appareils Bluetooth sans nom"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Désactiver le volume absolu"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Activer Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Connectivité améliorée"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Version Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Sélectionner la version Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Version Bluetooth MAP"</string>
@@ -284,7 +283,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Afficher les options pour la certification de l\'affichage sans fil"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Détailler les infos Wi-Fi, afficher par RSSI de SSID dans l\'outil de sélection Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Réduit la décharge de la batterie et améliore les performances du réseau"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Lorsque ce mode est activé, l\'adresse e-mail MAC de cet appareil peut changer lors de chaque connexion à un réseau pour lequel le changement aléatoire d\'adresse MAC est activé."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Lorsque ce mode est activé, l\'adresse MAC de cet appareil peut changer lors de chaque connexion à un réseau Wi-Fi pour lequel le changement aléatoire d\'adresse MAC est activé"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Facturé à l\'usage"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Non facturé à l\'usage"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Tailles des tampons de l\'enregistreur"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index f9d57c4..af43099 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sen nomes"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Desactivar volume absoluto"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Activar Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Conectividade mellorada"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versión de Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecciona a versión de Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versión de MAP de Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index aa1f960..3261f69 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"નામ વિનાના બ્લૂટૂથ ઉપકરણો બતાવો"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ચોક્કસ વૉલ્યૂમને અક્ષમ કરો"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche ચાલુ કરો"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"વિસ્તૃત કનેક્ટિવિટી"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"બ્લૂટૂથ AVRCP સંસ્કરણ"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"બ્લૂટૂથ AVRCP સંસ્કરણ પસંદ કરો"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"બ્લૂટૂથ MAP વર્ઝન"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 9b6a27a..904a70e 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"बिना नाम वाले ब्लूटूथ डिवाइस दिखाएं"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ब्लूटूथ से आवाज़ के नियंत्रण की सुविधा रोकें"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche चालू करें"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"कनेक्टिविटी बेहतर बनाएं"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ब्लूटूथ एवीआरसीपी वर्शन"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ब्लूटूथ AVRCP वर्शन चुनें"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ब्लूटूथ का MAP वर्शन"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 14e3330..3edc4527 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži Bluetooth uređaje bez naziva"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Onemogući apsolutnu glasnoću"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Omogući Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Poboljšana povezivost"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Verzija AVRCP-a za Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Odaberite verziju AVRCP-a za Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Verzija MAP-a za Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index d16ff03..fec2dd6 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Név nélküli Bluetooth-eszközök megjelenítése"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Abszolút hangerő funkció letiltása"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"A Gabeldorsche engedélyezése"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Enhanced Connectivity"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"A Bluetooth AVRCP-verziója"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"A Bluetooth AVRCP-verziójának kiválasztása"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"A Bluetooth MAP-verziója"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index b010b50..f219d24 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Ցուցադրել Bluetooth սարքերն առանց անունների"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Անջատել ձայնի բացարձակ ուժգնությունը"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Միացնել Gabeldorsche-ը"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Տվյալների լավացված փոխանակում"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP տարբերակը"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Ընտրել Bluetooth AVRCP տարբերակը"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP-ի տարբերակ"</string>
diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml
index 37cf189f..3ab50cc 100644
--- a/packages/SettingsLib/res/values-in/arrays.xml
+++ b/packages/SettingsLib/res/values-in/arrays.xml
@@ -31,7 +31,7 @@
<item msgid="7852381437933824454">"Memutus sambungan..."</item>
<item msgid="5046795712175415059">"Sambungan terputus"</item>
<item msgid="2473654476624070462">"Gagal"</item>
- <item msgid="9146847076036105115">"Dicekal"</item>
+ <item msgid="9146847076036105115">"Diblokir"</item>
<item msgid="4543924085816294893">"Menghindari sambungan buruk untuk sementara"</item>
</string-array>
<string-array name="wifi_status_with_ssid">
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 42ccd53..a6f8846 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -180,8 +180,8 @@
<string name="tts_engine_settings_button" msgid="477155276199968948">"Luncurkan setelan mesin"</string>
<string name="tts_engine_preference_section_title" msgid="3861562305498624904">"Mesin yang dipilih"</string>
<string name="tts_general_section_title" msgid="8919671529502364567">"Umum"</string>
- <string name="tts_reset_speech_pitch_title" msgid="7149398585468413246">"Setel ulang tinggi nada ucapan"</string>
- <string name="tts_reset_speech_pitch_summary" msgid="6822904157021406449">"Setel ulang tinggi nada diucapkannya teks menjadi default."</string>
+ <string name="tts_reset_speech_pitch_title" msgid="7149398585468413246">"Reset tinggi nada ucapan"</string>
+ <string name="tts_reset_speech_pitch_summary" msgid="6822904157021406449">"Reset tinggi nada diucapkannya teks menjadi default."</string>
<string-array name="tts_rate_entries">
<item msgid="9004239613505400644">"Sangat lambat"</item>
<item msgid="1815382991399815061">"Lambat"</item>
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Tampilkan perangkat Bluetooth tanpa nama"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Nonaktifkan volume absolut"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Aktifkan Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Konektivitas Yang Disempurnakan"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versi AVRCP Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Pilih Versi AVRCP Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versi MAP Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 0ebc341..caf2323 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Sýna Bluetooth-tæki án heita"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Slökkva á samstillingu hljóðstyrks"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Virkja Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Aukin tengigeta"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP-útgáfa"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Velja Bluetooth AVRCP-útgáfu"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP-útgáfa"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 50fdfc9..8d18727 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostra dispositivi Bluetooth senza nome"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Disattiva volume assoluto"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Attiva Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Connettività migliorata"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versione Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Seleziona versione Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versione Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index fb7d00f..fff881c 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"הצגת מכשירי Bluetooth ללא שמות"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"השבת עוצמת קול מוחלטת"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"הפעלת Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"קישוריות משופרת"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth גרסה AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"בחר Bluetooth גרסה AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"גרסת Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 3537cea..5e579b7 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth デバイスを名前なしで表示"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"絶対音量を無効にする"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche を有効にする"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"接続強化"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP バージョン"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP バージョンを選択する"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP バージョン"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 9b671a8..1b5fae9 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth-მოწყობილობების ჩვენება სახელების გარეშე"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ხმის აბსოლუტური სიძლიერის გათიშვა"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche-ის ჩართვა"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"კავშირის გაძლიერებული შესაძლებლობა"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth-ის AVRCP-ის ვერსია"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"აირჩიეთ Bluetooth-ის AVRCP-ის ვერსია"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP-ის ვერსია"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 279aca0..9c290e9 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth құрылғыларын атаусыз көрсету"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Абсолютті дыбыс деңгейін өшіру"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche функциясын іске қосу"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Жетілдірілген байланыс"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP нұсқасы"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP нұсқасын таңдау"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP нұсқасы"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 03065e8..2878db1 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"បង្ហាញឧបករណ៍ប្ល៊ូធូសគ្មានឈ្មោះ"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"បិទកម្រិតសំឡេងលឺខ្លាំង"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"បើក Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"ការតភ្ជាប់ដែលបានធ្វើឱ្យប្រសើរឡើង"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"កំណែប្ល៊ូធូស AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ជ្រើសរើសកំណែប្ល៊ូធូស AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"កំណែប៊្លូធូស MAP"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 71c5e49..7b01056 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ಹೆಸರುಗಳಿಲ್ಲದ ಬ್ಲೂಟೂತ್ ಸಾಧನಗಳನ್ನು ತೋರಿಸಿ"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ಸಂಪೂರ್ಣ ವಾಲ್ಯೂಮ್ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"ವರ್ಧಿತ ಸಂಪರ್ಕ"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ಬ್ಲೂಟೂತ್ AVRCP ಆವೃತ್ತಿ"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ಬ್ಲೂಟೂತ್ AVRCP ಆವೃತ್ತಿಯನ್ನು ಆಯ್ಕೆ ಮಾಡಿ"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ಬ್ಲೂಟೂತ್ MAP ಆವೃತ್ತಿ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 5d82eae..696ed29 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"이름이 없는 블루투스 기기 표시"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"절대 볼륨 사용 안함"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche 사용 설정"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"향상된 연결"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"블루투스 AVRCP 버전"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"블루투스 AVRCP 버전 선택"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"블루투스 MAP 버전"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 2702392..c4b5f7e 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Аталышсыз Bluetooth түзмөктөрү көрсөтүлсүн"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Үндүн абсолюттук деңгээли өчүрүлсүн"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche функциясын иштетүү"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Жакшыртылган туташуу"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP версиясы"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP версиясын тандоо"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP версиясы"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 7a2c338..a72861e 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ສະແດງອຸປະກອນ Bluetooth ທີ່ບໍ່ມີຊື່"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ປິດໃຊ້ລະດັບສຽງສົມບູນ"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"ເປີດໃຊ້ Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"ການເຊື່ອມຕໍ່ທີ່ເສີມແຕ່ງແລ້ວ"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ເວີຊັນ Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ເລືອກເວີຊັນ Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ເວີຊັນ Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index b73aa66..c72bf21 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Rodyti „Bluetooth“ įrenginius be pavadinimų"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Išjungti didžiausią garsą"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Įgalinti „Gabeldorsche“"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Patobulintas ryšys"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"„Bluetooth“ AVRCP versija"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Pasirinkite „Bluetooth“ AVRCP versiją"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"„Bluetooth“ MRK versija"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 8e5d24c..d95e57d 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Rādīt Bluetooth ierīces bez nosaukumiem"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Atspējot absolūto skaļumu"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Iespējot Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Uzlabota savienojamība"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP versija"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Atlasiet Bluetooth AVRCP versiju"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP versija"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 34299d8..fb7b634 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Прикажувај уреди со Bluetooth без имиња"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Оневозможете апсолутна јачина на звук"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Овозможи Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Подобрена поврзливост"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Верзија Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Изберете верзија Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Верзија на Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index c95f8bf..3c281c8 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"പേരില്ലാത്ത Bluetooth ഉപകരണങ്ങൾ കാണിക്കുക"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"അബ്സൊല്യൂട്ട് വോളിയം പ്രവർത്തനരഹിതമാക്കുക"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche പ്രവർത്തനക്ഷമമാക്കുക"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"മെച്ചപ്പെടുത്തിയ കണക്റ്റിവിറ്റി"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP പതിപ്പ്"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP പതിപ്പ് തിരഞ്ഞെടുക്കുക"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP പതിപ്പ്"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 8407db6..37fc5b4 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Нэргүй Bluetooth төхөөрөмжийг харуулах"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Үнэмлэхүй дууны түвшинг идэвхгүй болгох"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche-г идэвхжүүлэх"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Сайжруулсан холболт"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP хувилбар"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP хувилбарыг сонгох"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP хувилбар"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index c50f365..360f158 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"नावांशिवाय ब्लूटूथ डिव्हाइस दाखवा"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"संपूर्ण आवाज बंद करा"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"गाबलडॉर्ष सुरू करा"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"वर्धित कनेक्टिव्हिटी"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ब्लूटूथ AVRCP आवृत्ती"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ब्लूटूथ AVRCP आवृत्ती निवडा"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ब्लूटूथ MAP आवृत्ती"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index a0a434f..68356df2 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Tunjukkan peranti Bluetooth tanpa nama"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Lumpuhkan kelantangan mutlak"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Dayakan Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Kesambungan Dipertingkat"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versi AVRCP Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Pilih Versi AVRCP Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versi MAP Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index fa49929..3729a83 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"အမည်မရှိသော ဘလူးတုသ်စက်ပစ္စည်းများကို ပြသရန်"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ပကတိ အသံနှုန်း သတ်မှတ်ချက် ပိတ်ရန်"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche ကို ဖွင့်ရန်"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"အရည်အသွေးမြှင့်တင်ထားသော ချိတ်ဆက်နိုင်မှု"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ဘလူးတုသ် AVRCP ဗားရှင်း"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ဘလူးတုသ် AVRCP ဗားရှင်းကို ရွေးပါ"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ဘလူးတုသ် MAP ဗားရှင်း"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index aeaba31..0e0e761 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Vis Bluetooth-enheter uten navn"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Slå av funksjonen for absolutt volum"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Aktiver Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Forbedret tilkobling"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP-versjon"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Velg Bluetooth AVRCP-versjon"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP-versjon"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 4a2c171..762d830 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"नामकरण नगरिएका ब्लुटुथ यन्त्रहरू देखाउनुहोस्"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"निरपेक्ष आवाज असक्षम गर्नुहोस्"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche सक्षम पार्नुहोस्"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"परिष्कृत जडान"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ब्लुटुथको AVRCP संस्करण"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ब्लुटुथको AVRCP संस्करण चयन गर्नुहोस्"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ब्लुटुथको MAP संस्करण"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 32cc39e..83b72e9 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth-apparaten zonder namen weergeven"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Absoluut volume uitschakelen"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche inschakelen"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Verbeterde connectiviteit"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth-AVRCP-versie"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth-AVRCP-versie selecteren"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"MAP-versie voor bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 8e5bf25..d200f50 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ବ୍ଲୁଟୂଥ୍ ଡିଭାଇସ୍ଗୁଡ଼ିକୁ ନାମ ବିନା ଦେଖନ୍ତୁ"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ପୂର୍ଣ୍ଣ ଭଲ୍ୟୁମ୍ ଅକ୍ଷମ କରନ୍ତୁ"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"ଗାବେଲ୍ଡୋର୍ସ ସକ୍ରିୟ କରନ୍ତୁ"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"ଏନହାନ୍ସଡ୍ କନେକ୍ଟିଭିଟି"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ବ୍ଲୁଟୂଥ୍ AVRCP ଭର୍ସନ୍"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ବ୍ଲୁଟୂଥ୍ AVRCP ଭର୍ସନ୍"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ବ୍ଲୁଟୁଥ୍ MAP ସଂସ୍କରଣ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 1570013..354ee12 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ਅਨਾਮ ਬਲੂਟੁੱਥ ਡੀਵਾਈਸਾਂ ਦਿਖਾਓ"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ਪੂਰਨ ਅਵਾਜ਼ ਨੂੰ ਬੰਦ ਕਰੋ"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche ਨੂੰ ਚਾਲੂ ਕਰੋ"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"ਵਿਸਤ੍ਰਿਤ ਕਨੈਕਟੀਵਿਟੀ"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ਬਲੂਟੁੱਥ AVRCP ਵਰਜਨ"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ਬਲੂਟੁੱਥ AVRCP ਵਰਜਨ ਚੁਣੋ"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP ਵਰਜਨ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 1120c50..095412c 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Pokaż urządzenia Bluetooth bez nazw"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Wyłącz głośność bezwzględną"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Włącz Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Lepsza obsługa połączeń"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Wersja AVRCP Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Wybierz wersję AVRCP Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Wersja MAP Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 4214a27..895a987 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sem nomes"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Desativar volume absoluto"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Ativar Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Conectividade melhorada"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versão do Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecionar versão do Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versão MAP do Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 508cbfc..2d9f037 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sem nomes"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Desativar volume absoluto"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Ativar o Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Conetividade melhorada"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versão de Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecionar versão de Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versão do MAP do Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 4214a27..895a987 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sem nomes"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Desativar volume absoluto"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Ativar Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Conectividade melhorada"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versão do Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecionar versão do Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versão MAP do Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 663d3f7..728db17 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Afișați dispozitivele Bluetooth fără nume"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Dezactivați volumul absolut"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Activați Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Conectivitate îmbunătățită"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versiunea AVRCP pentru Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selectați versiunea AVRCP pentru Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versiunea MAP pentru Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 9c0a2f5..ff2115e 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Показывать Bluetooth-устройства без названий"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Отключить абсолютный уровень громкости"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Включить Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Улучшенный обмен данными"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Версия Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Выберите версию Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Версия Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 8d0e93e..a883cc6 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"නම් නොමැති බ්ලූටූත් උපාංග පෙන්වන්න"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"නිරපේක්ෂ හඩ පරිමාව අබල කරන්න"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche සබල කරන්න"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"වැඩිදියුණු කළ සබැඳුම් හැකියාව"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"බ්ලූටූත් AVRCP අනුවාදය"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"බ්ලූටූත් AVRCP අනුවාදය තෝරන්න"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP අනුවාදය"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index f39a741..05c6379 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Zobrazovať zariadenia Bluetooth bez názvov"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Zakázať absolútnu hlasitosť"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Povoliť Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Zlepšené možnosti pripojenia"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Verzia rozhrania Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Zvoľte verziu rozhrania Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Verzia profilu Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 233c8e4..fd216e8 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži naprave Bluetooth brez imen"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Onemogočanje absolutne glasnosti"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Omogoči Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Izboljšana povezljivost"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Različica profila AVRCP za Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Izberite različico profila AVRCP za Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Različica profila MAP za Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 6af1062..002c7fc 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Shfaq pajisjet me Bluetooth pa emra"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Çaktivizo volumin absolut"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Aktivizo Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Lidhshmëria e përmirësuar"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versioni AVRCP i Bluetooth-it"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Zgjidh versionin AVRCP të Bluetooth-it"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versioni MAP i Bluetooth-it"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 74c2aec..25a1beb7 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Прикажи Bluetooth уређаје без назива"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Онемогући главно подешавање јачине звука"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Омогући Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Побољшано повезивање"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Верзија Bluetooth AVRCP-а"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Изаберите верзију Bluetooth AVRCP-а"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Верзија Bluetooth MAP-а"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index fe1b0a8..352cb0a 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Visa namnlösa Bluetooth-enheter"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Inaktivera Absolute volume"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Aktivera Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Förbättrad anslutning"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"AVRCP-version för Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Välj AVRCP-version för Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"MAP-version för Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 5c80627..d2891a0 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Onyesha vifaa vya Bluetooth visivyo na majina"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Zima sauti kamili"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Washa Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Muunganisho Ulioboreshwa"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Toleo la Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Chagua Toleo la Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Toleo la Ramani ya Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 241644f..7837dd8 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"பெயர்கள் இல்லாத புளூடூத் சாதனங்களைக் காட்டு"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"அப்சல்யூட் ஒலியளவு அம்சத்தை முடக்கு"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorscheவை இயக்கு"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"மேம்படுத்தப்பட்ட இணைப்புநிலை"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"புளூடூத் AVRCP பதிப்பு"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"புளூடூத் AVRCP பதிப்பைத் தேர்ந்தெடு"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"புளூடூத்தின் MAP பதிப்பு"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index a9ec2ea9..60001a0 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"పేర్లు లేని బ్లూటూత్ పరికరాలు చూపించు"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"సంపూర్ణ వాల్యూమ్ను నిలిపివేయి"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorscheను ఎనేబుల్ చేయి"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"మెరుగైన కనెక్టివిటీ"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"బ్లూటూత్ AVRCP వెర్షన్"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"బ్లూటూత్ AVRCP సంస్కరణను ఎంచుకోండి"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"బ్లూటూత్ MAP వెర్షన్"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index b8343c6..defc33e 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"แสดงอุปกรณ์บลูทูธที่ไม่มีชื่อ"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ปิดใช้การควบคุมระดับเสียงของอุปกรณ์อื่น"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"เปิดใช้ Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"การเชื่อมต่อที่ปรับปรุงแล้ว"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"เวอร์ชันของบลูทูธ AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"เลือกเวอร์ชันของบลูทูธ AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"เวอร์ชัน MAP ของบลูทูธ"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 8aeb392..5d4e975 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Ipakita ang mga Bluetooth device na walang pangalan"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"I-disable ang absolute volume"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"I-enable ang Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Pinagandang Pagkakonekta"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bersyon ng AVRCP ng Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Pumili ng Bersyon ng AVRCP ng Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bersyon ng MAP ng Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index e6d9380..f01f3fa 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Adsız Bluetooth cihazlarını göster"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Mutlak sesi iptal et"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche\'yi etkileştir"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Gelişmiş Bağlantı"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP Sürümü"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP Sürümünü seçin"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP Sürümü"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index cf1fafd..9ca2f06 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Показувати пристрої Bluetooth без назв"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Вимкнути абсолютну гучність"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Увімкнути Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Покращене з\'єднання"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Версія Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Виберіть версію Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Версія Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index b7fbe6f..8953f50 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"بغیر نام والے بلوٹوتھ آلات دکھائیں"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"مطلق والیوم کو غیر فعال کریں"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche فعال کریں"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"بہتر کردہ کنیکٹوٹی"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"بلوٹوتھ AVRCP ورژن"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"بلوٹوتھ AVRCP ورژن منتخب کریں"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"بلوٹوتھ MAP ورژن"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index f81731a..f25b3ac 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth qurilmalarini nomlarisiz ko‘rsatish"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Tovush balandligining mutlaq darajasini faolsizlantirish"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche funksiyasini yoqish"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Kuchaytirilgan aloqa"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP versiyasi"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP versiyasini tanlang"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP versiyasi"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index b7ccf8d..b5798f3 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Hiển thị các thiết bị Bluetooth không có tên"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Vô hiệu hóa âm lượng tuyệt đối"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Bật tính năng Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Kết nối nâng cao"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Phiên bản Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Chọn phiên bản Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Phiên bản Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 75c1333..c4dcfff 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"显示没有名称的蓝牙设备"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"停用绝对音量功能"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"启用“Gabeldorsche”"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"增强连接性"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"蓝牙 AVRCP 版本"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"选择蓝牙 AVRCP 版本"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"蓝牙 MAP 版本"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 26ddfb1..e04651c 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"顯示沒有名稱的藍牙裝置"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"停用絕對音量功能"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"啟用 Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"強化連線功能"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"藍牙 AVRCP 版本"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"選擇藍牙 AVRCP 版本"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"藍牙 MAP 版本"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 72ea043..a1ae6b6 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"顯示沒有名稱的藍牙裝置"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"停用絕對音量功能"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"啟用 Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"加強型連線"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"藍牙 AVRCP 版本"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"選取藍牙 AVRCP 版本"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"藍牙 MAP 版本"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 6b8739f..2dafad8 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bonisa amadivayisi e-Bluetooth ngaphandle kwamagama"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Khubaza ivolumu ngokuphelele"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Nika amandla i-Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Ukuxhumeka Okuthuthukisiwe"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Inguqulo ye-Bluetooth ye-AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Khetha inguqulo ye-Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Inguqulo ye-Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/development/DeveloperOptionsPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/development/DeveloperOptionsPreferenceController.java
index f757aa4..b29595e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/development/DeveloperOptionsPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/development/DeveloperOptionsPreferenceController.java
@@ -24,7 +24,7 @@
import com.android.settingslib.core.AbstractPreferenceController;
/**
- * This controller is used handle changes for the master switch in the developer options page.
+ * This controller is used handle changes for the primary switch in the developer options page.
*
* All Preference Controllers that are a part of the developer options page should inherit this
* class.
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerAllowlistBackend.java
similarity index 69%
rename from packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
rename to packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerAllowlistBackend.java
index 3c647a7..c501b3a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerAllowlistBackend.java
@@ -34,44 +34,50 @@
import com.android.internal.util.ArrayUtils;
/**
- * Handles getting/changing the whitelist for the exceptions to battery saving features.
+ * Handles getting/changing the allowlist for the exceptions to battery saving features.
*/
-public class PowerWhitelistBackend {
+public class PowerAllowlistBackend {
- private static final String TAG = "PowerWhitelistBackend";
+ private static final String TAG = "PowerAllowlistBackend";
private static final String DEVICE_IDLE_SERVICE = "deviceidle";
- private static PowerWhitelistBackend sInstance;
+ private static PowerAllowlistBackend sInstance;
private final Context mAppContext;
private final IDeviceIdleController mDeviceIdleService;
- private final ArraySet<String> mWhitelistedApps = new ArraySet<>();
- private final ArraySet<String> mSysWhitelistedApps = new ArraySet<>();
+ private final ArraySet<String> mAllowlistedApps = new ArraySet<>();
+ private final ArraySet<String> mSysAllowlistedApps = new ArraySet<>();
private final ArraySet<String> mDefaultActiveApps = new ArraySet<>();
- public PowerWhitelistBackend(Context context) {
+ public PowerAllowlistBackend(Context context) {
this(context, IDeviceIdleController.Stub.asInterface(
ServiceManager.getService(DEVICE_IDLE_SERVICE)));
}
@VisibleForTesting
- PowerWhitelistBackend(Context context, IDeviceIdleController deviceIdleService) {
+ PowerAllowlistBackend(Context context, IDeviceIdleController deviceIdleService) {
mAppContext = context.getApplicationContext();
mDeviceIdleService = deviceIdleService;
refreshList();
}
- public int getWhitelistSize() {
- return mWhitelistedApps.size();
+ public int getAllowlistSize() {
+ return mAllowlistedApps.size();
}
- public boolean isSysWhitelisted(String pkg) {
- return mSysWhitelistedApps.contains(pkg);
+ /**
+ * Check if target package is in System allow list
+ */
+ public boolean isSysAllowlisted(String pkg) {
+ return mSysAllowlistedApps.contains(pkg);
}
- public boolean isWhitelisted(String pkg) {
- if (mWhitelistedApps.contains(pkg)) {
+ /**
+ * Check if target package is in allow list
+ */
+ public boolean isAllowlisted(String pkg) {
+ if (mAllowlistedApps.contains(pkg)) {
return true;
}
@@ -87,7 +93,7 @@
*/
public boolean isDefaultActiveApp(String pkg) {
// Additionally, check if pkg is default dialer/sms. They are considered essential apps and
- // should be automatically whitelisted (otherwise user may be able to set restriction on
+ // should be automatically allowlisted (otherwise user may be able to set restriction on
// them, leading to bad device behavior.)
if (mDefaultActiveApps.contains(pkg)) {
@@ -103,12 +109,17 @@
return false;
}
- public boolean isWhitelisted(String[] pkgs) {
+ /**
+ *
+ * @param pkgs a list of packageName
+ * @return true when one of package is in allow list
+ */
+ public boolean isAllowlisted(String[] pkgs) {
if (ArrayUtils.isEmpty(pkgs)) {
return false;
}
for (String pkg : pkgs) {
- if (isWhitelisted(pkg)) {
+ if (isAllowlisted(pkg)) {
return true;
}
}
@@ -116,40 +127,51 @@
return false;
}
+ /**
+ * Add app into power save allow list.
+ * @param pkg packageName
+ */
public void addApp(String pkg) {
try {
mDeviceIdleService.addPowerSaveWhitelistApp(pkg);
- mWhitelistedApps.add(pkg);
+ mAllowlistedApps.add(pkg);
} catch (RemoteException e) {
Log.w(TAG, "Unable to reach IDeviceIdleController", e);
}
}
+ /**
+ * Remove package from power save allow list.
+ * @param pkg
+ */
public void removeApp(String pkg) {
try {
mDeviceIdleService.removePowerSaveWhitelistApp(pkg);
- mWhitelistedApps.remove(pkg);
+ mAllowlistedApps.remove(pkg);
} catch (RemoteException e) {
Log.w(TAG, "Unable to reach IDeviceIdleController", e);
}
}
+ /**
+ * Refresh all of lists
+ */
@VisibleForTesting
public void refreshList() {
- mSysWhitelistedApps.clear();
- mWhitelistedApps.clear();
+ mSysAllowlistedApps.clear();
+ mAllowlistedApps.clear();
mDefaultActiveApps.clear();
if (mDeviceIdleService == null) {
return;
}
try {
- final String[] whitelistedApps = mDeviceIdleService.getFullPowerWhitelist();
- for (String app : whitelistedApps) {
- mWhitelistedApps.add(app);
+ final String[] allowlistedApps = mDeviceIdleService.getFullPowerWhitelist();
+ for (String app : allowlistedApps) {
+ mAllowlistedApps.add(app);
}
- final String[] sysWhitelistedApps = mDeviceIdleService.getSystemPowerWhitelist();
- for (String app : sysWhitelistedApps) {
- mSysWhitelistedApps.add(app);
+ final String[] sysAllowlistedApps = mDeviceIdleService.getSystemPowerWhitelist();
+ for (String app : sysAllowlistedApps) {
+ mSysAllowlistedApps.add(app);
}
final boolean hasTelephony = mAppContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_TELEPHONY);
@@ -171,9 +193,13 @@
}
}
- public static PowerWhitelistBackend getInstance(Context context) {
+ /**
+ * @param context
+ * @return a PowerAllowlistBackend object
+ */
+ public static PowerAllowlistBackend getInstance(Context context) {
if (sInstance == null) {
- sInstance = new PowerWhitelistBackend(context);
+ sInstance = new PowerAllowlistBackend(context);
}
return sInstance;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
index 4941f7e..8ac4349 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
@@ -135,7 +135,7 @@
// Ignore
}
} else {
- // Blacklist all other apps, system or downloaded
+ // Denylist all other apps, system or downloaded
try {
ApplicationInfo info = mIPm.getApplicationInfo(packageName, 0, userId);
if (info != null) {
@@ -258,11 +258,11 @@
}
}
- // Establish master/slave relationship for entries that share a package name
+ // Establish primary/secondary relationship for entries that share a package name
HashMap<String,SelectableAppInfo> packageMap = new HashMap<String,SelectableAppInfo>();
for (SelectableAppInfo info : mVisibleApps) {
if (packageMap.containsKey(info.packageName)) {
- info.masterEntry = packageMap.get(info.packageName);
+ info.primaryEntry = packageMap.get(info.packageName);
} else {
packageMap.put(info.packageName, info);
}
@@ -366,12 +366,12 @@
public CharSequence appName;
public CharSequence activityName;
public Drawable icon;
- public SelectableAppInfo masterEntry;
+ public SelectableAppInfo primaryEntry;
@Override
public String toString() {
return packageName + ": appName=" + appName + "; activityName=" + activityName
- + "; icon=" + icon + "; masterEntry=" + masterEntry;
+ + "; icon=" + icon + "; primaryEntry=" + primaryEntry;
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
index 11c799e..94e28f2 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
@@ -290,12 +290,12 @@
@Test
public void sendShowAdminSupportDetailsIntent_extraRestrictionProvided() {
EnforcedAdmin enforcedAdmin = new EnforcedAdmin();
- enforcedAdmin.enforcedRestriction = "Dummy";
+ enforcedAdmin.enforcedRestriction = "Fake";
RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, enforcedAdmin);
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mContext).startActivityAsUser(intentCaptor.capture(), any());
- assertThat(intentCaptor.getValue().getExtra(EXTRA_RESTRICTION)).isEqualTo("Dummy");
+ assertThat(intentCaptor.getValue().getExtra(EXTRA_RESTRICTION)).isEqualTo("Fake");
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/MasterSwitchControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/PrimarySwitchControllerTest.java
similarity index 86%
rename from packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/MasterSwitchControllerTest.java
rename to packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/PrimarySwitchControllerTest.java
index 69d0f2e..9e4cde8 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/MasterSwitchControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/PrimarySwitchControllerTest.java
@@ -23,16 +23,16 @@
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
-public class MasterSwitchControllerTest {
+public class PrimarySwitchControllerTest {
@Rule
public final ExpectedException thrown = ExpectedException.none();
- private MasterSwitchController mController;
+ private PrimarySwitchController mController;
@Before
public void setUp() {
- mController = new TestMasterSwitchController("123");
+ mController = new TestPrimarySwitchController("123");
}
@Test
@@ -49,11 +49,11 @@
mController.getBundle();
}
- static class TestMasterSwitchController extends MasterSwitchController {
+ static class TestPrimarySwitchController extends PrimarySwitchController {
private String mKey;
- TestMasterSwitchController(String key) {
+ TestPrimarySwitchController(String key) {
mKey = key;
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/SwitchesProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/SwitchesProviderTest.java
index a740e68..bd0100b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/SwitchesProviderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/SwitchesProviderTest.java
@@ -35,7 +35,7 @@
import android.content.pm.ProviderInfo;
import android.os.Bundle;
-import com.android.settingslib.drawer.MasterSwitchControllerTest.TestMasterSwitchController;
+import com.android.settingslib.drawer.PrimarySwitchControllerTest.TestPrimarySwitchController;
import com.android.settingslib.drawer.SwitchController.MetaData;
import org.junit.Before;
@@ -124,8 +124,8 @@
}
@Test
- public void getSwitchData_shouldNotReturnMasterSwitchData() {
- final SwitchController controller = new TestMasterSwitchController("123");
+ public void getSwitchData_shouldNotReturnPrimarySwitchData() {
+ final SwitchController controller = new TestPrimarySwitchController("123");
mSwitchesProvider.addSwitchController(controller);
mSwitchesProvider.attachInfo(mContext, mProviderInfo);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerAllowlistBackendTest.java
similarity index 67%
rename from packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
rename to packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerAllowlistBackendTest.java
index 2090892..4f11fb1 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerAllowlistBackendTest.java
@@ -47,7 +47,7 @@
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowDefaultDialerManager.class, ShadowSmsApplication.class})
-public class PowerWhitelistBackendTest {
+public class PowerAllowlistBackendTest {
private static final String PACKAGE_ONE = "com.example.packageone";
private static final String PACKAGE_TWO = "com.example.packagetwo";
@@ -56,7 +56,7 @@
private IDeviceIdleController mDeviceIdleService;
@Mock
private DevicePolicyManager mDevicePolicyManager;
- private PowerWhitelistBackend mPowerWhitelistBackend;
+ private PowerAllowlistBackend mPowerAllowlistBackend;
private ShadowPackageManager mPackageManager;
private Context mContext;
@@ -74,81 +74,81 @@
mPackageManager.setSystemFeature(PackageManager.FEATURE_TELEPHONY, true);
doReturn(mDevicePolicyManager).when(mContext).getSystemService(DevicePolicyManager.class);
- mPowerWhitelistBackend = new PowerWhitelistBackend(mContext, mDeviceIdleService);
+ mPowerAllowlistBackend = new PowerAllowlistBackend(mContext, mDeviceIdleService);
}
@Test
- public void testIsWhitelisted() throws Exception {
+ public void testIsAllowlisted() throws Exception {
doReturn(new String[] {PACKAGE_ONE}).when(mDeviceIdleService).getFullPowerWhitelist();
- mPowerWhitelistBackend.refreshList();
+ mPowerAllowlistBackend.refreshList();
- assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
- assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse();
- assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_ONE})).isTrue();
- assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_TWO})).isFalse();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_TWO)).isFalse();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(new String[] {PACKAGE_ONE})).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(new String[] {PACKAGE_TWO})).isFalse();
- mPowerWhitelistBackend.addApp(PACKAGE_TWO);
+ mPowerAllowlistBackend.addApp(PACKAGE_TWO);
verify(mDeviceIdleService, atLeastOnce()).addPowerSaveWhitelistApp(PACKAGE_TWO);
- assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
- assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isTrue();
- assertThat(mPowerWhitelistBackend.isWhitelisted(
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_TWO)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(
new String[] {PACKAGE_ONE, PACKAGE_TWO})).isTrue();
- mPowerWhitelistBackend.removeApp(PACKAGE_TWO);
+ mPowerAllowlistBackend.removeApp(PACKAGE_TWO);
verify(mDeviceIdleService, atLeastOnce()).removePowerSaveWhitelistApp(PACKAGE_TWO);
- assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
- assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse();
- assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_ONE})).isTrue();
- assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_TWO})).isFalse();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_TWO)).isFalse();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(new String[] {PACKAGE_ONE})).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(new String[] {PACKAGE_TWO})).isFalse();
- mPowerWhitelistBackend.removeApp(PACKAGE_ONE);
+ mPowerAllowlistBackend.removeApp(PACKAGE_ONE);
verify(mDeviceIdleService, atLeastOnce()).removePowerSaveWhitelistApp(PACKAGE_ONE);
- assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isFalse();
- assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse();
- assertThat(mPowerWhitelistBackend.isWhitelisted(
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isFalse();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_TWO)).isFalse();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(
new String[] {PACKAGE_ONE, PACKAGE_TWO})).isFalse();
}
@Test
- public void isWhitelisted_shouldWhitelistDefaultSms() {
+ public void isAllowlisted_shouldAllowlistDefaultSms() {
final String testSms = "com.android.test.defaultsms";
ShadowSmsApplication.setDefaultSmsApplication(new ComponentName(testSms, "receiver"));
- mPowerWhitelistBackend.refreshList();
+ mPowerAllowlistBackend.refreshList();
- assertThat(mPowerWhitelistBackend.isWhitelisted(testSms)).isTrue();
- assertThat(mPowerWhitelistBackend.isDefaultActiveApp(testSms)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(testSms)).isTrue();
+ assertThat(mPowerAllowlistBackend.isDefaultActiveApp(testSms)).isTrue();
}
@Test
- public void isWhitelisted_shouldWhitelistDefaultDialer() {
+ public void isAllowlisted_shouldAllowlistDefaultDialer() {
final String testDialer = "com.android.test.defaultdialer";
ShadowDefaultDialerManager.setDefaultDialerApplication(testDialer);
- mPowerWhitelistBackend.refreshList();
+ mPowerAllowlistBackend.refreshList();
- assertThat(mPowerWhitelistBackend.isWhitelisted(testDialer)).isTrue();
- assertThat(mPowerWhitelistBackend.isDefaultActiveApp(testDialer)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(testDialer)).isTrue();
+ assertThat(mPowerAllowlistBackend.isDefaultActiveApp(testDialer)).isTrue();
}
@Test
- public void isWhitelisted_shouldWhitelistActiveDeviceAdminApp() {
+ public void isAllowlisted_shouldAllowlistActiveDeviceAdminApp() {
doReturn(true).when(mDevicePolicyManager).packageHasActiveAdmins(PACKAGE_ONE);
- assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
- assertThat(mPowerWhitelistBackend.isDefaultActiveApp(PACKAGE_ONE)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isTrue();
+ assertThat(mPowerAllowlistBackend.isDefaultActiveApp(PACKAGE_ONE)).isTrue();
}
@Test
- public void testIsSystemWhitelisted() throws Exception {
+ public void testIsSystemAllowlisted() throws Exception {
doReturn(new String[] {PACKAGE_ONE}).when(mDeviceIdleService).getSystemPowerWhitelist();
- mPowerWhitelistBackend.refreshList();
+ mPowerAllowlistBackend.refreshList();
- assertThat(mPowerWhitelistBackend.isSysWhitelisted(PACKAGE_ONE)).isTrue();
- assertThat(mPowerWhitelistBackend.isSysWhitelisted(PACKAGE_TWO)).isFalse();
- assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isFalse();
+ assertThat(mPowerAllowlistBackend.isSysAllowlisted(PACKAGE_ONE)).isTrue();
+ assertThat(mPowerAllowlistBackend.isSysAllowlisted(PACKAGE_TWO)).isFalse();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isFalse();
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompatTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompatTest.java
index b930aa6..84d722a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompatTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompatTest.java
@@ -197,61 +197,61 @@
public void isValidSystemNonAuxAsciiCapableIme() {
// System IME w/ no subtype
assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme(
- createDummyIme(true, false)))
+ createFakeIme(true, false)))
.isFalse();
// System IME w/ non-Aux and non-ASCII-capable "keyboard" subtype
assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme(
- createDummyIme(true, false, createDummySubtype("keyboard", false, false))))
+ createFakeIme(true, false, createFakeSubtype("keyboard", false, false))))
.isFalse();
// System IME w/ non-Aux and ASCII-capable "keyboard" subtype
assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme(
- createDummyIme(true, false, createDummySubtype("keyboard", false, true))))
+ createFakeIme(true, false, createFakeSubtype("keyboard", false, true))))
.isTrue();
// System IME w/ Aux and ASCII-capable "keyboard" subtype
assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme(
- createDummyIme(true, true, createDummySubtype("keyboard", true, true))))
+ createFakeIme(true, true, createFakeSubtype("keyboard", true, true))))
.isFalse();
// System IME w/ non-Aux and ASCII-capable "voice" subtype
assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme(
- createDummyIme(true, false, createDummySubtype("voice", false, true))))
+ createFakeIme(true, false, createFakeSubtype("voice", false, true))))
.isFalse();
// System IME w/ non-Aux and non-ASCII-capable subtype + Non-Aux and ASCII-capable subtype
assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme(
- createDummyIme(true, false,
- createDummySubtype("keyboard", false, true),
- createDummySubtype("keyboard", false, false))))
+ createFakeIme(true, false,
+ createFakeSubtype("keyboard", false, true),
+ createFakeSubtype("keyboard", false, false))))
.isTrue();
// Non-system IME w/ non-Aux and ASCII-capable "keyboard" subtype
assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme(
- createDummyIme(false, false, createDummySubtype("keyboard", false, true))))
+ createFakeIme(false, false, createFakeSubtype("keyboard", false, true))))
.isFalse();
}
- private static InputMethodInfo createDummyIme(boolean isSystem, boolean isAuxIme,
+ private static InputMethodInfo createFakeIme(boolean isSystem, boolean isAuxIme,
InputMethodSubtype... subtypes) {
final ResolveInfo ri = new ResolveInfo();
final ServiceInfo si = new ServiceInfo();
final ApplicationInfo ai = new ApplicationInfo();
- ai.packageName = "com.example.android.dummyime";
+ ai.packageName = "com.example.android.fakeime";
ai.enabled = true;
ai.flags |= (isSystem ? ApplicationInfo.FLAG_SYSTEM : 0);
si.applicationInfo = ai;
si.enabled = true;
- si.packageName = "com.example.android.dummyime";
- si.name = "Dummy IME";
+ si.packageName = "com.example.android.fakeime";
+ si.name = "Fake IME";
si.exported = true;
- si.nonLocalizedLabel = "Dummy IME";
+ si.nonLocalizedLabel = "Fake IME";
ri.serviceInfo = si;
return new InputMethodInfo(ri, isAuxIme, "", Arrays.asList(subtypes), 1, false);
}
- private static InputMethodSubtype createDummySubtype(
+ private static InputMethodSubtype createFakeSubtype(
String mode, boolean isAuxiliary, boolean isAsciiCapable) {
return new InputMethodSubtypeBuilder()
.setSubtypeNameResId(0)
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilTest.java
index 5171dda..97d8705 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilTest.java
@@ -195,55 +195,55 @@
public void isValidNonAuxAsciiCapableIme() {
// IME w/ no subtype
assertThat(InputMethodAndSubtypeUtil.isValidNonAuxAsciiCapableIme(
- createDummyIme(false)))
+ createFakeIme(false)))
.isFalse();
// IME w/ non-Aux and non-ASCII-capable "keyboard" subtype
assertThat(InputMethodAndSubtypeUtil.isValidNonAuxAsciiCapableIme(
- createDummyIme(false, createDummySubtype("keyboard", false, false))))
+ createFakeIme(false, createFakeSubtype("keyboard", false, false))))
.isFalse();
// IME w/ non-Aux and ASCII-capable "keyboard" subtype
assertThat(InputMethodAndSubtypeUtil.isValidNonAuxAsciiCapableIme(
- createDummyIme(false, createDummySubtype("keyboard", false, true))))
+ createFakeIme(false, createFakeSubtype("keyboard", false, true))))
.isTrue();
// IME w/ Aux and ASCII-capable "keyboard" subtype
assertThat(InputMethodAndSubtypeUtil.isValidNonAuxAsciiCapableIme(
- createDummyIme(true, createDummySubtype("keyboard", true, true))))
+ createFakeIme(true, createFakeSubtype("keyboard", true, true))))
.isFalse();
// IME w/ non-Aux and ASCII-capable "voice" subtype
assertThat(InputMethodAndSubtypeUtil.isValidNonAuxAsciiCapableIme(
- createDummyIme(false, createDummySubtype("voice", false, true))))
+ createFakeIme(false, createFakeSubtype("voice", false, true))))
.isFalse();
// IME w/ non-Aux and non-ASCII-capable subtype + Non-Aux and ASCII-capable subtype
assertThat(InputMethodAndSubtypeUtil.isValidNonAuxAsciiCapableIme(
- createDummyIme(false,
- createDummySubtype("keyboard", false, true),
- createDummySubtype("keyboard", false, false))))
+ createFakeIme(false,
+ createFakeSubtype("keyboard", false, true),
+ createFakeSubtype("keyboard", false, false))))
.isTrue();
}
- private static InputMethodInfo createDummyIme(boolean isAuxIme,
+ private static InputMethodInfo createFakeIme(boolean isAuxIme,
InputMethodSubtype... subtypes) {
final ResolveInfo ri = new ResolveInfo();
final ServiceInfo si = new ServiceInfo();
final ApplicationInfo ai = new ApplicationInfo();
- ai.packageName = "com.example.android.dummyime";
+ ai.packageName = "com.example.android.fakeime";
ai.enabled = true;
si.applicationInfo = ai;
si.enabled = true;
- si.packageName = "com.example.android.dummyime";
- si.name = "Dummy IME";
+ si.packageName = "com.example.android.fakeime";
+ si.name = "Fake IME";
si.exported = true;
- si.nonLocalizedLabel = "Dummy IME";
+ si.nonLocalizedLabel = "Fake IME";
ri.serviceInfo = si;
return new InputMethodInfo(ri, isAuxIme, "", Arrays.asList(subtypes), 1, false);
}
- private static InputMethodSubtype createDummySubtype(
+ private static InputMethodSubtype createFakeSubtype(
String mode, boolean isAuxiliary, boolean isAsciiCapable) {
return new InputMethodSubtypeBuilder()
.setSubtypeNameResId(0)
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 18c2957..4eea8ad 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -112,7 +112,6 @@
Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
Settings.Secure.VR_DISPLAY_MODE,
Settings.Secure.NOTIFICATION_BADGING,
- Settings.Secure.NOTIFICATION_FEEDBACK_ENABLED,
Settings.Secure.NOTIFICATION_DISMISS_RTL,
Settings.Secure.QS_AUTO_ADDED_TILES,
Settings.Secure.SCREENSAVER_ENABLED,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index dd94d2e..a02d67f 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -149,5 +149,6 @@
VALIDATORS.put(Global.CUSTOM_BUGREPORT_HANDLER_APP, ANY_STRING_VALIDATOR);
VALIDATORS.put(Global.CUSTOM_BUGREPORT_HANDLER_USER, ANY_INTEGER_VALIDATOR);
VALIDATORS.put(Global.DEVELOPMENT_SETTINGS_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Global.NOTIFICATION_FEEDBACK_ENABLED, BOOLEAN_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 91f3f4a..c68ddbd 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -189,7 +189,6 @@
VALIDATORS.put(Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.SHOW_NOTIFICATION_SNOOZE, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.NOTIFICATION_HISTORY_ENABLED, BOOLEAN_VALIDATOR);
- VALIDATORS.put(Secure.NOTIFICATION_FEEDBACK_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ZEN_DURATION, ANY_INTEGER_VALIDATOR);
VALIDATORS.put(Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.SHOW_ZEN_SETTINGS_SUGGESTION, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index c1543fd..bfd5b1cc 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -81,6 +81,7 @@
sBroadcastOnRestore.add(Settings.Secure.DARK_THEME_CUSTOM_START_TIME);
sBroadcastOnRestore.add(Settings.Secure.DARK_THEME_CUSTOM_END_TIME);
sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED);
+ sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
}
private interface SettingsLookup {
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 24f8104..4bb8f45 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -389,6 +389,7 @@
Settings.Global.NITZ_UPDATE_DIFF,
Settings.Global.NITZ_UPDATE_SPACING,
Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
+ Settings.Global.NOTIFICATION_FEEDBACK_ENABLED,
Settings.Global.NR_NSA_TRACKING_SCREEN_OFF_MODE,
Settings.Global.NSD_ON,
Settings.Global.NTP_SERVER,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index aa96087..319b44c 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -320,19 +320,6 @@
<!-- Permissions required for CTS test - AdbManagerTest -->
<uses-permission android:name="android.permission.MANAGE_DEBUGGING" />
- <!-- Permissions required for ATS tests - AtsCarHostTestCases, AtsCarDeviceApp -->
- <uses-permission android:name="android.car.permission.CAR_DRIVING_STATE" />
- <!-- Permissions required for ATS tests - AtsDeviceInfo, AtsAudioDeviceTestCases -->
- <uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME" />
- <!-- Permissions required for ATS tests - AtsDeviceInfo -->
- <uses-permission android:name="android.car.permission.CAR_DIAGNOSTICS" />
- <!-- Permissions required for ATS tests - AtsDeviceInfo -->
- <uses-permission android:name="android.car.permission.CLEAR_CAR_DIAGNOSTICS" />
- <!-- Permissions required for ATS tests - AtsCarHostTestCases -->
- <uses-permission android:name="android.car.permission.CONTROL_APP_BLOCKING" />
- <!-- Permissions required for ATS tests - AtsCarHostTestCases -->
- <uses-permission android:name="android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION" />
-
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SimAppDialog/Android.bp b/packages/SimAppDialog/Android.bp
index 176035f..1c680bb 100644
--- a/packages/SimAppDialog/Android.bp
+++ b/packages/SimAppDialog/Android.bp
@@ -7,7 +7,8 @@
static_libs: [
"androidx.legacy_legacy-support-v4",
- "setup-wizard-lib",
+ "setupcompat",
+ "setupdesign",
],
resource_dirs: ["res"],
diff --git a/packages/SimAppDialog/AndroidManifest.xml b/packages/SimAppDialog/AndroidManifest.xml
index 873f6c5..e7368f3 100644
--- a/packages/SimAppDialog/AndroidManifest.xml
+++ b/packages/SimAppDialog/AndroidManifest.xml
@@ -23,7 +23,7 @@
android:name=".InstallCarrierAppActivity"
android:exported="true"
android:permission="android.permission.NETWORK_SETTINGS"
- android:theme="@style/SuwThemeGlif.Light">
+ android:theme="@style/SudThemeGlif.Light">
</activity>
</application>
</manifest>
diff --git a/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml b/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml
index 12f9bb6..68113db 100644
--- a/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml
+++ b/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml
@@ -14,18 +14,17 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.setupwizardlib.GlifLayout
+<com.google.android.setupdesign.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/setup_wizard_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:icon="@drawable/ic_signal_cellular_alt_rounded"
- app:suwHeaderText="@string/install_carrier_app_title"
- app:suwFooter="@layout/install_carrier_app_footer">
+ app:sucHeaderText="@string/install_carrier_app_title">
<LinearLayout
- style="@style/SuwContentFrame"
+ style="@style/SudContentFrame"
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -33,12 +32,12 @@
<TextView
android:id="@+id/install_carrier_app_description"
- style="@style/SuwDescription.Glif"
+ style="@style/SudDescription.Glif"
android:text="@string/install_carrier_app_description_default"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
- <com.android.setupwizardlib.view.FillContentLayout
+ <com.google.android.setupdesign.view.FillContentLayout
android:id="@+id/illo_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -47,12 +46,12 @@
<ImageView
android:src="@drawable/illo_sim_app_dialog"
- style="@style/SuwContentIllustration"
+ style="@style/SudContentIllustration"
android:contentDescription="@string/install_carrier_app_image_content_description"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
- </com.android.setupwizardlib.view.FillContentLayout>
-</LinearLayout>
+ </com.google.android.setupdesign.view.FillContentLayout>
+ </LinearLayout>
-</com.android.setupwizardlib.GlifLayout>
+</com.google.android.setupdesign.GlifLayout>
diff --git a/packages/SimAppDialog/res/layout/install_carrier_app_footer.xml b/packages/SimAppDialog/res/layout/install_carrier_app_footer.xml
deleted file mode 100644
index 10dcb77..0000000
--- a/packages/SimAppDialog/res/layout/install_carrier_app_footer.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<com.android.setupwizardlib.view.ButtonBarLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/footer"
- style="@style/SuwGlifButtonBar.Stackable"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <Button
- android:id="@+id/skip_button"
- style="@style/SuwGlifButton.Secondary"
- android:text="@string/install_carrier_app_defer_action"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1"/>
-
- <Button
- android:id="@+id/download_button"
- style="@style/SuwGlifButton.Primary"
- android:text="@string/install_carrier_app_download_action"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-</com.android.setupwizardlib.view.ButtonBarLayout>
diff --git a/packages/SimAppDialog/res/values/styles.xml b/packages/SimAppDialog/res/values/styles.xml
new file mode 100644
index 0000000..824e380
--- /dev/null
+++ b/packages/SimAppDialog/res/values/styles.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+
+ <style name="SetupWizardPartnerResource">
+ <!-- Disable to use partner overlay theme for outside setupwizard flow. -->
+ <item name="sucUsePartnerResource">false</item>
+ <!-- Enable heavy theme style inside setupwizard flow. -->
+ <item name="sudUsePartnerHeavyTheme">true</item>
+ </style>
+
+</resources>
diff --git a/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java b/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java
index abe82a8..0b6f9bb 100644
--- a/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java
+++ b/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java
@@ -17,14 +17,17 @@
import android.app.Activity;
import android.content.Intent;
+import android.content.res.Resources;
import android.os.Bundle;
import android.sysprop.SetupWizardProperties;
import android.text.TextUtils;
import android.view.View;
-import android.widget.Button;
import android.widget.TextView;
-import com.android.setupwizardlib.util.WizardManagerHelper;
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
+import com.google.android.setupdesign.GlifLayout;
+import com.google.android.setupdesign.util.ThemeResolver;
/**
* Activity that gives a user the choice to download the SIM app or defer until a later time
@@ -35,7 +38,7 @@
* Can display the carrier app name if its passed into the intent with key
* {@link #BUNDLE_KEY_CARRIER_NAME}
*/
-public class InstallCarrierAppActivity extends Activity implements View.OnClickListener {
+public class InstallCarrierAppActivity extends Activity {
/**
* Key for the carrier app name that will be displayed as the app to download. If unset, a
* default description will be used
@@ -50,20 +53,33 @@
protected void onCreate(Bundle icicle) {
// Setup theme for aosp/pixel
setTheme(
- WizardManagerHelper.getThemeRes(
- SetupWizardProperties.theme().orElse(""),
- R.style.SuwThemeGlif_Light
- )
- );
+ new ThemeResolver.Builder()
+ .setDefaultTheme(R.style.SudThemeGlifV3_Light)
+ .build()
+ .resolve(SetupWizardProperties.theme().orElse(""),
+ /* suppressDayNight= */ false));
super.onCreate(icicle);
setContentView(R.layout.install_carrier_app_activity);
- Button notNowButton = findViewById(R.id.skip_button);
- notNowButton.setOnClickListener(this);
+ GlifLayout layout = findViewById(R.id.setup_wizard_layout);
+ FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class);
+ mixin.setSecondaryButton(
+ new FooterButton.Builder(this)
+ .setText(R.string.install_carrier_app_defer_action)
+ .setListener(this::onSkipButtonClick)
+ .setButtonType(FooterButton.ButtonType.SKIP)
+ .setTheme(R.style.SudGlifButton_Secondary)
+ .build());
- Button downloadButton = findViewById(R.id.download_button);
- downloadButton.setOnClickListener(this);
+ mixin.setPrimaryButton(
+ new FooterButton.Builder(this)
+ .setText(R.string.install_carrier_app_download_action)
+ .setListener(this::onDownloadButtonClick)
+ .setButtonType(FooterButton.ButtonType.OTHER)
+ .setTheme(R.style.SudGlifButton_Primary)
+ .build());
+
// Show/hide illo depending on whether one was provided in a resource overlay
boolean showIllo = getResources().getBoolean(R.bool.show_sim_app_dialog_illo);
@@ -82,15 +98,17 @@
}
@Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.skip_button:
- finish(DEFER_RESULT);
- break;
- case R.id.download_button:
- finish(DOWNLOAD_RESULT);
- break;
- }
+ protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) {
+ theme.applyStyle(R.style.SetupWizardPartnerResource, true);
+ super.onApplyThemeResource(theme, resid, first);
+ }
+
+ protected void onSkipButtonClick(View view) {
+ finish(DEFER_RESULT);
+ }
+
+ protected void onDownloadButtonClick(View view) {
+ finish(DOWNLOAD_RESULT);
}
private void finish(int resultCode) {
diff --git a/packages/SystemUI/res/layout/media_view.xml b/packages/SystemUI/res/layout/media_view.xml
index 3c641af..ed870f8 100644
--- a/packages/SystemUI/res/layout/media_view.xml
+++ b/packages/SystemUI/res/layout/media_view.xml
@@ -210,8 +210,98 @@
android:layout_width="@dimen/qs_media_icon_size"
android:layout_height="@dimen/qs_media_icon_size" />
- <!-- Buttons to remove this view when no longer needed -->
- <include
- layout="@layout/qs_media_panel_options"
- android:visibility="gone" />
+ <!-- Constraints are set here as they are the same regardless of host -->
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/qs_media_panel_outer_padding"
+ android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
+ android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+ android:id="@+id/media_text"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:textColor="@color/media_primary_text"
+ android:text="@string/controls_media_title"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/remove_text"
+ app:layout_constraintVertical_chainStyle="spread_inside"/>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
+ android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+ android:id="@+id/remove_text"
+ android:fontFamily="@*android:string/config_headlineFontFamily"
+ android:singleLine="true"
+ android:textColor="@color/media_primary_text"
+ android:text="@string/controls_media_close_session"
+ app:layout_constraintTop_toBottomOf="@id/media_text"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/settings"/>
+
+ <FrameLayout
+ android:id="@+id/settings"
+ android:background="@drawable/qs_media_light_source"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
+ android:paddingBottom="@dimen/qs_media_panel_outer_padding"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/remove_text">
+
+ <TextView
+ android:layout_gravity="bottom"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:textColor="@android:color/white"
+ android:text="@string/controls_media_settings_button" />
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/cancel"
+ android:background="@drawable/qs_media_light_source"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+ android:paddingBottom="@dimen/qs_media_panel_outer_padding"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/dismiss" >
+
+ <TextView
+ android:layout_gravity="bottom"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:textColor="@android:color/white"
+ android:text="@string/cancel" />
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/dismiss"
+ android:background="@drawable/qs_media_light_source"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+ android:paddingBottom="@dimen/qs_media_panel_outer_padding"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent">
+
+ <TextView
+ android:layout_gravity="bottom"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:textColor="@android:color/white"
+ android:text="@string/controls_media_dismiss_button"
+ />
+ </FrameLayout>
</com.android.systemui.util.animation.TransitionLayout>
diff --git a/packages/SystemUI/res/layout/qs_media_panel_options.xml b/packages/SystemUI/res/layout/qs_media_panel_options.xml
deleted file mode 100644
index e72c0e8..0000000
--- a/packages/SystemUI/res/layout/qs_media_panel_options.xml
+++ /dev/null
@@ -1,61 +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
- -->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/qs_media_controls_options"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:padding="16dp"
- android:orientation="vertical">
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:layout_weight="1"
- android:minWidth="48dp"
- android:layout_gravity="start|bottom"
- android:gravity="bottom"
- android:id="@+id/remove"
- android:orientation="horizontal">
- <ImageView
- android:layout_width="18dp"
- android:layout_height="18dp"
- android:id="@+id/remove_icon"
- android:layout_marginEnd="16dp"
- android:tint="@color/media_primary_text"
- android:src="@drawable/ic_clear"/>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/remove_text"
- android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
- android:singleLine="true"
- android:textColor="@color/media_primary_text"
- android:text="@string/controls_media_close_session" />
- </LinearLayout>
- <TextView
- android:id="@+id/cancel"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:layout_weight="1"
- android:minWidth="48dp"
- android:layout_gravity="end|bottom"
- android:gravity="bottom"
- android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
- android:textColor="@android:color/white"
- android:text="@string/cancel" />
-</LinearLayout>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index fa620df..fba43a6 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -515,13 +515,11 @@
<!-- Whether or not to add a "people" notifications section -->
<bool name="config_usePeopleFiltering">false</bool>
- <!-- Defines the blacklist for system icons. That is to say, the icons in the status bar that
- are part of the blacklist are never displayed. Each item in the blacklist must be a string
- defined in core/res/res/config.xml to properly blacklist the icon.
-
- TODO: See if we can rename this config variable.
+ <!-- Defines system icons to be excluded from the display. That is to say, the icons in the
+ status bar that are part of this list are never displayed. Each item in the list must be a
+ string defined in core/res/res/config.xml to properly exclude the icon.
-->
- <string-array name="config_statusBarIconBlackList" translatable="false">
+ <string-array name="config_statusBarIconsToExclude" translatable="false">
<item>@*android:string/status_bar_rotate</item>
<item>@*android:string/status_bar_headset</item>
</string-array>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 77d3f45..823c1ff 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2799,7 +2799,7 @@
<!-- Explanation for closing controls associated with a specific media session [CHAR_LIMIT=NONE] -->
<string name="controls_media_close_session">Hide the current session.</string>
<!-- Label for a button that will hide media controls [CHAR_LIMIT=30] -->
- <string name="controls_media_dismiss_button">Hide</string>
+ <string name="controls_media_dismiss_button">Dismiss</string>
<!-- Label for button to resume media playback [CHAR_LIMIT=NONE] -->
<string name="controls_media_resume">Resume</string>
<!-- Label for button to go to media control settings screen [CHAR_LIMIT=30] -->
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index 816bcf8..d5f74a8 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -53,8 +53,8 @@
ActivityInfo.CONFIG_DENSITY | ActivityInfo.CONFIG_ORIENTATION;
@VisibleForTesting
- protected WindowMagnificationController mWindowMagnificationController;
- protected final ModeSwitchesController mModeSwitchesController;
+ protected WindowMagnificationAnimationController mWindowMagnificationAnimationController;
+ private final ModeSwitchesController mModeSwitchesController;
private final Handler mHandler;
private final AccessibilityManager mAccessibilityManager;
private final CommandQueue mCommandQueue;
@@ -72,6 +72,11 @@
Context.ACCESSIBILITY_SERVICE);
mCommandQueue = commandQueue;
mModeSwitchesController = modeSwitchesController;
+ final WindowMagnificationController controller = new WindowMagnificationController(mContext,
+ mHandler, new SfVsyncFrameCallbackProvider(), null,
+ new SurfaceControl.Transaction(), this);
+ mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
+ mContext, controller);
}
@Override
@@ -81,9 +86,7 @@
return;
}
mLastConfiguration.setTo(newConfig);
- if (mWindowMagnificationController != null) {
- mWindowMagnificationController.onConfigurationChanged(configDiff);
- }
+ mWindowMagnificationAnimationController.onConfigurationChanged(configDiff);
if (mModeSwitchesController != null) {
mModeSwitchesController.onConfigurationChanged(configDiff);
}
@@ -97,39 +100,25 @@
@MainThread
void enableWindowMagnification(int displayId, float scale, float centerX, float centerY) {
//TODO: b/144080869 support multi-display.
- if (mWindowMagnificationController == null) {
- mWindowMagnificationController = new WindowMagnificationController(mContext,
- mHandler,
- new SfVsyncFrameCallbackProvider(),
- null, new SurfaceControl.Transaction(),
- this);
- }
- mWindowMagnificationController.enableWindowMagnification(scale, centerX, centerY);
+ mWindowMagnificationAnimationController.enableWindowMagnification(scale, centerX, centerY);
}
@MainThread
void setScale(int displayId, float scale) {
//TODO: b/144080869 support multi-display.
- if (mWindowMagnificationController != null) {
- mWindowMagnificationController.setScale(scale);
- }
+ mWindowMagnificationAnimationController.setScale(scale);
}
@MainThread
void moveWindowMagnifier(int displayId, float offsetX, float offsetY) {
//TODO: b/144080869 support multi-display.
- if (mWindowMagnificationController != null) {
- mWindowMagnificationController.moveWindowMagnifier(offsetX, offsetY);
- }
+ mWindowMagnificationAnimationController.moveWindowMagnifier(offsetX, offsetY);
}
@MainThread
void disableWindowMagnification(int displayId) {
//TODO: b/144080869 support multi-display.
- if (mWindowMagnificationController != null) {
- mWindowMagnificationController.deleteWindowMagnification();
- }
- mWindowMagnificationController = null;
+ mWindowMagnificationAnimationController.deleteWindowMagnification();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
new file mode 100644
index 0000000..ae51623
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
@@ -0,0 +1,272 @@
+/*
+ * 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.accessibility;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.annotation.IntDef;
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.Log;
+import android.view.animation.AccelerateInterpolator;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Provides same functionality of {@link WindowMagnificationController}. Some methods run with
+ * the animation.
+ */
+class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUpdateListener,
+ Animator.AnimatorListener {
+
+ private static final String TAG = "WindowMagnificationBridge";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({STATE_DISABLED, STATE_ENABLED, STATE_DISABLING, STATE_ENABLING})
+ @interface MagnificationState {}
+
+ //The window magnification is disabled.
+ private static final int STATE_DISABLED = 0;
+ //The window magnification is enabled.
+ private static final int STATE_ENABLED = 1;
+ //The window magnification is going to be disabled when the animation is end.
+ private static final int STATE_DISABLING = 2;
+ //The animation is running for enabling the window magnification.
+ private static final int STATE_ENABLING = 3;
+
+ private final WindowMagnificationController mController;
+ private final ValueAnimator mValueAnimator;
+ private final AnimationSpec mStartSpec = new AnimationSpec();
+ private final AnimationSpec mEndSpec = new AnimationSpec();
+ private final Context mContext;
+
+ @MagnificationState
+ private int mState = STATE_DISABLED;
+
+ WindowMagnificationAnimationController(
+ Context context, WindowMagnificationController controller) {
+ this(context, controller, newValueAnimator(context.getResources()));
+ }
+
+ @VisibleForTesting
+ WindowMagnificationAnimationController(Context context,
+ WindowMagnificationController controller, ValueAnimator valueAnimator) {
+ mContext = context;
+ mController = controller;
+ mValueAnimator = valueAnimator;
+ mValueAnimator.addUpdateListener(this);
+ mValueAnimator.addListener(this);
+ }
+
+ /**
+ * Wraps {@link WindowMagnificationController#enableWindowMagnification(float, float, float)}
+ * with transition animation. If the window magnification is not enabled, the scale will start
+ * from 1.0 and the center won't be changed during the animation. If {@link #mState} is
+ * {@code STATE_DISABLING}, the animation runs in reverse.
+ *
+ * @param scale the target scale, or {@link Float#NaN} to leave unchanged.
+ * @param centerX the screen-relative X coordinate around which to center,
+ * or {@link Float#NaN} to leave unchanged.
+ * @param centerY the screen-relative Y coordinate around which to center,
+ * or {@link Float#NaN} to leave unchanged.
+ *
+ * @see #onAnimationUpdate(ValueAnimator)
+ */
+ void enableWindowMagnification(float scale, float centerX, float centerY) {
+ if (mState == STATE_ENABLING) {
+ mValueAnimator.cancel();
+ }
+ setupEnableAnimationSpecs(scale, centerX, centerY);
+
+ if (mEndSpec.equals(mStartSpec)) {
+ setState(STATE_ENABLED);
+ } else {
+ if (mState == STATE_DISABLING) {
+ mValueAnimator.reverse();
+ } else {
+ mValueAnimator.start();
+ }
+ setState(STATE_ENABLING);
+ }
+ }
+
+ private void setupEnableAnimationSpecs(float scale, float centerX, float centerY) {
+ final float currentScale = mController.getScale();
+ final float currentCenterX = mController.getCenterX();
+ final float currentCenterY = mController.getCenterY();
+
+ if (mState == STATE_DISABLED) {
+ //We don't need to offset the center during the animation.
+ mStartSpec.set(/* scale*/ 1.0f, centerX, centerY);
+ mEndSpec.set(Float.isNaN(scale) ? mContext.getResources().getInteger(
+ R.integer.magnification_default_scale) : scale, centerX, centerY);
+ } else {
+ mStartSpec.set(currentScale, currentCenterX, currentCenterY);
+ mEndSpec.set(Float.isNaN(scale) ? currentScale : scale,
+ Float.isNaN(centerX) ? currentCenterX : centerX,
+ Float.isNaN(centerY) ? currentCenterY : centerY);
+ }
+ if (DEBUG) {
+ Log.d(TAG, "SetupEnableAnimationSpecs : mStartSpec = " + mStartSpec + ", endSpec = "
+ + mEndSpec);
+ }
+ }
+
+ /**
+ * Wraps {@link WindowMagnificationController#setScale(float)}. If the animation is
+ * running, it has no effect.
+ */
+ void setScale(float scale) {
+ if (mValueAnimator.isRunning()) {
+ return;
+ }
+ mController.setScale(scale);
+ }
+
+ /**
+ * Wraps {@link WindowMagnificationController#deleteWindowMagnification()}} with transition
+ * animation. If the window magnification is enabling, it runs the animation in reverse.
+ */
+ void deleteWindowMagnification() {
+ if (mState == STATE_DISABLED || mState == STATE_DISABLING) {
+ return;
+ }
+ mStartSpec.set(/* scale*/ 1.0f, Float.NaN, Float.NaN);
+ mEndSpec.set(/* scale*/ mController.getScale(), Float.NaN, Float.NaN);
+
+ mValueAnimator.reverse();
+ setState(STATE_DISABLING);
+ }
+
+ /**
+ * Wraps {@link WindowMagnificationController#moveWindowMagnifier(float, float)}. If the
+ * animation is running, it has no effect.
+ * @param offsetX the amount in pixels to offset the window magnifier in the X direction, in
+ * current screen pixels.
+ * @param offsetY the amount in pixels to offset the window magnifier in the Y direction, in
+ * current screen pixels.
+ */
+ void moveWindowMagnifier(float offsetX, float offsetY) {
+ if (mValueAnimator.isRunning()) {
+ return;
+ }
+ mController.moveWindowMagnifier(offsetX, offsetY);
+ }
+
+ void onConfigurationChanged(int configDiff) {
+ mController.onConfigurationChanged(configDiff);
+ }
+
+ private void setState(@MagnificationState int state) {
+ if (DEBUG) {
+ Log.d(TAG, "setState from " + mState + " to " + state);
+ }
+ mState = state;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mState == STATE_DISABLING) {
+ mController.deleteWindowMagnification();
+ setState(STATE_DISABLED);
+ } else if (mState == STATE_ENABLING) {
+ setState(STATE_ENABLED);
+ } else {
+ Log.w(TAG, "onAnimationEnd unexpected state:" + mState);
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final float fract = animation.getAnimatedFraction();
+ final float sentScale = mStartSpec.mScale + (mEndSpec.mScale - mStartSpec.mScale) * fract;
+ final float centerX =
+ mStartSpec.mCenterX + (mEndSpec.mCenterX - mStartSpec.mCenterX) * fract;
+ final float centerY =
+ mStartSpec.mCenterY + (mEndSpec.mCenterY - mStartSpec.mCenterY) * fract;
+ mController.enableWindowMagnification(sentScale, centerX, centerY);
+ }
+
+ private static ValueAnimator newValueAnimator(Resources resources) {
+ final ValueAnimator valueAnimator = new ValueAnimator();
+ valueAnimator.setDuration(
+ resources.getInteger(com.android.internal.R.integer.config_longAnimTime));
+ valueAnimator.setInterpolator(new AccelerateInterpolator(2.5f));
+ valueAnimator.setFloatValues(0.0f, 1.0f);
+ return valueAnimator;
+ }
+
+ private static class AnimationSpec {
+ private float mScale = Float.NaN;
+ private float mCenterX = Float.NaN;
+ private float mCenterY = Float.NaN;
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+
+ if (other == null || getClass() != other.getClass()) {
+ return false;
+ }
+
+ final AnimationSpec s = (AnimationSpec) other;
+ return mScale == s.mScale && mCenterX == s.mCenterX && mCenterY == s.mCenterY;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (mScale != +0.0f ? Float.floatToIntBits(mScale) : 0);
+ result = 31 * result + (mCenterX != +0.0f ? Float.floatToIntBits(mCenterX) : 0);
+ result = 31 * result + (mCenterY != +0.0f ? Float.floatToIntBits(mCenterY) : 0);
+ return result;
+ }
+
+ void set(float scale, float centerX, float centerY) {
+ mScale = scale;
+ mCenterX = centerX;
+ mCenterY = centerY;
+ }
+
+ @Override
+ public String toString() {
+ return "AnimationSpec{"
+ + "mScale=" + mScale
+ + ", mCenterX=" + mCenterX
+ + ", mCenterY=" + mCenterY
+ + '}';
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 798b751..6d3e8ba 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -150,7 +150,7 @@
mMirrorViewGeometryVsyncCallback =
l -> {
- if (mMirrorView != null && mMirrorSurface != null) {
+ if (isWindowVisible() && mMirrorSurface != null) {
calculateSourceBounds(mMagnificationFrame, mScale);
// The final destination for the magnification surface should be at 0,0
// since the ViewRootImpl's position will change
@@ -502,7 +502,7 @@
/**
* Enables window magnification with specified parameters.
*
- * @param scale the target scale
+ * @param scale the target scale, or {@link Float#NaN} to leave unchanged
* @param centerX the screen-relative X coordinate around which to center,
* or {@link Float#NaN} to leave unchanged.
* @param centerY the screen-relative Y coordinate around which to center,
@@ -513,10 +513,10 @@
: centerX - mMagnificationFrame.exactCenterX();
final float offsetY = Float.isNaN(centerY) ? 0
: centerY - mMagnificationFrame.exactCenterY();
- mScale = scale;
+ mScale = Float.isNaN(scale) ? mScale : scale;
setMagnificationFrameBoundary();
updateMagnificationFramePosition((int) offsetX, (int) offsetY);
- if (mMirrorView == null) {
+ if (!isWindowVisible()) {
createMirrorWindow();
showControls();
} else {
@@ -527,10 +527,10 @@
/**
* Sets the scale of the magnified region if it's visible.
*
- * @param scale the target scale
+ * @param scale the target scale, or {@link Float#NaN} to leave unchanged
*/
void setScale(float scale) {
- if (mMirrorView == null || mScale == scale) {
+ if (!isWindowVisible() || mScale == scale) {
return;
}
enableWindowMagnification(scale, Float.NaN, Float.NaN);
@@ -552,4 +552,35 @@
modifyWindowMagnification(mTransaction);
}
}
+
+ /**
+ * Gets the scale.
+ * @return {@link Float#NaN} if the window is invisible.
+ */
+ float getScale() {
+ return isWindowVisible() ? mScale : Float.NaN;
+ }
+
+ /**
+ * Returns the screen-relative X coordinate of the center of the magnified bounds.
+ *
+ * @return the X coordinate. {@link Float#NaN} if the window is invisible.
+ */
+ float getCenterX() {
+ return isWindowVisible() ? mMagnificationFrame.exactCenterX() : Float.NaN;
+ }
+
+ /**
+ * Returns the screen-relative Y coordinate of the center of the magnified bounds.
+ *
+ * @return the Y coordinate. {@link Float#NaN} if the window is invisible.
+ */
+ float getCenterY() {
+ return isWindowVisible() ? mMagnificationFrame.exactCenterY() : Float.NaN;
+ }
+
+ //The window is visible when it is existed.
+ private boolean isWindowVisible() {
+ return mMirrorView != null;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index 4df6660..6512624 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -281,9 +281,11 @@
* @return {@code true} iff the app-op for should be shown to the user
*/
private boolean isUserVisible(int appOpCode, int uid, String packageName) {
- // currently OP_SYSTEM_ALERT_WINDOW does not correspond to a platform permission
- // which may be user senstive, so for now always show it to the user.
- if (appOpCode == AppOpsManager.OP_SYSTEM_ALERT_WINDOW) {
+ // currently OP_SYSTEM_ALERT_WINDOW and OP_MONITOR_HIGH_POWER_LOCATION
+ // 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) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 8748926..27863ba 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -697,6 +697,9 @@
pw.print(" desiredHeight: "); pw.println(getDesiredHeightString());
pw.print(" suppressNotif: "); pw.println(shouldSuppressNotification());
pw.print(" autoExpand: "); pw.println(shouldAutoExpand());
+ if (mExpandedView != null) {
+ mExpandedView.dump(fd, pw, args);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index bb57219..c5639ea 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -84,6 +84,7 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dumpable;
+import com.android.systemui.bubbles.animation.StackAnimationController;
import com.android.systemui.bubbles.dagger.BubbleModule;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.model.SysUiState;
@@ -173,6 +174,12 @@
@Nullable private BubbleStackView mStackView;
private BubbleIconFactory mBubbleIconFactory;
+ /**
+ * The relative position of the stack when we removed it and nulled it out. If the stack is
+ * re-created, it will re-appear at this position.
+ */
+ @Nullable private BubbleStackView.RelativeStackPosition mPositionFromRemovedStack;
+
// Tracks the id of the current (foreground) user.
private int mCurrentUserId;
// Saves notification keys of active bubbles when users are switched.
@@ -736,6 +743,7 @@
mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator,
mSysUiState, this::onAllBubblesAnimatedOut, this::onImeVisibilityChanged,
this::hideCurrentInputMethod);
+ mStackView.setStackStartPosition(mPositionFromRemovedStack);
mStackView.addView(mBubbleScrim);
if (mExpandListener != null) {
mStackView.setExpandListener(mExpandListener);
@@ -806,6 +814,7 @@
try {
mAddedToWindowManager = false;
if (mStackView != null) {
+ mPositionFromRemovedStack = mStackView.getRelativeStackPosition();
mWindowManager.removeView(mStackView);
mStackView.removeView(mBubbleScrim);
mStackView = null;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 318a987..d0f6181 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -34,6 +34,7 @@
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.ActivityOptions;
@@ -77,6 +78,9 @@
import com.android.systemui.recents.TriangleShape;
import com.android.systemui.statusbar.AlphaOptimizedButton;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
/**
* Container for the expanded bubble view, handles rendering the caret and settings icon.
*/
@@ -593,14 +597,17 @@
*/
void update(Bubble bubble) {
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "update: bubble=" + (bubble != null ? bubble.getKey() : "null"));
+ Log.d(TAG, "update: bubble=" + bubble);
+ }
+ if (mStackView == null) {
+ Log.w(TAG, "Stack is null for bubble: " + bubble);
+ return;
}
boolean isNew = mBubble == null || didBackingContentChange(bubble);
if (isNew || bubble != null && bubble.getKey().equals(mBubble.getKey())) {
mBubble = bubble;
mSettingsIcon.setContentDescription(getResources().getString(
R.string.bubbles_settings_button_description, bubble.getAppName()));
-
mSettingsIcon.setAccessibilityDelegate(
new AccessibilityDelegate() {
@Override
@@ -808,4 +815,15 @@
}
return null;
}
+
+ /**
+ * Description of current expanded view state.
+ */
+ public void dump(
+ @NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.print("BubbleExpandedView");
+ pw.print(" taskId: "); pw.println(mTaskId);
+ pw.print(" activityViewStatus: "); pw.println(mActivityViewStatus);
+ pw.print(" stackView: "); pw.println(mStackView);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index b3fbfd6..ec9644a 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -253,13 +253,8 @@
/** Layout change listener that moves the stack to the nearest valid position on rotation. */
private OnLayoutChangeListener mOrientationChangedListener;
- /** Whether the stack was on the left side of the screen prior to rotation. */
- private boolean mWasOnLeftBeforeRotation = false;
- /**
- * How far down the screen the stack was before rotation, in terms of percentage of the way down
- * the allowable region. Defaults to -1 if not set.
- */
- private float mVerticalPosPercentBeforeRotation = -1;
+
+ @Nullable private RelativeStackPosition mRelativeStackPositionBeforeRotation;
private int mMaxBubbles;
private int mBubbleSize;
@@ -940,9 +935,10 @@
mExpandedViewContainer.setTranslationY(getExpandedViewY());
mExpandedViewContainer.setAlpha(1f);
}
- if (mVerticalPosPercentBeforeRotation >= 0) {
- mStackAnimationController.moveStackToSimilarPositionAfterRotation(
- mWasOnLeftBeforeRotation, mVerticalPosPercentBeforeRotation);
+ if (mRelativeStackPositionBeforeRotation != null) {
+ mStackAnimationController.setStackPosition(
+ mRelativeStackPositionBeforeRotation);
+ mRelativeStackPositionBeforeRotation = null;
}
removeOnLayoutChangeListener(mOrientationChangedListener);
};
@@ -1189,13 +1185,7 @@
com.android.internal.R.dimen.status_bar_height);
mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
- final RectF allowablePos = mStackAnimationController.getAllowableStackPositionRegion();
- mWasOnLeftBeforeRotation = mStackAnimationController.isStackOnLeftSide();
- mVerticalPosPercentBeforeRotation =
- (mStackAnimationController.getStackPosition().y - allowablePos.top)
- / (allowablePos.bottom - allowablePos.top);
- mVerticalPosPercentBeforeRotation =
- Math.max(0f, Math.min(1f, mVerticalPosPercentBeforeRotation));
+ mRelativeStackPositionBeforeRotation = mStackAnimationController.getRelativeStackPosition();
addOnLayoutChangeListener(mOrientationChangedListener);
hideFlyoutImmediate();
@@ -1459,7 +1449,7 @@
if (getBubbleCount() == 0 && mShouldShowUserEducation) {
// Override the default stack position if we're showing user education.
mStackAnimationController.setStackPosition(
- mStackAnimationController.getDefaultStartPosition());
+ mStackAnimationController.getStartPosition());
}
if (getBubbleCount() == 0) {
@@ -1674,7 +1664,7 @@
// Post so we have height of mUserEducationView
mUserEducationView.post(() -> {
final int viewHeight = mUserEducationView.getHeight();
- PointF stackPosition = mStackAnimationController.getDefaultStartPosition();
+ PointF stackPosition = mStackAnimationController.getStartPosition();
final float translationY = stackPosition.y + (mBubbleSize / 2) - (viewHeight / 2);
mUserEducationView.setTranslationY(translationY);
mUserEducationView.animate()
@@ -2740,10 +2730,18 @@
.floatValue();
}
+ public void setStackStartPosition(RelativeStackPosition position) {
+ mStackAnimationController.setStackStartPosition(position);
+ }
+
public PointF getStackPosition() {
return mStackAnimationController.getStackPosition();
}
+ public RelativeStackPosition getRelativeStackPosition() {
+ return mStackAnimationController.getRelativeStackPosition();
+ }
+
/**
* Logs the bubble UI event.
*
@@ -2797,4 +2795,47 @@
}
return bubbles;
}
+
+ /**
+ * Representation of stack position that uses relative properties rather than absolute
+ * coordinates. This is used to maintain similar stack positions across configuration changes.
+ */
+ public static class RelativeStackPosition {
+ /** Whether to place the stack at the leftmost allowed position. */
+ private boolean mOnLeft;
+
+ /**
+ * How far down the vertically allowed region to place the stack. For example, if the stack
+ * allowed region is between y = 100 and y = 1100 and this is 0.2f, we'll place the stack at
+ * 100 + (0.2f * 1000) = 300.
+ */
+ private float mVerticalOffsetPercent;
+
+ public RelativeStackPosition(boolean onLeft, float verticalOffsetPercent) {
+ mOnLeft = onLeft;
+ mVerticalOffsetPercent = clampVerticalOffsetPercent(verticalOffsetPercent);
+ }
+
+ /** Constructs a relative position given a region and a point in that region. */
+ public RelativeStackPosition(PointF position, RectF region) {
+ mOnLeft = position.x < region.width() / 2;
+ mVerticalOffsetPercent =
+ clampVerticalOffsetPercent((position.y - region.top) / region.height());
+ }
+
+ /** Ensures that the offset percent is between 0f and 1f. */
+ private float clampVerticalOffsetPercent(float offsetPercent) {
+ return Math.max(0f, Math.min(1f, offsetPercent));
+ }
+
+ /**
+ * Given an allowable stack position region, returns the point within that region
+ * represented by this relative position.
+ */
+ public PointF getAbsolutePositionInRegion(RectF region) {
+ return new PointF(
+ mOnLeft ? region.left : region.right,
+ region.top + mVerticalOffsetPercent * region.height());
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
index 1929fc4..5749169 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
@@ -103,11 +103,12 @@
@Override
protected void onPostExecute(BubbleViewInfo viewInfo) {
- if (viewInfo != null) {
- mBubble.setViewInfo(viewInfo);
- if (mCallback != null && !isCancelled()) {
- mCallback.onBubbleViewsReady(mBubble);
- }
+ if (isCancelled() || viewInfo == null) {
+ return;
+ }
+ mBubble.setViewInfo(viewInfo);
+ if (mCallback != null) {
+ mCallback.onBubbleViewsReady(mBubble);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index b378469..e835ea2 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -35,6 +35,7 @@
import androidx.dynamicanimation.animation.SpringForce;
import com.android.systemui.R;
+import com.android.systemui.bubbles.BubbleStackView;
import com.android.systemui.util.FloatingContentCoordinator;
import com.android.systemui.util.animation.PhysicsAnimator;
import com.android.systemui.util.magnetictarget.MagnetizedObject;
@@ -125,6 +126,9 @@
*/
private Rect mAnimatingToBounds = new Rect();
+ /** Initial starting location for the stack. */
+ @Nullable private BubbleStackView.RelativeStackPosition mStackStartPosition;
+
/** Whether or not the stack's start position has been set. */
private boolean mStackMovedToStartPosition = false;
@@ -431,21 +435,6 @@
return stackPos;
}
- /**
- * Moves the stack in response to rotation. We keep it in the most similar position by keeping
- * it on the same side, and positioning it the same percentage of the way down the screen
- * (taking status bar/nav bar into account by using the allowable region's height).
- */
- public void moveStackToSimilarPositionAfterRotation(boolean wasOnLeft, float verticalPercent) {
- final RectF allowablePos = getAllowableStackPositionRegion();
- final float allowableRegionHeight = allowablePos.bottom - allowablePos.top;
-
- final float x = wasOnLeft ? allowablePos.left : allowablePos.right;
- final float y = (allowableRegionHeight * verticalPercent) + allowablePos.top;
-
- setStackPosition(new PointF(x, y));
- }
-
/** Description of current animation controller state. */
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("StackAnimationController state:");
@@ -815,7 +804,7 @@
} else {
// When all children are removed ensure stack position is sane
setStackPosition(mRestingStackPosition == null
- ? getDefaultStartPosition()
+ ? getStartPosition()
: mRestingStackPosition);
// Remove the stack from the coordinator since we don't have any bubbles and aren't
@@ -868,7 +857,7 @@
mLayout.setVisibility(View.INVISIBLE);
mLayout.post(() -> {
setStackPosition(mRestingStackPosition == null
- ? getDefaultStartPosition()
+ ? getStartPosition()
: mRestingStackPosition);
mStackMovedToStartPosition = true;
mLayout.setVisibility(View.VISIBLE);
@@ -938,15 +927,47 @@
}
}
- /** Returns the default stack position, which is on the top left. */
- public PointF getDefaultStartPosition() {
- boolean isRtl = mLayout != null
- && mLayout.getResources().getConfiguration().getLayoutDirection()
- == View.LAYOUT_DIRECTION_RTL;
- return new PointF(isRtl
- ? getAllowableStackPositionRegion().right
- : getAllowableStackPositionRegion().left,
- getAllowableStackPositionRegion().top + mStackStartingVerticalOffset);
+ public void setStackPosition(BubbleStackView.RelativeStackPosition position) {
+ setStackPosition(position.getAbsolutePositionInRegion(getAllowableStackPositionRegion()));
+ }
+
+ public BubbleStackView.RelativeStackPosition getRelativeStackPosition() {
+ return new BubbleStackView.RelativeStackPosition(
+ mStackPosition, getAllowableStackPositionRegion());
+ }
+
+ /**
+ * Sets the starting position for the stack, where it will be located when the first bubble is
+ * added.
+ */
+ public void setStackStartPosition(BubbleStackView.RelativeStackPosition position) {
+ mStackStartPosition = position;
+ }
+
+ /**
+ * Returns the starting stack position. If {@link #setStackStartPosition} was called, this will
+ * return that position - otherwise, a reasonable default will be returned.
+ */
+ @Nullable public PointF getStartPosition() {
+ if (mLayout == null) {
+ return null;
+ }
+
+ if (mStackStartPosition == null) {
+ // Start on the left if we're in LTR, right otherwise.
+ final boolean startOnLeft =
+ mLayout.getResources().getConfiguration().getLayoutDirection()
+ != View.LAYOUT_DIRECTION_RTL;
+
+ final float startingVerticalOffset = mLayout.getResources().getDimensionPixelOffset(
+ R.dimen.bubble_stack_starting_offset_y);
+
+ mStackStartPosition = new BubbleStackView.RelativeStackPosition(
+ startOnLeft,
+ startingVerticalOffset / getAllowableStackPositionRegion().height());
+ }
+
+ return mStackStartPosition.getAbsolutePositionInRegion(getAllowableStackPositionRegion());
}
private boolean isStackPositionSet() {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/CustomIconCache.kt b/packages/SystemUI/src/com/android/systemui/controls/CustomIconCache.kt
new file mode 100644
index 0000000..cca0f16
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/CustomIconCache.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls
+
+import android.content.ComponentName
+import android.graphics.drawable.Icon
+import androidx.annotation.GuardedBy
+import javax.inject.Inject
+import javax.inject.Singleton
+
+/**
+ * Icon cache for custom icons sent with controls.
+ *
+ * It assumes that only one component can be current at the time, to minimize the number of icons
+ * stored at a given time.
+ */
+@Singleton
+class CustomIconCache @Inject constructor() {
+
+ private var currentComponent: ComponentName? = null
+ @GuardedBy("cache")
+ private val cache: MutableMap<String, Icon> = LinkedHashMap()
+
+ /**
+ * Store an icon in the cache.
+ *
+ * If the icons currently stored do not correspond to the component to be stored, the cache is
+ * cleared first.
+ */
+ fun store(component: ComponentName, controlId: String, icon: Icon?) {
+ if (component != currentComponent) {
+ clear()
+ currentComponent = component
+ }
+ synchronized(cache) {
+ if (icon != null) {
+ cache.put(controlId, icon)
+ } else {
+ cache.remove(controlId)
+ }
+ }
+ }
+
+ /**
+ * Retrieves a custom icon stored in the cache.
+ *
+ * It will return null if the component requested is not the one whose icons are stored, or if
+ * there is no icon cached for that id.
+ */
+ fun retrieve(component: ComponentName, controlId: String): Icon? {
+ if (component != currentComponent) return null
+ return synchronized(cache) {
+ cache.get(controlId)
+ }
+ }
+
+ private fun clear() {
+ synchronized(cache) {
+ cache.clear()
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
index ff40a8a..f68388d 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
@@ -29,6 +29,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.android.systemui.R
import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.controls.CustomIconCache
import com.android.systemui.controls.controller.ControlsControllerImpl
import com.android.systemui.controls.controller.StructureInfo
import com.android.systemui.globalactions.GlobalActionsComponent
@@ -42,7 +43,8 @@
class ControlsEditingActivity @Inject constructor(
private val controller: ControlsControllerImpl,
broadcastDispatcher: BroadcastDispatcher,
- private val globalActionsComponent: GlobalActionsComponent
+ private val globalActionsComponent: GlobalActionsComponent,
+ private val customIconCache: CustomIconCache
) : LifecycleActivity() {
companion object {
@@ -170,7 +172,7 @@
private fun setUpList() {
val controls = controller.getFavoritesForStructure(component, structure)
- model = FavoritesModel(component, controls, favoritesModelCallback)
+ model = FavoritesModel(customIconCache, component, controls, favoritesModelCallback)
val elevation = resources.getFloat(R.dimen.control_card_elevation)
val recyclerView = requireViewById<RecyclerView>(R.id.list)
recyclerView.alpha = 0.0f
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt
index 4ef64a5..ad0e7a5 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt
@@ -114,11 +114,27 @@
val controlStatus: ControlStatus
) : ElementWrapper(), ControlInterface by controlStatus
+private fun nullIconGetter(_a: ComponentName, _b: String): Icon? = null
+
data class ControlInfoWrapper(
override val component: ComponentName,
val controlInfo: ControlInfo,
override var favorite: Boolean
) : ElementWrapper(), ControlInterface {
+
+ var customIconGetter: (ComponentName, String) -> Icon? = ::nullIconGetter
+ private set
+
+ // Separate constructor so the getter is not used in auto-generated methods
+ constructor(
+ component: ComponentName,
+ controlInfo: ControlInfo,
+ favorite: Boolean,
+ customIconGetter: (ComponentName, String) -> Icon?
+ ): this(component, controlInfo, favorite) {
+ this.customIconGetter = customIconGetter
+ }
+
override val controlId: String
get() = controlInfo.controlId
override val title: CharSequence
@@ -128,8 +144,7 @@
override val deviceType: Int
get() = controlInfo.deviceType
override val customIcon: Icon?
- // Will need to address to support for edit activity
- get() = null
+ get() = customIconGetter(component, controlId)
}
data class DividerWrapper(
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt
index 5242501..f9ce636 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt
@@ -21,6 +21,7 @@
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import com.android.systemui.controls.ControlInterface
+import com.android.systemui.controls.CustomIconCache
import com.android.systemui.controls.controller.ControlInfo
import java.util.Collections
@@ -35,6 +36,7 @@
* @property favoritesModelCallback callback to notify on first change and empty favorites
*/
class FavoritesModel(
+ private val customIconCache: CustomIconCache,
private val componentName: ComponentName,
favorites: List<ControlInfo>,
private val favoritesModelCallback: FavoritesModelCallback
@@ -83,7 +85,7 @@
}
override val elements: List<ElementWrapper> = favorites.map {
- ControlInfoWrapper(componentName, it, true)
+ ControlInfoWrapper(componentName, it, true, customIconCache::retrieve)
} + DividerWrapper()
/**
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
index 22d6b6b..e15380b 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
@@ -92,7 +92,7 @@
override fun setValue(cvh: ControlViewHolder, templateId: String, newValue: Float) {
bouncerOrRun(Action(cvh.cws.ci.controlId, {
cvh.action(FloatAction(templateId, newValue))
- }, true /* blockable */))
+ }, false /* blockable */))
}
override fun longPress(cvh: ControlViewHolder) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 1eb7e21..5f75c96 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -44,6 +44,7 @@
import android.widget.TextView
import com.android.systemui.R
import com.android.systemui.controls.ControlsServiceInfo
+import com.android.systemui.controls.CustomIconCache
import com.android.systemui.controls.controller.ControlInfo
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.controller.StructureInfo
@@ -75,7 +76,8 @@
@Main val sharedPreferences: SharedPreferences,
val controlActionCoordinator: ControlActionCoordinator,
private val activityStarter: ActivityStarter,
- private val shadeController: ShadeController
+ private val shadeController: ShadeController,
+ private val iconCache: CustomIconCache
) : ControlsUiController {
companion object {
@@ -502,6 +504,7 @@
controls.forEach { c ->
controlsById.get(ControlKey(componentName, c.getControlId()))?.let {
Log.d(ControlsUiController.TAG, "onRefreshState() for id: " + c.getControlId())
+ iconCache.store(componentName, c.controlId, c.customIcon)
val cws = ControlWithState(componentName, it.ci, c)
val key = ControlKey(componentName, c.getControlId())
controlsById.put(key, cws)
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
index 900c11f..9fdbb6d 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
@@ -29,7 +29,6 @@
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyguard.KeyguardSliceProvider;
import com.android.systemui.onehanded.dagger.OneHandedModule;
-import com.android.systemui.pip.phone.PipMenuActivity;
import com.android.systemui.pip.phone.dagger.PipModule;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.InjectionInflationController;
@@ -133,9 +132,4 @@
* Member injection into the supplied argument.
*/
void inject(KeyguardSliceProvider keyguardSliceProvider);
-
- /**
- * Member injection into the supplied argument.
- */
- void inject(PipMenuActivity pipMenuActivity);
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index de53168..7f610d1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -3,7 +3,6 @@
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
-import android.graphics.Color
import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS
import android.util.Log
import android.util.MathUtils
@@ -151,7 +150,7 @@
pageIndicator = mediaFrame.requireViewById(R.id.media_page_indicator)
mediaCarouselScrollHandler = MediaCarouselScrollHandler(mediaCarousel, pageIndicator,
executor, mediaManager::onSwipeToDismiss, this::updatePageIndicatorLocation,
- falsingManager)
+ this::closeGuts, falsingManager)
isRtl = context.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL
inflateSettingsButton()
mediaContent = mediaCarousel.requireViewById(R.id.media_carousel)
@@ -470,6 +469,12 @@
}
}
+ fun closeGuts() {
+ mediaPlayers.values.forEach {
+ it.closeGuts(true)
+ }
+ }
+
/**
* Update the size of the carousel, remeasuring it if necessary.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
index 3096908..77cac50 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
@@ -56,6 +56,7 @@
private val mainExecutor: DelayableExecutor,
private val dismissCallback: () -> Unit,
private var translationChangedListener: () -> Unit,
+ private val closeGuts: () -> Unit,
private val falsingManager: FalsingManager
) {
/**
@@ -452,6 +453,7 @@
val nowScrolledIn = scrollIntoCurrentMedia != 0
if (newIndex != activeMediaIndex || wasScrolledIn != nowScrolledIn) {
activeMediaIndex = newIndex
+ closeGuts()
updatePlayerVisibilities()
}
val relativeLocation = activeMediaIndex.toFloat() + if (playerWidthPlusPadding > 0)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 3fc162e..e55678dc 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -16,6 +16,8 @@
package com.android.systemui.media;
+import static android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS;
+
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
@@ -45,6 +47,7 @@
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import com.android.systemui.util.animation.TransitionLayout;
import java.util.List;
@@ -52,6 +55,8 @@
import javax.inject.Inject;
+import dagger.Lazy;
+
/**
* A view controller used for Media Playback.
*/
@@ -59,6 +64,8 @@
private static final String TAG = "MediaControlPanel";
private static final float DISABLED_ALPHA = 0.38f;
+ private static final Intent SETTINGS_INTENT = new Intent(ACTION_MEDIA_CONTROLS_SETTINGS);
+
// Button IDs for QS controls
static final int[] ACTION_IDS = {
R.id.action0,
@@ -78,6 +85,8 @@
private MediaViewController mMediaViewController;
private MediaSession.Token mToken;
private MediaController mController;
+ private KeyguardDismissUtil mKeyguardDismissUtil;
+ private Lazy<MediaDataManager> mMediaDataManagerLazy;
private int mBackgroundColor;
private int mAlbumArtSize;
private int mAlbumArtRadius;
@@ -93,12 +102,15 @@
@Inject
public MediaControlPanel(Context context, @Background Executor backgroundExecutor,
ActivityStarter activityStarter, MediaViewController mediaViewController,
- SeekBarViewModel seekBarViewModel) {
+ SeekBarViewModel seekBarViewModel, Lazy<MediaDataManager> lazyMediaDataManager,
+ KeyguardDismissUtil keyguardDismissUtil) {
mContext = context;
mBackgroundExecutor = backgroundExecutor;
mActivityStarter = activityStarter;
mSeekBarViewModel = seekBarViewModel;
mMediaViewController = mediaViewController;
+ mMediaDataManagerLazy = lazyMediaDataManager;
+ mKeyguardDismissUtil = keyguardDismissUtil;
loadDimens();
mViewOutlineProvider = new ViewOutlineProvider() {
@@ -174,6 +186,21 @@
mSeekBarViewModel.getProgress().observeForever(mSeekBarObserver);
mSeekBarViewModel.attachTouchHandlers(vh.getSeekBar());
mMediaViewController.attach(player);
+
+ mViewHolder.getPlayer().setOnLongClickListener(v -> {
+ if (!mMediaViewController.isGutsVisible()) {
+ mMediaViewController.openGuts();
+ return true;
+ } else {
+ return false;
+ }
+ });
+ mViewHolder.getCancel().setOnClickListener(v -> {
+ closeGuts();
+ });
+ mViewHolder.getSettings().setOnClickListener(v -> {
+ mActivityStarter.startActivity(SETTINGS_INTENT, true /* dismissShade */);
+ });
}
/**
@@ -205,6 +232,7 @@
PendingIntent clickIntent = data.getClickIntent();
if (clickIntent != null) {
mViewHolder.getPlayer().setOnClickListener(v -> {
+ if (mMediaViewController.isGutsVisible()) return;
mActivityStarter.postStartActivityDismissingKeyguard(clickIntent);
});
}
@@ -329,14 +357,38 @@
final MediaController controller = getController();
mBackgroundExecutor.execute(() -> mSeekBarViewModel.updateController(controller));
- // Set up long press menu
- // TODO: b/156036025 bring back media guts
+ // Dismiss
+ mViewHolder.getDismiss().setOnClickListener(v -> {
+ if (data.getNotificationKey() != null) {
+ closeGuts();
+ mKeyguardDismissUtil.executeWhenUnlocked(() -> {
+ mMediaDataManagerLazy.get().dismissMediaData(data.getNotificationKey(),
+ MediaViewController.GUTS_ANIMATION_DURATION + 100);
+ return true;
+ }, /* requiresShadeOpen */ true);
+ } else {
+ Log.w(TAG, "Dismiss media with null notification. Token uid="
+ + data.getToken().getUid());
+ }
+ });
// TODO: We don't need to refresh this state constantly, only if the state actually changed
// to something which might impact the measurement
mMediaViewController.refreshState();
}
+ /**
+ * Close the guts for this player.
+ * @param immediate {@code true} if it should be closed without animation
+ */
+ public void closeGuts(boolean immediate) {
+ mMediaViewController.closeGuts(immediate);
+ }
+
+ private void closeGuts() {
+ closeGuts(false);
+ }
+
@UiThread
private Drawable scaleDrawable(Icon icon) {
if (icon == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index d82150f2..8a51c85 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -48,6 +48,7 @@
import com.android.systemui.statusbar.notification.row.HybridGroupManager
import com.android.systemui.util.Assert
import com.android.systemui.util.Utils
+import com.android.systemui.util.concurrency.DelayableExecutor
import java.io.FileDescriptor
import java.io.IOException
import java.io.PrintWriter
@@ -90,7 +91,7 @@
class MediaDataManager(
private val context: Context,
@Background private val backgroundExecutor: Executor,
- @Main private val foregroundExecutor: Executor,
+ @Main private val foregroundExecutor: DelayableExecutor,
private val mediaControllerFactory: MediaControllerFactory,
private val broadcastDispatcher: BroadcastDispatcher,
dumpManager: DumpManager,
@@ -107,7 +108,7 @@
constructor(
context: Context,
@Background backgroundExecutor: Executor,
- @Main foregroundExecutor: Executor,
+ @Main foregroundExecutor: DelayableExecutor,
mediaControllerFactory: MediaControllerFactory,
dumpManager: DumpManager,
broadcastDispatcher: BroadcastDispatcher,
@@ -183,10 +184,7 @@
val listenersCopy = listeners.toSet()
val toRemove = mediaEntries.filter { it.value.packageName == packageName }
toRemove.forEach {
- mediaEntries.remove(it.key)
- listenersCopy.forEach { listener ->
- listener.onMediaDataRemoved(it.key)
- }
+ removeEntry(it.key, listenersCopy)
}
}
@@ -269,6 +267,18 @@
}
}
+ private fun removeEntry(key: String, listenersCopy: Set<Listener>) {
+ mediaEntries.remove(key)
+ listenersCopy.forEach {
+ it.onMediaDataRemoved(key)
+ }
+ }
+
+ fun dismissMediaData(key: String, delay: Long) {
+ val listenersCopy = listeners.toSet()
+ foregroundExecutor.executeDelayed({ removeEntry(key, listenersCopy) }, delay)
+ }
+
private fun loadMediaDataInBgForResumption(
userId: Int,
desc: MediaDescription,
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index fc33391..70f01d5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -293,6 +293,13 @@
return viewHost
}
+ /**
+ * Close the guts in all players in [MediaCarouselController].
+ */
+ fun closeGuts() {
+ mediaCarouselController.closeGuts()
+ }
+
private fun createUniqueObjectHost(): UniqueObjectHostView {
val viewHost = UniqueObjectHostView(context)
viewHost.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
index 38817d7..92eeed4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
@@ -37,6 +37,11 @@
private val mediaHostStatesManager: MediaHostStatesManager
) {
+ companion object {
+ @JvmField
+ val GUTS_ANIMATION_DURATION = 500L
+ }
+
/**
* A listener when the current dimensions of the player change
*/
@@ -169,6 +174,12 @@
*/
val expandedLayout = ConstraintSet()
+ /**
+ * Whether the guts are visible for the associated player.
+ */
+ var isGutsVisible = false
+ private set
+
init {
collapsedLayout.load(context, R.xml.media_collapsed)
expandedLayout.load(context, R.xml.media_expanded)
@@ -189,6 +200,37 @@
configurationController.removeCallback(configurationListener)
}
+ /**
+ * Show guts with an animated transition.
+ */
+ fun openGuts() {
+ if (isGutsVisible) return
+ isGutsVisible = true
+ animatePendingStateChange(GUTS_ANIMATION_DURATION, 0L)
+ setCurrentState(currentStartLocation,
+ currentEndLocation,
+ currentTransitionProgress,
+ applyImmediately = false)
+ }
+
+ /**
+ * Close the guts for the associated player.
+ *
+ * @param immediate if `false`, it will animate the transition.
+ */
+ @JvmOverloads
+ fun closeGuts(immediate: Boolean = false) {
+ if (!isGutsVisible) return
+ isGutsVisible = false
+ if (!immediate) {
+ animatePendingStateChange(GUTS_ANIMATION_DURATION, 0L)
+ }
+ setCurrentState(currentStartLocation,
+ currentEndLocation,
+ currentTransitionProgress,
+ applyImmediately = immediate)
+ }
+
private fun ensureAllMeasurements() {
val mediaStates = mediaHostStatesManager.mediaHostStates
for (entry in mediaStates) {
@@ -203,6 +245,24 @@
if (expansion > 0) expandedLayout else collapsedLayout
/**
+ * Set the views to be showing/hidden based on the [isGutsVisible] for a given
+ * [TransitionViewState].
+ */
+ private fun setGutsViewState(viewState: TransitionViewState) {
+ PlayerViewHolder.controlsIds.forEach { id ->
+ viewState.widgetStates.get(id)?.let { state ->
+ // Make sure to use the unmodified state if guts are not visible
+ state.alpha = if (isGutsVisible) 0f else state.alpha
+ state.gone = if (isGutsVisible) true else state.gone
+ }
+ }
+ PlayerViewHolder.gutsIds.forEach { id ->
+ viewState.widgetStates.get(id)?.alpha = if (isGutsVisible) 1f else 0f
+ viewState.widgetStates.get(id)?.gone = !isGutsVisible
+ }
+ }
+
+ /**
* Obtain a new viewState for a given media state. This usually returns a cached state, but if
* it's not available, it will recreate one by measuring, which may be expensive.
*/
@@ -211,7 +271,7 @@
return null
}
// Only a subset of the state is relevant to get a valid viewState. Let's get the cachekey
- var cacheKey = getKey(state, tmpKey)
+ var cacheKey = getKey(state, isGutsVisible, tmpKey)
val viewState = viewStates[cacheKey]
if (viewState != null) {
// we already have cached this measurement, let's continue
@@ -228,6 +288,7 @@
constraintSetForExpansion(state.expansion),
TransitionViewState())
+ setGutsViewState(result)
// We don't want to cache interpolated or null states as this could quickly fill up
// our cache. We only cache the start and the end states since the interpolation
// is cheap
@@ -252,11 +313,12 @@
return result
}
- private fun getKey(state: MediaHostState, result: CacheKey): CacheKey {
+ private fun getKey(state: MediaHostState, guts: Boolean, result: CacheKey): CacheKey {
result.apply {
heightMeasureSpec = state.measurementInput?.heightMeasureSpec ?: 0
widthMeasureSpec = state.measurementInput?.widthMeasureSpec ?: 0
expansion = state.expansion
+ gutsVisible = guts
}
return result
}
@@ -432,5 +494,6 @@
private data class CacheKey(
var widthMeasureSpec: Int = -1,
var heightMeasureSpec: Int = -1,
- var expansion: Float = 0.0f
+ var expansion: Float = 0.0f,
+ var gutsVisible: Boolean = false
)
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
index 600fdc2..11551ac 100644
--- a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
@@ -23,6 +23,7 @@
import android.widget.ImageView
import android.widget.SeekBar
import android.widget.TextView
+import androidx.constraintlayout.widget.ConstraintSet
import com.android.systemui.R
import com.android.systemui.util.animation.TransitionLayout
@@ -59,6 +60,11 @@
val action3 = itemView.requireViewById<ImageButton>(R.id.action3)
val action4 = itemView.requireViewById<ImageButton>(R.id.action4)
+ // Settings screen
+ val cancel = itemView.requireViewById<View>(R.id.cancel)
+ val dismiss = itemView.requireViewById<View>(R.id.dismiss)
+ val settings = itemView.requireViewById<View>(R.id.settings)
+
init {
(player.background as IlluminationDrawable).let {
it.registerLightSource(seamless)
@@ -67,6 +73,9 @@
it.registerLightSource(action2)
it.registerLightSource(action3)
it.registerLightSource(action4)
+ it.registerLightSource(cancel)
+ it.registerLightSource(dismiss)
+ it.registerLightSource(settings)
}
}
@@ -83,9 +92,6 @@
}
}
- // Settings screen
- val options = itemView.requireViewById<View>(R.id.qs_media_controls_options)
-
companion object {
/**
* Creates a PlayerViewHolder.
@@ -105,5 +111,29 @@
progressTimes.layoutDirection = View.LAYOUT_DIRECTION_LTR
}
}
+
+ val controlsIds = setOf(
+ R.id.icon,
+ R.id.app_name,
+ R.id.album_art,
+ R.id.header_title,
+ R.id.header_artist,
+ R.id.media_seamless,
+ R.id.notification_media_progress_time,
+ R.id.media_progress_bar,
+ R.id.action0,
+ R.id.action1,
+ R.id.action2,
+ R.id.action3,
+ R.id.action4,
+ R.id.icon
+ )
+ val gutsIds = setOf(
+ R.id.media_text,
+ R.id.remove_text,
+ R.id.cancel,
+ R.id.dismiss,
+ R.id.settings
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
index 8a67da5..b28730d0 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
@@ -16,11 +16,13 @@
package com.android.systemui.onehanded;
+import android.content.ContentResolver;
import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Handler;
+import android.provider.Settings;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -48,12 +50,15 @@
@Singleton
public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Dumpable {
private static final String TAG = "OneHandedTutorialHandler";
+ private static final int MAX_TUTORIAL_SHOW_COUNT = 2;
private final Rect mLastUpdatedBounds = new Rect();
private final WindowManager mWindowManager;
private View mTutorialView;
private Point mDisplaySize = new Point();
private Handler mUpdateHandler;
+ private ContentResolver mContentResolver;
+ private boolean mCanShowTutorial;
/**
* Container of the tutorial panel showing at outside region when one handed starting
@@ -71,6 +76,7 @@
@Inject
public OneHandedTutorialHandler(Context context) {
context.getDisplay().getRealSize(mDisplaySize);
+ mContentResolver = context.getContentResolver();
mUpdateHandler = new Handler();
mWindowManager = context.getSystemService(WindowManager.class);
mTargetViewContainer = new FrameLayout(context);
@@ -79,12 +85,20 @@
R.fraction.config_one_handed_offset, 1, 1));
mTutorialView = LayoutInflater.from(context).inflate(R.xml.one_handed_tutorial, null);
mTargetViewContainer.addView(mTutorialView);
- createOrUpdateTutorialTarget();
+ mCanShowTutorial = (Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, 0) >= MAX_TUTORIAL_SHOW_COUNT)
+ ? false : true;
+ if (mCanShowTutorial) {
+ createOrUpdateTutorialTarget();
+ }
}
@Override
public void onStartFinished(Rect bounds) {
- mUpdateHandler.post(() -> updateFinished(View.VISIBLE, 0f));
+ mUpdateHandler.post(() -> {
+ updateFinished(View.VISIBLE, 0f);
+ updateTutorialCount();
+ });
}
@Override
@@ -94,10 +108,23 @@
}
private void updateFinished(int visible, float finalPosition) {
+ if (!canShowTutorial()) {
+ return;
+ }
+
mTargetViewContainer.setVisibility(visible);
mTargetViewContainer.setTranslationY(finalPosition);
}
+ private void updateTutorialCount() {
+ int showCount = Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, 0);
+ showCount = Math.min(MAX_TUTORIAL_SHOW_COUNT, showCount + 1);
+ mCanShowTutorial = showCount < MAX_TUTORIAL_SHOW_COUNT;
+ Settings.Secure.putInt(mContentResolver,
+ Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, showCount);
+ }
+
/**
* Adds the tutorial target view to the WindowManager and update its layout, so it's ready
* to be animated in.
@@ -153,7 +180,19 @@
pw.println(mLastUpdatedBounds);
}
+ private boolean canShowTutorial() {
+ if (!mCanShowTutorial) {
+ mTargetViewContainer.setVisibility(View.GONE);
+ return false;
+ }
+
+ return true;
+ }
+
private void onAnimationUpdate(float value) {
+ if (!canShowTutorial()) {
+ return;
+ }
mTargetViewContainer.setVisibility(View.VISIBLE);
mTargetViewContainer.setTransitionGroup(true);
mTargetViewContainer.setTranslationY(value - mTargetViewContainer.getHeight());
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
index 7201931..4931388 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
@@ -53,16 +53,16 @@
public static final int TRANSITION_DIRECTION_NONE = 0;
public static final int TRANSITION_DIRECTION_SAME = 1;
public static final int TRANSITION_DIRECTION_TO_PIP = 2;
- public static final int TRANSITION_DIRECTION_TO_FULLSCREEN = 3;
- public static final int TRANSITION_DIRECTION_TO_SPLIT_SCREEN = 4;
+ public static final int TRANSITION_DIRECTION_LEAVE_PIP = 3;
+ public static final int TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN = 4;
public static final int TRANSITION_DIRECTION_REMOVE_STACK = 5;
@IntDef(prefix = { "TRANSITION_DIRECTION_" }, value = {
TRANSITION_DIRECTION_NONE,
TRANSITION_DIRECTION_SAME,
TRANSITION_DIRECTION_TO_PIP,
- TRANSITION_DIRECTION_TO_FULLSCREEN,
- TRANSITION_DIRECTION_TO_SPLIT_SCREEN,
+ TRANSITION_DIRECTION_LEAVE_PIP,
+ TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN,
TRANSITION_DIRECTION_REMOVE_STACK
})
@Retention(RetentionPolicy.SOURCE)
@@ -73,8 +73,8 @@
}
public static boolean isOutPipDirection(@TransitionDirection int direction) {
- return direction == TRANSITION_DIRECTION_TO_FULLSCREEN
- || direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN;
+ return direction == TRANSITION_DIRECTION_LEAVE_PIP
+ || direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN;
}
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 312d6d6..025341c 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -23,12 +23,12 @@
import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_ALPHA;
import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
+import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
+import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_NONE;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_REMOVE_STACK;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_SAME;
-import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
-import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_SPLIT_SCREEN;
import static com.android.systemui.pip.PipAnimationController.isInPipDirection;
import static com.android.systemui.pip.PipAnimationController.isOutPipDirection;
@@ -99,6 +99,7 @@
private final Handler mUpdateHandler;
private final PipBoundsHandler mPipBoundsHandler;
private final PipAnimationController mPipAnimationController;
+ private final PipUiEventLogger mPipUiEventLoggerLogger;
private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>();
private final Rect mLastReportedBounds = new Rect();
private final int mEnterExitAnimationDuration;
@@ -209,7 +210,8 @@
@NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
@Nullable Divider divider,
@NonNull DisplayController displayController,
- @NonNull PipAnimationController pipAnimationController) {
+ @NonNull PipAnimationController pipAnimationController,
+ @NonNull PipUiEventLogger pipUiEventLogger) {
mMainHandler = new Handler(Looper.getMainLooper());
mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
mPipBoundsHandler = boundsHandler;
@@ -217,6 +219,7 @@
.getInteger(R.integer.config_pipResizeAnimationDuration);
mSurfaceTransactionHelper = surfaceTransactionHelper;
mPipAnimationController = pipAnimationController;
+ mPipUiEventLoggerLogger = pipUiEventLogger;
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
mSplitDivider = divider;
displayController.addDisplayWindowListener(this);
@@ -279,14 +282,16 @@
return;
}
+ mPipUiEventLoggerLogger.log(
+ PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN);
final Configuration initialConfig = mInitialState.remove(mToken.asBinder());
final boolean orientationDiffers = initialConfig.windowConfiguration.getRotation()
!= mPipBoundsHandler.getDisplayRotation();
final WindowContainerTransaction wct = new WindowContainerTransaction();
final Rect destinationBounds = initialConfig.windowConfiguration.getBounds();
final int direction = syncWithSplitScreenBounds(destinationBounds)
- ? TRANSITION_DIRECTION_TO_SPLIT_SCREEN
- : TRANSITION_DIRECTION_TO_FULLSCREEN;
+ ? TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
+ : TRANSITION_DIRECTION_LEAVE_PIP;
if (orientationDiffers) {
// Send started callback though animation is ignored.
sendOnPipTransitionStarted(direction);
@@ -303,7 +308,10 @@
mSurfaceTransactionHelper.scale(tx, mLeash, destinationBounds,
mLastReportedBounds);
tx.setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height());
- wct.setActivityWindowingMode(mToken, direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN
+ // We set to fullscreen here for now, but later it will be set to UNDEFINED for
+ // the proper windowing mode to take place. See #applyWindowingModeChangeOnExit.
+ wct.setActivityWindowingMode(mToken,
+ direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
: WINDOWING_MODE_FULLSCREEN);
wct.setBounds(mToken, destinationBounds);
@@ -327,7 +335,7 @@
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_TO_SPLIT_SCREEN) {
+ if (mSplitDivider != null && direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
wct.reparent(mToken, mSplitDivider.getSecondaryRoot(), true /* onTop */);
}
}
@@ -378,6 +386,9 @@
mInitialState.put(mToken.asBinder(), new Configuration(mTaskInfo.configuration));
mPictureInPictureParams = mTaskInfo.pictureInPictureParams;
+ mPipUiEventLoggerLogger.setTaskInfo(mTaskInfo);
+ mPipUiEventLoggerLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_ENTER);
+
if (mShouldDeferEnteringPip) {
if (DEBUG) Log.d(TAG, "Defer entering PiP animation, fixed rotation is ongoing");
// if deferred, hide the surface till fixed rotation is completed
@@ -451,10 +462,11 @@
private void sendOnPipTransitionStarted(
@PipAnimationController.TransitionDirection int direction) {
+ final Rect pipBounds = new Rect(mLastReportedBounds);
runOnMainHandler(() -> {
for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
- callback.onPipTransitionStarted(mTaskInfo.baseActivity, direction);
+ callback.onPipTransitionStarted(mTaskInfo.baseActivity, direction, pipBounds);
}
});
}
@@ -510,6 +522,7 @@
mPictureInPictureParams = null;
mInPip = false;
mExitingPip = false;
+ mPipUiEventLoggerLogger.setTaskInfo(null);
}
@Override
@@ -625,7 +638,7 @@
* {@link PictureInPictureParams} would affect the bounds.
*/
private boolean applyPictureInPictureParams(@NonNull PictureInPictureParams params) {
- final boolean changed = (mPictureInPictureParams == null) ? true : !Objects.equals(
+ final boolean changed = (mPictureInPictureParams == null) || !Objects.equals(
mPictureInPictureParams.getAspectRatioRational(), params.getAspectRatioRational());
if (changed) {
mPictureInPictureParams = params;
@@ -842,7 +855,7 @@
} else if (isOutPipDirection(direction)) {
// If we are animating to fullscreen, then we need to reset the override bounds
// on the task to ensure that the task "matches" the parent's bounds.
- taskBounds = (direction == TRANSITION_DIRECTION_TO_FULLSCREEN)
+ taskBounds = (direction == TRANSITION_DIRECTION_LEAVE_PIP)
? null : destinationBounds;
applyWindowingModeChangeOnExit(wct, direction);
} else {
@@ -970,7 +983,7 @@
/**
* Callback when the pip transition is started.
*/
- void onPipTransitionStarted(ComponentName activity, int direction);
+ void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds);
/**
* Callback when the pip transition is finished.
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.java b/packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.java
new file mode 100644
index 0000000..5e2cd9c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.java
@@ -0,0 +1,97 @@
+/*
+ * 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.pip;
+
+import android.app.TaskInfo;
+
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+
+/**
+ * Helper class that ends PiP log to UiEvent, see also go/uievent
+ */
+@Singleton
+public class PipUiEventLogger {
+
+ private final UiEventLogger mUiEventLogger;
+
+ private TaskInfo mTaskInfo;
+
+ @Inject
+ public PipUiEventLogger(UiEventLogger uiEventLogger) {
+ mUiEventLogger = uiEventLogger;
+ }
+
+ public void setTaskInfo(TaskInfo taskInfo) {
+ mTaskInfo = taskInfo;
+ }
+
+ /**
+ * Sends log via UiEvent, reference go/uievent for how to debug locally
+ */
+ public void log(PipUiEventEnum event) {
+ if (mTaskInfo == null) {
+ return;
+ }
+ mUiEventLogger.log(event, mTaskInfo.userId, mTaskInfo.topActivity.getPackageName());
+ }
+
+ /**
+ * Enums for logging the PiP events to UiEvent
+ */
+ public enum PipUiEventEnum implements UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "Activity enters picture-in-picture mode")
+ PICTURE_IN_PICTURE_ENTER(603),
+
+ @UiEvent(doc = "Expands from picture-in-picture to fullscreen")
+ PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN(604),
+
+ @UiEvent(doc = "Removes picture-in-picture by tap close button")
+ PICTURE_IN_PICTURE_TAP_TO_REMOVE(605),
+
+ @UiEvent(doc = "Removes picture-in-picture by drag to dismiss area")
+ PICTURE_IN_PICTURE_DRAG_TO_REMOVE(606),
+
+ @UiEvent(doc = "Shows picture-in-picture menu")
+ PICTURE_IN_PICTURE_SHOW_MENU(607),
+
+ @UiEvent(doc = "Hides picture-in-picture menu")
+ PICTURE_IN_PICTURE_HIDE_MENU(608),
+
+ @UiEvent(doc = "Changes the aspect ratio of picture-in-picture window. This is inherited"
+ + " from previous Tron-based logging and currently not in use.")
+ PICTURE_IN_PICTURE_CHANGE_ASPECT_RATIO(609),
+
+ @UiEvent(doc = "User resize of the picture-in-picture window")
+ PICTURE_IN_PICTURE_RESIZE(610);
+
+ private final int mId;
+
+ PipUiEventEnum(int id) {
+ mId = id;
+ }
+
+ @Override
+ public int getId() {
+ return mId;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java
index c715398..a133189 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java
@@ -131,7 +131,7 @@
result = true;
break;
case AccessibilityNodeInfo.ACTION_EXPAND:
- mMotionHelper.expandPipToFullscreen();
+ mMotionHelper.expandLeavePip();
result = true;
break;
default:
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 582cd04..9dfa864 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -47,6 +47,8 @@
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.pip.phone.dagger.PipMenuActivityClass;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputConsumerController;
@@ -181,7 +183,7 @@
!= WINDOWING_MODE_PINNED) {
return;
}
- mTouchHandler.getMotionHelper().expandPipToFullscreen(clearedTask /* skipAnimation */);
+ mTouchHandler.getMotionHelper().expandLeavePip(clearedTask /* skipAnimation */);
}
};
@@ -250,6 +252,7 @@
@Inject
public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
+ @PipMenuActivityClass Class<?> pipMenuActivityClass,
DisplayController displayController,
FloatingContentCoordinator floatingContentCoordinator,
DeviceConfigProxy deviceConfig,
@@ -257,7 +260,8 @@
PipSnapAlgorithm pipSnapAlgorithm,
PipTaskOrganizer pipTaskOrganizer,
SysUiState sysUiState,
- ConfigurationController configController) {
+ ConfigurationController configController,
+ PipUiEventLogger pipUiEventLogger) {
mContext = context;
mActivityManager = ActivityManager.getService();
@@ -274,11 +278,12 @@
mPipTaskOrganizer.registerPipTransitionCallback(this);
mInputConsumerController = InputConsumerController.getPipInputConsumer();
mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher);
- mMenuController = new PipMenuActivityController(context, mMediaController,
- mInputConsumerController);
+ mMenuController = new PipMenuActivityController(context, pipMenuActivityClass,
+ mMediaController, mInputConsumerController);
mTouchHandler = new PipTouchHandler(context, mActivityManager,
mMenuController, mInputConsumerController, mPipBoundsHandler, mPipTaskOrganizer,
- floatingContentCoordinator, deviceConfig, pipSnapAlgorithm, sysUiState);
+ floatingContentCoordinator, deviceConfig, pipSnapAlgorithm, sysUiState,
+ pipUiEventLogger);
mAppOpsListener = new PipAppOpsListener(context, mActivityManager,
mTouchHandler.getMotionHelper());
displayController.addDisplayChangingController(mRotationController);
@@ -318,7 +323,7 @@
*/
@Override
public void expandPip() {
- mTouchHandler.getMotionHelper().expandPipToFullscreen(false /* skipAnimation */);
+ mTouchHandler.getMotionHelper().expandLeavePip(false /* skipAnimation */);
}
/**
@@ -371,10 +376,10 @@
}
@Override
- public void onPipTransitionStarted(ComponentName activity, int direction) {
+ public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) {
if (isOutPipDirection(direction)) {
// Exiting PIP, save the reentry bounds to restore to when re-entering.
- updateReentryBounds();
+ updateReentryBounds(pipBounds);
mPipBoundsHandler.onSaveReentryBounds(activity, mReentryBounds);
}
// Disable touches while the animation is running
@@ -391,15 +396,8 @@
/**
* Update the bounds used to save the re-entry size and snap fraction when exiting PIP.
*/
- public void updateReentryBounds() {
- // On phones, the expansion animation that happens on pip tap before restoring
- // to fullscreen makes it so that the last reported bounds are the expanded
- // bounds. We want to restore to the unexpanded bounds when re-entering pip,
- // so we use the bounds before expansion (normal) instead of the reported
- // bounds.
- Rect reentryBounds = mTouchHandler.getNormalBounds();
- // Apply the snap fraction of the current bounds to the normal bounds.
- final Rect bounds = mPipTaskOrganizer.getLastReportedBounds();
+ public void updateReentryBounds(Rect bounds) {
+ final Rect reentryBounds = mTouchHandler.getUserResizeBounds();
float snapFraction = mPipBoundsHandler.getSnapFraction(bounds);
mPipBoundsHandler.applySnapFraction(reentryBounds, snapFraction);
mReentryBounds.set(reentryBounds);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index d6f3e16..1b1b2de 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -76,17 +76,15 @@
import android.widget.LinearLayout;
import com.android.systemui.Interpolators;
-import com.android.systemui.SystemUIFactory;
import com.android.wm.shell.R;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import javax.inject.Inject;
-
/**
* Translucent activity that gets started on top of a task in PIP to allow the user to control it.
+ * TODO(b/150319024): PipMenuActivity will move to a Window
*/
public class PipMenuActivity extends Activity {
@@ -126,19 +124,11 @@
private final List<RemoteAction> mActions = new ArrayList<>();
private AccessibilityManager mAccessibilityManager;
- private View mViewRoot;
private Drawable mBackgroundDrawable;
private View mMenuContainer;
private LinearLayout mActionsGroup;
- private View mSettingsButton;
- private View mDismissButton;
- private View mResizeHandle;
- private View mTopEndContainer;
private int mBetweenActionPaddingLand;
- @Inject
- PipMenuIconsAlgorithm mPipMenuIconsAlgorithm;
-
private AnimatorSet mMenuContainerAnimator;
private ValueAnimator.AnimatorUpdateListener mMenuBgUpdateListener =
@@ -193,6 +183,9 @@
break;
}
case MESSAGE_MENU_EXPANDED : {
+ if (mMenuContainerAnimator == null) {
+ return;
+ }
mMenuContainerAnimator.setStartDelay(MENU_SHOW_ON_EXPAND_START_DELAY);
mMenuContainerAnimator.start();
break;
@@ -202,6 +195,9 @@
break;
}
case MESSAGE_UPDATE_MENU_LAYOUT: {
+ if (mPipMenuIconsAlgorithm == null) {
+ return;
+ }
final Rect bounds = (Rect) msg.obj;
mPipMenuIconsAlgorithm.onBoundsChanged(bounds);
break;
@@ -214,6 +210,13 @@
private final Runnable mFinishRunnable = this::hideMenu;
+ protected View mViewRoot;
+ protected View mSettingsButton;
+ protected View mDismissButton;
+ protected View mResizeHandle;
+ protected View mTopEndContainer;
+ protected PipMenuIconsAlgorithm mPipMenuIconsAlgorithm;
+
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
// Set the flags to allow us to watch for outside touches and also hide the menu and start
@@ -222,8 +225,6 @@
super.onCreate(savedInstanceState);
- SystemUIFactory.getInstance().getRootComponent().inject(this);
-
setContentView(R.layout.pip_menu_activity);
mAccessibilityManager = getSystemService(AccessibilityManager.class);
@@ -254,7 +255,7 @@
mActionsGroup = findViewById(R.id.actions_group);
mBetweenActionPaddingLand = getResources().getDimensionPixelSize(
R.dimen.pip_between_action_padding_land);
-
+ mPipMenuIconsAlgorithm = new PipMenuIconsAlgorithm(this.getApplicationContext());
mPipMenuIconsAlgorithm.bindViews((ViewGroup) mViewRoot, (ViewGroup) mTopEndContainer,
mResizeHandle, mSettingsButton, mDismissButton);
updateFromIntent(getIntent());
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 267c5ea..383f6b3 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -110,6 +110,8 @@
void onPipShowMenu();
}
+ /** TODO(b/150319024): PipMenuActivity will move to a Window */
+ private Class<?> mPipMenuActivityClass;
private Context mContext;
private PipMediaController mMediaController;
private InputConsumerController mInputConsumerController;
@@ -185,11 +187,13 @@
}
};
- public PipMenuActivityController(Context context,
- PipMediaController mediaController, InputConsumerController inputConsumerController) {
+ public PipMenuActivityController(Context context, Class<?> pipMenuActivityClass,
+ PipMediaController mediaController, InputConsumerController inputConsumerController
+ ) {
mContext = context;
mMediaController = mediaController;
mInputConsumerController = inputConsumerController;
+ mPipMenuActivityClass = pipMenuActivityClass;
}
public boolean isMenuActivityVisible() {
@@ -454,7 +458,7 @@
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
if (pinnedStackInfo != null && pinnedStackInfo.taskIds != null &&
pinnedStackInfo.taskIds.length > 0) {
- Intent intent = new Intent(mContext, PipMenuActivity.class);
+ Intent intent = new Intent(mContext, mPipMenuActivityClass);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(EXTRA_CONTROLLER_MESSENGER, mMessenger);
intent.putExtra(EXTRA_ACTIONS, resolveMenuActions());
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuIconsAlgorithm.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuIconsAlgorithm.java
index 69a04d8..6cfed07 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuIconsAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuIconsAlgorithm.java
@@ -24,8 +24,6 @@
import android.view.ViewGroup;
import android.widget.FrameLayout;
-import javax.inject.Inject;
-
/**
* Helper class to calculate and place the menu icons on the PIP Menu.
*/
@@ -40,8 +38,7 @@
protected View mSettingsButton;
protected View mDismissButton;
- @Inject
- public PipMenuIconsAlgorithm(Context context) {
+ protected PipMenuIconsAlgorithm(Context context) {
}
/**
@@ -56,7 +53,6 @@
mDismissButton = dismissButton;
}
-
/**
* Updates the position of the drag handle based on where the PIP window is on the screen.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index ca3ef24..19138fd 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -54,7 +54,7 @@
private static final int SHRINK_STACK_FROM_MENU_DURATION = 250;
private static final int EXPAND_STACK_TO_MENU_DURATION = 250;
- private static final int EXPAND_STACK_TO_FULLSCREEN_DURATION = 300;
+ private static final int LEAVE_PIP_DURATION = 300;
private static final int SHIFT_DURATION = 300;
/** Friction to use for PIP when it moves via physics fling animations. */
@@ -154,7 +154,7 @@
private final PipTaskOrganizer.PipTransitionCallback mPipTransitionCallback =
new PipTaskOrganizer.PipTransitionCallback() {
@Override
- public void onPipTransitionStarted(ComponentName activity, int direction) {}
+ public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) {}
@Override
public void onPipTransitionFinished(ComponentName activity, int direction) {
@@ -304,16 +304,18 @@
}
/**
- * Resizes the pinned stack back to fullscreen.
+ * Resizes the pinned stack back to unknown windowing mode, which could be freeform or
+ * * fullscreen depending on the display area's windowing mode.
*/
- void expandPipToFullscreen() {
- expandPipToFullscreen(false /* skipAnimation */);
+ void expandLeavePip() {
+ expandLeavePip(false /* skipAnimation */);
}
/**
- * Resizes the pinned stack back to fullscreen.
+ * Resizes the pinned stack back to unknown windowing mode, which could be freeform or
+ * fullscreen depending on the display area's windowing mode.
*/
- void expandPipToFullscreen(boolean skipAnimation) {
+ void expandLeavePip(boolean skipAnimation) {
if (DEBUG) {
Log.d(TAG, "exitPip: skipAnimation=" + skipAnimation
+ " callers=\n" + Debug.getCallers(5, " "));
@@ -323,7 +325,7 @@
mPipTaskOrganizer.getUpdateHandler().post(() -> {
mPipTaskOrganizer.exitPip(skipAnimation
? 0
- : EXPAND_STACK_TO_FULLSCREEN_DURATION);
+ : LEAVE_PIP_DURATION);
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
index d884fa9..9c42f8b 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
@@ -52,6 +52,7 @@
import com.android.systemui.model.SysUiState;
import com.android.systemui.pip.PipBoundsHandler;
import com.android.systemui.pip.PipTaskOrganizer;
+import com.android.systemui.pip.PipUiEventLogger;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.wm.shell.R;
@@ -88,6 +89,7 @@
private final Point mMaxSize = new Point();
private final Point mMinSize = new Point();
private final Rect mLastResizeBounds = new Rect();
+ private final Rect mUserResizeBounds = new Rect();
private final Rect mLastDownBounds = new Rect();
private final Rect mDragCornerSize = new Rect();
private final Rect mTmpTopLeftCorner = new Rect();
@@ -109,13 +111,15 @@
private InputMonitor mInputMonitor;
private InputEventReceiver mInputEventReceiver;
private PipTaskOrganizer mPipTaskOrganizer;
+ private PipUiEventLogger mPipUiEventLogger;
private int mCtrlType;
public PipResizeGestureHandler(Context context, PipBoundsHandler pipBoundsHandler,
PipMotionHelper motionHelper, DeviceConfigProxy deviceConfig,
PipTaskOrganizer pipTaskOrganizer, Function<Rect, Rect> movementBoundsSupplier,
- Runnable updateMovementBoundsRunnable, SysUiState sysUiState) {
+ Runnable updateMovementBoundsRunnable, SysUiState sysUiState,
+ PipUiEventLogger pipUiEventLogger) {
mContext = context;
mDisplayId = context.getDisplayId();
mMainExecutor = context.getMainExecutor();
@@ -125,6 +129,7 @@
mMovementBoundsSupplier = movementBoundsSupplier;
mUpdateMovementBoundsRunnable = updateMovementBoundsRunnable;
mSysUiState = sysUiState;
+ mPipUiEventLogger = pipUiEventLogger;
context.getDisplay().getRealSize(mMaxSize);
reloadResources();
@@ -181,6 +186,7 @@
void onActivityUnpinned() {
mIsAttached = false;
+ mUserResizeBounds.setEmpty();
updateIsEnabled();
}
@@ -329,6 +335,7 @@
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (!mLastResizeBounds.isEmpty()) {
+ mUserResizeBounds.set(mLastResizeBounds);
mPipTaskOrganizer.scheduleFinishResizePip(mLastResizeBounds,
(Rect bounds) -> {
new Handler(Looper.getMainLooper()).post(() -> {
@@ -337,6 +344,8 @@
resetState();
});
});
+ mPipUiEventLogger.log(
+ PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_RESIZE);
} else {
resetState();
}
@@ -351,6 +360,14 @@
mThresholdCrossed = false;
}
+ void setUserResizeBounds(Rect bounds) {
+ mUserResizeBounds.set(bounds);
+ }
+
+ Rect getUserResizeBounds() {
+ return mUserResizeBounds;
+ }
+
void updateMaxSize(int maxX, int maxY) {
mMaxSize.set(maxX, maxY);
}
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 5434b62..b20ea4e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -34,7 +34,6 @@
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
-import android.util.Pair;
import android.util.Size;
import android.view.Gravity;
import android.view.IPinnedStackController;
@@ -55,13 +54,13 @@
import androidx.dynamicanimation.animation.SpringForce;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.logging.MetricsLoggerWrapper;
import com.android.systemui.R;
import com.android.systemui.model.SysUiState;
import com.android.systemui.pip.PipAnimationController;
import com.android.systemui.pip.PipBoundsHandler;
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;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.DismissCircleView;
@@ -94,6 +93,8 @@
private final WindowManager mWindowManager;
private final IActivityManager mActivityManager;
private final PipBoundsHandler mPipBoundsHandler;
+ private final PipUiEventLogger mPipUiEventLogger;
+
private PipResizeGestureHandler mPipResizeGestureHandler;
private IPinnedStackController mPinnedStackController;
@@ -132,9 +133,6 @@
// The current movement bounds
private Rect mMovementBounds = new Rect();
- // The current resized bounds, changed by user resize.
- // This is used during expand/un-expand to save/restore the user's resized size.
- @VisibleForTesting Rect mResizedBounds = new Rect();
// The reference inset bounds, used to determine the dismiss fraction
private Rect mInsetBounds = new Rect();
@@ -193,16 +191,12 @@
@Override
public void onPipExpand() {
- mMotionHelper.expandPipToFullscreen();
+ mMotionHelper.expandLeavePip();
}
@Override
public void onPipDismiss() {
- Pair<ComponentName, Integer> topPipActivity = PipUtils.getTopPipActivity(mContext,
- mActivityManager);
- if (topPipActivity.first != null) {
- MetricsLoggerWrapper.logPictureInPictureDismissByTap(mContext, topPipActivity);
- }
+ mPipUiEventLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_TAP_TO_REMOVE);
mTouchState.removeDoubleTapTimeoutCallback();
mMotionHelper.dismissPip();
}
@@ -223,7 +217,8 @@
FloatingContentCoordinator floatingContentCoordinator,
DeviceConfigProxy deviceConfig,
PipSnapAlgorithm pipSnapAlgorithm,
- SysUiState sysUiState) {
+ SysUiState sysUiState,
+ PipUiEventLogger pipUiEventLogger) {
// Initialize the Pip input consumer
mContext = context;
mActivityManager = activityManager;
@@ -238,7 +233,7 @@
mPipResizeGestureHandler =
new PipResizeGestureHandler(context, pipBoundsHandler, mMotionHelper,
deviceConfig, pipTaskOrganizer, this::getMovementBounds,
- this::updateMovementBounds, sysUiState);
+ this::updateMovementBounds, sysUiState, pipUiEventLogger);
mTouchState = new PipTouchState(ViewConfiguration.get(context), mHandler,
() -> mMenuController.showMenuWithDelay(MENU_STATE_FULL, mMotionHelper.getBounds(),
true /* allowMenuTimeout */, willResizeMenu(), shouldShowResizeHandle()),
@@ -259,6 +254,8 @@
pipTaskOrganizer, pipSnapAlgorithm, this::onAccessibilityShowMenu,
this::updateMovementBounds, mHandler);
+ mPipUiEventLogger = pipUiEventLogger;
+
mTargetView = new DismissCircleView(context);
mTargetViewContainer = new FrameLayout(context);
mTargetViewContainer.setBackgroundDrawable(
@@ -307,11 +304,8 @@
hideDismissTarget();
});
- Pair<ComponentName, Integer> topPipActivity = PipUtils.getTopPipActivity(mContext,
- mActivityManager);
- if (topPipActivity.first != null) {
- MetricsLoggerWrapper.logPictureInPictureDismissByDrag(mContext, topPipActivity);
- }
+ mPipUiEventLogger.log(
+ PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_DRAG_TO_REMOVE);
}
});
@@ -383,7 +377,6 @@
mFloatingContentCoordinator.onContentRemoved(mMotionHelper);
}
- mResizedBounds.setEmpty();
mPipResizeGestureHandler.onActivityUnpinned();
}
@@ -393,9 +386,8 @@
mMotionHelper.synchronizePinnedStackBounds();
updateMovementBounds();
if (direction == TRANSITION_DIRECTION_TO_PIP) {
- // updates mResizedBounds only if it's an entering PiP animation
- // mResized should be otherwise updated in setMenuState.
- mResizedBounds.set(mMotionHelper.getBounds());
+ // Set the initial bounds as the user resize bounds.
+ mPipResizeGestureHandler.setUserResizeBounds(mMotionHelper.getBounds());
}
if (mShowPipMenuOnAnimationEnd) {
@@ -808,9 +800,7 @@
// Save the current snap fraction and if we do not drag or move the PiP, then
// we store back to this snap fraction. Otherwise, we'll reset the snap
// fraction and snap to the closest edge.
- // Also save the current resized bounds so when the menu disappears, we can restore it.
if (resize) {
- mResizedBounds.set(mMotionHelper.getBounds());
Rect expandedBounds = new Rect(mExpandedBounds);
mSavedSnapFraction = mMotionHelper.animateToExpandedState(expandedBounds,
mMovementBounds, mExpandedMovementBounds, callback);
@@ -839,7 +829,7 @@
}
if (mDeferResizeToNormalBoundsUntilRotation == -1) {
- Rect restoreBounds = new Rect(mResizedBounds);
+ Rect restoreBounds = new Rect(getUserResizeBounds());
Rect restoredMovementBounds = new Rect();
mSnapAlgorithm.getMovementBounds(restoreBounds, mInsetBounds,
restoredMovementBounds, mIsImeShowing ? mImeHeight : 0);
@@ -856,8 +846,10 @@
// If pip menu has dismissed, we should register the A11y ActionReplacingConnection for pip
// as well, or it can't handle a11y focus and pip menu can't perform any action.
onRegistrationChanged(menuState == MENU_STATE_NONE);
- if (menuState != MENU_STATE_CLOSE) {
- MetricsLoggerWrapper.logPictureInPictureMenuVisible(mContext, menuState == MENU_STATE_FULL);
+ if (menuState == MENU_STATE_NONE) {
+ mPipUiEventLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_HIDE_MENU);
+ } else if (menuState == MENU_STATE_FULL) {
+ mPipUiEventLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_SHOW_MENU);
}
}
@@ -890,6 +882,10 @@
return mNormalBounds;
}
+ Rect getUserResizeBounds() {
+ return mPipResizeGestureHandler.getUserResizeBounds();
+ }
+
/**
* Gesture controlling normal movement of the PIP.
*/
@@ -991,7 +987,7 @@
// Expand to fullscreen if this is a double tap
// the PiP should be frozen until the transition ends
setTouchEnabled(false);
- mMotionHelper.expandPipToFullscreen();
+ mMotionHelper.expandLeavePip();
} else if (mMenuState != MENU_STATE_FULL) {
if (!mTouchState.isWaitingForDoubleTap()) {
// User has stalled long enough for this not to be a drag or a double tap, just
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java b/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java
new file mode 100644
index 0000000..114c30e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.pip.phone.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface PipMenuActivityClass {
+}
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 2138f09..0167028 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -663,7 +663,7 @@
};
@Override
- public void onPipTransitionStarted(ComponentName activity, int direction) { }
+ public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) { }
@Override
public void onPipTransitionFinished(ComponentName activity, int direction) {
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
index d5a14f7..affc5ee 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
@@ -45,7 +45,6 @@
@Singleton
class PrivacyItemController @Inject constructor(
- context: Context,
private val appOpsController: AppOpsController,
@Main uiExecutor: DelayableExecutor,
@Background private val bgExecutor: Executor,
@@ -57,16 +56,21 @@
@VisibleForTesting
internal companion object {
- val OPS = intArrayOf(AppOpsManager.OP_CAMERA,
- AppOpsManager.OP_RECORD_AUDIO,
+ val OPS_MIC_CAMERA = intArrayOf(AppOpsManager.OP_CAMERA,
+ AppOpsManager.OP_RECORD_AUDIO)
+ val OPS_LOCATION = intArrayOf(
AppOpsManager.OP_COARSE_LOCATION,
AppOpsManager.OP_FINE_LOCATION)
+ val OPS = OPS_MIC_CAMERA + OPS_LOCATION
val intentFilter = IntentFilter().apply {
addAction(Intent.ACTION_USER_SWITCHED)
addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)
}
const val TAG = "PrivacyItemController"
+ private const val ALL_INDICATORS =
+ SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED
+ private const val MIC_CAMERA = SystemUiDeviceConfigFlags.PROPERTY_MIC_CAMERA_ENABLED
}
@VisibleForTesting
@@ -74,9 +78,14 @@
@Synchronized get() = field.toList() // Returns a shallow copy of the list
@Synchronized set
- private fun isPermissionsHubEnabled(): Boolean {
+ private fun isAllIndicatorsEnabled(): Boolean {
return deviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, false)
+ ALL_INDICATORS, false)
+ }
+
+ private fun isMicCameraEnabled(): Boolean {
+ return deviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+ MIC_CAMERA, false)
}
private var currentUserIds = emptyList<Int>()
@@ -94,23 +103,28 @@
uiExecutor.execute(notifyChanges)
}
- var indicatorsAvailable = isPermissionsHubEnabled()
+ var allIndicatorsAvailable = isAllIndicatorsEnabled()
private set
- @VisibleForTesting
- internal val devicePropertiesChangedListener =
+ var micCameraAvailable = isMicCameraEnabled()
+ private set
+
+ private val devicePropertiesChangedListener =
object : DeviceConfig.OnPropertiesChangedListener {
override fun onPropertiesChanged(properties: DeviceConfig.Properties) {
if (DeviceConfig.NAMESPACE_PRIVACY.equals(properties.getNamespace()) &&
- properties.getKeyset().contains(
- SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED)) {
- val flag = properties.getBoolean(
- SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, false)
- if (indicatorsAvailable != flag) {
- // This is happening already in the UI executor, so we can iterate in the
- indicatorsAvailable = flag
- callbacks.forEach { it.get()?.onFlagChanged(flag) }
+ (properties.keyset.contains(ALL_INDICATORS) ||
+ properties.keyset.contains(MIC_CAMERA))) {
+
+ // Running on the ui executor so can iterate on callbacks
+ if (properties.keyset.contains(ALL_INDICATORS)) {
+ allIndicatorsAvailable = properties.getBoolean(ALL_INDICATORS, false)
+ callbacks.forEach { it.get()?.onFlagAllChanged(allIndicatorsAvailable) }
}
+ if (properties.keyset.contains(MIC_CAMERA)) {
+ micCameraAvailable = properties.getBoolean(MIC_CAMERA, false)
+ callbacks.forEach { it.get()?.onFlagMicCameraChanged(micCameraAvailable) }
+ }
internalUiExecutor.updateListeningState()
}
}
@@ -123,6 +137,10 @@
packageName: String,
active: Boolean
) {
+ // Check if we care about this code right now
+ if (!allIndicatorsAvailable && code in OPS_LOCATION) {
+ return
+ }
val userId = UserHandle.getUserId(uid)
if (userId in currentUserIds) {
update(false)
@@ -166,13 +184,16 @@
}
/**
- * Updates listening status based on whether there are callbacks and the indicators are enabled
+ * Updates listening status based on whether there are callbacks and the indicators are enabled.
+ *
+ * Always listen to all OPS so we don't have to figure out what we should be listening to. We
+ * still have to filter anyway. Updates are filtered in the callback.
*
* This is only called from private (add/remove)Callback and from the config listener, all in
* main thread.
*/
private fun setListeningState() {
- val listen = !callbacks.isEmpty() and indicatorsAvailable
+ val listen = !callbacks.isEmpty() and (allIndicatorsAvailable || micCameraAvailable)
if (listening == listen) return
listening = listen
if (listening) {
@@ -233,14 +254,19 @@
AppOpsManager.OP_RECORD_AUDIO -> PrivacyType.TYPE_MICROPHONE
else -> return null
}
+ if (type == PrivacyType.TYPE_LOCATION && !allIndicatorsAvailable) return null
val app = PrivacyApplication(appOpItem.packageName, appOpItem.uid)
return PrivacyItem(type, app)
}
interface Callback {
fun onPrivacyItemsChanged(privacyItems: List<PrivacyItem>)
+
@JvmDefault
- fun onFlagChanged(flag: Boolean) {}
+ fun onFlagAllChanged(flag: Boolean) {}
+
+ @JvmDefault
+ fun onFlagMicCameraChanged(flag: Boolean) {}
}
internal inner class Receiver : BroadcastReceiver() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 560998b..22c735d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -185,7 +185,9 @@
fakeDragBy(getScrollX() - mScroller.getCurrX());
} else if (isFakeDragging()) {
endFakeDrag();
- mBounceAnimatorSet.start();
+ if (mBounceAnimatorSet != null) {
+ mBounceAnimatorSet.start();
+ }
setOffscreenPageLimit(1);
}
super.computeScroll();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 2dc82dd..2e258d5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -151,7 +151,8 @@
private Space mSpace;
private BatteryMeterView mBatteryRemainingIcon;
private RingerModeTracker mRingerModeTracker;
- private boolean mPermissionsHubEnabled;
+ private boolean mAllIndicatorsEnabled;
+ private boolean mMicCameraIndicatorsEnabled;
private PrivacyItemController mPrivacyItemController;
private final UiEventLogger mUiEventLogger;
@@ -178,13 +179,26 @@
}
@Override
- public void onFlagChanged(boolean flag) {
- if (mPermissionsHubEnabled != flag) {
- StatusIconContainer iconContainer = requireViewById(R.id.statusIcons);
- iconContainer.setIgnoredSlots(getIgnoredIconSlots());
- setChipVisibility(!mPrivacyChip.getPrivacyList().isEmpty());
+ public void onFlagAllChanged(boolean flag) {
+ if (mAllIndicatorsEnabled != flag) {
+ mAllIndicatorsEnabled = flag;
+ update();
}
}
+
+ @Override
+ public void onFlagMicCameraChanged(boolean flag) {
+ if (mMicCameraIndicatorsEnabled != flag) {
+ mMicCameraIndicatorsEnabled = flag;
+ update();
+ }
+ }
+
+ private void update() {
+ StatusIconContainer iconContainer = requireViewById(R.id.statusIcons);
+ iconContainer.setIgnoredSlots(getIgnoredIconSlots());
+ setChipVisibility(!mPrivacyChip.getPrivacyList().isEmpty());
+ }
};
@Inject
@@ -267,7 +281,8 @@
mRingerModeTextView.setSelected(true);
mNextAlarmTextView.setSelected(true);
- mPermissionsHubEnabled = mPrivacyItemController.getIndicatorsAvailable();
+ mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable();
+ mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable();
}
public QuickQSPanel getHeaderQsPanel() {
@@ -276,13 +291,15 @@
private List<String> getIgnoredIconSlots() {
ArrayList<String> ignored = new ArrayList<>();
- ignored.add(mContext.getResources().getString(
- com.android.internal.R.string.status_bar_camera));
- ignored.add(mContext.getResources().getString(
- com.android.internal.R.string.status_bar_microphone));
- if (mPermissionsHubEnabled) {
+ if (getChipEnabled()) {
ignored.add(mContext.getResources().getString(
- com.android.internal.R.string.status_bar_location));
+ com.android.internal.R.string.status_bar_camera));
+ ignored.add(mContext.getResources().getString(
+ com.android.internal.R.string.status_bar_microphone));
+ if (mAllIndicatorsEnabled) {
+ ignored.add(mContext.getResources().getString(
+ com.android.internal.R.string.status_bar_location));
+ }
}
return ignored;
@@ -300,7 +317,7 @@
}
private void setChipVisibility(boolean chipVisible) {
- if (chipVisible && mPermissionsHubEnabled) {
+ if (chipVisible && getChipEnabled()) {
mPrivacyChip.setVisibility(View.VISIBLE);
// Makes sure that the chip is logged as viewed at most once each time QS is opened
// mListening makes sure that the callback didn't return after the user closed QS
@@ -607,7 +624,8 @@
mAlarmController.addCallback(this);
mLifecycle.setCurrentState(Lifecycle.State.RESUMED);
// Get the most up to date info
- mPermissionsHubEnabled = mPrivacyItemController.getIndicatorsAvailable();
+ mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable();
+ mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable();
mPrivacyItemController.addCallback(mPICCallback);
} else {
mZenController.removeCallback(this);
@@ -747,4 +765,8 @@
updateHeaderTextContainerAlphaAnimator();
}
}
+
+ private boolean getChipEnabled() {
+ return mMicCameraIndicatorsEnabled || mAllIndicatorsEnabled;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 8c485a6..d2aaaede 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -451,15 +451,17 @@
if (listening) {
if (mListeners.add(listener) && mListeners.size() == 1) {
if (DEBUG) Log.d(TAG, "handleSetListening true");
- mLifecycle.setCurrentState(RESUMED);
handleSetListening(listening);
- refreshState(); // Ensure we get at least one refresh after listening.
+ mUiHandler.post(() -> {
+ mLifecycle.setCurrentState(RESUMED);
+ refreshState(); // Ensure we get at least one refresh after listening.
+ });
}
} else {
if (mListeners.remove(listener) && mListeners.size() == 0) {
if (DEBUG) Log.d(TAG, "handleSetListening false");
- mLifecycle.setCurrentState(STARTED);
handleSetListening(listening);
+ mUiHandler.post(() -> mLifecycle.setCurrentState(STARTED));
}
}
updateIsFullQs();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index eb794a8..c64fc50 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -130,6 +130,7 @@
: mPowerSave ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
state.icon = mIcon;
state.label = mContext.getString(R.string.battery_detail_switch_title);
+ state.secondaryLabel = "";
state.contentDescription = state.label;
state.value = mPowerSave;
state.expandedAccessibilityClassName = Switch.class.getName();
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java
index 6f5ceab..6d1299b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java
@@ -205,7 +205,8 @@
mPublicNotificationBuilder
.setContentTitle(mResources.getString(R.string.screenshot_saved_title))
.setContentText(mResources.getString(R.string.screenshot_saved_text))
- .setContentIntent(PendingIntent.getActivity(mContext, 0, launchIntent, 0))
+ .setContentIntent(PendingIntent
+ .getActivity(mContext, 0, launchIntent, PendingIntent.FLAG_IMMUTABLE))
.setWhen(now)
.setAutoCancel(true)
.setColor(mContext.getColor(
@@ -213,7 +214,8 @@
mNotificationBuilder
.setContentTitle(mResources.getString(R.string.screenshot_saved_title))
.setContentText(mResources.getString(R.string.screenshot_saved_text))
- .setContentIntent(PendingIntent.getActivity(mContext, 0, launchIntent, 0))
+ .setContentIntent(PendingIntent
+ .getActivity(mContext, 0, launchIntent, PendingIntent.FLAG_IMMUTABLE))
.setWhen(now)
.setAutoCancel(true)
.setColor(mContext.getColor(
diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContentResolverProvider.kt b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContentResolverProvider.kt
new file mode 100644
index 0000000..9d05843
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContentResolverProvider.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.settings
+
+import android.content.ContentResolver
+
+interface CurrentUserContentResolverProvider {
+
+ val currentUserContentResolver: ContentResolver
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt
index 825a7f3..d7c4caaa 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt
@@ -16,6 +16,7 @@
package com.android.systemui.settings
+import android.content.ContentResolver
import android.content.Context
import android.os.UserHandle
import androidx.annotation.VisibleForTesting
@@ -31,7 +32,7 @@
class CurrentUserContextTracker internal constructor(
private val sysuiContext: Context,
broadcastDispatcher: BroadcastDispatcher
-) {
+) : CurrentUserContentResolverProvider {
private val userTracker: CurrentUserTracker
private var initialized = false
@@ -44,6 +45,9 @@
return _curUserContext!!
}
+ override val currentUserContentResolver: ContentResolver
+ get() = currentUserContext.contentResolver
+
init {
userTracker = object : CurrentUserTracker(broadcastDispatcher) {
override fun onUserSwitched(newUserId: Int) {
@@ -54,8 +58,8 @@
fun initialize() {
initialized = true
- _curUserContext = makeUserContext(userTracker.currentUserId)
userTracker.startTracking()
+ _curUserContext = makeUserContext(userTracker.currentUserId)
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java b/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java
index 2c5c3ce..eb5bd5c 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java
@@ -19,10 +19,12 @@
import android.content.Context;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.settings.CurrentUserContentResolverProvider;
import com.android.systemui.settings.CurrentUserContextTracker;
import javax.inject.Singleton;
+import dagger.Binds;
import dagger.Module;
import dagger.Provides;
@@ -30,7 +32,7 @@
* Dagger Module for classes found within the com.android.systemui.settings package.
*/
@Module
-public interface SettingsModule {
+public abstract class SettingsModule {
/**
* Provides and initializes a CurrentUserContextTracker
@@ -45,4 +47,9 @@
tracker.initialize();
return tracker;
}
+
+ @Binds
+ @Singleton
+ abstract CurrentUserContentResolverProvider bindCurrentUserContentResolverTracker(
+ CurrentUserContextTracker tracker);
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 4007abb..d40b666 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -78,6 +78,22 @@
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();
+ }
}
);
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java
index 81649f6..1ee8abb 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java
@@ -50,8 +50,7 @@
/**
* Controls the docked stack divider.
*/
-public class DividerController implements DividerView.DividerCallbacks,
- DisplayController.OnDisplaysChangedListener {
+public class DividerController implements DisplayController.OnDisplaysChangedListener {
static final boolean DEBUG = false;
private static final String TAG = "Divider";
@@ -257,8 +256,8 @@
mView = (DividerView)
LayoutInflater.from(dctx).inflate(R.layout.docked_stack_divider, null);
DisplayLayout displayLayout = mDisplayController.getDisplayLayout(mContext.getDisplayId());
- mView.injectDependencies(mWindowManager, mDividerState, this, mSplits, mSplitLayout,
- mImePositionProcessor, mWindowManagerProxy);
+ mView.injectDependencies(mWindowManager, mDividerState, mForcedResizableController, mSplits,
+ mSplitLayout, mImePositionProcessor, mWindowManagerProxy);
mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE);
mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, null /* transaction */);
final int size = dctx.getResources().getDimensionPixelSize(
@@ -397,7 +396,22 @@
}
}
- /** Called when there's a task undocking. */
+ /** Called when there's an activity forced resizable. */
+ public void onActivityForcedResizable(String packageName, int taskId, int reason) {
+ mForcedResizableController.activityForcedResizable(packageName, taskId, reason);
+ }
+
+ /** Called when there's an activity dismissing split screen. */
+ public void onActivityDismissingSplitScreen() {
+ mForcedResizableController.activityDismissingSplitScreen();
+ }
+
+ /** Called when there's an activity launch on secondary display failed. */
+ public void onActivityLaunchOnSecondaryDisplayFailed() {
+ mForcedResizableController.activityLaunchOnSecondaryDisplayFailed();
+ }
+
+ /** Called when there's a task undocking. */
public void onUndockingTask() {
if (mView != null) {
mView.onUndockingTask();
@@ -426,17 +440,7 @@
mForcedResizableController.onAppTransitionFinished();
}
- @Override
- public void onDraggingStart() {
- mForcedResizableController.onDraggingStart();
- }
-
- @Override
- public void onDraggingEnd() {
- mForcedResizableController.onDraggingEnd();
- }
-
- /** Dumps current status of Divider.*/
+ /** Dumps current status of Split Screen. */
public void dump(PrintWriter pw) {
pw.print(" mVisible="); pw.println(mVisible);
pw.print(" mMinimized="); pw.println(mMinimized);
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
index f412cc0..ff8bab0 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
@@ -28,15 +28,13 @@
import android.widget.Toast;
import com.android.systemui.R;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.TaskStackChangeListener;
import java.util.function.Consumer;
/**
* Controller that decides when to show the {@link ForcedResizableInfoActivity}.
*/
-public class ForcedResizableInfoActivityController {
+final class ForcedResizableInfoActivityController implements DividerView.DividerCallbacks {
private static final String SELF_PACKAGE_NAME = "com.android.systemui";
@@ -47,12 +45,7 @@
private final ArraySet<String> mPackagesShownInSession = new ArraySet<>();
private boolean mDividerDragging;
- private final Runnable mTimeoutRunnable = new Runnable() {
- @Override
- public void run() {
- showPending();
- }
- };
+ private final Runnable mTimeoutRunnable = this::showPending;
private final Consumer<Boolean> mDockedStackExistsListener = exists -> {
if (!exists) {
@@ -78,44 +71,28 @@
public ForcedResizableInfoActivityController(Context context,
DividerController dividerController) {
mContext = context;
- ActivityManagerWrapper.getInstance().registerTaskStackListener(
- new TaskStackChangeListener() {
- @Override
- public void onActivityForcedResizable(String packageName, int taskId,
- int reason) {
- activityForcedResizable(packageName, taskId, reason);
- }
-
- @Override
- public void onActivityDismissingDockedStack() {
- activityDismissingDockedStack();
- }
-
- @Override
- public void onActivityLaunchOnSecondaryDisplayFailed() {
- activityLaunchOnSecondaryDisplayFailed();
- }
- });
dividerController.registerInSplitScreenListener(mDockedStackExistsListener);
}
- public void onAppTransitionFinished() {
+ @Override
+ public void onDraggingStart() {
+ mDividerDragging = true;
+ mHandler.removeCallbacks(mTimeoutRunnable);
+ }
+
+ @Override
+ public void onDraggingEnd() {
+ mDividerDragging = false;
+ showPending();
+ }
+
+ void onAppTransitionFinished() {
if (!mDividerDragging) {
showPending();
}
}
- void onDraggingStart() {
- mDividerDragging = true;
- mHandler.removeCallbacks(mTimeoutRunnable);
- }
-
- void onDraggingEnd() {
- mDividerDragging = false;
- showPending();
- }
-
- private void activityForcedResizable(String packageName, int taskId, int reason) {
+ void activityForcedResizable(String packageName, int taskId, int reason) {
if (debounce(packageName)) {
return;
}
@@ -123,12 +100,12 @@
postTimeout();
}
- private void activityDismissingDockedStack() {
+ void activityDismissingSplitScreen() {
Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text,
Toast.LENGTH_SHORT).show();
}
- private void activityLaunchOnSecondaryDisplayFailed() {
+ void activityLaunchOnSecondaryDisplayFailed() {
Toast.makeText(mContext, R.string.activity_launch_on_secondary_display_failed_text,
Toast.LENGTH_SHORT).show();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java
index ca0f62e..b813b62 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java
@@ -20,9 +20,16 @@
import android.content.ContentResolver;
import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
import android.os.UserHandle;
import android.provider.Settings;
+import androidx.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import javax.inject.Inject;
@@ -35,23 +42,42 @@
* should show an indicator.
*/
@Singleton
-public class AssistantFeedbackController {
+public class AssistantFeedbackController extends ContentObserver {
+ private final Uri FEEDBACK_URI
+ = Settings.Global.getUriFor(Settings.Global.NOTIFICATION_FEEDBACK_ENABLED);
private ContentResolver mResolver;
+ private boolean mFeedbackEnabled;
+
/** Injected constructor */
@Inject
public AssistantFeedbackController(Context context) {
+ super(new Handler(Looper.getMainLooper()));
mResolver = context.getContentResolver();
+ mResolver.registerContentObserver(FEEDBACK_URI, false, this, UserHandle.USER_ALL);
+ update(null);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, @Nullable Uri uri, int flags) {
+ update(uri);
+ }
+
+ @VisibleForTesting
+ public void update(@Nullable Uri uri) {
+ if (uri == null || FEEDBACK_URI.equals(uri)) {
+ mFeedbackEnabled = Settings.Global.getInt(mResolver,
+ Settings.Global.NOTIFICATION_FEEDBACK_ENABLED, 0)
+ != 0;
+ }
}
/**
* Determines whether to show any user controls related to the assistant. This is based on the
- * settings flag {@link Settings.Secure.NOTIFICATION_FEEDBACK_ENABLED}
+ * settings flag {@link Settings.Global.NOTIFICATION_FEEDBACK_ENABLED}
*/
public boolean isFeedbackEnabled() {
- return Settings.Secure.getIntForUser(mResolver,
- Settings.Secure.NOTIFICATION_FEEDBACK_ENABLED, 0,
- UserHandle.USER_CURRENT) == 1;
+ return mFeedbackEnabled;
}
/**
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 99cb476..a87311a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -2620,6 +2620,7 @@
super.onClosingFinished();
resetHorizontalPanelPosition();
setClosingWithAlphaFadeout(false);
+ mMediaHierarchyManager.closeGuts();
}
private void setClosingWithAlphaFadeout(boolean closing) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index b2cfcea..8cb54ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -662,16 +662,18 @@
mIconController.setIconVisibility(mSlotCamera, showCamera);
mIconController.setIconVisibility(mSlotMicrophone, showMicrophone);
- mIconController.setIconVisibility(mSlotLocation, showLocation);
+ if (mPrivacyItemController.getAllIndicatorsAvailable()) {
+ mIconController.setIconVisibility(mSlotLocation, showLocation);
+ }
}
@Override
public void onLocationActiveChanged(boolean active) {
- if (!mPrivacyItemController.getIndicatorsAvailable()) updateLocation();
+ if (!mPrivacyItemController.getAllIndicatorsAvailable()) updateLocationFromController();
}
// Updates the status view based on the current state of location requests.
- private void updateLocation() {
+ private void updateLocationFromController() {
if (mLocationController.isLocationActive()) {
mIconController.setIconVisibility(mSlotLocation, true);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index b89cb21..8ff7a41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -86,7 +86,7 @@
static ArraySet<String> getIconHideList(Context context, String hideListStr) {
ArraySet<String> ret = new ArraySet<>();
String[] hideList = hideListStr == null
- ? context.getResources().getStringArray(R.array.config_statusBarIconBlackList)
+ ? context.getResources().getStringArray(R.array.config_statusBarIconsToExclude)
: hideListStr.split(",");
for (String slot : hideList) {
if (!TextUtils.isEmpty(slot)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index 673549a..e5a4679 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -79,6 +79,13 @@
default void setReverseState(boolean isReverse) {}
/**
+ * Returns {@code true} if extreme battery saver is on.
+ */
+ default boolean isExtremeSaverOn() {
+ return false;
+ }
+
+ /**
* A listener that will be notified whenever a change in battery level or power save mode has
* occurred.
*/
@@ -92,6 +99,9 @@
default void onReverseChanged(boolean isReverse, int level, String name) {
}
+
+ default void onExtremeBatterySaverChanged(boolean isExtreme) {
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java b/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java
index b25df5f..5e72808 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java
@@ -104,9 +104,13 @@
.setContentText(String.format(
"SystemUI has detected %d leaked objects. Tap to send", garbageCount))
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
- .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0,
+ .setContentIntent(PendingIntent.getActivityAsUser(
+ mContext,
+ 0,
getIntent(hprofFile, dumpFile),
- PendingIntent.FLAG_UPDATE_CURRENT, null, UserHandle.CURRENT));
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE,
+ null,
+ UserHandle.CURRENT));
notiMan.notify(TAG, 0, builder.build());
} catch (IOException e) {
Log.e(TAG, "Couldn't dump heap for leak", e);
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
index 9fa03df..06806d0 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
@@ -338,7 +338,7 @@
@Override
public void run() {
unregister();
- mSensor.alertListeners();
+ onProximityEvent(null);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellModule.java
index 5b2c39d..d2c61cc 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellModule.java
@@ -21,6 +21,8 @@
import android.view.IWindowManager;
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.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.SystemWindows;
@@ -65,4 +67,12 @@
return new DisplayImeController.Builder(wmService, displayController, mainHandler,
transactionPool).build();
}
+
+ /** TODO(b/150319024): PipMenuActivity will move to a Window */
+ @Singleton
+ @PipMenuActivityClass
+ @Provides
+ static Class<?> providePipMenuActivityClass() {
+ return PipMenuActivity.class;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
index fbc8e9d..ac567e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
@@ -25,6 +25,7 @@
import android.os.RemoteException;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.view.Display;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IWindowMagnificationConnection;
@@ -47,6 +48,7 @@
*/
@SmallTest
@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
public class IWindowMagnificationConnectionTest extends SysuiTestCase {
private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY;
@@ -57,7 +59,7 @@
@Mock
private IWindowMagnificationConnectionCallback mConnectionCallback;
@Mock
- private WindowMagnificationController mWindowMagnificationController;
+ private WindowMagnificationAnimationController mWindowMagnificationAnimationController;
@Mock
private ModeSwitchesController mModeSwitchesController;
private IWindowMagnificationConnection mIWindowMagnificationConnection;
@@ -74,7 +76,8 @@
any(IWindowMagnificationConnection.class));
mWindowMagnification = new WindowMagnification(getContext(),
getContext().getMainThreadHandler(), mCommandQueue, mModeSwitchesController);
- mWindowMagnification.mWindowMagnificationController = mWindowMagnificationController;
+ mWindowMagnification.mWindowMagnificationAnimationController =
+ mWindowMagnificationAnimationController;
mWindowMagnification.requestWindowMagnificationConnection(true);
assertNotNull(mIWindowMagnificationConnection);
mIWindowMagnificationConnection.setConnectionCallback(mConnectionCallback);
@@ -86,7 +89,7 @@
Float.NaN);
waitForIdleSync();
- verify(mWindowMagnificationController).enableWindowMagnification(3.0f, Float.NaN,
+ verify(mWindowMagnificationAnimationController).enableWindowMagnification(3.0f, Float.NaN,
Float.NaN);
}
@@ -99,7 +102,7 @@
mIWindowMagnificationConnection.disableWindowMagnification(TEST_DISPLAY);
waitForIdleSync();
- verify(mWindowMagnificationController).deleteWindowMagnification();
+ verify(mWindowMagnificationAnimationController).deleteWindowMagnification();
}
@Test
@@ -107,7 +110,7 @@
mIWindowMagnificationConnection.setScale(TEST_DISPLAY, 3.0f);
waitForIdleSync();
- verify(mWindowMagnificationController).setScale(3.0f);
+ verify(mWindowMagnificationAnimationController).setScale(3.0f);
}
@Test
@@ -115,7 +118,7 @@
mIWindowMagnificationConnection.moveWindowMagnifier(TEST_DISPLAY, 100f, 200f);
waitForIdleSync();
- verify(mWindowMagnificationController).moveWindowMagnifier(100f, 200f);
+ verify(mWindowMagnificationAnimationController).moveWindowMagnifier(100f, 200f);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
new file mode 100644
index 0000000..add0843
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
@@ -0,0 +1,362 @@
+/*
+ * 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.accessibility;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.animation.ValueAnimator;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.testing.AndroidTestingRunner;
+import android.view.SurfaceControl;
+import android.view.animation.AccelerateInterpolator;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+
+import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+
+@MediumTest
+@RunWith(AndroidTestingRunner.class)
+public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
+
+ private static final float DEFAULT_SCALE = 3.0f;
+ private static final float DEFAULT_CENTER_X = 400.0f;
+ private static final float DEFAULT_CENTER_Y = 500.0f;
+ private static final long ANIMATION_DURATION_MS = 100;
+
+ private AtomicReference<Float> mCurrentScale = new AtomicReference<>((float) 0);
+ private AtomicReference<Float> mCurrentCenterX = new AtomicReference<>((float) 0);
+ private AtomicReference<Float> mCurrentCenterY = new AtomicReference<>((float) 0);
+ private ArgumentCaptor<Float> mScaleCaptor = ArgumentCaptor.forClass(Float.class);
+ private ArgumentCaptor<Float> mCenterXCaptor = ArgumentCaptor.forClass(Float.class);
+ private ArgumentCaptor<Float> mCenterYCaptor = ArgumentCaptor.forClass(Float.class);
+
+ @Mock
+ Handler mHandler;
+ @Mock
+ SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
+ @Mock
+ WindowMagnifierCallback mWindowMagnifierCallback;
+
+ private SpyWindowMagnificationController mController;
+ private WindowMagnificationController mSpyController;
+ private WindowMagnificationAnimationController mWindowMagnificationAnimationController;
+ private Instrumentation mInstrumentation;
+ private long mWaitingAnimationPeriod;
+ private long mWaitIntermediateAnimationPeriod;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mWaitingAnimationPeriod = ANIMATION_DURATION_MS + 50;
+ mWaitIntermediateAnimationPeriod = ANIMATION_DURATION_MS / 2;
+ mController = new SpyWindowMagnificationController(mContext, mHandler,
+ mSfVsyncFrameProvider, null, new SurfaceControl.Transaction(),
+ mWindowMagnifierCallback);
+ mSpyController = mController.getSpyController();
+ mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
+ mContext, mController, newValueAnimator());
+ }
+
+ @Test
+ public void enableWindowMagnification_disabled_expectedStartAndEndValues() {
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+
+ verify(mSpyController, atLeast(2)).enableWindowMagnification(
+ mScaleCaptor.capture(),
+ mCenterXCaptor.capture(), mCenterYCaptor.capture());
+ verifyStartValue(mScaleCaptor, 1.0f);
+ verifyStartValue(mCenterXCaptor, DEFAULT_CENTER_X);
+ verifyStartValue(mCenterYCaptor, DEFAULT_CENTER_Y);
+ verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
+ }
+
+ @Test
+ public void enableWindowMagnification_enabling_expectedStartAndEndValues() {
+ enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod);
+ final float targetScale = DEFAULT_SCALE + 1.0f;
+ final float targetCenterX = DEFAULT_CENTER_X + 100;
+ final float targetCenterY = DEFAULT_CENTER_Y + 100;
+
+ mInstrumentation.runOnMainSync(() -> {
+ Mockito.reset(mSpyController);
+ mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+ targetCenterX, targetCenterY);
+ mCurrentScale.set(mController.getScale());
+ mCurrentCenterX.set(mController.getCenterX());
+ mCurrentCenterY.set(mController.getCenterY());
+ });
+
+ SystemClock.sleep(mWaitingAnimationPeriod);
+
+ verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
+ mCenterXCaptor.capture(), mCenterYCaptor.capture());
+ verifyStartValue(mScaleCaptor, mCurrentScale.get());
+ verifyStartValue(mCenterXCaptor, mCurrentCenterX.get());
+ verifyStartValue(mCenterYCaptor, mCurrentCenterY.get());
+ verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
+ }
+
+ @Test
+ public void enableWindowMagnification_disabling_expectedStartAndEndValues() {
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+ deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod);
+ final float targetScale = DEFAULT_SCALE + 1.0f;
+ final float targetCenterX = DEFAULT_CENTER_X + 100;
+ final float targetCenterY = DEFAULT_CENTER_Y + 100;
+
+ mInstrumentation.runOnMainSync(
+ () -> {
+ Mockito.reset(mSpyController);
+ mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+ targetCenterX, targetCenterY);
+ mCurrentScale.set(mController.getScale());
+ mCurrentCenterX.set(mController.getCenterX());
+ mCurrentCenterY.set(mController.getCenterY());
+ });
+ SystemClock.sleep(mWaitingAnimationPeriod);
+
+ verify(mSpyController, atLeast(2)).enableWindowMagnification(
+ mScaleCaptor.capture(),
+ mCenterXCaptor.capture(), mCenterYCaptor.capture());
+ //Animating in reverse, so we only check if the start values are greater than current.
+ assertTrue(mScaleCaptor.getAllValues().get(0) > mCurrentScale.get());
+ assertEquals(targetScale, mScaleCaptor.getValue(), 0f);
+ assertTrue(mCenterXCaptor.getAllValues().get(0) > mCurrentCenterX.get());
+ assertEquals(targetCenterX, mCenterXCaptor.getValue(), 0f);
+ assertTrue(mCenterYCaptor.getAllValues().get(0) > mCurrentCenterY.get());
+ assertEquals(targetCenterY, mCenterYCaptor.getValue(), 0f);
+ verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
+ }
+
+ @Test
+ public void enableWindowMagnificationWithSameScale_doNothing() {
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+
+ verify(mSpyController, never()).enableWindowMagnification(anyFloat(), anyFloat(),
+ anyFloat());
+ }
+
+ @Test
+ public void setScale_enabled_expectedScale() {
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+
+ mInstrumentation.runOnMainSync(
+ () -> mWindowMagnificationAnimationController.setScale(DEFAULT_SCALE + 1));
+
+ verify(mSpyController).setScale(DEFAULT_SCALE + 1);
+ verifyFinalSpec(DEFAULT_SCALE + 1, DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
+ }
+
+ @Test
+ public void deleteWindowMagnification_enabled_expectedStartAndEndValues() {
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+
+ deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+
+ verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
+ mCenterXCaptor.capture(), mCenterYCaptor.capture());
+ verify(mSpyController).deleteWindowMagnification();
+ verifyStartValue(mScaleCaptor, DEFAULT_SCALE);
+ verifyStartValue(mCenterXCaptor, Float.NaN);
+ verifyStartValue(mCenterYCaptor, Float.NaN);
+ verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
+ }
+
+ @Test
+ public void deleteWindowMagnification_disabled_doNothing() {
+ deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+
+ Mockito.verifyNoMoreInteractions(mSpyController);
+ }
+
+ @Test
+ public void deleteWindowMagnification_enabling_checkStartAndEndValues() {
+ enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod);
+
+ //It just reverse the animation, so we don't need to wait the whole duration.
+ mInstrumentation.runOnMainSync(
+ () -> {
+ Mockito.reset(mSpyController);
+ mWindowMagnificationAnimationController.deleteWindowMagnification();
+ mCurrentScale.set(mController.getScale());
+ mCurrentCenterX.set(mController.getCenterX());
+ mCurrentCenterY.set(mController.getCenterY());
+ });
+ SystemClock.sleep(mWaitingAnimationPeriod);
+
+ verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
+ mCenterXCaptor.capture(), mCenterYCaptor.capture());
+ verify(mSpyController).deleteWindowMagnification();
+
+ //The animation is in verse, so we only check the start values should no be greater than
+ // the current one.
+ assertTrue(mScaleCaptor.getAllValues().get(0) <= mCurrentScale.get());
+ assertEquals(1.0f, mScaleCaptor.getValue(), 0f);
+ verifyStartValue(mCenterXCaptor, Float.NaN);
+ verifyStartValue(mCenterYCaptor, Float.NaN);
+ verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
+ }
+
+ @Test
+ public void deleteWindowMagnification_disabling_checkStartAndValues() {
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+ deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod);
+
+ deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+
+ verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
+ mCenterXCaptor.capture(), mCenterYCaptor.capture());
+ verify(mSpyController).deleteWindowMagnification();
+ assertEquals(1.0f, mScaleCaptor.getValue(), 0f);
+ verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
+ }
+
+ @Test
+ public void moveWindowMagnifier_enabled() {
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+
+ mInstrumentation.runOnMainSync(
+ () -> mWindowMagnificationAnimationController.moveWindowMagnifier(100f, 200f));
+
+ verify(mSpyController).moveWindowMagnifier(100f, 200f);
+ verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X + 100f, DEFAULT_CENTER_Y + 100f);
+ }
+
+ @Test
+ public void onConfigurationChanged_passThrough() {
+ mWindowMagnificationAnimationController.onConfigurationChanged(100);
+
+ verify(mSpyController).onConfigurationChanged(100);
+ }
+ private void verifyFinalSpec(float expectedScale, float expectedCenterX,
+ float expectedCenterY) {
+ assertEquals(expectedScale, mController.getScale(), 0f);
+ assertEquals(expectedCenterX, mController.getCenterX(), 0f);
+ assertEquals(expectedCenterY, mController.getCenterY(), 0f);
+ }
+
+ private void enableWindowMagnificationAndWaitAnimating(long duration) {
+ mInstrumentation.runOnMainSync(
+ () -> {
+ Mockito.reset(mSpyController);
+ mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
+ DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
+ });
+ SystemClock.sleep(duration);
+ }
+
+ private void deleteWindowMagnificationAndWaitAnimating(long duration) {
+ mInstrumentation.runOnMainSync(
+ () -> {
+ resetMockObjects();
+ mWindowMagnificationAnimationController.deleteWindowMagnification();
+ });
+ SystemClock.sleep(duration);
+ }
+
+ private void verifyStartValue(ArgumentCaptor<Float> captor, float startValue) {
+ assertEquals(startValue, captor.getAllValues().get(0), 0f);
+ }
+
+ private void resetMockObjects() {
+ Mockito.reset(mSpyController);
+ }
+
+ /**
+ * It observes the methods in {@link WindowMagnificationController} since we couldn't spy it
+ * directly.
+ */
+ private static class SpyWindowMagnificationController extends WindowMagnificationController {
+ private WindowMagnificationController mSpyController;
+
+ SpyWindowMagnificationController(Context context, Handler handler,
+ SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
+ MirrorWindowControl mirrorWindowControl, SurfaceControl.Transaction transaction,
+ WindowMagnifierCallback callback) {
+ super(context, handler, sfVsyncFrameProvider, mirrorWindowControl, transaction,
+ callback);
+ mSpyController = Mockito.mock(WindowMagnificationController.class);
+ }
+
+ WindowMagnificationController getSpyController() {
+ return mSpyController;
+ }
+
+ @Override
+ void enableWindowMagnification(float scale, float centerX, float centerY) {
+ super.enableWindowMagnification(scale, centerX, centerY);
+ mSpyController.enableWindowMagnification(scale, centerX, centerY);
+ }
+
+ @Override
+ void deleteWindowMagnification() {
+ super.deleteWindowMagnification();
+ mSpyController.deleteWindowMagnification();
+ }
+
+ @Override
+ void moveWindowMagnifier(float offsetX, float offsetY) {
+ super.moveWindowMagnifier(offsetX, offsetX);
+ mSpyController.moveWindowMagnifier(offsetX, offsetY);
+ }
+
+ @Override
+ void setScale(float scale) {
+ super.setScale(scale);
+ mSpyController.setScale(scale);
+ }
+
+ @Override
+ void onConfigurationChanged(int configDiff) {
+ super.onConfigurationChanged(configDiff);
+ mSpyController.onConfigurationChanged(configDiff);
+ }
+
+ }
+
+ private static ValueAnimator newValueAnimator() {
+ final ValueAnimator valueAnimator = new ValueAnimator();
+ valueAnimator.setDuration(ANIMATION_DURATION_MS);
+ valueAnimator.setInterpolator(new AccelerateInterpolator(2.5f));
+ valueAnimator.setFloatValues(0.0f, 1.0f);
+ return valueAnimator;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 2007fbb..1515cec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -18,6 +18,7 @@
import static android.view.Choreographer.FrameCallback;
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.atLeastOnce;
@@ -83,9 +84,8 @@
@After
public void tearDown() {
- mInstrumentation.runOnMainSync(() -> {
- mWindowMagnificationController.deleteWindowMagnification();
- });
+ mInstrumentation.runOnMainSync(
+ () -> mWindowMagnificationController.deleteWindowMagnification());
}
@Test
@@ -121,4 +121,18 @@
verify(mSfVsyncFrameProvider, atLeastOnce()).postFrameCallback(any());
}
+
+ @Test
+ public void setScale_expectedValue() {
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+ Float.NaN);
+ });
+
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.setScale(3.0f);
+ });
+
+ assertEquals(3.0f, mWindowMagnificationController.getScale(), 0);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
index 4136013..936558b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
@@ -26,6 +26,7 @@
import android.graphics.Rect;
import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.view.Display;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IWindowMagnificationConnection;
@@ -45,6 +46,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
public class WindowMagnificationTest extends SysuiTestCase {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/CustomIconCacheTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/CustomIconCacheTest.kt
new file mode 100644
index 0000000..4d0f2ed
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/CustomIconCacheTest.kt
@@ -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.controls
+
+import android.content.ComponentName
+import android.graphics.drawable.Icon
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class CustomIconCacheTest : SysuiTestCase() {
+
+ companion object {
+ private val TEST_COMPONENT1 = ComponentName.unflattenFromString("pkg/.cls1")!!
+ private val TEST_COMPONENT2 = ComponentName.unflattenFromString("pkg/.cls2")!!
+ private const val CONTROL_ID_1 = "TEST_CONTROL_1"
+ private const val CONTROL_ID_2 = "TEST_CONTROL_2"
+ }
+
+ @Mock(stubOnly = true)
+ private lateinit var icon1: Icon
+ @Mock(stubOnly = true)
+ private lateinit var icon2: Icon
+ private lateinit var customIconCache: CustomIconCache
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ customIconCache = CustomIconCache()
+ }
+
+ @Test
+ fun testIconStoredCorrectly() {
+ customIconCache.store(TEST_COMPONENT1, CONTROL_ID_1, icon1)
+
+ assertTrue(icon1 === customIconCache.retrieve(TEST_COMPONENT1, CONTROL_ID_1))
+ }
+
+ @Test
+ fun testIconNotStoredReturnsNull() {
+ customIconCache.store(TEST_COMPONENT1, CONTROL_ID_1, icon1)
+
+ assertNull(customIconCache.retrieve(TEST_COMPONENT1, CONTROL_ID_2))
+ }
+
+ @Test
+ fun testWrongComponentReturnsNull() {
+ customIconCache.store(TEST_COMPONENT1, CONTROL_ID_1, icon1)
+
+ assertNull(customIconCache.retrieve(TEST_COMPONENT2, CONTROL_ID_1))
+ }
+
+ @Test
+ fun testChangeComponentOldComponentIsRemoved() {
+ customIconCache.store(TEST_COMPONENT1, CONTROL_ID_1, icon1)
+ customIconCache.store(TEST_COMPONENT2, CONTROL_ID_2, icon2)
+
+ assertNull(customIconCache.retrieve(TEST_COMPONENT1, CONTROL_ID_1))
+ assertNull(customIconCache.retrieve(TEST_COMPONENT1, CONTROL_ID_2))
+ }
+
+ @Test
+ fun testChangeComponentCorrectIconRetrieved() {
+ customIconCache.store(TEST_COMPONENT1, CONTROL_ID_1, icon1)
+ customIconCache.store(TEST_COMPONENT2, CONTROL_ID_1, icon2)
+
+ assertTrue(icon2 === customIconCache.retrieve(TEST_COMPONENT2, CONTROL_ID_1))
+ }
+
+ @Test
+ fun testStoreNull() {
+ customIconCache.store(TEST_COMPONENT1, CONTROL_ID_1, icon1)
+ customIconCache.store(TEST_COMPONENT1, CONTROL_ID_1, null)
+
+ assertNull(customIconCache.retrieve(TEST_COMPONENT1, CONTROL_ID_1))
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt
index ce33a8d..f0003ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt
@@ -22,6 +22,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.controls.ControlInterface
+import com.android.systemui.controls.CustomIconCache
import com.android.systemui.controls.controller.ControlInfo
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
@@ -57,6 +58,8 @@
private lateinit var callback: FavoritesModel.FavoritesModelCallback
@Mock
private lateinit var adapter: RecyclerView.Adapter<*>
+ @Mock
+ private lateinit var customIconCache: CustomIconCache
private lateinit var model: FavoritesModel
private lateinit var dividerWrapper: DividerWrapper
@@ -64,7 +67,7 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
- model = FavoritesModel(TEST_COMPONENT, INITIAL_FAVORITES, callback)
+ model = FavoritesModel(customIconCache, TEST_COMPONENT, INITIAL_FAVORITES, callback)
model.attachAdapter(adapter)
dividerWrapper = model.elements.first { it is DividerWrapper } as DividerWrapper
}
@@ -89,7 +92,7 @@
@Test
fun testInitialElements() {
val expected = INITIAL_FAVORITES.map {
- ControlInfoWrapper(TEST_COMPONENT, it, true)
+ ControlInfoWrapper(TEST_COMPONENT, it, true, customIconCache::retrieve)
} + DividerWrapper()
assertEquals(expected, model.elements)
}
@@ -287,5 +290,13 @@
verify(callback).onFirstChange()
}
+ @Test
+ fun testCacheCalledWhenGettingCustomIcon() {
+ val wrapper = model.elements[0] as ControlInfoWrapper
+ wrapper.customIcon
+
+ verify(customIconCache).retrieve(TEST_COMPONENT, wrapper.controlId)
+ }
+
private fun getDividerPosition(): Int = model.elements.indexOf(dividerWrapper)
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
index ac8c671..4c54954 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
@@ -88,7 +88,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper()
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class GlobalActionsDialogTest extends SysuiTestCase {
private GlobalActionsDialog mGlobalActionsDialog;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index c63781c..8a30b00 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.media
+import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Color
import android.graphics.drawable.GradientDrawable
@@ -23,6 +24,7 @@
import android.media.MediaMetadata
import android.media.session.MediaSession
import android.media.session.PlaybackState
+import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
@@ -35,24 +37,31 @@
import androidx.constraintlayout.widget.ConstraintSet
import androidx.lifecycle.LiveData
import androidx.test.filters.SmallTest
-import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.statusbar.phone.KeyguardDismissUtil
import com.android.systemui.util.animation.TransitionLayout
import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.any
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
+import dagger.Lazy
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers
+import org.mockito.ArgumentMatchers.anyLong
import org.mockito.Mock
+import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
+import org.mockito.Mockito.`when` as whenever
private const val KEY = "TEST_KEY"
private const val APP = "APP"
@@ -81,6 +90,8 @@
@Mock private lateinit var seekBarViewModel: SeekBarViewModel
@Mock private lateinit var seekBarData: LiveData<SeekBarViewModel.Progress>
@Mock private lateinit var mediaViewController: MediaViewController
+ @Mock private lateinit var keyguardDismissUtil: KeyguardDismissUtil
+ @Mock private lateinit var mediaDataManager: MediaDataManager
@Mock private lateinit var expandedSet: ConstraintSet
@Mock private lateinit var collapsedSet: ConstraintSet
private lateinit var appIcon: ImageView
@@ -100,6 +111,9 @@
private lateinit var action2: ImageButton
private lateinit var action3: ImageButton
private lateinit var action4: ImageButton
+ private lateinit var settings: View
+ private lateinit var cancel: View
+ private lateinit var dismiss: View
private lateinit var session: MediaSession
private val device = MediaDeviceData(true, null, DEVICE_NAME)
@@ -114,7 +128,7 @@
whenever(mediaViewController.collapsedLayout).thenReturn(collapsedSet)
player = MediaControlPanel(context, bgExecutor, activityStarter, mediaViewController,
- seekBarViewModel)
+ seekBarViewModel, Lazy { mediaDataManager }, keyguardDismissUtil)
whenever(seekBarViewModel.progress).thenReturn(seekBarData)
// Mock out a view holder for the player to attach to.
@@ -156,6 +170,12 @@
whenever(holder.action3).thenReturn(action3)
action4 = ImageButton(context)
whenever(holder.action4).thenReturn(action4)
+ settings = View(context)
+ whenever(holder.settings).thenReturn(settings)
+ cancel = View(context)
+ whenever(holder.cancel).thenReturn(cancel)
+ dismiss = View(context)
+ whenever(holder.dismiss).thenReturn(dismiss)
// Create media session
val metadataBuilder = MediaMetadata.Builder().apply {
@@ -254,4 +274,79 @@
assertThat(seamlessText.getText()).isEqualTo(DEVICE_NAME)
assertThat(seamless.isEnabled()).isFalse()
}
+
+ @Test
+ fun longClick_gutsClosed() {
+ player.attach(holder)
+ whenever(mediaViewController.isGutsVisible).thenReturn(false)
+
+ val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
+ verify(holder.player).setOnLongClickListener(captor.capture())
+
+ captor.value.onLongClick(holder.player)
+ verify(mediaViewController).openGuts()
+ }
+
+ @Test
+ fun longClick_gutsOpen() {
+ player.attach(holder)
+ whenever(mediaViewController.isGutsVisible).thenReturn(true)
+
+ val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
+ verify(holder.player).setOnLongClickListener(captor.capture())
+
+ captor.value.onLongClick(holder.player)
+ verify(mediaViewController, never()).openGuts()
+ }
+
+ @Test
+ fun cancelButtonClick_animation() {
+ player.attach(holder)
+
+ cancel.callOnClick()
+
+ verify(mediaViewController).closeGuts(false)
+ }
+
+ @Test
+ fun settingsButtonClick() {
+ player.attach(holder)
+
+ settings.callOnClick()
+
+ val captor = ArgumentCaptor.forClass(Intent::class.java)
+ verify(activityStarter).startActivity(captor.capture(), eq(true))
+
+ assertThat(captor.value.action).isEqualTo(ACTION_MEDIA_CONTROLS_SETTINGS)
+ }
+
+ @Test
+ fun dismissButtonClick() {
+ player.attach(holder)
+ val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
+ emptyList(), PACKAGE, session.getSessionToken(), null, null, true, null,
+ notificationKey = KEY)
+ player.bind(state)
+
+ dismiss.callOnClick()
+ val captor = ArgumentCaptor.forClass(ActivityStarter.OnDismissAction::class.java)
+ verify(keyguardDismissUtil).executeWhenUnlocked(captor.capture(), anyBoolean())
+
+ captor.value.onDismiss()
+ verify(mediaDataManager).dismissMediaData(eq(KEY), anyLong())
+ }
+
+ @Test
+ fun dismissButtonClick_nullNotificationKey() {
+ player.attach(holder)
+ val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
+ emptyList(), PACKAGE, session.getSessionToken(), null, null, true, null)
+ player.bind(state)
+
+ verify(keyguardDismissUtil, never())
+ .executeWhenUnlocked(
+ any(ActivityStarter.OnDismissAction::class.java),
+ ArgumentMatchers.anyBoolean()
+ )
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 59c2d0e..3789e6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -217,6 +217,20 @@
assertThat(data.actions).hasSize(1)
}
+ @Test
+ fun testDismissMedia_listenerCalled() {
+ val listener = mock(MediaDataManager.Listener::class.java)
+ mediaDataManager.addListener(listener)
+ mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+ mediaDataManager.onMediaDataLoaded(KEY, oldKey = null, data = mock(MediaData::class.java))
+ mediaDataManager.dismissMediaData(KEY, 0L)
+
+ foregroundExecutor.advanceClockToLast()
+ foregroundExecutor.runAllReady()
+
+ verify(listener).onMediaDataRemoved(eq(KEY))
+ }
+
/**
* Simple implementation of [MediaDataManager.Listener] for the test.
*
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
index 91c5ff8..d86dfa5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
@@ -142,4 +142,11 @@
verify(mediaCarouselController).onDesiredLocationChanged(ArgumentMatchers.anyInt(),
any(MediaHostState::class.java), anyBoolean(), anyLong(), anyLong())
}
+
+ @Test
+ fun testCloseGutsRelayToCarousel() {
+ mediaHiearchyManager.closeGuts()
+
+ verify(mediaCarouselController).closeGuts()
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
index c9c1111..f0066ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
@@ -16,7 +16,7 @@
package com.android.systemui.pip;
-import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN;
+import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
import static org.junit.Assert.assertEquals;
@@ -116,9 +116,9 @@
animator = mPipAnimationController
.getAnimator(mLeash, new Rect(), 0f, 1f)
- .setTransitionDirection(TRANSITION_DIRECTION_TO_FULLSCREEN);
+ .setTransitionDirection(TRANSITION_DIRECTION_LEAVE_PIP);
assertEquals("Transition to fullscreen mode",
- animator.getTransitionDirection(), TRANSITION_DIRECTION_TO_FULLSCREEN);
+ animator.getTransitionDirection(), TRANSITION_DIRECTION_LEAVE_PIP);
}
@Test
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 96bb521..9f67722 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
@@ -37,6 +37,7 @@
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;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.FloatingContentCoordinator;
@@ -85,6 +86,9 @@
@Mock
private SysUiState mSysUiState;
+ @Mock
+ private PipUiEventLogger mPipUiEventLogger;
+
private PipSnapAlgorithm mPipSnapAlgorithm;
private PipMotionHelper mMotionHelper;
private PipResizeGestureHandler mPipResizeGestureHandler;
@@ -104,7 +108,7 @@
mPipTouchHandler = new PipTouchHandler(mContext, mActivityManager,
mPipMenuActivityController, mInputConsumerController, mPipBoundsHandler,
mPipTaskOrganizer, mFloatingContentCoordinator, mDeviceConfigProxy,
- mPipSnapAlgorithm, mSysUiState);
+ mPipSnapAlgorithm, 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/privacy/PrivacyItemControllerFlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt
new file mode 100644
index 0000000..4ba29e6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.privacy
+
+import android.os.UserManager
+import android.provider.DeviceConfig
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.appops.AppOpsController
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.util.DeviceConfigProxy
+import com.android.systemui.util.DeviceConfigProxyFake
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.atLeastOnce
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class PrivacyItemControllerFlagsTest : SysuiTestCase() {
+ companion object {
+ fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
+ fun <T> eq(value: T): T = Mockito.eq(value) ?: value
+ fun <T> any(): T = Mockito.any<T>()
+
+ private const val ALL_INDICATORS =
+ SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED
+ private const val MIC_CAMERA = SystemUiDeviceConfigFlags.PROPERTY_MIC_CAMERA_ENABLED
+ }
+
+ @Mock
+ private lateinit var appOpsController: AppOpsController
+ @Mock
+ private lateinit var callback: PrivacyItemController.Callback
+ @Mock
+ private lateinit var userManager: UserManager
+ @Mock
+ private lateinit var broadcastDispatcher: BroadcastDispatcher
+ @Mock
+ private lateinit var dumpManager: DumpManager
+
+ private lateinit var privacyItemController: PrivacyItemController
+ private lateinit var executor: FakeExecutor
+ private lateinit var deviceConfigProxy: DeviceConfigProxy
+
+ fun PrivacyItemController(): PrivacyItemController {
+ return PrivacyItemController(
+ appOpsController,
+ executor,
+ executor,
+ broadcastDispatcher,
+ deviceConfigProxy,
+ userManager,
+ dumpManager
+ )
+ }
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ executor = FakeExecutor(FakeSystemClock())
+ deviceConfigProxy = DeviceConfigProxyFake()
+
+ privacyItemController = PrivacyItemController()
+ privacyItemController.addCallback(callback)
+
+ executor.runAllReady()
+ }
+
+ @Test
+ fun testNotListeningByDefault() {
+ assertFalse(privacyItemController.allIndicatorsAvailable)
+ assertFalse(privacyItemController.micCameraAvailable)
+
+ verify(appOpsController, never()).addCallback(any(), any())
+ }
+
+ @Test
+ fun testMicCameraChanged() {
+ changeMicCamera(true)
+ executor.runAllReady()
+
+ verify(callback).onFlagMicCameraChanged(true)
+ verify(callback, never()).onFlagAllChanged(anyBoolean())
+
+ assertTrue(privacyItemController.micCameraAvailable)
+ assertFalse(privacyItemController.allIndicatorsAvailable)
+ }
+
+ @Test
+ fun testAllChanged() {
+ changeAll(true)
+ executor.runAllReady()
+
+ verify(callback).onFlagAllChanged(true)
+ verify(callback, never()).onFlagMicCameraChanged(anyBoolean())
+
+ assertTrue(privacyItemController.allIndicatorsAvailable)
+ assertFalse(privacyItemController.micCameraAvailable)
+ }
+
+ @Test
+ fun testBothChanged() {
+ changeAll(true)
+ changeMicCamera(true)
+ executor.runAllReady()
+
+ verify(callback, atLeastOnce()).onFlagAllChanged(true)
+ verify(callback, atLeastOnce()).onFlagMicCameraChanged(true)
+
+ assertTrue(privacyItemController.allIndicatorsAvailable)
+ assertTrue(privacyItemController.micCameraAvailable)
+ }
+
+ @Test
+ fun testAll_listeningToAll() {
+ changeAll(true)
+ executor.runAllReady()
+
+ verify(appOpsController).addCallback(eq(PrivacyItemController.OPS), any())
+ }
+
+ @Test
+ fun testMicCamera_listening() {
+ changeMicCamera(true)
+ executor.runAllReady()
+
+ verify(appOpsController).addCallback(eq(PrivacyItemController.OPS), any())
+ }
+
+ @Test
+ fun testAll_listening() {
+ changeAll(true)
+ executor.runAllReady()
+
+ verify(appOpsController).addCallback(eq(PrivacyItemController.OPS), any())
+ }
+
+ @Test
+ fun testAllFalse_notListening() {
+ changeAll(true)
+ executor.runAllReady()
+ changeAll(false)
+ executor.runAllReady()
+
+ verify(appOpsController).removeCallback(any(), any())
+ }
+
+ @Test
+ fun testSomeListening_stillListening() {
+ changeAll(true)
+ changeMicCamera(true)
+ executor.runAllReady()
+ changeAll(false)
+ executor.runAllReady()
+
+ verify(appOpsController, never()).removeCallback(any(), any())
+ }
+
+ @Test
+ fun testAllDeleted_stopListening() {
+ changeAll(true)
+ executor.runAllReady()
+ changeAll(null)
+ executor.runAllReady()
+
+ verify(appOpsController).removeCallback(any(), any())
+ }
+
+ @Test
+ fun testMicDeleted_stopListening() {
+ changeMicCamera(true)
+ executor.runAllReady()
+ changeMicCamera(null)
+ executor.runAllReady()
+
+ verify(appOpsController).removeCallback(any(), any())
+ }
+
+ private fun changeMicCamera(value: Boolean?) = changeProperty(MIC_CAMERA, value)
+ private fun changeAll(value: Boolean?) = changeProperty(ALL_INDICATORS, value)
+
+ private fun changeProperty(name: String, value: Boolean?) {
+ deviceConfigProxy.setProperty(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ name,
+ value?.toString(),
+ false
+ )
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
index dddc350..fb42baa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
@@ -18,7 +18,6 @@
import android.app.ActivityManager
import android.app.AppOpsManager
-import android.content.Context
import android.content.Intent
import android.content.pm.UserInfo
import android.os.UserHandle
@@ -69,10 +68,11 @@
companion object {
val CURRENT_USER_ID = ActivityManager.getCurrentUser()
val TEST_UID = CURRENT_USER_ID * UserHandle.PER_USER_RANGE
- const val SYSTEM_UID = 1000
const val TEST_PACKAGE_NAME = "test"
- const val DEVICE_SERVICES_STRING = "Device services"
- const val TAG = "PrivacyItemControllerTest"
+
+ private const val ALL_INDICATORS =
+ SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED
+ private const val MIC_CAMERA = SystemUiDeviceConfigFlags.PROPERTY_MIC_CAMERA_ENABLED
fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
fun <T> eq(value: T): T = Mockito.eq(value) ?: value
fun <T> any(): T = Mockito.any<T>()
@@ -97,9 +97,8 @@
private lateinit var executor: FakeExecutor
private lateinit var deviceConfigProxy: DeviceConfigProxy
- fun PrivacyItemController(context: Context): PrivacyItemController {
+ fun PrivacyItemController(): PrivacyItemController {
return PrivacyItemController(
- context,
appOpsController,
executor,
executor,
@@ -116,11 +115,8 @@
executor = FakeExecutor(FakeSystemClock())
deviceConfigProxy = DeviceConfigProxyFake()
- appOpsController = mDependency.injectMockDependency(AppOpsController::class.java)
-
- deviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_PRIVACY,
- SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED,
- "true", false)
+ // Listen to everything by default
+ changeAll(true)
doReturn(listOf(object : UserInfo() {
init {
@@ -128,7 +124,7 @@
}
})).`when`(userManager).getProfiles(anyInt())
- privacyItemController = PrivacyItemController(mContext)
+ privacyItemController = PrivacyItemController()
}
@Test
@@ -276,15 +272,59 @@
@Test
fun testNotListeningWhenIndicatorsDisabled() {
- deviceConfigProxy.setProperty(
- DeviceConfig.NAMESPACE_PRIVACY,
- SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED,
- "false",
- false
- )
+ changeAll(false)
privacyItemController.addCallback(callback)
executor.runAllReady()
verify(appOpsController, never()).addCallback(eq(PrivacyItemController.OPS),
any())
}
+
+ @Test
+ fun testNotSendingLocationWhenOnlyMicCamera() {
+ changeAll(false)
+ changeMicCamera(true)
+ executor.runAllReady()
+
+ doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 0),
+ AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, "", 0)))
+ .`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+
+ privacyItemController.addCallback(callback)
+ executor.runAllReady()
+
+ verify(callback).onPrivacyItemsChanged(capture(argCaptor))
+
+ assertEquals(1, argCaptor.value.size)
+ assertEquals(PrivacyType.TYPE_CAMERA, argCaptor.value[0].privacyType)
+ }
+
+ @Test
+ fun testNotUpdated_LocationChangeWhenOnlyMicCamera() {
+ doReturn(listOf(AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, "", 0)))
+ .`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+
+ privacyItemController.addCallback(callback)
+ changeAll(false)
+ changeMicCamera(true)
+ executor.runAllReady()
+ reset(callback) // Clean callback
+
+ verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
+ argCaptorCallback.value.onActiveStateChanged(
+ AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true)
+
+ verify(callback, never()).onPrivacyItemsChanged(any())
+ }
+
+ private fun changeMicCamera(value: Boolean?) = changeProperty(MIC_CAMERA, value)
+ private fun changeAll(value: Boolean?) = changeProperty(ALL_INDICATORS, value)
+
+ private fun changeProperty(name: String, value: Boolean?) {
+ deviceConfigProxy.setProperty(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ name,
+ value?.toString(),
+ false
+ )
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 103e558..cccb65d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -74,7 +74,7 @@
import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
@SmallTest
public class QSTileImplTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
index 2d276bb..6b54791 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
@@ -47,7 +47,7 @@
import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper()
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
public class ScreenRecordTileTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
index 619d244..fb8c3d9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
@@ -57,8 +57,8 @@
@Before
public void setUp() {
- switchSetting(ON);
mAssistantFeedbackController = new AssistantFeedbackController(mContext);
+ switchSetting(ON);
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME,
0, null, TEST_UID, 0, new Notification(),
UserHandle.CURRENT, null, 0);
@@ -72,7 +72,6 @@
@Test
public void testUserControls_settingEnabled() {
- switchSetting(ON);
assertTrue(mAssistantFeedbackController.isFeedbackEnabled());
}
@@ -113,7 +112,8 @@
}
private void switchSetting(int setting) {
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
- Settings.Secure.NOTIFICATION_FEEDBACK_ENABLED, setting, UserHandle.USER_CURRENT);
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.NOTIFICATION_FEEDBACK_ENABLED, setting);
+ mAssistantFeedbackController.update(null);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
index ae87eef..781f875 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
@@ -41,7 +41,7 @@
import org.mockito.Mockito;
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper()
+@RunWithLooper(setAsMainLooper = true)
@SmallTest
public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java
index a16fb5e..86dacc1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java
@@ -37,7 +37,7 @@
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidTestingRunner.class)
@SmallTest
public class CallbackControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/LifecycleFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/LifecycleFragmentTest.java
index 0e1c560..b2f57d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/LifecycleFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/LifecycleFragmentTest.java
@@ -39,7 +39,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidTestingRunner.class)
@SmallTest
public class LifecycleFragmentTest extends SysuiBaseFragmentTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java
index 486939d..4f509ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java
@@ -49,7 +49,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidTestingRunner.class)
@SmallTest
public class SysuiLifecycleTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
index 8ba11da..c5a197e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.util.sensors;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -80,6 +81,8 @@
mFakeExecutor.runAllReady();
assertFalse(mFakeProximitySensor.isRegistered());
+ assertEquals(1, mTestableCallback.mNumCalls);
+ assertNull(mTestableCallback.mLastResult);
}
@Test
@@ -110,9 +113,12 @@
private static class TestableCallback implements Consumer<Boolean> {
Boolean mLastResult;
+ int mNumCalls = 0;
+
@Override
public void accept(Boolean result) {
mLastResult = result;
+ mNumCalls++;
}
}
}
diff --git a/packages/Tethering/res/values/config.xml b/packages/Tethering/res/values/config.xml
index 9b9dcde..5f8d299 100644
--- a/packages/Tethering/res/values/config.xml
+++ b/packages/Tethering/res/values/config.xml
@@ -73,6 +73,9 @@
<!-- Use the old dnsmasq DHCP server for tethering instead of the framework implementation. -->
<bool translatable="false" name="config_tether_enable_legacy_dhcp_server">false</bool>
+ <!-- Use legacy wifi p2p dedicated address instead of randomize address. -->
+ <bool translatable="false" name="config_tether_enable_legacy_wifi_p2p_dedicated_ip">false</bool>
+
<!-- Dhcp range (min, max) to use for tethering purposes -->
<string-array translatable="false" name="config_tether_dhcp_range">
</string-array>
diff --git a/packages/Tethering/res/values/overlayable.xml b/packages/Tethering/res/values/overlayable.xml
index 6a33d55..0ee7a99 100644
--- a/packages/Tethering/res/values/overlayable.xml
+++ b/packages/Tethering/res/values/overlayable.xml
@@ -30,6 +30,7 @@
-->
<item type="bool" name="config_tether_enable_bpf_offload"/>
<item type="bool" name="config_tether_enable_legacy_dhcp_server"/>
+ <item type="bool" name="config_tether_enable_legacy_wifi_p2p_dedicated_ip"/>
<item type="integer" name="config_tether_offload_poll_interval"/>
<item type="array" name="config_tether_upstream_types"/>
<item type="bool" name="config_tether_upstream_automatic"/>
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
index aa58a4b..fd9e360 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
@@ -15,6 +15,8 @@
*/
package com.android.networkstack.tethering;
+import static android.net.TetheringManager.TETHERING_WIFI_P2P;
+
import static java.util.Arrays.asList;
import android.content.Context;
@@ -58,6 +60,7 @@
private static final int BYTE_MASK = 0xff;
// reserved for bluetooth tethering.
private static final int BLUETOOTH_RESERVED = 44;
+ private static final int WIFI_P2P_RESERVED = 49;
private static final byte DEFAULT_ID = (byte) 42;
// Upstream monitor would be stopped when tethering is down. When tethering restart, downstream
@@ -71,15 +74,18 @@
// 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
// Tethering use 192.168.0.0/16 that has 256 contiguous class C network numbers.
private static final String DEFAULT_TETHERING_PREFIX = "192.168.0.0/16";
+ private static final String LEGACY_WIFI_P2P_IFACE_ADDRESS = "192.168.49.1/24";
private final IpPrefix mTetheringPrefix;
private final ConnectivityManager mConnectivityMgr;
+ private final TetheringConfiguration mConfig;
- public PrivateAddressCoordinator(Context context) {
+ public PrivateAddressCoordinator(Context context, TetheringConfiguration config) {
mDownstreams = new ArraySet<>();
mUpstreamPrefixMap = new ArrayMap<>();
mTetheringPrefix = new IpPrefix(DEFAULT_TETHERING_PREFIX);
mConnectivityMgr = (ConnectivityManager) context.getSystemService(
Context.CONNECTIVITY_SERVICE);
+ mConfig = config;
}
/**
@@ -141,12 +147,21 @@
mUpstreamPrefixMap.removeAll(toBeRemoved);
}
+ private boolean isReservedSubnet(final int subnet) {
+ return subnet == BLUETOOTH_RESERVED || subnet == WIFI_P2P_RESERVED;
+ }
+
/**
* Pick a random available address and mark its prefix as in use for the provided IpServer,
* returns null if there is no available address.
*/
@Nullable
public LinkAddress requestDownstreamAddress(final IpServer ipServer) {
+ if (mConfig.shouldEnableWifiP2pDedicatedIp()
+ && ipServer.interfaceType() == TETHERING_WIFI_P2P) {
+ return new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS);
+ }
+
// Address would be 192.168.[subAddress]/24.
final byte[] bytes = mTetheringPrefix.getRawAddress();
final int subAddress = getRandomSubAddr();
@@ -154,7 +169,7 @@
bytes[3] = getSanitizedAddressSuffix(subAddress, (byte) 0, (byte) 1, (byte) 0xff);
for (int i = 0; i < MAX_UBYTE; i++) {
final int newSubNet = (subNet + i) & BYTE_MASK;
- if (newSubNet == BLUETOOTH_RESERVED) continue;
+ if (isReservedSubnet(newSubNet)) continue;
bytes[2] = (byte) newSubNet;
final InetAddress addr;
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
index cfc6575..7dd5290 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -320,10 +320,13 @@
mExecutor = new TetheringThreadExecutor(mHandler);
mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor);
mNetdCallback = new NetdCallback();
- mPrivateAddressCoordinator = new PrivateAddressCoordinator(mContext);
// Load tethering configuration.
updateConfiguration();
+ // It is OK for the configuration to be passed to the PrivateAddressCoordinator at
+ // construction time because the only part of the configuration it uses is
+ // shouldEnableWifiP2pDedicatedIp(), and currently do not support changing that.
+ mPrivateAddressCoordinator = new PrivateAddressCoordinator(mContext, mConfig);
// Must be initialized after tethering configuration is loaded because BpfCoordinator
// constructor needs to use the configuration.
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
index e1771a5..5783805 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
@@ -84,6 +84,9 @@
public static final String TETHER_ENABLE_LEGACY_DHCP_SERVER =
"tether_enable_legacy_dhcp_server";
+ public static final String USE_LEGACY_WIFI_P2P_DEDICATED_IP =
+ "use_legacy_wifi_p2p_dedicated_ip";
+
/**
* Default value that used to periodic polls tether offload stats from tethering offload HAL
* to make the data warnings work.
@@ -113,6 +116,7 @@
private final int mOffloadPollInterval;
// TODO: Add to TetheringConfigurationParcel if required.
private final boolean mEnableBpfOffload;
+ private final boolean mEnableWifiP2pDedicatedIp;
public TetheringConfiguration(Context ctx, SharedLog log, int id) {
final SharedLog configLog = log.forSubComponent("config");
@@ -156,6 +160,10 @@
R.integer.config_tether_offload_poll_interval,
DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
+ mEnableWifiP2pDedicatedIp = getResourceBoolean(res,
+ R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip,
+ false /* defaultValue */);
+
configLog.log(toString());
}
@@ -199,6 +207,11 @@
return !TextUtils.isEmpty(provisioningAppNoUi);
}
+ /** Check whether dedicated wifi p2p address is enabled. */
+ public boolean shouldEnableWifiP2pDedicatedIp() {
+ return mEnableWifiP2pDedicatedIp;
+ }
+
/** Does the dumping.*/
public void dump(PrintWriter pw) {
pw.print("activeDataSubId: ");
@@ -233,6 +246,9 @@
pw.print("enableLegacyDhcpServer: ");
pw.println(enableLegacyDhcpServer);
+
+ pw.print("enableWifiP2pDedicatedIp: ");
+ pw.println(mEnableWifiP2pDedicatedIp);
}
/** Returns the string representation of this object.*/
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
index 2c0df6f..8e93c2e 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
@@ -15,6 +15,11 @@
*/
package com.android.networkstack.tethering;
+import static android.net.TetheringManager.TETHERING_ETHERNET;
+import static android.net.TetheringManager.TETHERING_USB;
+import static android.net.TetheringManager.TETHERING_WIFI;
+import static android.net.TetheringManager.TETHERING_WIFI_P2P;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.mockito.Mockito.never;
@@ -54,22 +59,34 @@
@Mock private IpServer mHotspotIpServer;
@Mock private IpServer mUsbIpServer;
@Mock private IpServer mEthernetIpServer;
+ @Mock private IpServer mWifiP2pIpServer;
@Mock private Context mContext;
@Mock private ConnectivityManager mConnectivityMgr;
+ @Mock private TetheringConfiguration mConfig;
private PrivateAddressCoordinator mPrivateAddressCoordinator;
private final IpPrefix mBluetoothPrefix = new IpPrefix("192.168.44.0/24");
+ private final LinkAddress mLegacyWifiP2pAddress = new LinkAddress("192.168.49.1/24");
private final Network mWifiNetwork = new Network(1);
private final Network mMobileNetwork = new Network(2);
private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork};
+ private void setUpIpServers() throws Exception {
+ when(mUsbIpServer.interfaceType()).thenReturn(TETHERING_USB);
+ when(mEthernetIpServer.interfaceType()).thenReturn(TETHERING_ETHERNET);
+ when(mHotspotIpServer.interfaceType()).thenReturn(TETHERING_WIFI);
+ when(mWifiP2pIpServer.interfaceType()).thenReturn(TETHERING_WIFI_P2P);
+ }
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mConnectivityMgr);
when(mConnectivityMgr.getAllNetworks()).thenReturn(mAllNetworks);
- mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext));
+ when(mConfig.shouldEnableWifiP2pDedicatedIp()).thenReturn(false);
+ setUpIpServers();
+ mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext, mConfig));
}
@Test
@@ -256,4 +273,38 @@
final IpPrefix ethPrefix = PrefixUtils.asIpPrefix(ethAddr);
assertEquals(predefinedPrefix, ethPrefix);
}
+
+ private int getSubAddress(final byte... ipv4Address) {
+ assertEquals(4, ipv4Address.length);
+
+ int subnet = Byte.toUnsignedInt(ipv4Address[2]);
+ return (subnet << 8) + ipv4Address[3];
+ }
+
+ private void assertReseveredWifiP2pPrefix() throws Exception {
+ LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mHotspotIpServer);
+ final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address);
+ final IpPrefix legacyWifiP2pPrefix = PrefixUtils.asIpPrefix(mLegacyWifiP2pAddress);
+ assertNotEquals(legacyWifiP2pPrefix, hotspotPrefix);
+ mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
+ }
+
+ @Test
+ public void testEnableLegacyWifiP2PAddress() throws Exception {
+ when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(
+ getSubAddress(mLegacyWifiP2pAddress.getAddress().getAddress()));
+ // No matter #shouldEnableWifiP2pDedicatedIp() is enabled or not, legacy wifi p2p prefix
+ // is resevered.
+ assertReseveredWifiP2pPrefix();
+
+ when(mConfig.shouldEnableWifiP2pDedicatedIp()).thenReturn(true);
+ assertReseveredWifiP2pPrefix();
+
+ // If #shouldEnableWifiP2pDedicatedIp() is enabled, wifi P2P gets the configured address.
+ LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mWifiP2pIpServer);
+ assertEquals(mLegacyWifiP2pAddress, address);
+ mPrivateAddressCoordinator.releaseDownstream(mWifiP2pIpServer);
+ }
}
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
index a9ac4e2..dc0940c 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
@@ -128,6 +128,8 @@
.thenReturn(new String[0]);
when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
false);
+ when(mResources.getBoolean(R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip))
+ .thenReturn(false);
initializeBpfOffloadConfiguration(true, null /* unset */);
mHasTelephonyManager = true;
@@ -413,4 +415,17 @@
R.string.config_mobile_hotspot_provision_response)).thenReturn(
PROVISIONING_APP_RESPONSE);
}
+
+ @Test
+ public void testEnableLegacyWifiP2PAddress() throws Exception {
+ final TetheringConfiguration defaultCfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+ assertFalse(defaultCfg.shouldEnableWifiP2pDedicatedIp());
+
+ when(mResources.getBoolean(R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip))
+ .thenReturn(true);
+ final TetheringConfiguration testCfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+ assertTrue(testCfg.shouldEnableWifiP2pDedicatedIp());
+ }
}
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index b0e401b..3f712dd 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -3706,33 +3706,40 @@
// OS: O
BACKUP_SETTINGS = 818;
+ // DEPRECATED: The metrics has been migrated to UiEvent per go/uievent.
// ACTION: Picture-in-picture was explicitly entered for an activity
// VALUE: true if it was entered while hiding as a result of moving to
// another task, false otherwise
- ACTION_PICTURE_IN_PICTURE_ENTERED = 819;
+ ACTION_PICTURE_IN_PICTURE_ENTERED = 819 [deprecated=true];
+ // DEPRECATED: The metrics has been migrated to UiEvent per go/uievent.
// ACTION: The activity currently in picture-in-picture was expanded back to fullscreen
// PACKAGE: The package name of the activity that was expanded back to fullscreen
- ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN = 820;
+ ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN = 820 [deprecated=true];
+ // DEPRECATED: The metrics no longer used after migration to UiEvent per go/uievent.
// ACTION: The activity currently in picture-in-picture was minimized
// VALUE: True if the PiP was minimized, false otherwise
- ACTION_PICTURE_IN_PICTURE_MINIMIZED = 821;
+ ACTION_PICTURE_IN_PICTURE_MINIMIZED = 821 [deprecated=true];
+ // DEPRECATED: The metrics has been migrated to UiEvent per go/uievent.
// ACTION: Picture-in-picture was dismissed via the dismiss button
// VALUE: 0 if dismissed by tap, 1 if dismissed by drag
- ACTION_PICTURE_IN_PICTURE_DISMISSED = 822;
+ ACTION_PICTURE_IN_PICTURE_DISMISSED = 822 [deprecated=true];
- // ACTION: The visibility of the picture-in-picture meny
+ // DEPRECATED: The metrics has been migrated to UiEvent per go/uievent.
+ // ACTION: The visibility of the picture-in-picture menu
// VALUE: Whether or not the menu is visible
- ACTION_PICTURE_IN_PICTURE_MENU = 823;
+ ACTION_PICTURE_IN_PICTURE_MENU = 823 [deprecated=true];
+ // DEPRECATED: The metrics has been migrated to UiEvent per go/uievent.
// Enclosing category for group of PICTURE_IN_PICTURE_ASPECT_RATIO_FOO events,
// logged when the aspect ratio changes
- ACTION_PICTURE_IN_PICTURE_ASPECT_RATIO_CHANGED = 824;
+ ACTION_PICTURE_IN_PICTURE_ASPECT_RATIO_CHANGED = 824 [deprecated=true];
+ // DEPRECATED: The metrics no longer used after migration to UiEvent per go/uievent.
// The current aspect ratio of the PiP, logged when it changes.
- PICTURE_IN_PICTURE_ASPECT_RATIO = 825;
+ PICTURE_IN_PICTURE_ASPECT_RATIO = 825 [deprecated=true];
// FIELD - length in dp of ACTION_LS_* gestures, or zero if not applicable
// CATEGORY: GLOBAL_SYSTEM_UI
diff --git a/services/Android.bp b/services/Android.bp
index f0144ac..ef52c2a 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -30,6 +30,7 @@
":services.midi-sources",
":services.net-sources",
":services.print-sources",
+ ":services.profcollect-sources",
":services.restrictions-sources",
":services.startop.iorap-sources",
":services.systemcaptions-sources",
@@ -73,6 +74,7 @@
"services.net",
"services.people",
"services.print",
+ "services.profcollect",
"services.restrictions",
"services.startop",
"services.systemcaptions",
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 2cd4c69..b134022 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -443,7 +443,11 @@
if (reboundAService || configurationChanged) {
onUserStateChangedLocked(userState);
}
- migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, packageName);
+ // Passing 0 for restoreFromSdkInt to have this migration check execute each
+ // time. It can make sure a11y button settings are correctly if there's an a11y
+ // service updated and modifies the a11y button configuration.
+ migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, packageName,
+ /* restoreFromSdkInt = */0);
}
}
@@ -554,7 +558,9 @@
synchronized (mLock) {
restoreEnabledAccessibilityServicesLocked(
intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE),
- intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE));
+ intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE),
+ intent.getIntExtra(Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT,
+ 0));
}
} else if (ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED.equals(which)) {
synchronized (mLock) {
@@ -563,6 +569,12 @@
intent.getIntExtra(Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT,
0));
}
+ } else if (Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS.equals(which)) {
+ synchronized (mLock) {
+ restoreAccessibilityButtonTargetsLocked(
+ intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE),
+ intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE));
+ }
}
}
}
@@ -588,7 +600,7 @@
final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM);
final Set<String> targetsFromSetting = new ArraySet<>();
readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
- userState.mUserId, targetsFromSetting, str -> str);
+ userState.mUserId, str -> str, targetsFromSetting);
final boolean targetsContainMagnification = targetsFromSetting.contains(
MAGNIFICATION_CONTROLLER_NAME);
if (targetsContainMagnification == displayMagnificationNavBarEnabled) {
@@ -1189,7 +1201,14 @@
// the state since the context in which the current user
// state was used has changed since it was inactive.
onUserStateChangedLocked(userState);
- migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, null);
+ // It's better to have this migration in SettingsProvider. Unfortunately,
+ // SettingsProvider migrated database in a very early stage which A11yManagerService
+ // haven't finished or started the initialization. We cannot get enough information from
+ // A11yManagerService to execute these migrations in SettingsProvider. Passing 0 for
+ // restoreFromSdkInt to have this migration check execute every time, because we did not
+ // find out a way to detect the device finished the OTA and switch the user.
+ migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, null,
+ /* restoreFromSdkInt = */0);
if (announceNewUser) {
// Schedule announcement of the current user if needed.
@@ -1234,7 +1253,8 @@
// Called only during settings restore; currently supports only the owner user
// TODO: http://b/22388012
- void restoreEnabledAccessibilityServicesLocked(String oldSetting, String newSetting) {
+ void restoreEnabledAccessibilityServicesLocked(String oldSetting, String newSetting,
+ int restoreFromSdkInt) {
readComponentNamesFromStringLocked(oldSetting, mTempComponentNameSet, false);
readComponentNamesFromStringLocked(newSetting, mTempComponentNameSet, true);
@@ -1246,7 +1266,32 @@
userState.mEnabledServices,
UserHandle.USER_SYSTEM);
onUserStateChangedLocked(userState);
- migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, null);
+ migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, null, restoreFromSdkInt);
+ }
+
+ /**
+ * User could enable accessibility services and configure accessibility button during the SUW.
+ * Merges current value of accessibility button settings into the restored one to make sure
+ * user's preferences of accessibility button updated in SUW are not lost.
+ *
+ * Called only during settings restore; currently supports only the owner user
+ * TODO: http://b/22388012
+ */
+ void restoreAccessibilityButtonTargetsLocked(String oldSetting, String newSetting) {
+ final Set<String> targetsFromSetting = new ArraySet<>();
+ readColonDelimitedStringToSet(oldSetting, str -> str, targetsFromSetting,
+ /* doMerge = */false);
+ readColonDelimitedStringToSet(newSetting, str -> str, targetsFromSetting,
+ /* doMerge = */true);
+
+ final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM);
+ userState.mAccessibilityButtonTargets.clear();
+ userState.mAccessibilityButtonTargets.addAll(targetsFromSetting);
+ persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
+ UserHandle.USER_SYSTEM, userState.mAccessibilityButtonTargets, str -> str);
+
+ scheduleNotifyClientsOfServicesStateChangeLocked(userState);
+ onUserStateChangedLocked(userState);
}
private int getClientStateLocked(AccessibilityUserState userState) {
@@ -1569,8 +1614,8 @@
*/
private void readComponentNamesFromSettingLocked(String settingName, int userId,
Set<ComponentName> outComponentNames) {
- readColonDelimitedSettingToSet(settingName, userId, outComponentNames,
- str -> ComponentName.unflattenFromString(str));
+ readColonDelimitedSettingToSet(settingName, userId,
+ str -> ComponentName.unflattenFromString(str), outComponentNames);
}
/**
@@ -1585,8 +1630,8 @@
private void readComponentNamesFromStringLocked(String names,
Set<ComponentName> outComponentNames,
boolean doMerge) {
- readColonDelimitedStringToSet(names, outComponentNames, doMerge,
- str -> ComponentName.unflattenFromString(str));
+ readColonDelimitedStringToSet(names, str -> ComponentName.unflattenFromString(str),
+ outComponentNames, doMerge);
}
@Override
@@ -1596,15 +1641,15 @@
componentName -> componentName.flattenToShortString());
}
- private <T> void readColonDelimitedSettingToSet(String settingName, int userId, Set<T> outSet,
- Function<String, T> toItem) {
+ private <T> void readColonDelimitedSettingToSet(String settingName, int userId,
+ Function<String, T> toItem, Set<T> outSet) {
final String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
settingName, userId);
- readColonDelimitedStringToSet(settingValue, outSet, false, toItem);
+ readColonDelimitedStringToSet(settingValue, toItem, outSet, false);
}
- private <T> void readColonDelimitedStringToSet(String names, Set<T> outSet, boolean doMerge,
- Function<String, T> toItem) {
+ private <T> void readColonDelimitedStringToSet(String names, Function<String, T> toItem,
+ Set<T> outSet, boolean doMerge) {
if (!doMerge) {
outSet.clear();
}
@@ -2104,7 +2149,7 @@
final String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, userState.mUserId);
final Set<String> targetsFromSetting = new ArraySet<>();
- readColonDelimitedStringToSet(settingValue, targetsFromSetting, false, str -> str);
+ readColonDelimitedStringToSet(settingValue, str -> str, targetsFromSetting, false);
// Fall back to device's default a11y service, only when setting is never updated.
if (settingValue == null) {
final String defaultService = mContext.getString(
@@ -2128,7 +2173,7 @@
private boolean readAccessibilityButtonTargetsLocked(AccessibilityUserState userState) {
final Set<String> targetsFromSetting = new ArraySet<>();
readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
- userState.mUserId, targetsFromSetting, str -> str);
+ userState.mUserId, str -> str, targetsFromSetting);
final Set<String> currentTargets =
userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON);
@@ -2392,9 +2437,15 @@
* (It happens when an enabled accessibility service package is upgraded.)
*
* @param packageName The package name to check, or {@code null} to check all services.
+ * @param restoreFromSdkInt The target sdk version of the restored source device, or {@code 0}
+ * if the caller is not related to the restore.
*/
private void migrateAccessibilityButtonSettingsIfNecessaryLocked(
- AccessibilityUserState userState, @Nullable String packageName) {
+ AccessibilityUserState userState, @Nullable String packageName, int restoreFromSdkInt) {
+ // No need to migrate settings if they are restored from a version after Q.
+ if (restoreFromSdkInt > Build.VERSION_CODES.Q) {
+ return;
+ }
final Set<String> buttonTargets =
userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON);
int lastSize = buttonTargets.size();
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
index 44c4bf4..b6f2a47 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -16,8 +16,10 @@
package com.android.server.accessibility.magnification;
+import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -61,6 +63,8 @@
private static final boolean DEBUG = false;
private static final String LOG_TAG = "FullScreenMagnificationController";
+ private static final Runnable STUB_RUNNABLE = () -> {
+ };
public static final float MIN_SCALE = 1.0f;
public static final float MAX_SCALE = 8.0f;
@@ -292,7 +296,7 @@
// Adjust the current spec's offsets if necessary.
if (updateCurrentSpecWithOffsetsLocked(
mCurrentMagnificationSpec.offsetX, mCurrentMagnificationSpec.offsetY)) {
- sendSpecToAnimation(mCurrentMagnificationSpec, false);
+ sendSpecToAnimation(mCurrentMagnificationSpec, null);
}
onMagnificationChangedLocked();
}
@@ -300,17 +304,18 @@
}
}
- void sendSpecToAnimation(MagnificationSpec spec, boolean animate) {
+ void sendSpecToAnimation(MagnificationSpec spec, Runnable endCallback) {
if (DEBUG) {
Slog.i(LOG_TAG,
- "sendSpecToAnimation(spec = " + spec + ", animate = " + animate + ")");
+ "sendSpecToAnimation(spec = " + spec + ", endCallback = " + endCallback
+ + ")");
}
if (Thread.currentThread().getId() == mMainThreadId) {
- mSpecAnimationBridge.updateSentSpecMainThread(spec, animate);
+ mSpecAnimationBridge.updateSentSpecMainThread(spec, endCallback);
} else {
final Message m = PooledLambda.obtainMessage(
SpecAnimationBridge::updateSentSpecMainThread,
- mSpecAnimationBridge, spec, animate);
+ mSpecAnimationBridge, spec, endCallback);
mControllerCtx.getHandler().sendMessage(m);
}
}
@@ -410,6 +415,11 @@
@GuardedBy("mLock")
boolean reset(boolean animate) {
+ return reset(transformToStubRunnable(animate));
+ }
+
+ @GuardedBy("mLock")
+ boolean reset(Runnable endCallback) {
if (!mRegistered) {
return false;
}
@@ -420,7 +430,7 @@
onMagnificationChangedLocked();
}
mIdOfLastServiceToMagnify = INVALID_ID;
- sendSpecToAnimation(spec, animate);
+ sendSpecToAnimation(spec, endCallback);
return changed;
}
@@ -448,24 +458,24 @@
final float centerX = normPivotX + offsetX;
final float centerY = normPivotY + offsetY;
mIdOfLastServiceToMagnify = id;
- return setScaleAndCenter(scale, centerX, centerY, animate, id);
+ return setScaleAndCenter(scale, centerX, centerY, transformToStubRunnable(animate), id);
}
@GuardedBy("mLock")
boolean setScaleAndCenter(float scale, float centerX, float centerY,
- boolean animate, int id) {
+ Runnable endCallback, int id) {
if (!mRegistered) {
return false;
}
if (DEBUG) {
Slog.i(LOG_TAG,
"setScaleAndCenterLocked(scale = " + scale + ", centerX = " + centerX
- + ", centerY = " + centerY + ", animate = " + animate
+ + ", centerY = " + centerY + ", endCallback = " + endCallback
+ ", id = " + id
+ ")");
}
final boolean changed = updateMagnificationSpecLocked(scale, centerX, centerY);
- sendSpecToAnimation(mCurrentMagnificationSpec, animate);
+ sendSpecToAnimation(mCurrentMagnificationSpec, endCallback);
if (isMagnifying() && (id != INVALID_ID)) {
mIdOfLastServiceToMagnify = id;
}
@@ -531,7 +541,7 @@
if (id != INVALID_ID) {
mIdOfLastServiceToMagnify = id;
}
- sendSpecToAnimation(mCurrentMagnificationSpec, false);
+ sendSpecToAnimation(mCurrentMagnificationSpec, null);
}
boolean updateCurrentSpecWithOffsetsLocked(float nonNormOffsetX, float nonNormOffsetY) {
@@ -865,12 +875,26 @@
* the spec did not change
*/
public boolean reset(int displayId, boolean animate) {
+ return reset(displayId, animate ? STUB_RUNNABLE : null);
+ }
+
+ /**
+ * Resets the magnification scale and center, optionally animating the
+ * transition.
+ *
+ * @param displayId The logical display id.
+ * @param endCallback Called when the animation is ended or the spec did not change.
+ * {@code null} to transition immediately
+ * @return {@code true} if the magnification spec changed, {@code false} if
+ * the spec did not change
+ */
+ public boolean reset(int displayId, Runnable endCallback) {
synchronized (mLock) {
final DisplayMagnification display = mDisplays.get(displayId);
if (display == null) {
return false;
}
- return display.reset(animate);
+ return display.reset(endCallback);
}
}
@@ -921,7 +945,8 @@
if (display == null) {
return false;
}
- return display.setScaleAndCenter(Float.NaN, centerX, centerY, animate, id);
+ return display.setScaleAndCenter(Float.NaN, centerX, centerY,
+ animate ? STUB_RUNNABLE : null, id);
}
}
@@ -944,12 +969,35 @@
*/
public boolean setScaleAndCenter(int displayId, float scale, float centerX, float centerY,
boolean animate, int id) {
+ return setScaleAndCenter(displayId, scale, centerX, centerY,
+ transformToStubRunnable(animate), id);
+ }
+
+ /**
+ * Sets the scale and center of the magnified region, optionally
+ * animating the transition. If animation is disabled, the transition
+ * is immediate.
+ *
+ * @param displayId The logical display id.
+ * @param scale the target scale, or {@link Float#NaN} to leave unchanged
+ * @param centerX the screen-relative X coordinate around which to
+ * center and scale, or {@link Float#NaN} to leave unchanged
+ * @param centerY the screen-relative Y coordinate around which to
+ * center and scale, or {@link Float#NaN} to leave unchanged
+ * @param endCallback called when the transition is finished successfully or the spec did not
+ * change. {@code null} to transition immediately.
+ * @param id the ID of the service requesting the change
+ * @return {@code true} if the magnification spec changed, {@code false} if
+ * the spec did not change
+ */
+ public boolean setScaleAndCenter(int displayId, float scale, float centerX, float centerY,
+ Runnable endCallback, int id) {
synchronized (mLock) {
final DisplayMagnification display = mDisplays.get(displayId);
if (display == null) {
return false;
}
- return display.setScaleAndCenter(scale, centerX, centerY, animate, id);
+ return display.setScaleAndCenter(scale, centerX, centerY, endCallback, id);
}
}
@@ -1160,7 +1208,8 @@
* Class responsible for animating spec on the main thread and sending spec
* updates to the window manager.
*/
- private static class SpecAnimationBridge implements ValueAnimator.AnimatorUpdateListener {
+ private static class SpecAnimationBridge implements ValueAnimator.AnimatorUpdateListener,
+ Animator.AnimatorListener {
private final ControllerContext mControllerCtx;
/**
@@ -1180,6 +1229,8 @@
*/
private final ValueAnimator mValueAnimator;
+ // Called when the callee wants animating and the sent spec matches the target spec.
+ private Runnable mEndCallback;
private final Object mLock;
private final int mDisplayId;
@@ -1197,6 +1248,7 @@
mValueAnimator.setInterpolator(new DecelerateInterpolator(2.5f));
mValueAnimator.setFloatValues(0.0f, 1.0f);
mValueAnimator.addUpdateListener(this);
+ mValueAnimator.addListener(this);
}
/**
@@ -1216,24 +1268,36 @@
}
}
- public void updateSentSpecMainThread(MagnificationSpec spec, boolean animate) {
+ void updateSentSpecMainThread(MagnificationSpec spec, Runnable endCallback) {
if (mValueAnimator.isRunning()) {
+ // Avoid AnimationEnd Callback.
+ mEndCallback = null;
mValueAnimator.cancel();
}
+ mEndCallback = endCallback;
// If the current and sent specs don't match, update the sent spec.
synchronized (mLock) {
final boolean changed = !mSentMagnificationSpec.equals(spec);
if (changed) {
- if (animate) {
+ if (mEndCallback != null) {
animateMagnificationSpecLocked(spec);
} else {
setMagnificationSpecLocked(spec);
}
+ } else {
+ sendEndCallbackMainThread();
}
}
}
+ private void sendEndCallbackMainThread() {
+ if (mEndCallback != null) {
+ mEndCallback.run();
+ mEndCallback = null;
+ }
+ }
+
@GuardedBy("mLock")
private void setMagnificationSpecLocked(MagnificationSpec spec) {
if (mEnabled) {
@@ -1270,6 +1334,26 @@
}
}
}
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ sendEndCallbackMainThread();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+
+ }
}
private static class ScreenStateObserver extends BroadcastReceiver {
@@ -1395,4 +1479,9 @@
return mAnimationDuration;
}
}
+
+ @Nullable
+ private static Runnable transformToStubRunnable(boolean animate) {
+ return animate ? STUB_RUNNABLE : null;
+ }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
index bd25f2b..3ee5b28 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -25,10 +25,12 @@
import android.annotation.Nullable;
import android.content.Context;
+import android.graphics.Point;
import android.provider.Settings;
import android.util.Log;
import android.util.MathUtils;
import android.util.Slog;
+import android.view.Display;
import android.view.MotionEvent;
import com.android.internal.annotations.VisibleForTesting;
@@ -90,6 +92,8 @@
private MotionEventDispatcherDelegate mMotionEventDispatcherDelegate;
private final int mDisplayId;
+ private final Context mContext;
+ private final Point mTempPoint = new Point();
private final Queue<MotionEvent> mDebugOutputEventHistory;
@@ -107,7 +111,7 @@
Slog.i(LOG_TAG,
"WindowMagnificationGestureHandler() , displayId = " + displayId + ")");
}
-
+ mContext = context;
mWindowMagnificationMgr = windowMagnificationMgr;
mDetectShortcutTrigger = detectShortcutTrigger;
mDisplayId = displayId;
@@ -184,7 +188,14 @@
if (!mDetectShortcutTrigger) {
return;
}
- toggleMagnification(Float.NaN, Float.NaN);
+ final Point screenSize = mTempPoint;
+ getScreenSize(mTempPoint);
+ toggleMagnification(screenSize.x / 2.0f, screenSize.y / 2.0f);
+ }
+
+ private void getScreenSize(Point outSize) {
+ final Display display = mContext.getDisplay();
+ display.getRealSize(outSize);
}
@Override
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 1093515..e76ec74 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -79,6 +79,7 @@
":framework_native_aidl",
":gsiservice_aidl",
":idmap2_aidl",
+ ":inputconstants_aidl",
":installd_aidl",
":storaged_aidl",
":vold_aidl",
diff --git a/services/core/java/android/os/BatteryStatsInternal.java b/services/core/java/android/os/BatteryStatsInternal.java
index 7cf5fd6..b7fed87 100644
--- a/services/core/java/android/os/BatteryStatsInternal.java
+++ b/services/core/java/android/os/BatteryStatsInternal.java
@@ -50,5 +50,5 @@
* Informs battery stats of binder stats for the given work source UID.
*/
public abstract void noteBinderCallStats(int workSourceUid, long incrementalBinderCallCount,
- Collection<BinderCallsStats.CallStat> callStats);
+ Collection<BinderCallsStats.CallStat> callStats, int[] binderThreadNativeTids);
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 7381da1..6d71c8e 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -34,7 +34,6 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
-import android.net.LinkProperties;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -46,8 +45,6 @@
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.telephony.Annotation;
-import android.telephony.Annotation.ApnType;
-import android.telephony.Annotation.DataFailureCause;
import android.telephony.Annotation.RadioPowerState;
import android.telephony.Annotation.SrvccState;
import android.telephony.BarringInfo;
@@ -80,7 +77,9 @@
import android.telephony.data.ApnSetting;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsReasonInfo;
+import android.util.ArrayMap;
import android.util.LocalLog;
+import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
@@ -103,6 +102,7 @@
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
+import java.util.Objects;
/**
* Since phone process can be restarted, this class provides a centralized place
@@ -302,13 +302,18 @@
@RadioPowerState
private int mRadioPowerState = TelephonyManager.RADIO_POWER_UNAVAILABLE;
- private final LocalLog mLocalLog = new LocalLog(100);
+ private final LocalLog mLocalLog = new LocalLog(200);
- private final LocalLog mListenLog = new LocalLog(100);
+ private final LocalLog mListenLog = new LocalLog(00);
- // Per-phoneMap of APN Type to DataConnectionState
- private List<Map<Integer, PreciseDataConnectionState>> mPreciseDataConnectionStates =
- new ArrayList<Map<Integer, PreciseDataConnectionState>>();
+ /**
+ * Per-phone map of precise data connection state. The key of the map is the pair of transport
+ * type and APN setting. This is the cache to prevent redundant callbacks to the listeners.
+ * A precise data connection with state {@link TelephonyManager#DATA_DISCONNECTED} removes
+ * its entry from the map.
+ */
+ private List<Map<Pair<Integer, ApnSetting>, PreciseDataConnectionState>>
+ mPreciseDataConnectionStates;
static final int ENFORCE_COARSE_LOCATION_PERMISSION_MASK =
PhoneStateListener.LISTEN_REGISTRATION_FAILURE
@@ -521,7 +526,7 @@
mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
mForegroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
mBackgroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
- mPreciseDataConnectionStates.add(new HashMap<Integer, PreciseDataConnectionState>());
+ mPreciseDataConnectionStates.add(new ArrayMap<>());
mBarringInfo.add(i, new BarringInfo());
mTelephonyDisplayInfos[i] = null;
}
@@ -610,7 +615,7 @@
mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
mForegroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
mBackgroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
- mPreciseDataConnectionStates.add(new HashMap<Integer, PreciseDataConnectionState>());
+ mPreciseDataConnectionStates.add(new ArrayMap<>());
mBarringInfo.add(i, new BarringInfo());
mTelephonyDisplayInfos[i] = null;
}
@@ -1687,38 +1692,25 @@
*
* @param phoneId the phoneId carrying the data connection
* @param subId the subscriptionId for the data connection
- * @param apnType the apn type bitmask, defined with {@code ApnSetting#TYPE_*} flags.
* @param preciseState a PreciseDataConnectionState that has info about the data connection
*/
@Override
- public void notifyDataConnectionForSubscriber(
- int phoneId, int subId, @ApnType int apnType, PreciseDataConnectionState preciseState) {
+ public void notifyDataConnectionForSubscriber(int phoneId, int subId,
+ @NonNull PreciseDataConnectionState preciseState) {
if (!checkNotifyPermission("notifyDataConnection()" )) {
return;
}
- String apn = "";
- int state = TelephonyManager.DATA_UNKNOWN;
- int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
- LinkProperties linkProps = null;
+ ApnSetting apnSetting = preciseState.getApnSetting();
- if (preciseState != null) {
- apn = preciseState.getDataConnectionApn();
- state = preciseState.getState();
- networkType = preciseState.getNetworkType();
- linkProps = preciseState.getLinkProperties();
- }
- if (VDBG) {
- log("notifyDataConnectionForSubscriber: subId=" + subId
- + " state=" + state + "' apn='" + apn
- + "' apnType=" + apnType + " networkType=" + networkType
- + "' preciseState=" + preciseState);
- }
+ int apnTypes = apnSetting.getApnTypeBitmask();
+ int state = preciseState.getState();
+ int networkType = preciseState.getNetworkType();
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
// We only call the callback when the change is for default APN type.
- if ((ApnSetting.TYPE_DEFAULT & apnType) != 0
+ if ((ApnSetting.TYPE_DEFAULT & apnTypes) != 0
&& (mDataConnectionState[phoneId] != state
|| mDataConnectionNetworkType[phoneId] != networkType)) {
String str = "onDataConnectionStateChanged("
@@ -1747,19 +1739,11 @@
mDataConnectionNetworkType[phoneId] = networkType;
}
- boolean needsNotify = false;
- // State has been cleared for this APN Type
- if (preciseState == null) {
- // We try clear the state and check if the state was previously not cleared
- needsNotify = mPreciseDataConnectionStates.get(phoneId).remove(apnType) != null;
- } else {
- // We need to check to see if the state actually changed
- PreciseDataConnectionState oldPreciseState =
- mPreciseDataConnectionStates.get(phoneId).put(apnType, preciseState);
- needsNotify = !preciseState.equals(oldPreciseState);
- }
-
- if (needsNotify) {
+ Pair<Integer, ApnSetting> key = Pair.create(preciseState.getTransportType(),
+ preciseState.getApnSetting());
+ PreciseDataConnectionState oldState = mPreciseDataConnectionStates.get(phoneId)
+ .remove(key);
+ if (!Objects.equals(oldState, preciseState)) {
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)
@@ -1771,54 +1755,22 @@
}
}
}
+ handleRemoveListLocked();
+
+ broadcastDataConnectionStateChanged(phoneId, subId, preciseState);
+
+ String str = "notifyDataConnectionForSubscriber: phoneId=" + phoneId + " subId="
+ + subId + " " + preciseState;
+ log(str);
+ mLocalLog.log(str);
+ }
+
+ // If the state is disconnected, it would be the end of life cycle of a data
+ // connection, so remove it from the cache.
+ if (preciseState.getState() != TelephonyManager.DATA_DISCONNECTED) {
+ mPreciseDataConnectionStates.get(phoneId).put(key, preciseState);
}
}
- handleRemoveListLocked();
- }
-
- broadcastDataConnectionStateChanged(state, apn, apnType, subId);
- }
-
- /**
- * Stub to satisfy the ITelephonyRegistry aidl interface; do not use this function.
- * @see #notifyDataConnectionFailedForSubscriber
- */
- public void notifyDataConnectionFailed(String apnType) {
- loge("This function should not be invoked");
- }
-
- private void notifyDataConnectionFailedForSubscriber(int phoneId, int subId, int apnType) {
- if (!checkNotifyPermission("notifyDataConnectionFailed()")) {
- return;
- }
- if (VDBG) {
- log("notifyDataConnectionFailedForSubscriber: subId=" + subId
- + " apnType=" + apnType);
- }
- synchronized (mRecords) {
- if (validatePhoneId(phoneId)) {
- mPreciseDataConnectionStates.get(phoneId).put(
- apnType,
- new PreciseDataConnectionState.Builder()
- .setApnSetting(new ApnSetting.Builder()
- .setApnTypeBitmask(apnType)
- .build())
- .build());
- for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)
- && idMatch(r.subId, subId, phoneId)) {
- try {
- r.callback.onPreciseDataConnectionStateChanged(
- mPreciseDataConnectionStates.get(phoneId).get(apnType));
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
- }
- }
- }
- }
-
- handleRemoveListLocked();
}
}
@@ -1972,43 +1924,6 @@
}
@Override
- public void notifyPreciseDataConnectionFailed(int phoneId, int subId, @ApnType int apnType,
- String apn, @DataFailureCause int failCause) {
- if (!checkNotifyPermission("notifyPreciseDataConnectionFailed()")) {
- return;
- }
-
- // precise notify invokes imprecise notify
- notifyDataConnectionFailedForSubscriber(phoneId, subId, apnType);
-
- synchronized (mRecords) {
- if (validatePhoneId(phoneId)) {
- mPreciseDataConnectionStates.get(phoneId).put(
- apnType,
- new PreciseDataConnectionState.Builder()
- .setApnSetting(new ApnSetting.Builder()
- .setApnTypeBitmask(apnType)
- .build())
- .setFailCause(failCause)
- .build());
- for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)
- && idMatch(r.subId, subId, phoneId)) {
- try {
- r.callback.onPreciseDataConnectionStateChanged(
- mPreciseDataConnectionStates.get(phoneId).get(apnType));
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
- }
- }
- }
- }
- handleRemoveListLocked();
- }
- }
-
- @Override
public void notifySrvccStateChanged(int subId, @SrvccState int state) {
if (!checkNotifyPermission("notifySrvccStateChanged()")) {
return;
@@ -2578,16 +2493,18 @@
}
}
- private void broadcastDataConnectionStateChanged(int state, String apn,
- int apnType, int subId) {
+ private void broadcastDataConnectionStateChanged(int slotIndex, int subId,
+ @NonNull PreciseDataConnectionState pdcs) {
// Note: not reporting to the battery stats service here, because the
// status bar takes care of that after taking into account all of the
// required info.
Intent intent = new Intent(ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
- intent.putExtra(PHONE_CONSTANTS_STATE_KEY, TelephonyUtils.dataStateToString(state));
- intent.putExtra(PHONE_CONSTANTS_DATA_APN_KEY, apn);
+ intent.putExtra(PHONE_CONSTANTS_STATE_KEY,
+ TelephonyUtils.dataStateToString(pdcs.getState()));
+ intent.putExtra(PHONE_CONSTANTS_DATA_APN_KEY, pdcs.getApnSetting().getApnName());
intent.putExtra(PHONE_CONSTANTS_DATA_APN_TYPE_KEY,
- ApnSetting.getApnTypesStringFromBitmask(apnType));
+ ApnSetting.getApnTypesStringFromBitmask(pdcs.getApnSetting().getApnTypeBitmask()));
+ intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, slotIndex);
intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL, Manifest.permission.READ_PHONE_STATE);
}
@@ -2973,7 +2890,7 @@
/**
* Returns a string representation of the radio technology (network type)
* currently in use on the device.
- * @param subId for which network type is returned
+ * @param type for which network type is returned
* @return the name of the radio technology
*
*/
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 72f29b4..2534a53 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -76,6 +76,8 @@
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
+import libcore.util.NativeAllocationRegistry;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -115,7 +117,6 @@
// If HAL supports callbacks set the timeout to ASYNC_TIMEOUT_MULTIPLIER * duration.
private static final long ASYNC_TIMEOUT_MULTIPLIER = 2;
-
// 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
@@ -128,8 +129,6 @@
private final LinkedList<VibrationInfo> mPreviousVibrations;
private final int mPreviousVibrationsLimit;
private final boolean mAllowPriorityVibrationsInLowPowerMode;
- private final boolean mSupportsAmplitudeControl;
- private final boolean mSupportsExternalControl;
private final List<Integer> mSupportedEffects;
private final long mCapabilities;
private final int mDefaultVibrationAmplitude;
@@ -174,22 +173,23 @@
private int mRingIntensity;
private SparseArray<Vibration> mAlwaysOnEffects = new SparseArray<>();
- static native boolean vibratorExists();
- static native void vibratorInit();
+ static native long vibratorInit();
+
+ static native long vibratorGetFinalizer();
+ static native boolean vibratorExists(long controllerPtr);
static native void vibratorOn(long milliseconds);
- static native void vibratorOff();
- static native boolean vibratorSupportsAmplitudeControl();
- static native void vibratorSetAmplitude(int amplitude);
- static native int[] vibratorGetSupportedEffects();
+ static native void vibratorOff(long controllerPtr);
+ static native void vibratorSetAmplitude(long controllerPtr, int amplitude);
+ static native int[] vibratorGetSupportedEffects(long controllerPtr);
static native long vibratorPerformEffect(long effect, long strength, Vibration vibration,
boolean withCallback);
static native void vibratorPerformComposedEffect(
VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration);
- static native boolean vibratorSupportsExternalControl();
- static native void vibratorSetExternalControl(boolean enabled);
- static native long vibratorGetCapabilities();
- static native void vibratorAlwaysOnEnable(long id, long effect, long strength);
- static native void vibratorAlwaysOnDisable(long id);
+ static native void vibratorSetExternalControl(long controllerPtr, boolean enabled);
+ static native long vibratorGetCapabilities(long controllerPtr);
+ static native void vibratorAlwaysOnEnable(long controllerPtr, long id, long effect,
+ long strength);
+ static native void vibratorAlwaysOnDisable(long controllerPtr, long id);
private final IUidObserver mUidObserver = new IUidObserver.Stub() {
@Override public void onUidStateChanged(int uid, int procState, long procStateSeq,
@@ -370,13 +370,20 @@
mNativeWrapper = injector.getNativeWrapper();
mH = injector.createHandler(Looper.myLooper());
- mNativeWrapper.vibratorInit();
+ long controllerPtr = mNativeWrapper.vibratorInit();
+ long finalizerPtr = mNativeWrapper.vibratorGetFinalizer();
+
+ if (finalizerPtr != 0) {
+ NativeAllocationRegistry registry =
+ NativeAllocationRegistry.createMalloced(
+ VibratorService.class.getClassLoader(), finalizerPtr);
+ registry.registerNativeAllocation(this, controllerPtr);
+ }
+
// Reset the hardware to a default state, in case this is a runtime
// restart instead of a fresh boot.
mNativeWrapper.vibratorOff();
- mSupportsAmplitudeControl = mNativeWrapper.vibratorSupportsAmplitudeControl();
- mSupportsExternalControl = mNativeWrapper.vibratorSupportsExternalControl();
mSupportedEffects = asList(mNativeWrapper.vibratorGetSupportedEffects());
mCapabilities = mNativeWrapper.vibratorGetCapabilities();
@@ -605,7 +612,8 @@
synchronized (mInputDeviceVibrators) {
// Input device vibrators don't support amplitude controls yet, but are still used over
// the system vibrator when connected.
- return mSupportsAmplitudeControl && mInputDeviceVibrators.isEmpty();
+ return hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)
+ && mInputDeviceVibrators.isEmpty();
}
}
@@ -1288,7 +1296,7 @@
}
private void doVibratorSetAmplitude(int amplitude) {
- if (mSupportsAmplitudeControl) {
+ if (hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
mNativeWrapper.vibratorSetAmplitude(amplitude);
}
}
@@ -1708,14 +1716,25 @@
@VisibleForTesting
public static class NativeWrapper {
+ private long mNativeControllerPtr = 0;
+
/** Checks if vibrator exists on device. */
public boolean vibratorExists() {
- return VibratorService.vibratorExists();
+ return VibratorService.vibratorExists(mNativeControllerPtr);
}
- /** Initializes connection to vibrator HAL service. */
- public void vibratorInit() {
- VibratorService.vibratorInit();
+ /**
+ * Returns native pointer to newly created controller and initializes connection to vibrator
+ * HAL service.
+ */
+ public long vibratorInit() {
+ mNativeControllerPtr = VibratorService.vibratorInit();
+ return mNativeControllerPtr;
+ }
+
+ /** Returns pointer to native finalizer function to be called by GC. */
+ public long vibratorGetFinalizer() {
+ return VibratorService.vibratorGetFinalizer();
}
/** Turns vibrator on for given time. */
@@ -1725,22 +1744,17 @@
/** Turns vibrator off. */
public void vibratorOff() {
- VibratorService.vibratorOff();
- }
-
- /** Returns true if vibrator supports {@link #vibratorSetAmplitude(int)}. */
- public boolean vibratorSupportsAmplitudeControl() {
- return VibratorService.vibratorSupportsAmplitudeControl();
+ VibratorService.vibratorOff(mNativeControllerPtr);
}
/** Sets the amplitude for the vibrator to run. */
public void vibratorSetAmplitude(int amplitude) {
- VibratorService.vibratorSetAmplitude(amplitude);
+ VibratorService.vibratorSetAmplitude(mNativeControllerPtr, amplitude);
}
/** Returns all predefined effects supported by the device vibrator. */
public int[] vibratorGetSupportedEffects() {
- return VibratorService.vibratorGetSupportedEffects();
+ return VibratorService.vibratorGetSupportedEffects(mNativeControllerPtr);
}
/** Turns vibrator on to perform one of the supported effects. */
@@ -1755,29 +1769,24 @@
VibratorService.vibratorPerformComposedEffect(effect, vibration);
}
- /** Returns true if vibrator supports {@link #vibratorSetExternalControl(boolean)}. */
- public boolean vibratorSupportsExternalControl() {
- return VibratorService.vibratorSupportsExternalControl();
- }
-
/** Enabled the device vibrator to be controlled by another service. */
public void vibratorSetExternalControl(boolean enabled) {
- VibratorService.vibratorSetExternalControl(enabled);
+ VibratorService.vibratorSetExternalControl(mNativeControllerPtr, enabled);
}
/** Returns all capabilities of the device vibrator. */
public long vibratorGetCapabilities() {
- return VibratorService.vibratorGetCapabilities();
+ return VibratorService.vibratorGetCapabilities(mNativeControllerPtr);
}
/** Enable always-on vibration with given id and effect. */
public void vibratorAlwaysOnEnable(long id, long effect, long strength) {
- VibratorService.vibratorAlwaysOnEnable(id, effect, strength);
+ VibratorService.vibratorAlwaysOnEnable(mNativeControllerPtr, id, effect, strength);
}
/** Disable always-on vibration for given id. */
public void vibratorAlwaysOnDisable(long id) {
- VibratorService.vibratorAlwaysOnDisable(id);
+ VibratorService.vibratorAlwaysOnDisable(mNativeControllerPtr, id);
}
}
@@ -1852,7 +1861,7 @@
@Override
public int onExternalVibrationStart(ExternalVibration vib) {
- if (!mSupportsExternalControl) {
+ if (!hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
return SCALE_MUTE;
}
if (ActivityManager.checkComponentPermission(android.Manifest.permission.VIBRATE,
@@ -2142,10 +2151,10 @@
if (hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
pw.println(" Compose effects");
}
- if (mSupportsAmplitudeControl || hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
+ if (hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
pw.println(" Amplitude control");
}
- if (mSupportsExternalControl || hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
+ if (hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
pw.println(" External control");
}
if (hasCapability(IVibrator.CAP_EXTERNAL_AMPLITUDE_CONTROL)) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 1680963..33a92e6 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2559,12 +2559,12 @@
private int getAllowMode(Intent service, @Nullable String callingPackage) {
if (callingPackage == null || service.getComponent() == null) {
- return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE_OR_FULL;
+ return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
}
if (callingPackage.equals(service.getComponent().getPackageName())) {
- return ActivityManagerInternal.ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL;
+ return ActivityManagerInternal.ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE;
} else {
- return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE_OR_FULL;
+ return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c187772..91a1487 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -41,6 +41,7 @@
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.FactoryTest.FACTORY_TEST_OFF;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
@@ -130,10 +131,10 @@
import static com.android.server.wm.ActivityTaskManagerService.DUMP_RECENTS_CMD;
import static com.android.server.wm.ActivityTaskManagerService.DUMP_RECENTS_SHORT_CMD;
import static com.android.server.wm.ActivityTaskManagerService.DUMP_STARTER_CMD;
-import static com.android.server.wm.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
import static com.android.server.wm.ActivityTaskManagerService.relaunchReasonToString;
+
import android.Manifest;
import android.Manifest.permission;
import android.annotation.BroadcastBehavior;
@@ -1955,7 +1956,7 @@
nativeTotalPss += Debug.getPss(stats.get(j).pid, null, null);
}
memInfo.readMemInfo();
- synchronized (ActivityManagerService.this) {
+ synchronized (mProcessStats.mLock) {
if (DEBUG_PSS) Slog.d(TAG_PSS, "Collected native and kernel memory in "
+ (SystemClock.uptimeMillis()-start) + "ms");
final long cachedKb = memInfo.getCachedSizeKb();
@@ -7047,9 +7048,7 @@
mUsageStatsService.prepareShutdown();
}
mBatteryStatsService.shutdown();
- synchronized (this) {
- mProcessStats.shutdownLocked();
- }
+ mProcessStats.shutdown();
return timedout;
}
@@ -12351,7 +12350,7 @@
MemInfoReader memInfo = new MemInfoReader();
memInfo.readMemInfo();
if (nativeProcTotalPss > 0) {
- synchronized (this) {
+ synchronized (mProcessStats.mLock) {
final long cachedKb = memInfo.getCachedSizeKb();
final long freeKb = memInfo.getFreeSizeKb();
final long zramKb = memInfo.getZramTotalSizeKb();
@@ -12933,7 +12932,7 @@
MemInfoReader memInfo = new MemInfoReader();
memInfo.readMemInfo();
if (nativeProcTotalPss > 0) {
- synchronized (this) {
+ synchronized (mProcessStats.mLock) {
final long cachedKb = memInfo.getCachedSizeKb();
final long freeKb = memInfo.getFreeSizeKb();
final long zramKb = memInfo.getZramTotalSizeKb();
@@ -16504,9 +16503,7 @@
}
@Override public void run() {
- synchronized (mService) {
- mProcessStats.writeStateAsyncLocked();
- }
+ mProcessStats.writeStateAsync();
}
}
@@ -16556,9 +16553,13 @@
}
mLastMemoryLevel = memFactor;
mLastNumProcesses = mProcessList.getLruSizeLocked();
- boolean allChanged = mProcessStats.setMemFactorLocked(
- memFactor, mAtmInternal != null ? !mAtmInternal.isSleeping() : true, now);
- final int trackerMemFactor = mProcessStats.getMemFactorLocked();
+ boolean allChanged;
+ int trackerMemFactor;
+ synchronized (mProcessStats.mLock) {
+ allChanged = mProcessStats.setMemFactorLocked(
+ memFactor, mAtmInternal != null ? !mAtmInternal.isSleeping() : true, now);
+ trackerMemFactor = mProcessStats.getMemFactorLocked();
+ }
if (memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL) {
if (mLowRamStartTime == 0) {
mLowRamStartTime = now;
@@ -18353,19 +18354,20 @@
throw new SecurityException("Requires permission " + FILTER_EVENTS);
}
ProcessRecord proc;
- long timeout;
+ long timeoutMillis;
synchronized (this) {
synchronized (mPidsSelfLocked) {
proc = mPidsSelfLocked.get(pid);
}
- timeout = proc != null ? proc.getInputDispatchingTimeout() : KEY_DISPATCHING_TIMEOUT_MS;
+ timeoutMillis = proc != null ? proc.getInputDispatchingTimeoutMillis() :
+ DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
}
if (inputDispatchingTimedOut(proc, null, null, null, null, aboveSystem, reason)) {
- return -1;
+ return 0;
}
- return timeout;
+ return timeoutMillis;
}
/**
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 5081b36..d72998b 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -227,8 +227,9 @@
@Override
public void noteBinderCallStats(int workSourceUid, long incrementatCallCount,
- Collection<BinderCallsStats.CallStat> callStats) {
- mStats.noteBinderCallStats(workSourceUid, incrementatCallCount, callStats);
+ Collection<BinderCallsStats.CallStat> callStats, int[] binderThreadNativeTids) {
+ mStats.noteBinderCallStats(workSourceUid, incrementatCallCount, callStats,
+ binderThreadNativeTids);
}
}
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 8970ec4..0f2dfcc 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -116,6 +116,10 @@
WidgetFlags.KEY_ENABLE_CURSOR_DRAG_FROM_ANYWHERE, boolean.class,
WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT));
sDeviceConfigEntries.add(new DeviceConfigEntry<Integer>(
+ DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL,
+ WidgetFlags.KEY_CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL, int.class,
+ WidgetFlags.CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL_DEFAULT));
+ sDeviceConfigEntries.add(new DeviceConfigEntry<Integer>(
DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.FINGER_TO_CURSOR_DISTANCE,
WidgetFlags.KEY_FINGER_TO_CURSOR_DISTANCE, int.class,
WidgetFlags.FINGER_TO_CURSOR_DISTANCE_DEFAULT));
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index f0343e1..bf15f1737 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -659,13 +659,15 @@
updateUidsLocked(activeUids, nowElapsed);
- if (mService.mProcessStats.shouldWriteNowLocked(now)) {
- mService.mHandler.post(new ActivityManagerService.ProcStatsRunnable(mService,
- mService.mProcessStats));
- }
+ synchronized (mService.mProcessStats.mLock) {
+ if (mService.mProcessStats.shouldWriteNowLocked(now)) {
+ mService.mHandler.post(new ActivityManagerService.ProcStatsRunnable(mService,
+ mService.mProcessStats));
+ }
- // Run this after making sure all procstates are updated.
- mService.mProcessStats.updateTrackingAssociationsLocked(mAdjSeq, now);
+ // Run this after making sure all procstates are updated.
+ mService.mProcessStats.updateTrackingAssociationsLocked(mAdjSeq, now);
+ }
if (DEBUG_OOM_ADJ) {
final long duration = SystemClock.uptimeMillis() - now;
diff --git a/services/core/java/com/android/server/am/PendingTempWhitelists.java b/services/core/java/com/android/server/am/PendingTempWhitelists.java
index b36e3c7..50d58f0 100644
--- a/services/core/java/com/android/server/am/PendingTempWhitelists.java
+++ b/services/core/java/com/android/server/am/PendingTempWhitelists.java
@@ -32,13 +32,13 @@
void put(int uid, ActivityManagerService.PendingTempWhitelist value) {
mPendingTempWhitelist.put(uid, value);
- mService.mAtmInternal.onUidAddedToPendingTempWhitelist(uid, value.tag);
+ mService.mAtmInternal.onUidAddedToPendingTempAllowlist(uid, value.tag);
}
void removeAt(int index) {
final int uid = mPendingTempWhitelist.keyAt(index);
mPendingTempWhitelist.removeAt(index);
- mService.mAtmInternal.onUidRemovedFromPendingTempWhitelist(uid);
+ mService.mAtmInternal.onUidRemovedFromPendingTempAllowlist(uid);
}
ActivityManagerService.PendingTempWhitelist get(int uid) {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index cd4302b..e3e1339 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -673,30 +673,33 @@
public void makeActive(IApplicationThread _thread, ProcessStatsService tracker) {
if (thread == null) {
- final ProcessState origBase = baseProcessTracker;
- if (origBase != null) {
- origBase.setState(ProcessStats.STATE_NOTHING,
- tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList.mPkgList);
- for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
- FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
- uid, processName, pkgList.keyAt(ipkg),
- ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING),
- pkgList.valueAt(ipkg).appVersion);
+ synchronized (tracker.mLock) {
+ final ProcessState origBase = baseProcessTracker;
+ if (origBase != null) {
+ origBase.setState(ProcessStats.STATE_NOTHING,
+ tracker.getMemFactorLocked(), SystemClock.uptimeMillis(),
+ pkgList.mPkgList);
+ for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
+ FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
+ uid, processName, pkgList.keyAt(ipkg),
+ ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING),
+ pkgList.valueAt(ipkg).appVersion);
+ }
+ origBase.makeInactive();
}
- origBase.makeInactive();
- }
- baseProcessTracker = tracker.getProcessStateLocked(info.packageName, info.uid,
- info.longVersionCode, processName);
- baseProcessTracker.makeActive();
- for (int i=0; i<pkgList.size(); i++) {
- ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
- if (holder.state != null && holder.state != origBase) {
- holder.state.makeInactive();
- }
- tracker.updateProcessStateHolderLocked(holder, pkgList.keyAt(i), info.uid,
+ baseProcessTracker = tracker.getProcessStateLocked(info.packageName, info.uid,
info.longVersionCode, processName);
- if (holder.state != baseProcessTracker) {
- holder.state.makeActive();
+ baseProcessTracker.makeActive();
+ for (int i = 0, ipkg = pkgList.size(); i < ipkg; i++) {
+ ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
+ if (holder.state != null && holder.state != origBase) {
+ holder.state.makeInactive();
+ }
+ tracker.updateProcessStateHolderLocked(holder, pkgList.keyAt(i), info.uid,
+ info.longVersionCode, processName);
+ if (holder.state != baseProcessTracker) {
+ holder.state.makeActive();
+ }
}
}
}
@@ -707,27 +710,30 @@
public void makeInactive(ProcessStatsService tracker) {
thread = null;
mWindowProcessController.setThread(null);
- final ProcessState origBase = baseProcessTracker;
- if (origBase != null) {
+ synchronized (tracker.mLock) {
+ final ProcessState origBase = baseProcessTracker;
if (origBase != null) {
- origBase.setState(ProcessStats.STATE_NOTHING,
- tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList.mPkgList);
- for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
- FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
- uid, processName, pkgList.keyAt(ipkg),
- ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING),
- pkgList.valueAt(ipkg).appVersion);
+ if (origBase != null) {
+ origBase.setState(ProcessStats.STATE_NOTHING,
+ tracker.getMemFactorLocked(), SystemClock.uptimeMillis(),
+ pkgList.mPkgList);
+ for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
+ FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
+ uid, processName, pkgList.keyAt(ipkg),
+ ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING),
+ pkgList.valueAt(ipkg).appVersion);
+ }
+ origBase.makeInactive();
}
- origBase.makeInactive();
- }
- baseProcessTracker = null;
- for (int i=0; i<pkgList.size(); i++) {
- ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
- if (holder.state != null && holder.state != origBase) {
- holder.state.makeInactive();
+ baseProcessTracker = null;
+ for (int i = 0, ipkg = pkgList.size(); i < ipkg; i++) {
+ ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
+ if (holder.state != null && holder.state != origBase) {
+ holder.state.makeInactive();
+ }
+ holder.pkg = null;
+ holder.state = null;
}
- holder.pkg = null;
- holder.state = null;
}
}
}
@@ -1026,17 +1032,19 @@
*/
public boolean addPackage(String pkg, long versionCode, ProcessStatsService tracker) {
if (!pkgList.containsKey(pkg)) {
- ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
- versionCode);
- if (baseProcessTracker != null) {
- tracker.updateProcessStateHolderLocked(holder, pkg, info.uid, versionCode,
- processName);
- pkgList.put(pkg, holder);
- if (holder.state != baseProcessTracker) {
- holder.state.makeActive();
+ synchronized (tracker.mLock) {
+ ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
+ versionCode);
+ if (baseProcessTracker != null) {
+ tracker.updateProcessStateHolderLocked(holder, pkg, info.uid, versionCode,
+ processName);
+ pkgList.put(pkg, holder);
+ if (holder.state != baseProcessTracker) {
+ holder.state.makeActive();
+ }
+ } else {
+ pkgList.put(pkg, holder);
}
- } else {
- pkgList.put(pkg, holder);
}
return true;
}
@@ -1072,31 +1080,33 @@
public void resetPackageList(ProcessStatsService tracker) {
final int N = pkgList.size();
if (baseProcessTracker != null) {
- long now = SystemClock.uptimeMillis();
- baseProcessTracker.setState(ProcessStats.STATE_NOTHING,
- tracker.getMemFactorLocked(), now, pkgList.mPkgList);
- for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
- FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
- uid, processName, pkgList.keyAt(ipkg),
- ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING),
- pkgList.valueAt(ipkg).appVersion);
- }
- if (N != 1) {
- for (int i=0; i<N; i++) {
- ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
- if (holder.state != null && holder.state != baseProcessTracker) {
- holder.state.makeInactive();
- }
-
+ synchronized (tracker.mLock) {
+ long now = SystemClock.uptimeMillis();
+ baseProcessTracker.setState(ProcessStats.STATE_NOTHING,
+ tracker.getMemFactorLocked(), now, pkgList.mPkgList);
+ for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
+ FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
+ uid, processName, pkgList.keyAt(ipkg),
+ ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING),
+ pkgList.valueAt(ipkg).appVersion);
}
- pkgList.clear();
- ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
- info.longVersionCode);
- tracker.updateProcessStateHolderLocked(holder, info.packageName, info.uid,
- info.longVersionCode, processName);
- pkgList.put(info.packageName, holder);
- if (holder.state != baseProcessTracker) {
- holder.state.makeActive();
+ if (N != 1) {
+ for (int i = 0; i < N; i++) {
+ ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
+ if (holder.state != null && holder.state != baseProcessTracker) {
+ holder.state.makeInactive();
+ }
+
+ }
+ pkgList.clear();
+ ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
+ info.longVersionCode);
+ tracker.updateProcessStateHolderLocked(holder, info.packageName, info.uid,
+ info.longVersionCode, processName);
+ pkgList.put(info.packageName, holder);
+ if (holder.state != baseProcessTracker) {
+ holder.state.makeActive();
+ }
}
}
} else if (N != 1) {
@@ -1522,8 +1532,8 @@
}
}
- public long getInputDispatchingTimeout() {
- return mWindowProcessController.getInputDispatchingTimeout();
+ public long getInputDispatchingTimeoutMillis() {
+ return mWindowProcessController.getInputDispatchingTimeoutMillis();
}
public int getProcessClassEnum() {
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index a168af5a..4e8c386 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -71,33 +71,62 @@
final ActivityManagerService mAm;
final File mBaseDir;
- ProcessStats mProcessStats;
+
+ // Note: The locking order of the below 3 locks should be:
+ // mLock, mPendingWriteLock, mFileLock
+
+ // The lock object to protect the internal state/structures
+ final Object mLock = new Object();
+
+ // The lock object to protect the access to pending writes
+ final Object mPendingWriteLock = new Object();
+
+ // The lock object to protect the access to all of the file read/write
+ final ReentrantLock mFileLock = new ReentrantLock();
+
+ @GuardedBy("mLock")
+ final ProcessStats mProcessStats;
+
+ @GuardedBy("mFileLock")
AtomicFile mFile;
+
+ @GuardedBy("mLock")
boolean mCommitPending;
+
+ @GuardedBy("mLock")
boolean mShuttingDown;
+
+ @GuardedBy("mLock")
int mLastMemOnlyState = -1;
boolean mMemFactorLowered;
- final ReentrantLock mWriteLock = new ReentrantLock();
- final Object mPendingWriteLock = new Object();
+ @GuardedBy("mPendingWriteLock")
AtomicFile mPendingWriteFile;
+
+ @GuardedBy("mPendingWriteLock")
Parcel mPendingWrite;
+
+ @GuardedBy("mPendingWriteLock")
boolean mPendingWriteCommitted;
+
+ @GuardedBy("mLock")
long mLastWriteTime;
/** For CTS to inject the screen state. */
- @GuardedBy("mAm")
+ @GuardedBy("mLock")
Boolean mInjectedScreenState;
public ProcessStatsService(ActivityManagerService am, File file) {
mAm = am;
mBaseDir = file;
mBaseDir.mkdirs();
- mProcessStats = new ProcessStats(true);
- updateFile();
+ synchronized (mLock) {
+ mProcessStats = new ProcessStats(true);
+ updateFileLocked();
+ }
SystemProperties.addChangeCallback(new Runnable() {
@Override public void run() {
- synchronized (mAm) {
+ synchronized (mLock) {
if (mProcessStats.evaluateSystemProperties(false)) {
mProcessStats.mFlags |= ProcessStats.FLAG_SYSPROPS;
writeStateLocked(true, true);
@@ -121,32 +150,33 @@
}
}
- @GuardedBy("mAm")
- public void updateProcessStateHolderLocked(ProcessStats.ProcessStateHolder holder,
+ @GuardedBy("mLock")
+ void updateProcessStateHolderLocked(ProcessStats.ProcessStateHolder holder,
String packageName, int uid, long versionCode, String processName) {
holder.pkg = mProcessStats.getPackageStateLocked(packageName, uid, versionCode);
holder.state = mProcessStats.getProcessStateLocked(holder.pkg, processName);
}
- @GuardedBy("mAm")
- public ProcessState getProcessStateLocked(String packageName,
+ @GuardedBy("mLock")
+ ProcessState getProcessStateLocked(String packageName,
int uid, long versionCode, String processName) {
return mProcessStats.getProcessStateLocked(packageName, uid, versionCode, processName);
}
- @GuardedBy("mAm")
- public ServiceState getServiceStateLocked(String packageName, int uid,
+ ServiceState getServiceState(String packageName, int uid,
long versionCode, String processName, String className) {
- return mProcessStats.getServiceStateLocked(packageName, uid, versionCode, processName,
- className);
+ synchronized (mLock) {
+ return mProcessStats.getServiceStateLocked(packageName, uid, versionCode, processName,
+ className);
+ }
}
- public boolean isMemFactorLowered() {
+ boolean isMemFactorLowered() {
return mMemFactorLowered;
}
- @GuardedBy("mAm")
- public boolean setMemFactorLocked(int memFactor, boolean screenOn, long now) {
+ @GuardedBy("mLock")
+ boolean setMemFactorLocked(int memFactor, boolean screenOn, long now) {
mMemFactorLowered = memFactor < mLastMemOnlyState;
mLastMemOnlyState = memFactor;
if (mInjectedScreenState != null) {
@@ -184,24 +214,24 @@
return false;
}
- @GuardedBy("mAm")
- public int getMemFactorLocked() {
+ @GuardedBy("mLock")
+ int getMemFactorLocked() {
return mProcessStats.mMemFactor != ProcessStats.STATE_NOTHING ? mProcessStats.mMemFactor : 0;
}
- @GuardedBy("mAm")
- public void addSysMemUsageLocked(long cachedMem, long freeMem, long zramMem, long kernelMem,
+ @GuardedBy("mLock")
+ void addSysMemUsageLocked(long cachedMem, long freeMem, long zramMem, long kernelMem,
long nativeMem) {
mProcessStats.addSysMemUsage(cachedMem, freeMem, zramMem, kernelMem, nativeMem);
}
- @GuardedBy("mAm")
- public void updateTrackingAssociationsLocked(int curSeq, long now) {
+ @GuardedBy("mLock")
+ void updateTrackingAssociationsLocked(int curSeq, long now) {
mProcessStats.updateTrackingAssociationsLocked(curSeq, now);
}
- @GuardedBy("mAm")
- public boolean shouldWriteNowLocked(long now) {
+ @GuardedBy("mLock")
+ boolean shouldWriteNowLocked(long now) {
if (now > (mLastWriteTime+WRITE_PERIOD)) {
if (SystemClock.elapsedRealtime()
> (mProcessStats.mTimePeriodStartRealtime+ProcessStats.COMMIT_PERIOD) &&
@@ -214,25 +244,27 @@
return false;
}
- @GuardedBy("mAm")
- public void shutdownLocked() {
+ void shutdown() {
Slog.w(TAG, "Writing process stats before shutdown...");
- mProcessStats.mFlags |= ProcessStats.FLAG_SHUTDOWN;
- writeStateSyncLocked();
- mShuttingDown = true;
+ synchronized (mLock) {
+ mProcessStats.mFlags |= ProcessStats.FLAG_SHUTDOWN;
+ writeStateSyncLocked();
+ mShuttingDown = true;
+ }
}
- @GuardedBy("mAm")
- public void writeStateAsyncLocked() {
- writeStateLocked(false);
+ void writeStateAsync() {
+ synchronized (mLock) {
+ writeStateLocked(false);
+ }
}
- @GuardedBy("mAm")
- public void writeStateSyncLocked() {
+ @GuardedBy("mLock")
+ private void writeStateSyncLocked() {
writeStateLocked(true);
}
- @GuardedBy("mAm")
+ @GuardedBy("mLock")
private void writeStateLocked(boolean sync) {
if (mShuttingDown) {
return;
@@ -242,8 +274,8 @@
writeStateLocked(sync, commitPending);
}
- @GuardedBy("mAm")
- public void writeStateLocked(boolean sync, final boolean commit) {
+ @GuardedBy("mLock")
+ private void writeStateLocked(boolean sync, final boolean commit) {
final long totalTime;
synchronized (mPendingWriteLock) {
final long now = SystemClock.uptimeMillis();
@@ -255,13 +287,13 @@
mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE;
}
mProcessStats.writeToParcel(mPendingWrite, 0);
- mPendingWriteFile = new AtomicFile(mFile.getBaseFile());
+ mPendingWriteFile = new AtomicFile(getCurrentFile());
mPendingWriteCommitted = commit;
}
if (commit) {
mProcessStats.resetSafely();
- updateFile();
- mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
+ updateFileLocked();
+ scheduleRequestPssAllProcs(true, false);
}
mLastWriteTime = SystemClock.uptimeMillis();
totalTime = SystemClock.uptimeMillis() - now;
@@ -279,14 +311,37 @@
performWriteState(totalTime);
}
- private void updateFile() {
- mFile = new AtomicFile(new File(mBaseDir, STATE_FILE_PREFIX
- + mProcessStats.mTimePeriodStartClockStr + STATE_FILE_SUFFIX));
+ private void scheduleRequestPssAllProcs(boolean always, boolean memLowered) {
+ mAm.mHandler.post(() -> {
+ synchronized (mAm) {
+ mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), always, memLowered);
+ }
+ });
+ }
+
+ @GuardedBy("mLock")
+ private void updateFileLocked() {
+ mFileLock.lock();
+ try {
+ mFile = new AtomicFile(new File(mBaseDir, STATE_FILE_PREFIX
+ + mProcessStats.mTimePeriodStartClockStr + STATE_FILE_SUFFIX));
+ } finally {
+ mFileLock.unlock();
+ }
mLastWriteTime = SystemClock.uptimeMillis();
}
- void performWriteState(long initialTime) {
- if (DEBUG) Slog.d(TAG, "Performing write to " + mFile.getBaseFile());
+ private File getCurrentFile() {
+ mFileLock.lock();
+ try {
+ return mFile.getBaseFile();
+ } finally {
+ mFileLock.unlock();
+ }
+ }
+
+ private void performWriteState(long initialTime) {
+ if (DEBUG) Slog.d(TAG, "Performing write to " + getCurrentFile());
Parcel data;
AtomicFile file;
synchronized (mPendingWriteLock) {
@@ -298,7 +353,7 @@
}
mPendingWrite = null;
mPendingWriteFile = null;
- mWriteLock.lock();
+ mFileLock.lock();
}
final long startTime = SystemClock.uptimeMillis();
@@ -316,13 +371,13 @@
file.failWrite(stream);
} finally {
data.recycle();
- trimHistoricStatesWriteLocked();
- mWriteLock.unlock();
+ trimHistoricStatesWriteLF();
+ mFileLock.unlock();
}
}
- @GuardedBy("mAm")
- boolean readLocked(ProcessStats stats, AtomicFile file) {
+ @GuardedBy("mFileLock")
+ private boolean readLF(ProcessStats stats, AtomicFile file) {
try {
FileInputStream stream = file.openRead();
stats.read(stream);
@@ -387,7 +442,8 @@
return true;
}
- private ArrayList<String> getCommittedFiles(int minNum, boolean inclCurrent,
+ @GuardedBy("mFileLock")
+ private ArrayList<String> getCommittedFilesLF(int minNum, boolean inclCurrent,
boolean inclCheckedIn) {
File[] files = mBaseDir.listFiles();
if (files == null || files.length <= minNum) {
@@ -414,9 +470,9 @@
return filesArray;
}
- @GuardedBy("mAm")
- public void trimHistoricStatesWriteLocked() {
- ArrayList<String> filesArray = getCommittedFiles(MAX_HISTORIC_STATES, false, true);
+ @GuardedBy("mFileLock")
+ private void trimHistoricStatesWriteLF() {
+ ArrayList<String> filesArray = getCommittedFilesLF(MAX_HISTORIC_STATES, false, true);
if (filesArray == null) {
return;
}
@@ -427,8 +483,8 @@
}
}
- @GuardedBy("mAm")
- boolean dumpFilteredProcessesCsvLocked(PrintWriter pw, String header,
+ @GuardedBy("mLock")
+ private boolean dumpFilteredProcessesCsvLocked(PrintWriter pw, String header,
boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
boolean sepProcStates, int[] procStates, long now, String reqPackage) {
ArrayList<ProcessState> procs = mProcessStats.collectProcessesLocked(
@@ -502,20 +558,21 @@
return res;
}
+ @Override
public byte[] getCurrentStats(List<ParcelFileDescriptor> historic) {
mAm.mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.PACKAGE_USAGE_STATS, null);
Parcel current = Parcel.obtain();
- synchronized (mAm) {
+ synchronized (mLock) {
long now = SystemClock.uptimeMillis();
mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
mProcessStats.mTimePeriodEndUptime = now;
mProcessStats.writeToParcel(current, now, 0);
}
- mWriteLock.lock();
+ mFileLock.lock();
try {
if (historic != null) {
- ArrayList<String> files = getCommittedFiles(0, false, true);
+ ArrayList<String> files = getCommittedFilesLF(0, false, true);
if (files != null) {
for (int i=files.size()-1; i>=0; i--) {
try {
@@ -529,7 +586,7 @@
}
}
} finally {
- mWriteLock.unlock();
+ mFileLock.unlock();
}
return current.marshall();
}
@@ -563,9 +620,9 @@
android.Manifest.permission.PACKAGE_USAGE_STATS, null);
long newHighWaterMark = highWaterMarkMs;
- mWriteLock.lock();
+ mFileLock.lock();
try {
- ArrayList<String> files = getCommittedFiles(0, false, true);
+ ArrayList<String> files = getCommittedFilesLF(0, false, true);
if (files != null) {
String highWaterMarkStr =
DateFormat.format("yyyy-MM-dd-HH-mm-ss", highWaterMarkMs).toString();
@@ -612,7 +669,7 @@
} catch (IOException e) {
Slog.w(TAG, "Failure opening procstat file", e);
} finally {
- mWriteLock.unlock();
+ mFileLock.unlock();
}
return newHighWaterMark;
}
@@ -625,7 +682,7 @@
return mAm.mConstants.MIN_ASSOC_LOG_DURATION;
}
- private ParcelFileDescriptor protoToParcelFileDescriptor(ProcessStats stats, int section)
+ private static ParcelFileDescriptor protoToParcelFileDescriptor(ProcessStats stats, int section)
throws IOException {
final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
Thread thr = new Thread("ProcessStats pipe output") {
@@ -645,12 +702,13 @@
return fds[0];
}
+ @Override
public ParcelFileDescriptor getStatsOverTime(long minTime) {
mAm.mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.PACKAGE_USAGE_STATS, null);
Parcel current = Parcel.obtain();
long curTime;
- synchronized (mAm) {
+ synchronized (mLock) {
long now = SystemClock.uptimeMillis();
mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
mProcessStats.mTimePeriodEndUptime = now;
@@ -658,11 +716,11 @@
curTime = mProcessStats.mTimePeriodEndRealtime
- mProcessStats.mTimePeriodStartRealtime;
}
- mWriteLock.lock();
+ mFileLock.lock();
try {
if (curTime < minTime) {
// Need to add in older stats to reach desired time.
- ArrayList<String> files = getCommittedFiles(0, false, true);
+ ArrayList<String> files = getCommittedFilesLF(0, false, true);
if (files != null && files.size() > 0) {
current.setDataPosition(0);
ProcessStats stats = ProcessStats.CREATOR.createFromParcel(current);
@@ -673,7 +731,7 @@
AtomicFile file = new AtomicFile(new File(files.get(i)));
i--;
ProcessStats moreStats = new ProcessStats(false);
- readLocked(moreStats, file);
+ readLF(moreStats, file);
if (moreStats.mReadError == null) {
stats.add(moreStats);
StringBuilder sb = new StringBuilder();
@@ -712,13 +770,14 @@
} catch (IOException e) {
Slog.w(TAG, "Failed building output pipe", e);
} finally {
- mWriteLock.unlock();
+ mFileLock.unlock();
}
return null;
}
+ @Override
public int getCurrentMemoryState() {
- synchronized (mAm) {
+ synchronized (mLock) {
return mLastMemOnlyState;
}
}
@@ -947,7 +1006,7 @@
} else if ("--current".equals(arg)) {
currentOnly = true;
} else if ("--commit".equals(arg)) {
- synchronized (mAm) {
+ synchronized (mLock) {
mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE;
writeStateLocked(true, true);
pw.println("Process stats committed.");
@@ -962,29 +1021,39 @@
}
section = parseSectionOptions(args[i]);
} else if ("--clear".equals(arg)) {
- synchronized (mAm) {
+ synchronized (mLock) {
mProcessStats.resetSafely();
- mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
- ArrayList<String> files = getCommittedFiles(0, true, true);
- if (files != null) {
- for (int fi=0; fi<files.size(); fi++) {
- (new File(files.get(fi))).delete();
+ scheduleRequestPssAllProcs(true, false);
+ mFileLock.lock();
+ try {
+ ArrayList<String> files = getCommittedFilesLF(0, true, true);
+ if (files != null) {
+ for (int fi = files.size() - 1; fi >= 0; fi--) {
+ (new File(files.get(fi))).delete();
+ }
}
+ } finally {
+ mFileLock.unlock();
}
pw.println("All process stats cleared.");
quit = true;
}
} else if ("--write".equals(arg)) {
- synchronized (mAm) {
+ synchronized (mLock) {
writeStateSyncLocked();
pw.println("Process stats written.");
quit = true;
}
} else if ("--read".equals(arg)) {
- synchronized (mAm) {
- readLocked(mProcessStats, mFile);
- pw.println("Process stats read.");
- quit = true;
+ synchronized (mLock) {
+ mFileLock.lock();
+ try {
+ readLF(mProcessStats, mFile);
+ pw.println("Process stats read.");
+ quit = true;
+ } finally {
+ mFileLock.unlock();
+ }
}
} else if ("--start-testing".equals(arg)) {
synchronized (mAm) {
@@ -999,17 +1068,17 @@
quit = true;
}
} else if ("--pretend-screen-on".equals(arg)) {
- synchronized (mAm) {
+ synchronized (mLock) {
mInjectedScreenState = true;
}
quit = true;
} else if ("--pretend-screen-off".equals(arg)) {
- synchronized (mAm) {
+ synchronized (mLock) {
mInjectedScreenState = false;
}
quit = true;
} else if ("--stop-pretend-screen".equals(arg)) {
- synchronized (mAm) {
+ synchronized (mLock) {
mInjectedScreenState = null;
}
quit = true;
@@ -1060,7 +1129,7 @@
}
}
pw.println();
- synchronized (mAm) {
+ synchronized (mLock) {
dumpFilteredProcessesCsvLocked(pw, null,
csvSepScreenStats, csvScreenStats, csvSepMemStats, csvMemStats,
csvSepProcStats, csvProcStats, now, reqPackage);
@@ -1090,14 +1159,26 @@
return;
} else if (lastIndex > 0) {
pw.print("LAST STATS AT INDEX "); pw.print(lastIndex); pw.println(":");
- ArrayList<String> files = getCommittedFiles(0, false, true);
- if (lastIndex >= files.size()) {
- pw.print("Only have "); pw.print(files.size()); pw.println(" data sets");
- return;
+
+ ArrayList<String> files;
+ AtomicFile file;
+ ProcessStats processStats;
+
+ mFileLock.lock();
+ try {
+ files = getCommittedFilesLF(0, false, true);
+ if (lastIndex >= files.size()) {
+ pw.print("Only have "); pw.print(files.size()); pw.println(" data sets");
+ return;
+ }
+ file = new AtomicFile(new File(files.get(lastIndex)));
+ processStats = new ProcessStats(false);
+ readLF(processStats, file);
+ } finally {
+ mFileLock.unlock();
}
- AtomicFile file = new AtomicFile(new File(files.get(lastIndex)));
- ProcessStats processStats = new ProcessStats(false);
- readLocked(processStats, file);
+
+ // No lock is needed now, since only us have the access to the 'processStats'.
if (processStats.mReadError != null) {
if (isCheckin || isCompact) pw.print("err,");
pw.print("Failure reading "); pw.print(files.get(lastIndex));
@@ -1118,7 +1199,7 @@
processStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails,
dumpAll, activeOnly, section);
if (dumpAll) {
- pw.print(" mFile="); pw.println(mFile.getBaseFile());
+ pw.print(" mFile="); pw.println(getCurrentFile());
}
} else {
processStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
@@ -1129,9 +1210,9 @@
boolean sepNeeded = false;
if ((dumpAll || isCheckin) && !currentOnly) {
- mWriteLock.lock();
+ mFileLock.lock();
try {
- ArrayList<String> files = getCommittedFiles(0, false, !isCheckin);
+ ArrayList<String> files = getCommittedFilesLF(0, false, !isCheckin);
if (files != null) {
int start = isCheckin ? 0 : (files.size() - maxNum);
if (start < 0) {
@@ -1142,7 +1223,7 @@
try {
AtomicFile file = new AtomicFile(new File(files.get(i)));
ProcessStats processStats = new ProcessStats(false);
- readLocked(processStats, file);
+ readLF(processStats, file);
if (processStats.mReadError != null) {
if (isCheckin || isCompact) pw.print("err,");
pw.print("Failure reading "); pw.print(files.get(i));
@@ -1188,11 +1269,11 @@
}
}
} finally {
- mWriteLock.unlock();
+ mFileLock.unlock();
}
}
if (!isCheckin) {
- synchronized (mAm) {
+ synchronized (mLock) {
if (isCompact) {
mProcessStats.dumpCheckinLocked(pw, reqPackage, section);
} else {
@@ -1204,7 +1285,7 @@
mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails,
dumpAll, activeOnly, section);
if (dumpAll) {
- pw.print(" mFile="); pw.println(mFile.getBaseFile());
+ pw.print(" mFile="); pw.println(getCurrentFile());
}
} else {
mProcessStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
@@ -1249,7 +1330,7 @@
// dump current procstats
long now;
- synchronized (mAm) {
+ synchronized (mLock) {
now = SystemClock.uptimeMillis();
final long token = proto.start(ProcessStatsServiceDumpProto.PROCSTATS_NOW);
mProcessStats.dumpDebug(proto, now, ProcessStats.REPORT_ALL);
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 022b04d..4a27030 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -528,8 +528,9 @@
return tracker;
}
if ((serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
- tracker = ams.mProcessStats.getServiceStateLocked(serviceInfo.packageName,
- serviceInfo.applicationInfo.uid, serviceInfo.applicationInfo.longVersionCode,
+ tracker = ams.mProcessStats.getServiceState(serviceInfo.packageName,
+ serviceInfo.applicationInfo.uid,
+ serviceInfo.applicationInfo.longVersionCode,
serviceInfo.processName, serviceInfo.name);
tracker.applyNewOwner(this);
}
@@ -546,7 +547,8 @@
public void makeRestarting(int memFactor, long now) {
if (restartTracker == null) {
if ((serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
- restartTracker = ams.mProcessStats.getServiceStateLocked(serviceInfo.packageName,
+ restartTracker = ams.mProcessStats.getServiceState(
+ serviceInfo.packageName,
serviceInfo.applicationInfo.uid,
serviceInfo.applicationInfo.longVersionCode,
serviceInfo.processName, serviceInfo.name);
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 19b671e..0658e81 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -23,11 +23,10 @@
import static android.app.ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
import static android.app.ActivityManager.USER_OP_IS_CURRENT;
import static android.app.ActivityManager.USER_OP_SUCCESS;
-import static android.app.ActivityManagerInternal.ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL;
-import static android.app.ActivityManagerInternal.ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL;
+import static android.app.ActivityManagerInternal.ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
-import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE_OR_FULL;
+import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
import static android.os.Process.SHELL_UID;
import static android.os.Process.SYSTEM_UID;
@@ -1910,12 +1909,11 @@
callingUid, -1, true) != PackageManager.PERMISSION_GRANTED) {
// If the caller does not have either permission, they are always doomed.
allow = false;
- } else if (allowMode == ALLOW_NON_FULL
- || allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL) {
+ } else if (allowMode == ALLOW_NON_FULL) {
// We are blanket allowing non-full access, you lucky caller!
allow = true;
- } else if (allowMode == ALLOW_NON_FULL_IN_PROFILE_OR_FULL
- || allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL) {
+ } else if (allowMode == ALLOW_NON_FULL_IN_PROFILE
+ || allowMode == ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) {
// We may or may not allow this depending on whether the two users are
// in the same profile.
allow = isSameProfileGroup;
@@ -1942,15 +1940,12 @@
builder.append("; this requires ");
builder.append(INTERACT_ACROSS_USERS_FULL);
if (allowMode != ALLOW_FULL_ONLY) {
- if (allowMode == ALLOW_NON_FULL
- || allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL
- || isSameProfileGroup) {
+ if (allowMode == ALLOW_NON_FULL || isSameProfileGroup) {
builder.append(" or ");
builder.append(INTERACT_ACROSS_USERS);
}
if (isSameProfileGroup
- && (allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL
- || allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL)) {
+ && allowMode == ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) {
builder.append(" or ");
builder.append(INTERACT_ACROSS_PROFILES);
}
@@ -1977,8 +1972,7 @@
private boolean canInteractWithAcrossProfilesPermission(
int allowMode, boolean isSameProfileGroup, int callingPid, int callingUid,
String callingPackage) {
- if (allowMode != ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL
- && allowMode != ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL) {
+ if (allowMode != ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) {
return false;
}
if (!isSameProfileGroup) {
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 74f3daf..ee441bf 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -19,7 +19,6 @@
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
-import static android.app.ActivityManagerInternal.ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL;
import static android.app.AppOpsManager.CALL_BACK_ON_SWITCHED_OP;
import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
@@ -129,7 +128,6 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
-import android.util.EventLog;
import android.util.KeyValueListParser;
import android.util.LongSparseArray;
import android.util.Pair;
@@ -163,7 +161,6 @@
import com.android.server.LockGuard;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemServiceManager;
-import com.android.server.am.ActivityManagerService;
import com.android.server.pm.PackageList;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -1892,6 +1889,7 @@
synchronized (this) {
if (mWriteScheduled) {
mWriteScheduled = false;
+ mHandler.removeCallbacks(mWriteRunner);
doWrite = true;
}
}
@@ -2200,11 +2198,8 @@
+ " by uid " + Binder.getCallingUid());
}
- int userId = UserHandle.getUserId(uid);
-
enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
verifyIncomingOp(code);
- verifyIncomingUser(userId);
code = AppOpsManager.opToSwitch(code);
if (permissionPolicyCallback == null) {
@@ -2449,12 +2444,8 @@
private void setMode(int code, int uid, @NonNull String packageName, int mode,
@Nullable IAppOpsCallback permissionPolicyCallback) {
enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
-
- int userId = UserHandle.getUserId(uid);
-
verifyIncomingOp(code);
- verifyIncomingUser(userId);
- verifyIncomingPackage(packageName, userId);
+ verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
ArraySet<ModeCallback> repCbs = null;
code = AppOpsManager.opToSwitch(code);
@@ -2867,11 +2858,8 @@
private int checkOperationImpl(int code, int uid, String packageName,
boolean raw) {
- int userId = UserHandle.getUserId(uid);
-
verifyIncomingOp(code);
- verifyIncomingUser(userId);
- verifyIncomingPackage(packageName, userId);
+ verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -2990,15 +2978,10 @@
String proxiedAttributionTag, int proxyUid, String proxyPackageName,
String proxyAttributionTag, boolean shouldCollectAsyncNotedOp, String message,
boolean shouldCollectMessage) {
- int proxiedUserId = UserHandle.getUserId(proxiedUid);
- int proxyUserId = UserHandle.getUserId(proxyUid);
-
verifyIncomingUid(proxyUid);
verifyIncomingOp(code);
- verifyIncomingUser(proxiedUserId);
- verifyIncomingUser(proxyUserId);
- verifyIncomingPackage(proxiedPackageName, proxiedUserId);
- verifyIncomingPackage(proxyPackageName, proxyUserId);
+ verifyIncomingPackage(proxiedPackageName, UserHandle.getUserId(proxiedUid));
+ verifyIncomingPackage(proxyPackageName, UserHandle.getUserId(proxyUid));
String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
if (resolveProxyPackageName == null) {
@@ -3048,12 +3031,9 @@
private int noteOperationImpl(int code, int uid, @Nullable String packageName,
@Nullable String attributionTag, boolean shouldCollectAsyncNotedOp,
@Nullable String message, boolean shouldCollectMessage) {
- int userId = UserHandle.getUserId(uid);
-
verifyIncomingUid(uid);
verifyIncomingOp(code);
- verifyIncomingUser(userId);
- verifyIncomingPackage(packageName, userId);
+ verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -3430,12 +3410,9 @@
public int startOperation(IBinder clientId, int code, int uid, String packageName,
String attributionTag, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
String message, boolean shouldCollectMessage) {
- int userId = UserHandle.getUserId(uid);
-
verifyIncomingUid(uid);
verifyIncomingOp(code);
- verifyIncomingUser(userId);
- verifyIncomingPackage(packageName, userId);
+ verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -3515,12 +3492,9 @@
@Override
public void finishOperation(IBinder clientId, int code, int uid, String packageName,
String attributionTag) {
- int userId = UserHandle.getUserId(uid);
-
verifyIncomingUid(uid);
verifyIncomingOp(code);
- verifyIncomingUser(userId);
- verifyIncomingPackage(packageName, userId);
+ verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -3749,33 +3723,6 @@
}
}
- private void verifyIncomingUser(@UserIdInt int userId) {
- int callingUid = Binder.getCallingUid();
- int callingUserId = UserHandle.getUserId(callingUid);
- int callingPid = Binder.getCallingPid();
-
- if (callingUserId != userId) {
- // Prevent endless loop between when checking appops inside of handleIncomingUser
- if (Binder.getCallingPid() == ActivityManagerService.MY_PID) {
- return;
- }
- long token = Binder.clearCallingIdentity();
- try {
- try {
- LocalServices.getService(ActivityManagerInternal.class).handleIncomingUser(
- callingPid, callingUid, userId, /* allowAll */ false,
- ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL, "appop operation", null);
- } catch (Exception e) {
- EventLog.writeEvent(0x534e4554, "153996875", "appop", userId);
-
- throw e;
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
- }
-
private @Nullable UidState getUidStateLocked(int uid, boolean edit) {
UidState uidState = mUidStates.get(uid);
if (uidState == null) {
@@ -5855,11 +5802,8 @@
return false;
}
}
- int userId = UserHandle.getUserId(uid);
-
verifyIncomingOp(code);
- verifyIncomingUser(userId);
- verifyIncomingPackage(packageName, userId);
+ verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
final String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
diff --git a/services/core/java/com/android/server/appop/TEST_MAPPING b/services/core/java/com/android/server/appop/TEST_MAPPING
index a3e1b7a..84de25c 100644
--- a/services/core/java/com/android/server/appop/TEST_MAPPING
+++ b/services/core/java/com/android/server/appop/TEST_MAPPING
@@ -7,9 +7,6 @@
"name": "CtsAppOps2TestCases"
},
{
- "name": "CtsAppOpHostTestCases"
- },
- {
"name": "FrameworksServicesTests",
"options": [
{
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 45f95fd..2bbbbf1 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -224,12 +224,35 @@
if (!addSpeakerphoneClient(cb, pid, on)) {
return false;
}
+ if (on) {
+ // Cancel BT SCO ON request by this same client: speakerphone and BT SCO routes
+ // are mutually exclusive.
+ // See symmetrical operation for startBluetoothScoForClient_Sync().
+ mBtHelper.stopBluetoothScoForPid(pid);
+ }
final boolean wasOn = isSpeakerphoneOn();
updateSpeakerphoneOn(eventSource);
return (wasOn != isSpeakerphoneOn());
}
}
+ /**
+ * Turns speakerphone off for a given pid and update speakerphone state.
+ * @param pid
+ */
+ @GuardedBy("mDeviceStateLock")
+ private void setSpeakerphoneOffForPid(int pid) {
+ SpeakerphoneClient client = getSpeakerphoneClientForPid(pid);
+ if (client == null) {
+ return;
+ }
+ client.unregisterDeathRecipient();
+ mSpeakerphoneClients.remove(client);
+ final String eventSource = new StringBuilder("setSpeakerphoneOffForPid(")
+ .append(pid).append(")").toString();
+ updateSpeakerphoneOn(eventSource);
+ }
+
@GuardedBy("mDeviceStateLock")
private void updateSpeakerphoneOn(String eventSource) {
if (isSpeakerphoneOnRequested()) {
@@ -488,6 +511,10 @@
/*package*/ void startBluetoothScoForClient_Sync(IBinder cb, int scoAudioMode,
@NonNull String eventSource) {
synchronized (mDeviceStateLock) {
+ // Cancel speakerphone ON request by this same client: speakerphone and BT SCO routes
+ // are mutually exclusive.
+ // See symmetrical operation for setSpeakerphoneOn(true).
+ setSpeakerphoneOffForPid(Binder.getCallingPid());
mBtHelper.startBluetoothScoForClient(cb, scoAudioMode, eventSource);
}
}
@@ -1379,6 +1406,16 @@
return false;
}
+ @GuardedBy("mDeviceStateLock")
+ private SpeakerphoneClient getSpeakerphoneClientForPid(int pid) {
+ for (SpeakerphoneClient cl : mSpeakerphoneClients) {
+ if (cl.getPid() == pid) {
+ return cl;
+ }
+ }
+ return null;
+ }
+
// List of clients requesting speakerPhone ON
@GuardedBy("mDeviceStateLock")
private final @NonNull ArrayList<SpeakerphoneClient> mSpeakerphoneClients =
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 32be03f..366f303 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -414,13 +414,6 @@
AppOpsManager.OP_AUDIO_MEDIA_VOLUME // STREAM_ASSISTANT
};
- private static Set<Integer> sDeviceVolumeBehaviorSupportedDeviceOutSet = new HashSet<>(
- Arrays.asList(
- AudioSystem.DEVICE_OUT_HDMI,
- AudioSystem.DEVICE_OUT_HDMI_ARC,
- AudioSystem.DEVICE_OUT_SPDIF,
- AudioSystem.DEVICE_OUT_LINE));
-
private final boolean mUseFixedVolume;
// If absolute volume is supported in AVRCP device
@@ -4952,11 +4945,6 @@
private void setDeviceVolumeBehaviorInternal(int audioSystemDeviceOut,
@AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior, @NonNull String caller) {
- if (!sDeviceVolumeBehaviorSupportedDeviceOutSet.contains(audioSystemDeviceOut)) {
- // unsupported for now
- throw new IllegalArgumentException("Unsupported device type " + audioSystemDeviceOut);
- }
-
// update device masks based on volume behavior
switch (deviceVolumeBehavior) {
case AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE:
@@ -4990,20 +4978,14 @@
* @param device the audio output device type
* @return the volume behavior for the device
*/
- public @AudioManager.DeviceVolumeBehaviorState int getDeviceVolumeBehavior(
- @NonNull AudioDeviceAttributes device) {
+ public @AudioManager.DeviceVolumeBehavior
+ int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
// verify permissions
enforceModifyAudioRoutingPermission();
// translate Java device type to native device type (for the devices masks for full / fixed)
final int audioSystemDeviceOut = AudioDeviceInfo.convertDeviceTypeToInternalDevice(
device.getType());
- if (!sDeviceVolumeBehaviorSupportedDeviceOutSet.contains(audioSystemDeviceOut)
- && audioSystemDeviceOut != AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP
- && audioSystemDeviceOut != AudioSystem.DEVICE_OUT_HEARING_AID) {
- throw new IllegalArgumentException("Unsupported volume behavior "
- + audioSystemDeviceOut);
- }
int setDeviceVolumeBehavior = retrieveStoredDeviceVolumeBehavior(audioSystemDeviceOut);
if (setDeviceVolumeBehavior != AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET) {
@@ -9081,7 +9063,7 @@
}
private void restoreDeviceVolumeBehavior() {
- for (int deviceType : sDeviceVolumeBehaviorSupportedDeviceOutSet) {
+ for (int deviceType : AudioSystem.DEVICE_OUT_ALL_SET) {
if (DEBUG_VOL) {
Log.d(TAG, "Retrieving Volume Behavior for DeviceType: " + deviceType);
}
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 5e8f1ef..ded0f9a3 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -432,19 +432,35 @@
// and this must be done on behalf of system server to make sure permissions are granted.
final long ident = Binder.clearCallingIdentity();
if (client != null) {
- AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(eventSource));
- client.requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED,
- SCO_MODE_VIRTUAL_CALL);
- // If a disconnection is pending, the client will be removed whne clearAllScoClients()
- // is called form receiveBtEvent()
- if (mScoAudioState != SCO_STATE_DEACTIVATE_REQ
- && mScoAudioState != SCO_STATE_DEACTIVATING) {
- client.remove(false /*stop */, true /*unregister*/);
- }
+ stopAndRemoveClient(client, eventSource);
}
Binder.restoreCallingIdentity(ident);
}
+ // @GuardedBy("AudioDeviceBroker.mSetModeLock")
+ @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+ /*package*/ synchronized void stopBluetoothScoForPid(int pid) {
+ ScoClient client = getScoClientForPid(pid);
+ if (client == null) {
+ return;
+ }
+ final String eventSource = new StringBuilder("stopBluetoothScoForPid(")
+ .append(pid).append(")").toString();
+ stopAndRemoveClient(client, eventSource);
+ }
+
+ @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+ private void stopAndRemoveClient(ScoClient client, @NonNull String eventSource) {
+ AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(eventSource));
+ client.requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED,
+ SCO_MODE_VIRTUAL_CALL);
+ // If a disconnection is pending, the client will be removed when clearAllScoClients()
+ // is called form receiveBtEvent()
+ if (mScoAudioState != SCO_STATE_DEACTIVATE_REQ
+ && mScoAudioState != SCO_STATE_DEACTIVATING) {
+ client.remove(false /*stop */, true /*unregister*/);
+ }
+ }
/*package*/ synchronized void setHearingAidVolume(int index, int streamType) {
if (mHearingAid == null) {
@@ -982,6 +998,16 @@
return null;
}
+ @GuardedBy("BtHelper.this")
+ private ScoClient getScoClientForPid(int pid) {
+ for (ScoClient cl : mScoClients) {
+ if (cl.getPid() == pid) {
+ return cl;
+ }
+ }
+ return null;
+ }
+
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
//@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
@GuardedBy("BtHelper.this")
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 74ed815..5a423793 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.input;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -66,6 +67,7 @@
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -181,8 +183,7 @@
// State for vibrator tokens.
private Object mVibratorLock = new Object();
- private HashMap<IBinder, VibratorToken> mVibratorTokens =
- new HashMap<IBinder, VibratorToken>();
+ private Map<IBinder, VibratorToken> mVibratorTokens = new ArrayMap<IBinder, VibratorToken>();
private int mNextVibratorTokenValue;
// State for the currently installed input filter.
@@ -190,12 +191,16 @@
IInputFilter mInputFilter; // guarded by mInputFilterLock
InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
+ private final Object mGestureMonitorPidsLock = new Object();
+ @GuardedBy("mGestureMonitorPidsLock")
+ private final ArrayMap<IBinder, Integer> mGestureMonitorPidsByToken = new ArrayMap<>();
+
// The associations of input devices to displays by port. Maps from input device port (String)
// to display id (int). Currently only accessed by InputReader.
private final Map<String, Integer> mStaticAssociations;
private final Object mAssociationsLock = new Object();
@GuardedBy("mAssociationLock")
- private final Map<String, Integer> mRuntimeAssociations = new HashMap<String, Integer>();
+ private final Map<String, Integer> mRuntimeAssociations = new ArrayMap<String, Integer>();
private static native long nativeInit(InputManagerService service,
Context context, MessageQueue messageQueue);
@@ -540,13 +545,17 @@
if (displayId < Display.DEFAULT_DISPLAY) {
throw new IllegalArgumentException("displayId must >= 0.");
}
+ final int pid = Binder.getCallingPid();
final long ident = Binder.clearCallingIdentity();
try {
InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
InputMonitorHost host = new InputMonitorHost(inputChannels[0]);
- nativeRegisterInputMonitor(mPtr, inputChannels[0], displayId,
- true /*isGestureMonitor*/);
+ nativeRegisterInputMonitor(
+ mPtr, inputChannels[0], displayId, true /*isGestureMonitor*/);
+ synchronized (mGestureMonitorPidsLock) {
+ mGestureMonitorPidsByToken.put(inputChannels[1].getToken(), pid);
+ }
return new InputMonitor(inputChannels[1], host);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -575,6 +584,9 @@
if (inputChannel == null) {
throw new IllegalArgumentException("inputChannel must not be null.");
}
+ synchronized (mGestureMonitorPidsLock) {
+ mGestureMonitorPidsByToken.remove(inputChannel.getToken());
+ }
nativeUnregisterInputChannel(mPtr, inputChannel);
}
@@ -1838,6 +1850,7 @@
if (dumpStr != null) {
pw.println(dumpStr);
dumpAssociations(pw);
+ dumpGestureMonitorPidsByToken(pw);
}
}
@@ -1861,6 +1874,19 @@
}
}
+ private void dumpGestureMonitorPidsByToken(PrintWriter pw) {
+ synchronized (mGestureMonitorPidsLock) {
+ if (!mGestureMonitorPidsByToken.isEmpty()) {
+ pw.println("Gesture monitor pids by token:");
+ for (int i = 0; i < mGestureMonitorPidsByToken.size(); i++) {
+ pw.print(" " + i + ": ");
+ pw.print(" token: " + mGestureMonitorPidsByToken.keyAt(i));
+ pw.println(" pid: " + mGestureMonitorPidsByToken.valueAt(i));
+ }
+ }
+ }
+ }
+
private boolean checkCallingPermission(String permission, String func) {
// Quick check: if the calling permission is me, it's all okay.
if (Binder.getCallingPid() == Process.myPid()) {
@@ -1883,6 +1909,7 @@
public void monitor() {
synchronized (mInputFilterLock) { }
synchronized (mAssociationsLock) { /* Test if blocked by associations lock. */}
+ synchronized (mGestureMonitorPidsLock) { /* Test if blocked by gesture monitor pids lock */}
nativeMonitor(mPtr);
}
@@ -1944,6 +1971,9 @@
// Native callback.
private void notifyInputChannelBroken(IBinder token) {
+ synchronized (mGestureMonitorPidsLock) {
+ mGestureMonitorPidsByToken.remove(token);
+ }
mWindowManagerCallbacks.notifyInputChannelBroken(token);
}
@@ -1959,8 +1989,12 @@
// Native callback.
private long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
String reason) {
- return mWindowManagerCallbacks.notifyANR(inputApplicationHandle,
- token, reason);
+ Integer gestureMonitorPid;
+ synchronized (mGestureMonitorPidsLock) {
+ gestureMonitorPid = mGestureMonitorPidsByToken.get(token);
+ }
+ return mWindowManagerCallbacks.notifyANR(inputApplicationHandle, token, gestureMonitorPid,
+ reason);
}
// Native callback.
@@ -2206,22 +2240,48 @@
* Callback interface implemented by the Window Manager.
*/
public interface WindowManagerCallbacks {
+ /**
+ * This callback is invoked when the confuguration changes.
+ */
public void notifyConfigurationChanged();
+ /**
+ * This callback is invoked when the lid switch changes state.
+ * @param whenNanos the time when the change occurred
+ * @param lidOpen true if the lid is open
+ */
public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
+ /**
+ * This callback is invoked when the camera lens cover switch changes state.
+ * @param whenNanos the time when the change occurred
+ * @param lensCovered true is the lens is covered
+ */
public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
+ /**
+ * This callback is invoked when an input channel is closed unexpectedly.
+ * @param token the connection token of the broken channel
+ */
public void notifyInputChannelBroken(IBinder token);
/**
- * Notifies the window manager about an application that is not responding.
- * Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch.
+ * Notify the window manager about an application that is not responding.
+ * Return a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch.
*/
long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
- String reason);
+ @Nullable Integer pid, String reason);
- public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
+ /**
+ * This callback is invoked when an event first arrives to InputDispatcher and before it is
+ * placed onto InputDispatcher's queue. If this event is intercepted, it will never be
+ * processed by InputDispacher.
+ * @param event The key event that's arriving to InputDispatcher
+ * @param policyFlags The policy flags
+ * @return the flags that tell InputDispatcher how to handle the event (for example, whether
+ * to pass it to the user)
+ */
+ int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
/**
* Provides an opportunity for the window manager policy to intercept early motion event
@@ -2231,11 +2291,23 @@
int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos,
int policyFlags);
- public long interceptKeyBeforeDispatching(IBinder token,
- KeyEvent event, int policyFlags);
+ /**
+ * This callback is invoked just before the key is about to be sent to an application.
+ * This allows the policy to make some last minute decisions on whether to intercept this
+ * key.
+ * @param token the window token that's about to receive this event
+ * @param event the key event that's being dispatched
+ * @param policyFlags the policy flags
+ * @return negative value if the key should be skipped (not sent to the app). 0 if the key
+ * should proceed getting dispatched to the app. positive value to indicate the additional
+ * time delay, in nanoseconds, to wait before sending this key to the app.
+ */
+ long interceptKeyBeforeDispatching(IBinder token, KeyEvent event, int policyFlags);
- public KeyEvent dispatchUnhandledKey(IBinder token,
- KeyEvent event, int policyFlags);
+ /**
+ * Dispatch unhandled key
+ */
+ KeyEvent dispatchUnhandledKey(IBinder token, KeyEvent event, int policyFlags);
public int getPointerLayer();
diff --git a/services/core/java/com/android/server/location/LocationFudger.java b/services/core/java/com/android/server/location/LocationFudger.java
index 1f458ed..6f35c8b 100644
--- a/services/core/java/com/android/server/location/LocationFudger.java
+++ b/services/core/java/com/android/server/location/LocationFudger.java
@@ -112,7 +112,7 @@
public Location createCoarse(Location fine) {
synchronized (this) {
if (fine == mCachedFineLocation) {
- return new Location(mCachedCoarseLocation);
+ return mCachedCoarseLocation;
}
}
@@ -154,7 +154,7 @@
mCachedCoarseLocation = coarse;
}
- return new Location(mCachedCoarseLocation);
+ return mCachedCoarseLocation;
}
/**
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index d3558f1..71f1833 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -17,43 +17,27 @@
package com.android.server.location;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
-import static android.app.AppOpsManager.OP_MOCK_LOCATION;
-import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
-import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.location.LocationManager.EXTRA_LOCATION_ENABLED;
-import static android.location.LocationManager.EXTRA_PROVIDER_ENABLED;
-import static android.location.LocationManager.EXTRA_PROVIDER_NAME;
import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
-import static android.location.LocationManager.KEY_LOCATION_CHANGED;
-import static android.location.LocationManager.KEY_PROVIDER_ENABLED;
-import static android.location.LocationManager.MODE_CHANGED_ACTION;
import static android.location.LocationManager.NETWORK_PROVIDER;
-import static android.location.LocationManager.PASSIVE_PROVIDER;
-import static android.location.LocationManager.PROVIDERS_CHANGED_ACTION;
-import static android.location.LocationManager.invalidateLocalLocationEnabledCaches;
-import static android.os.PowerManager.locationPowerSaveModeToString;
import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
-import static com.android.server.location.LocationPermissions.PERMISSION_NONE;
+import static com.android.server.location.LocationProviderManager.FASTEST_COARSE_INTERVAL_MS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import android.Manifest.permission;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.location.Criteria;
import android.location.GeocoderParams;
import android.location.Geofence;
@@ -78,17 +62,9 @@
import android.location.LocationTime;
import android.location.util.identity.CallerIdentity;
import android.os.Binder;
-import android.os.Build;
import android.os.Bundle;
-import android.os.CancellationSignal;
-import android.os.Handler;
-import android.os.IBinder;
import android.os.ICancellationSignal;
-import android.os.IRemoteCallback;
import android.os.ParcelFileDescriptor;
-import android.os.PowerManager;
-import android.os.PowerManager.ServiceType;
-import android.os.PowerManagerInternal;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -96,24 +72,16 @@
import android.os.WorkSource;
import android.os.WorkSource.WorkChain;
import android.stats.location.LocationStatsEnums;
-import android.text.TextUtils;
-import android.util.EventLog;
import android.util.IndentingPrintWriter;
import android.util.Log;
-import android.util.SparseArray;
import android.util.TimeUtils;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.content.PackageMonitor;
import com.android.internal.location.ProviderProperties;
-import com.android.internal.location.ProviderRequest;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
-import com.android.server.FgThread;
import com.android.server.LocalServices;
-import com.android.server.PendingIntentUtils;
import com.android.server.SystemService;
-import com.android.server.location.AbstractLocationProvider.State;
import com.android.server.location.LocationPermissions.PermissionLevel;
import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
import com.android.server.location.LocationRequestStatistics.PackageStatistics;
@@ -137,24 +105,17 @@
import com.android.server.location.util.SystemSettingsHelper;
import com.android.server.location.util.SystemUserInfoHelper;
import com.android.server.location.util.UserInfoHelper;
-import com.android.server.location.util.UserInfoHelper.UserListener;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
-import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
-import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.Objects;
import java.util.TreeMap;
import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.Executor;
/**
* The service class that manages LocationProviders and issues location
@@ -241,54 +202,21 @@
public static final String TAG = "LocationManagerService";
public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
- private static final String WAKELOCK_KEY = "*location*";
-
private static final String NETWORK_LOCATION_SERVICE_ACTION =
"com.android.location.service.v3.NetworkLocationProvider";
private static final String FUSED_LOCATION_SERVICE_ACTION =
"com.android.location.service.FusedLocationProvider";
- // The maximum interval a location request can have and still be considered "high power".
- private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
-
- // The fastest interval that applications can receive coarse locations
- private static final long FASTEST_COARSE_INTERVAL_MS = 10 * 60 * 1000;
-
- // maximum age of a location before it is no longer considered "current"
- private static final long MAX_CURRENT_LOCATION_AGE_MS = 10 * 1000;
-
- // Location Providers may sometimes deliver location updates
- // slightly faster that requested - provide grace period so
- // we don't unnecessarily filter events that are otherwise on
- // time
- private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
-
- private static final long GET_CURRENT_LOCATION_MAX_TIMEOUT_MS = 30000;
-
private static final String ATTRIBUTION_TAG = "LocationService";
private final Object mLock = new Object();
- private final Handler mHandler;
+ private final Context mContext;
+ private final Injector mInjector;
private final LocalService mLocalService;
- private final Injector mInjector;
-
- private final Context mContext;
- private final AppOpsHelper mAppOpsHelper;
- private final UserInfoHelper mUserInfoHelper;
- private final SettingsHelper mSettingsHelper;
- private final AppForegroundHelper mAppForegroundHelper;
- private final LocationUsageLogger mLocationUsageLogger;
-
private final GeofenceManager mGeofenceManager;
-
@Nullable private volatile GnssManagerService mGnssManagerService = null;
-
- private final PassiveLocationProviderManager mPassiveManager;
-
- private PowerManager mPowerManager;
-
private GeocoderProxy mGeocodeProvider;
@GuardedBy("mLock")
@@ -296,46 +224,30 @@
@GuardedBy("mLock")
private boolean mExtraLocationControllerPackageEnabled;
- // @GuardedBy("mLock")
- // hold lock for write or to prevent write, no lock for read
- final CopyOnWriteArrayList<LocationProviderManager> mProviderManagers =
+ // location provider managers
+
+ private final PassiveLocationProviderManager mPassiveManager;
+
+ // @GuardedBy("mProviderManagers")
+ // hold lock for writes, no lock necessary for simple reads
+ private final CopyOnWriteArrayList<LocationProviderManager> mProviderManagers =
new CopyOnWriteArrayList<>();
- @GuardedBy("mLock")
- private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
- private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
- new HashMap<>();
-
- private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
-
- @GuardedBy("mLock")
- @PowerManager.LocationPowerSaveMode
- private int mBatterySaverMode;
-
LocationManagerService(Context context, Injector injector) {
- mHandler = FgThread.getHandler();
- mLocalService = new LocalService();
-
- LocalServices.addService(LocationManagerInternal.class, mLocalService);
-
+ mContext = context.createAttributionContext(ATTRIBUTION_TAG);
mInjector = injector;
- mContext = context.createAttributionContext(ATTRIBUTION_TAG);
- mUserInfoHelper = injector.getUserInfoHelper();
- mAppOpsHelper = injector.getAppOpsHelper();
- mSettingsHelper = injector.getSettingsHelper();
- mAppForegroundHelper = injector.getAppForegroundHelper();
- mLocationUsageLogger = injector.getLocationUsageLogger();
+ mLocalService = new LocalService();
+ LocalServices.addService(LocationManagerInternal.class, mLocalService);
mGeofenceManager = new GeofenceManager(mContext, injector);
- // set up passive provider - we do this early because it has no dependencies on system
- // services or external code that isn't ready yet, and because this allows the variable to
- // be final. other more complex providers are initialized later, when system services are
- // ready
- mPassiveManager = new PassiveLocationProviderManager();
- mProviderManagers.add(mPassiveManager);
- mPassiveManager.setRealProvider(new PassiveProvider(mContext));
+ // set up passive provider first since it will be required for all other location providers,
+ // which are loaded later once the system is ready.
+ mPassiveManager = new PassiveLocationProviderManager(mContext, injector);
+ addLocationProviderManager(mPassiveManager, new PassiveProvider(mContext));
+
+ // TODO: load the gps provider here as well, which will require refactoring
// Let the package manager query which are the default location
// providers as they get certain permissions granted by default.
@@ -347,253 +259,77 @@
permissionManagerInternal.setLocationExtraPackagesProvider(
userId -> mContext.getResources().getStringArray(
com.android.internal.R.array.config_locationExtraPackageNames));
+ }
- // most startup is deferred until systemReady()
+ @Nullable
+ private LocationProviderManager getLocationProviderManager(String providerName) {
+ if (providerName == null) {
+ return null;
+ }
+
+ for (LocationProviderManager manager : mProviderManagers) {
+ if (providerName.equals(manager.getName())) {
+ return manager;
+ }
+ }
+
+ return null;
+ }
+
+ private LocationProviderManager getOrAddLocationProviderManager(String providerName) {
+ synchronized (mProviderManagers) {
+ for (LocationProviderManager manager : mProviderManagers) {
+ if (providerName.equals(manager.getName())) {
+ return manager;
+ }
+ }
+
+ LocationProviderManager manager = new LocationProviderManager(mContext, mInjector,
+ providerName, mPassiveManager);
+ addLocationProviderManager(manager, null);
+ return manager;
+ }
+ }
+
+ private void addLocationProviderManager(LocationProviderManager manager,
+ @Nullable AbstractLocationProvider realProvider) {
+ synchronized (mProviderManagers) {
+ Preconditions.checkState(getLocationProviderManager(manager.getName()) == null);
+
+ manager.startManager();
+ if (realProvider != null) {
+ manager.setRealProvider(realProvider);
+ }
+ mProviderManagers.add(manager);
+ }
+ }
+
+ private void removeLocationProviderManager(LocationProviderManager manager) {
+ synchronized (mProviderManagers) {
+ Preconditions.checkState(getLocationProviderManager(manager.getName()) == manager);
+
+ mProviderManagers.remove(manager);
+ manager.setMockProvider(null);
+ manager.setRealProvider(null);
+ manager.stopManager();
+ }
}
void onSystemReady() {
- synchronized (mLock) {
- mPowerManager = mContext.getSystemService(PowerManager.class);
-
- // add listeners
- mContext.getPackageManager().addOnPermissionsChangeListener(
- uid -> {
- // listener invoked on ui thread, move to our thread to reduce risk of
- // blocking ui thread
- mHandler.post(() -> {
- synchronized (mLock) {
- onPermissionsChangedLocked();
- }
- });
- });
-
- LocalServices.getService(PowerManagerInternal.class).registerLowPowerModeObserver(
- ServiceType.LOCATION,
- state -> {
- // listener invoked on ui thread, move to our thread to reduce risk of
- // blocking ui thread
- mHandler.post(() -> {
- synchronized (mLock) {
- onBatterySaverModeChangedLocked(state.locationMode);
- }
- });
- });
- mBatterySaverMode = mPowerManager.getLocationPowerSaveMode();
-
- mAppOpsHelper.addListener(this::onAppOpChanged);
-
- mSettingsHelper.addOnLocationEnabledChangedListener(this::onLocationModeChanged);
- mSettingsHelper.addOnBackgroundThrottleIntervalChangedListener(
- this::onBackgroundThrottleIntervalChanged);
- mSettingsHelper.addOnBackgroundThrottlePackageWhitelistChangedListener(
- this::onBackgroundThrottleWhitelistChanged);
- mSettingsHelper.addOnIgnoreSettingsPackageWhitelistChangedListener(
- this::onIgnoreSettingsWhitelistChanged);
-
- PackageMonitor packageMonitor = new PackageMonitor() {
- @Override
- public void onPackageDisappeared(String packageName, int reason) {
- synchronized (mLock) {
- LocationManagerService.this.onPackageDisappeared(packageName);
- }
- }
- };
- packageMonitor.register(mContext, null, true, mHandler);
-
- mUserInfoHelper.addListener(this::onUserChanged);
-
- mAppForegroundHelper.addListener(this::onAppForegroundChanged);
-
- IntentFilter screenIntentFilter = new IntentFilter();
- screenIntentFilter.addAction(Intent.ACTION_SCREEN_OFF);
- screenIntentFilter.addAction(Intent.ACTION_SCREEN_ON);
- mContext.registerReceiverAsUser(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())
- || Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
- onScreenStateChanged();
- }
- }
- }, UserHandle.ALL, screenIntentFilter, null, mHandler);
-
- // initialize the current users. we would get the user started notifications for these
- // users eventually anyways, but this takes care of it as early as possible.
- onUserChanged(UserHandle.USER_ALL, UserListener.USER_STARTED);
- }
+ mInjector.getSettingsHelper().addOnLocationEnabledChangedListener(
+ this::onLocationModeChanged);
}
void onSystemThirdPartyAppsCanStart() {
- synchronized (mLock) {
- // prepare providers
- initializeProvidersLocked();
- }
-
- // initialize gnss last because it has no awareness of boot phases and blindly assumes that
- // all other location providers are loaded at initialization
- initializeGnss();
- }
-
- private void onAppOpChanged(String packageName) {
- synchronized (mLock) {
- for (Receiver receiver : mReceivers.values()) {
- if (receiver.mCallerIdentity.getPackageName().equals(packageName)) {
- receiver.updateMonitoring(true);
- }
- }
-
- HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
- for (Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
- String provider = entry.getKey();
- for (UpdateRecord record : entry.getValue()) {
- if (record.mReceiver.mCallerIdentity.getPackageName().equals(packageName)) {
- affectedProviders.add(provider);
- }
- }
- }
- for (String provider : affectedProviders) {
- applyRequirementsLocked(provider);
- }
- }
- }
-
- @GuardedBy("mLock")
- private void onPermissionsChangedLocked() {
- for (LocationProviderManager manager : mProviderManagers) {
- applyRequirementsLocked(manager);
- }
- }
-
- @GuardedBy("mLock")
- private void onBatterySaverModeChangedLocked(int newLocationMode) {
- if (mBatterySaverMode == newLocationMode) {
- return;
- }
-
- if (D) {
- Log.d(TAG,
- "Battery Saver location mode changed from "
- + locationPowerSaveModeToString(mBatterySaverMode) + " to "
- + locationPowerSaveModeToString(newLocationMode));
- }
-
- mBatterySaverMode = newLocationMode;
-
- for (LocationProviderManager manager : mProviderManagers) {
- applyRequirementsLocked(manager);
- }
- }
-
- private void onScreenStateChanged() {
- synchronized (mLock) {
- if (mBatterySaverMode == PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF) {
- for (LocationProviderManager manager : mProviderManagers) {
- applyRequirementsLocked(manager);
- }
- }
- }
- }
-
- private void onLocationModeChanged(int userId) {
- boolean enabled = mSettingsHelper.isLocationEnabled(userId);
- LocationManager.invalidateLocalLocationEnabledCaches();
-
- if (D) {
- Log.d(TAG, "[u" + userId + "] location enabled = " + enabled);
- }
-
- Intent intent = new Intent(MODE_CHANGED_ACTION)
- .putExtra(EXTRA_LOCATION_ENABLED, enabled)
- .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
- .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
-
- synchronized (mLock) {
- for (LocationProviderManager manager : mProviderManagers) {
- manager.onEnabledChangedLocked(userId);
- }
- }
- }
-
- private void onPackageDisappeared(String packageName) {
- synchronized (mLock) {
- ArrayList<Receiver> deadReceivers = null;
-
- for (Receiver receiver : mReceivers.values()) {
- if (receiver.mCallerIdentity.getPackageName().equals(packageName)) {
- if (deadReceivers == null) {
- deadReceivers = new ArrayList<>();
- }
- deadReceivers.add(receiver);
- }
- }
-
- // perform removal outside of mReceivers loop
- if (deadReceivers != null) {
- for (Receiver receiver : deadReceivers) {
- removeUpdatesLocked(receiver);
- }
- }
- }
- }
-
- private void onAppForegroundChanged(int uid, boolean foreground) {
- synchronized (mLock) {
- HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
- for (Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
- String provider = entry.getKey();
- for (UpdateRecord record : entry.getValue()) {
- if (record.mReceiver.mCallerIdentity.getUid() == uid
- && record.mIsForegroundUid != foreground) {
- record.updateForeground(foreground);
-
- if (!isThrottlingExempt(record.mReceiver.mCallerIdentity)) {
- affectedProviders.add(provider);
- }
- }
- }
- }
- for (String provider : affectedProviders) {
- applyRequirementsLocked(provider);
- }
- }
- }
-
- private void onBackgroundThrottleIntervalChanged() {
- synchronized (mLock) {
- for (LocationProviderManager manager : mProviderManagers) {
- applyRequirementsLocked(manager);
- }
- }
- }
-
- private void onBackgroundThrottleWhitelistChanged() {
- synchronized (mLock) {
- for (LocationProviderManager manager : mProviderManagers) {
- applyRequirementsLocked(manager);
- }
- }
- }
-
- private void onIgnoreSettingsWhitelistChanged() {
- synchronized (mLock) {
- for (LocationProviderManager manager : mProviderManagers) {
- applyRequirementsLocked(manager);
- }
- }
- }
-
- @GuardedBy("mLock")
- private void initializeProvidersLocked() {
LocationProviderProxy networkProvider = LocationProviderProxy.createAndRegister(
mContext,
NETWORK_LOCATION_SERVICE_ACTION,
com.android.internal.R.bool.config_enableNetworkLocationOverlay,
com.android.internal.R.string.config_networkLocationProviderPackageName);
if (networkProvider != null) {
- LocationProviderManager networkManager = new LocationProviderManager(NETWORK_PROVIDER);
- mProviderManagers.add(networkManager);
- networkManager.setRealProvider(networkProvider);
+ LocationProviderManager networkManager = new LocationProviderManager(mContext,
+ mInjector, NETWORK_PROVIDER, mPassiveManager);
+ addLocationProviderManager(networkManager, networkProvider);
} else {
Log.w(TAG, "no network location provider found");
}
@@ -604,18 +340,28 @@
MATCH_DIRECT_BOOT_AWARE | MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM).isEmpty(),
"Unable to find a direct boot aware fused location provider");
- // bind to fused provider
LocationProviderProxy fusedProvider = LocationProviderProxy.createAndRegister(
mContext,
FUSED_LOCATION_SERVICE_ACTION,
com.android.internal.R.bool.config_enableFusedLocationOverlay,
com.android.internal.R.string.config_fusedLocationProviderPackageName);
if (fusedProvider != null) {
- LocationProviderManager fusedManager = new LocationProviderManager(FUSED_PROVIDER);
- mProviderManagers.add(fusedManager);
- fusedManager.setRealProvider(fusedProvider);
+ LocationProviderManager fusedManager = new LocationProviderManager(mContext, mInjector,
+ FUSED_PROVIDER, mPassiveManager);
+ addLocationProviderManager(fusedManager, fusedProvider);
} else {
- Log.e(TAG, "no fused location provider found");
+ Log.wtf(TAG, "no fused location provider found");
+ }
+
+ // initialize gnss last because it has no awareness of boot phases and blindly assumes that
+ // all other location providers are loaded at initialization
+ if (GnssManagerService.isGnssSupported()) {
+ mGnssManagerService = new GnssManagerService(mContext, mInjector);
+ mGnssManagerService.onSystemReady();
+
+ LocationProviderManager gnssManager = new LocationProviderManager(mContext, mInjector,
+ GPS_PROVIDER, mPassiveManager);
+ addLocationProviderManager(gnssManager, mGnssManagerService.getGnssLocationProvider());
}
// bind to geocoder provider
@@ -631,6 +377,18 @@
Log.e(TAG, "unable to bind ActivityRecognitionProxy");
}
+ // bind to gnss geofence proxy
+ if (GnssManagerService.isGnssSupported()) {
+ IGpsGeofenceHardware gpsGeofenceHardware = mGnssManagerService.getGpsGeofenceProxy();
+ if (gpsGeofenceHardware != null) {
+ GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, gpsGeofenceHardware);
+ if (provider == null) {
+ Log.e(TAG, "unable to bind to GeofenceProxy");
+ }
+ }
+ }
+
+ // create any predefined test providers
String[] testProviderStrings = mContext.getResources().getStringArray(
com.android.internal.R.array.config_testLocationProviders);
for (String testProviderString : testProviderStrings) {
@@ -646,763 +404,24 @@
Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
Integer.parseInt(fragments[8]) /* powerRequirement */,
Integer.parseInt(fragments[9]) /* accuracy */);
- LocationProviderManager manager = getLocationProviderManager(name);
- if (manager == null) {
- manager = new LocationProviderManager(name);
- mProviderManagers.add(manager);
- }
- manager.setMockProvider(
+ getOrAddLocationProviderManager(name).setMockProvider(
new MockProvider(properties, CallerIdentity.fromContext(mContext)));
}
}
- private void initializeGnss() {
- // Do not hold mLock when calling GnssManagerService#isGnssSupported() which calls into HAL.
- if (GnssManagerService.isGnssSupported()) {
- mGnssManagerService = new GnssManagerService(mContext, mInjector);
- mGnssManagerService.onSystemReady();
+ private void onLocationModeChanged(int userId) {
+ boolean enabled = mInjector.getSettingsHelper().isLocationEnabled(userId);
+ LocationManager.invalidateLocalLocationEnabledCaches();
- LocationProviderManager gnssManager = new LocationProviderManager(GPS_PROVIDER);
- synchronized (mLock) {
- mProviderManagers.add(gnssManager);
- }
- gnssManager.setRealProvider(mGnssManagerService.getGnssLocationProvider());
-
- // bind to geofence proxy
- IGpsGeofenceHardware gpsGeofenceHardware = mGnssManagerService.getGpsGeofenceProxy();
- if (gpsGeofenceHardware != null) {
- GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, gpsGeofenceHardware);
- if (provider == null) {
- Log.e(TAG, "unable to bind to GeofenceProxy");
- }
- }
- }
- }
-
- private void onUserChanged(@UserIdInt int userId, @UserListener.UserChange int change) {
- switch (change) {
- case UserListener.CURRENT_USER_CHANGED:
- synchronized (mLock) {
- for (LocationProviderManager manager : mProviderManagers) {
- manager.onEnabledChangedLocked(userId);
- }
- }
- break;
- case UserListener.USER_STARTED:
- synchronized (mLock) {
- for (LocationProviderManager manager : mProviderManagers) {
- manager.onUserStarted(userId);
- }
- }
- break;
- case UserListener.USER_STOPPED:
- synchronized (mLock) {
- for (LocationProviderManager manager : mProviderManagers) {
- manager.onUserStopped(userId);
- }
- }
- break;
- }
- }
-
- /**
- * Location provider manager, manages a LocationProvider.
- */
- class LocationProviderManager implements MockableLocationProvider.Listener {
-
- private final String mName;
-
- private final LocationFudger mLocationFudger;
-
- // if the provider is enabled for a given user id - null or not present means unknown
- @GuardedBy("mLock")
- private final SparseArray<Boolean> mEnabled;
-
- // last location for a given user
- @GuardedBy("mLock")
- private final SparseArray<Location> mLastLocation;
-
- // last coarse location for a given user
- @GuardedBy("mLock")
- private final SparseArray<Location> mLastCoarseLocation;
-
- // acquiring mLock makes operations on mProvider atomic, but is otherwise unnecessary
- protected final MockableLocationProvider mProvider;
-
- LocationProviderManager(String name) {
- mName = name;
- mLocationFudger = new LocationFudger(mSettingsHelper.getCoarseLocationAccuracyM());
- mEnabled = new SparseArray<>(2);
- mLastLocation = new SparseArray<>(2);
- mLastCoarseLocation = new SparseArray<>(2);
-
- // initialize last since this lets our reference escape
- mProvider = new MockableLocationProvider(mLock, this);
+ if (D) {
+ Log.d(TAG, "[u" + userId + "] location enabled = " + enabled);
}
- public String getName() {
- return mName;
- }
-
- public boolean hasProvider() {
- return mProvider.getProvider() != null;
- }
-
- public void setRealProvider(AbstractLocationProvider provider) {
- mProvider.setRealProvider(provider);
- }
-
- public void setMockProvider(@Nullable MockProvider provider) {
- synchronized (mLock) {
- mProvider.setMockProvider(provider);
-
- // when removing a mock provider, also clear any mock last locations and reset the
- // location fudger. the mock provider could have been used to infer the current
- // location fudger offsets.
- if (provider == null) {
- for (int i = 0; i < mLastLocation.size(); i++) {
- Location lastLocation = mLastLocation.valueAt(i);
- if (lastLocation != null && lastLocation.isFromMockProvider()) {
- mLastLocation.setValueAt(i, null);
- }
- }
-
- for (int i = 0; i < mLastCoarseLocation.size(); i++) {
- Location lastCoarseLocation = mLastCoarseLocation.valueAt(i);
- if (lastCoarseLocation != null && lastCoarseLocation.isFromMockProvider()) {
- mLastCoarseLocation.setValueAt(i, null);
- }
- }
-
- mLocationFudger.resetOffsets();
- }
- }
- }
-
- @Nullable
- public CallerIdentity getProviderIdentity() {
- return mProvider.getState().identity;
- }
-
- @Nullable
- public ProviderProperties getProperties() {
- return mProvider.getState().properties;
- }
-
- @Nullable
- public Location getLastLocation(int userId, @PermissionLevel int permissionlevel) {
- synchronized (mLock) {
- switch (permissionlevel) {
- case PERMISSION_COARSE:
- return mLastCoarseLocation.get(userId);
- case PERMISSION_FINE:
- return mLastLocation.get(userId);
- default:
- throw new AssertionError();
- }
- }
- }
-
- public void injectLastLocation(Location location, int userId) {
- synchronized (mLock) {
- if (mLastLocation.get(userId) == null) {
- setLastLocation(location, userId);
- }
- }
- }
-
- private void setLastLocation(Location location, int userId) {
- synchronized (mLock) {
- mLastLocation.put(userId, location);
-
- // update last coarse interval only if enough time has passed
- long timeDeltaMs = Long.MAX_VALUE;
- Location coarseLocation = mLastCoarseLocation.get(userId);
- if (coarseLocation != null) {
- timeDeltaMs = NANOSECONDS.toMillis(location.getElapsedRealtimeNanos())
- - NANOSECONDS.toMillis(coarseLocation.getElapsedRealtimeNanos());
- }
- if (timeDeltaMs > FASTEST_COARSE_INTERVAL_MS) {
- mLastCoarseLocation.put(userId, mLocationFudger.createCoarse(location));
- }
- }
- }
-
- public void setMockProviderAllowed(boolean enabled) {
- synchronized (mLock) {
- if (!mProvider.isMock()) {
- throw new IllegalArgumentException(mName + " provider is not a test provider");
- }
-
- mProvider.setMockProviderAllowed(enabled);
- }
- }
-
- public void setMockProviderLocation(Location location) {
- synchronized (mLock) {
- if (!mProvider.isMock()) {
- throw new IllegalArgumentException(mName + " provider is not a test provider");
- }
-
- String locationProvider = location.getProvider();
- if (!TextUtils.isEmpty(locationProvider) && !mName.equals(locationProvider)) {
- // The location has an explicit provider that is different from the mock
- // provider name. The caller may be trying to fool us via b/33091107.
- EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
- mName + "!=" + locationProvider);
- }
-
- mProvider.setMockProviderLocation(location);
- }
- }
-
- public List<LocationRequest> getMockProviderRequests() {
- synchronized (mLock) {
- if (!mProvider.isMock()) {
- throw new IllegalArgumentException(mName + " provider is not a test provider");
- }
-
- return mProvider.getCurrentRequest().locationRequests;
- }
- }
-
- public void setRequest(ProviderRequest request) {
- mProvider.setRequest(request);
- }
-
- public void sendExtraCommand(int uid, int pid, String command, Bundle extras) {
- mProvider.sendExtraCommand(uid, pid, command, extras);
- }
-
- @GuardedBy("mLock")
- @Override
- public void onReportLocation(Location location) {
- // don't validate mock locations
- if (!location.isFromMockProvider()) {
- if (location.getLatitude() == 0 && location.getLongitude() == 0) {
- Log.w(TAG, "blocking 0,0 location from " + mName + " provider");
- return;
- }
- }
-
- if (!location.isComplete()) {
- Log.w(TAG, "blocking incomplete location from " + mName + " provider");
- return;
- }
-
- // update last location if the provider is enabled or if servicing a bypass request
- boolean locationSettingsIgnored = mProvider.getCurrentRequest().locationSettingsIgnored;
- for (int userId : mUserInfoHelper.getRunningUserIds()) {
- if (locationSettingsIgnored || isEnabled(userId)) {
- setLastLocation(location, userId);
- }
- }
-
- handleLocationChangedLocked(this, location, mLocationFudger.createCoarse(location));
- }
-
- @GuardedBy("mLock")
- @Override
- public void onReportLocation(List<Location> locations) {
- if (mGnssManagerService == null || !GPS_PROVIDER.equals(mName)) {
- return;
- }
-
- mGnssManagerService.onReportLocation(locations);
- }
-
- @GuardedBy("mLock")
- @Override
- public void onStateChanged(State oldState, State newState) {
- if (oldState.allowed != newState.allowed) {
- if (D) {
- Log.d(TAG, mName + " provider allowed = " + newState.allowed);
- }
-
- onEnabledChangedLocked(UserHandle.USER_ALL);
- }
- }
-
- public void onUserStarted(int userId) {
- if (userId == UserHandle.USER_NULL) {
- return;
- } else if (userId == UserHandle.USER_ALL) {
- for (int runningUserId : mUserInfoHelper.getRunningUserIds()) {
- onUserStarted(runningUserId);
- }
- return;
- }
-
- Preconditions.checkArgument(userId >= 0);
-
- synchronized (mLock) {
- // clear the user's prior enabled state to prevent broadcast of enabled state
- // change. user starts should never result in a broadcast since the state has
- // technically not changed.
- mEnabled.put(userId, null);
- onEnabledChangedLocked(userId);
- }
- }
-
- public void onUserStopped(int userId) {
- if (userId == UserHandle.USER_NULL) {
- return;
- } else if (userId == UserHandle.USER_ALL) {
- mEnabled.clear();
- mLastLocation.clear();
- mLastCoarseLocation.clear();
- return;
- }
-
- Preconditions.checkArgument(userId >= 0);
-
- synchronized (mLock) {
- mEnabled.remove(userId);
- mLastLocation.remove(userId);
- mLastCoarseLocation.remove(userId);
- }
- }
-
- public boolean isEnabled(int userId) {
- if (userId == UserHandle.USER_NULL) {
- // used during initialization - ignore since many lower level operations (checking
- // settings for instance) do not support the null user
- return false;
- }
-
- Preconditions.checkArgument(userId >= 0);
-
- synchronized (mLock) {
- Boolean enabled = mEnabled.get(userId);
- if (enabled == null) {
- // this generally shouldn't occur, but might be possible due to race conditions
- // on when we are notified of new users
- Log.w(TAG, mName + " provider saw user " + userId + " unexpectedly");
- onEnabledChangedLocked(userId);
- enabled = Objects.requireNonNull(mEnabled.get(userId));
- }
-
- return enabled;
- }
- }
-
- @GuardedBy("mLock")
- public void onEnabledChangedLocked(int userId) {
- if (userId == UserHandle.USER_NULL) {
- // used during initialization - ignore since many lower level operations (checking
- // settings for instance) do not support the null user
- return;
- } else if (userId == UserHandle.USER_ALL) {
- for (int runningUserId : mUserInfoHelper.getRunningUserIds()) {
- onEnabledChangedLocked(runningUserId);
- }
- return;
- }
-
- Preconditions.checkArgument(userId >= 0);
-
- // if any property that contributes to "enabled" here changes state, it MUST result
- // in a direct or indrect call to onEnabledChangedLocked. this allows the provider to
- // guarantee that it will always eventually reach the correct state.
- boolean enabled = mProvider.getState().allowed
- && mUserInfoHelper.isCurrentUserId(userId)
- && mSettingsHelper.isLocationEnabled(userId);
-
- Boolean wasEnabled = mEnabled.get(userId);
- if (wasEnabled != null && wasEnabled == enabled) {
- return;
- }
-
- mEnabled.put(userId, enabled);
-
- if (D) {
- Log.d(TAG, "[u" + userId + "] " + mName + " provider enabled = " + enabled);
- }
-
- // clear last locations if we become disabled and if not servicing a bypass request
- if (!enabled && !mProvider.getCurrentRequest().locationSettingsIgnored) {
- mLastLocation.put(userId, null);
- mLastCoarseLocation.put(userId, null);
- }
-
- // do not send change notifications if we just saw this user for the first time
- if (wasEnabled != null) {
- // fused and passive provider never get public updates for legacy reasons
- if (!FUSED_PROVIDER.equals(mName) && !PASSIVE_PROVIDER.equals(mName)) {
- Intent intent = new Intent(PROVIDERS_CHANGED_ACTION)
- .putExtra(EXTRA_PROVIDER_NAME, mName)
- .putExtra(EXTRA_PROVIDER_ENABLED, enabled)
- .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
- .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
- }
- }
-
- updateProviderEnabledLocked(this, enabled);
- }
-
- public void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
- synchronized (mLock) {
- pw.print(mName + " provider");
- if (mProvider.isMock()) {
- pw.print(" [mock]");
- }
- pw.println(":");
-
- pw.increaseIndent();
-
- int[] userIds = mUserInfoHelper.getRunningUserIds();
- for (int userId : userIds) {
- if (userIds.length != 1) {
- pw.println("user " + userId + ":");
- pw.increaseIndent();
- }
- pw.println("last location=" + mLastLocation.get(userId));
- pw.println("last coarse location=" + mLastCoarseLocation.get(userId));
- pw.println("enabled=" + isEnabled(userId));
- if (userIds.length != 1) {
- pw.decreaseIndent();
- }
- }
- }
-
- mProvider.dump(fd, pw, args);
-
- pw.decreaseIndent();
- }
- }
-
- class PassiveLocationProviderManager extends LocationProviderManager {
-
- private PassiveLocationProviderManager() {
- super(PASSIVE_PROVIDER);
- }
-
- @Override
- public void setRealProvider(AbstractLocationProvider provider) {
- Preconditions.checkArgument(provider instanceof PassiveProvider);
- super.setRealProvider(provider);
- }
-
- @Override
- public void setMockProvider(@Nullable MockProvider provider) {
- if (provider != null) {
- throw new IllegalArgumentException("Cannot mock the passive provider");
- }
- }
-
- public void updateLocation(Location location) {
- synchronized (mLock) {
- PassiveProvider passiveProvider = (PassiveProvider) mProvider.getProvider();
- Preconditions.checkState(passiveProvider != null);
-
- long identity = Binder.clearCallingIdentity();
- try {
- passiveProvider.updateLocation(location);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- }
- }
-
- /**
- * A wrapper class holding either an ILocationListener or a PendingIntent to receive
- * location updates.
- */
- private final class Receiver extends LocationManagerServiceUtils.LinkedListenerBase implements
- PendingIntent.OnFinished {
- private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
-
- private final ILocationListener mListener;
- final PendingIntent mPendingIntent;
- final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
- private final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
- private final Object mKey;
-
- final HashMap<String, UpdateRecord> mUpdateRecords = new HashMap<>();
-
- // True if app ops has started monitoring this receiver for locations.
- private boolean mOpMonitoring;
- // True if app ops has started monitoring this receiver for high power (gps) locations.
- private boolean mOpHighPowerMonitoring;
- private int mPendingBroadcasts;
- PowerManager.WakeLock mWakeLock;
-
- private Receiver(ILocationListener listener, PendingIntent intent, CallerIdentity identity,
- WorkSource workSource, boolean hideFromAppOps) {
- super(identity);
- mListener = listener;
- mPendingIntent = intent;
- if (listener != null) {
- mKey = listener.asBinder();
- } else {
- mKey = intent;
- }
- if (workSource != null && workSource.isEmpty()) {
- workSource = null;
- }
- mWorkSource = workSource;
- mHideFromAppOps = hideFromAppOps;
-
- updateMonitoring(true);
-
- // construct/configure wakelock
- mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
- if (workSource == null) {
- workSource = mCallerIdentity.addToWorkSource(null);
- }
- mWakeLock.setWorkSource(workSource);
-
- // For a non-reference counted wakelock, each acquire will reset the timeout, and we
- // only need to release it once.
- mWakeLock.setReferenceCounted(false);
- }
-
- @Override
- public boolean equals(Object otherObj) {
- return (otherObj instanceof Receiver) && mKey.equals(((Receiver) otherObj).mKey);
- }
-
- @Override
- public int hashCode() {
- return mKey.hashCode();
- }
-
- @Override
- public String toString() {
- StringBuilder s = new StringBuilder();
- s.append("Reciever[");
- s.append(Integer.toHexString(System.identityHashCode(this)));
- if (mListener != null) {
- s.append(" listener");
- } else {
- s.append(" intent");
- }
- for (String p : mUpdateRecords.keySet()) {
- s.append(" ").append(mUpdateRecords.get(p).toString());
- }
- s.append(" monitoring location: ").append(mOpMonitoring);
- s.append("]");
- return s.toString();
- }
-
- /**
- * Update AppOp monitoring for this receiver.
- *
- * @param allow If true receiver is currently active, if false it's been removed.
- */
- public void updateMonitoring(boolean allow) {
- if (mHideFromAppOps) {
- return;
- }
-
- boolean requestingLocation = false;
- boolean requestingHighPowerLocation = false;
- if (allow) {
- // See if receiver has any enabled update records. Also note if any update records
- // are high power (has a high power provider with an interval under a threshold).
- for (UpdateRecord updateRecord : mUpdateRecords.values()) {
- LocationProviderManager manager = getLocationProviderManager(
- updateRecord.mProvider);
- if (manager == null) {
- continue;
- }
- if (!manager.isEnabled(UserHandle.getUserId(mCallerIdentity.getUid()))
- && !isSettingsExempt(updateRecord)) {
- continue;
- }
-
- requestingLocation = true;
- ProviderProperties properties = manager.getProperties();
- if (properties != null
- && properties.mPowerRequirement == Criteria.POWER_HIGH
- && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
- requestingHighPowerLocation = true;
- break;
- }
- }
- }
-
- // First update monitoring of any location request (including high power).
- mOpMonitoring = updateMonitoring(
- requestingLocation,
- mOpMonitoring,
- false);
-
- // Now update monitoring of high power requests only.
- mOpHighPowerMonitoring = updateMonitoring(
- requestingHighPowerLocation,
- mOpHighPowerMonitoring,
- true);
- }
-
- private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
- boolean highPower) {
- if (!currentlyMonitoring) {
- if (allowMonitoring) {
- if (!highPower) {
- return mAppOpsHelper.startOpNoThrow(OP_MONITOR_LOCATION, mCallerIdentity);
- } else {
- return mAppOpsHelper.startOpNoThrow(OP_MONITOR_HIGH_POWER_LOCATION,
- mCallerIdentity);
- }
- }
- } else {
- int permissionLevel = LocationPermissions.getPermissionLevel(mContext,
- mCallerIdentity.getUid(), mCallerIdentity.getPid());
- if (!allowMonitoring || permissionLevel == PERMISSION_NONE
- || !mAppOpsHelper.checkOpNoThrow(
- LocationPermissions.asAppOp(permissionLevel), mCallerIdentity)) {
- if (!highPower) {
- mAppOpsHelper.finishOp(OP_MONITOR_LOCATION, mCallerIdentity);
- } else {
- mAppOpsHelper.finishOp(OP_MONITOR_HIGH_POWER_LOCATION, mCallerIdentity);
- }
- return false;
- }
- }
-
- return currentlyMonitoring;
- }
-
- public boolean isListener() {
- return mListener != null;
- }
-
- public boolean isPendingIntent() {
- return mPendingIntent != null;
- }
-
- public ILocationListener getListener() {
- if (mListener != null) {
- return mListener;
- }
- throw new IllegalStateException("Request for non-existent listener");
- }
-
- public boolean callLocationChangedLocked(Location location,
- LocationRequest locationRequest) {
- if (mListener != null) {
- try {
- mListener.onLocationChanged(new Location(location), new IRemoteCallback.Stub() {
- @Override
- public void sendResult(Bundle data) {
- synchronized (mLock) {
- decrementPendingBroadcastsLocked();
- }
- }
- });
- // call this after broadcasting so we do not increment
- // if we throw an exception.
- incrementPendingBroadcastsLocked();
- } catch (RemoteException e) {
- return false;
- }
- } else {
- Intent locationChanged = new Intent();
- locationChanged.putExtra(KEY_LOCATION_CHANGED, new Location(location));
- try {
- mPendingIntent.send(mContext, 0, locationChanged, this, mHandler,
- LocationPermissions.asPermission(
- locationRequest.isCoarse() ? PERMISSION_COARSE
- : PERMISSION_FINE),
- PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
- // call this after broadcasting so we do not increment
- // if we throw an exception.
- incrementPendingBroadcastsLocked();
- } catch (PendingIntent.CanceledException e) {
- return false;
- }
- }
- return true;
- }
-
- private boolean callProviderEnabledLocked(String provider, boolean enabled,
- LocationRequest locationRequest) {
- // First update AppOp monitoring.
- // An app may get/lose location access as providers are enabled/disabled.
- updateMonitoring(true);
-
- if (mListener != null) {
- try {
- mListener.onProviderEnabledChanged(provider, enabled);
- } catch (RemoteException e) {
- return false;
- }
- } else {
- Intent providerIntent = new Intent();
- providerIntent.putExtra(KEY_PROVIDER_ENABLED, enabled);
- try {
- mPendingIntent.send(mContext, 0, providerIntent, null, mHandler,
- LocationPermissions.asPermission(
- locationRequest.isCoarse() ? PERMISSION_COARSE
- : PERMISSION_FINE),
- PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
- } catch (PendingIntent.CanceledException e) {
- return false;
- }
- }
- return true;
- }
-
- @Override
- public void binderDied() {
- synchronized (mLock) {
- removeUpdatesLocked(this);
- clearPendingBroadcastsLocked();
- }
- }
-
- @Override
- public void onSendFinished(PendingIntent pendingIntent, Intent intent,
- int resultCode, String resultData, Bundle resultExtras) {
- synchronized (mLock) {
- decrementPendingBroadcastsLocked();
- }
- }
-
- // this must be called while synchronized by caller in a synchronized block
- // containing the sending of the broadcaset
- private void incrementPendingBroadcastsLocked() {
- mPendingBroadcasts++;
- // so wakelock calls will succeed
- long identity = Binder.clearCallingIdentity();
- try {
- mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- private void decrementPendingBroadcastsLocked() {
- if (--mPendingBroadcasts == 0) {
- // so wakelock calls will succeed
- long identity = Binder.clearCallingIdentity();
- try {
- if (mWakeLock.isHeld()) {
- mWakeLock.release();
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- }
-
- public void clearPendingBroadcastsLocked() {
- if (mPendingBroadcasts > 0) {
- mPendingBroadcasts = 0;
- // so wakelock calls will succeed
- long identity = Binder.clearCallingIdentity();
- try {
- if (mWakeLock.isHeld()) {
- mWakeLock.release();
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- }
+ Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION)
+ .putExtra(LocationManager.EXTRA_LOCATION_ENABLED, enabled)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
}
@Override
@@ -1459,17 +478,6 @@
}
}
- @Nullable
- LocationProviderManager getLocationProviderManager(String providerName) {
- for (LocationProviderManager manager : mProviderManagers) {
- if (providerName.equals(manager.getName())) {
- return manager;
- }
- }
-
- return null;
- }
-
@Override
public List<String> getAllProviders() {
ArrayList<String> providers = new ArrayList<>(mProviderManagers.size());
@@ -1532,397 +540,16 @@
return null;
}
- @GuardedBy("mLock")
- private void updateProviderEnabledLocked(LocationProviderManager manager, boolean enabled) {
- ArrayList<Receiver> deadReceivers = null;
- ArrayList<UpdateRecord> records = mRecordsByProvider.get(manager.getName());
- if (records != null) {
- for (UpdateRecord record : records) {
- if (!mUserInfoHelper.isCurrentUserId(
- UserHandle.getUserId(record.mReceiver.mCallerIdentity.getUid()))) {
- continue;
- }
-
- // requests that ignore location settings will never provide notifications
- if (isSettingsExempt(record)) {
- continue;
- }
-
- // Sends a notification message to the receiver
- if (!record.mReceiver.callProviderEnabledLocked(manager.getName(), enabled,
- record.mRequest)) {
- if (deadReceivers == null) {
- deadReceivers = new ArrayList<>();
- }
- deadReceivers.add(record.mReceiver);
- }
- }
- }
-
- if (deadReceivers != null) {
- for (int i = deadReceivers.size() - 1; i >= 0; i--) {
- removeUpdatesLocked(deadReceivers.get(i));
- }
- }
-
- applyRequirementsLocked(manager);
- }
-
- @GuardedBy("mLock")
- private void applyRequirementsLocked(String providerName) {
- LocationProviderManager manager = getLocationProviderManager(providerName);
- if (manager != null) {
- applyRequirementsLocked(manager);
- }
- }
-
- @GuardedBy("mLock")
- private void applyRequirementsLocked(LocationProviderManager manager) {
- ArrayList<UpdateRecord> records = mRecordsByProvider.get(manager.getName());
- ProviderRequest.Builder providerRequest = new ProviderRequest.Builder();
-
- // if provider is not active, it should not respond to requests
-
- if (mProviderManagers.contains(manager) && records != null && !records.isEmpty()) {
- long backgroundThrottleInterval = mSettingsHelper.getBackgroundThrottleIntervalMs();
-
- ArrayList<LocationRequest> requests = new ArrayList<>(records.size());
-
- final boolean isForegroundOnlyMode =
- mBatterySaverMode == PowerManager.LOCATION_MODE_FOREGROUND_ONLY;
- final boolean shouldThrottleRequests =
- mBatterySaverMode
- == PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF
- && !mPowerManager.isInteractive();
- // initialize the low power mode to true and set to false if any of the records requires
- providerRequest.setLowPowerMode(true);
- for (UpdateRecord record : records) {
- CallerIdentity identity = record.mReceiver.mCallerIdentity;
- if (!mUserInfoHelper.isCurrentUserId(identity.getUserId())) {
- continue;
- }
-
- if (!mAppOpsHelper.checkOpNoThrow(LocationPermissions.asAppOp(
- record.mRequest.isCoarse() ? PERMISSION_COARSE : PERMISSION_FINE),
- identity)) {
- continue;
- }
- final boolean isBatterySaverDisablingLocation = shouldThrottleRequests
- || (isForegroundOnlyMode && !record.mIsForegroundUid);
- if (!manager.isEnabled(identity.getUserId()) || isBatterySaverDisablingLocation) {
- if (isSettingsExempt(record)) {
- providerRequest.setLocationSettingsIgnored(true);
- providerRequest.setLowPowerMode(false);
- } else {
- continue;
- }
- }
-
- LocationRequest locationRequest = record.mRealRequest;
- long interval = locationRequest.getInterval();
-
-
- // if we're forcing location, don't apply any throttling
- if (!providerRequest.isLocationSettingsIgnored() && !isThrottlingExempt(
- record.mReceiver.mCallerIdentity)) {
- if (!record.mIsForegroundUid) {
- interval = Math.max(interval, backgroundThrottleInterval);
- }
- if (interval != locationRequest.getInterval()) {
- locationRequest = new LocationRequest(locationRequest);
- locationRequest.setInterval(interval);
- }
- }
-
- record.mRequest = locationRequest;
- requests.add(locationRequest);
- if (!locationRequest.isLowPowerMode()) {
- providerRequest.setLowPowerMode(false);
- }
- if (interval < providerRequest.getInterval()) {
- providerRequest.setInterval(interval);
- }
- }
-
- providerRequest.setLocationRequests(requests);
-
- if (providerRequest.getInterval() < Long.MAX_VALUE) {
- // calculate who to blame for power
- // This is somewhat arbitrary. We pick a threshold interval
- // that is slightly higher that the minimum interval, and
- // spread the blame across all applications with a request
- // under that threshold.
- // TODO: overflow
- long thresholdInterval = (providerRequest.getInterval() + 1000) * 3 / 2;
- for (UpdateRecord record : records) {
- if (mUserInfoHelper.isCurrentUserId(
- UserHandle.getUserId(record.mReceiver.mCallerIdentity.getUid()))) {
- LocationRequest locationRequest = record.mRequest;
-
- // Don't assign battery blame for update records whose
- // client has no permission to receive location data.
- if (!providerRequest.getLocationRequests().contains(locationRequest)) {
- continue;
- }
-
- if (locationRequest.getInterval() <= thresholdInterval) {
- if (record.mReceiver.mWorkSource != null
- && isValidWorkSource(record.mReceiver.mWorkSource)) {
- providerRequest.getWorkSource().add(record.mReceiver.mWorkSource);
- } else {
- // Assign blame to caller if there's no WorkSource associated with
- // the request or if it's invalid.
- providerRequest.getWorkSource().add(
- record.mReceiver.mCallerIdentity.getUid(),
- record.mReceiver.mCallerIdentity.getPackageName());
- }
- }
- }
- }
- }
- }
-
- manager.setRequest(providerRequest.build());
- }
-
- /**
- * Whether a given {@code WorkSource} associated with a Location request is valid.
- */
- private static boolean isValidWorkSource(WorkSource workSource) {
- if (workSource.size() > 0) {
- // If the WorkSource has one or more non-chained UIDs, make sure they're accompanied
- // by tags.
- return workSource.getPackageName(0) != null;
- } else {
- // For now, make sure callers have supplied an attribution tag for use with
- // AppOpsManager. This might be relaxed in the future.
- final List<WorkChain> workChains = workSource.getWorkChains();
- return workChains != null && !workChains.isEmpty()
- && workChains.get(0).getAttributionTag() != null;
- }
- }
-
@Override
public String[] getBackgroundThrottlingWhitelist() {
- return mSettingsHelper.getBackgroundThrottlePackageWhitelist().toArray(new String[0]);
+ return mInjector.getSettingsHelper().getBackgroundThrottlePackageWhitelist().toArray(
+ new String[0]);
}
@Override
public String[] getIgnoreSettingsWhitelist() {
- return mSettingsHelper.getIgnoreSettingsPackageWhitelist().toArray(new String[0]);
- }
-
- private boolean isThrottlingExempt(CallerIdentity callerIdentity) {
- if (callerIdentity.getUid() == Process.SYSTEM_UID) {
- return true;
- }
-
- if (mSettingsHelper.getBackgroundThrottlePackageWhitelist().contains(
- callerIdentity.getPackageName())) {
- return true;
- }
-
- return mLocalService.isProvider(null, callerIdentity);
-
- }
-
- private boolean isSettingsExempt(UpdateRecord record) {
- if (!record.mRealRequest.isLocationSettingsIgnored()) {
- return false;
- }
-
- if (mSettingsHelper.getIgnoreSettingsPackageWhitelist().contains(
- record.mReceiver.mCallerIdentity.getPackageName())) {
- return true;
- }
-
- return mLocalService.isProvider(null, record.mReceiver.mCallerIdentity);
- }
-
- private class UpdateRecord {
- final String mProvider;
- private final LocationRequest mRealRequest; // original request from client
- LocationRequest mRequest; // possibly throttled version of the request
- private final Receiver mReceiver;
- private boolean mIsForegroundUid;
- private Location mLastFixBroadcast;
- private Throwable mStackTrace; // for debugging only
- private long mExpirationRealtimeMs;
-
- /**
- * Note: must be constructed with lock held.
- */
- private UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
- if (Build.IS_DEBUGGABLE) {
- Preconditions.checkState(Thread.holdsLock(mLock));
- }
- mExpirationRealtimeMs = request.getExpirationRealtimeMs(SystemClock.elapsedRealtime());
- mProvider = provider;
- mRealRequest = request;
- mRequest = request;
- mReceiver = receiver;
- mIsForegroundUid = mAppForegroundHelper.isAppForeground(
- mReceiver.mCallerIdentity.getUid());
-
- if (D && receiver.mCallerIdentity.getPid() == Process.myPid()) {
- mStackTrace = new Throwable();
- }
-
- ArrayList<UpdateRecord> records = mRecordsByProvider.computeIfAbsent(provider,
- k -> new ArrayList<>());
- if (!records.contains(this)) {
- records.add(this);
- }
-
- // Update statistics for historical location requests by package/provider
- mRequestStatistics.startRequesting(
- mReceiver.mCallerIdentity.getPackageName(),
- mReceiver.mCallerIdentity.getAttributionTag(),
- provider, request.getInterval(), mIsForegroundUid);
- }
-
- /**
- * Method to be called when record changes foreground/background
- */
- private void updateForeground(boolean isForeground) {
- mIsForegroundUid = isForeground;
- mRequestStatistics.updateForeground(
- mReceiver.mCallerIdentity.getPackageName(),
- mReceiver.mCallerIdentity.getAttributionTag(),
- mProvider, isForeground);
- }
-
- /**
- * Method to be called when a record will no longer be used.
- */
- private void disposeLocked(boolean removeReceiver) {
- if (Build.IS_DEBUGGABLE) {
- Preconditions.checkState(Thread.holdsLock(mLock));
- }
-
- CallerIdentity identity = mReceiver.mCallerIdentity;
- mRequestStatistics.stopRequesting(identity.getPackageName(),
- identity.getAttributionTag(),
- mProvider);
-
- mLocationUsageLogger.logLocationApiUsage(
- LocationStatsEnums.USAGE_ENDED,
- LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
- identity.getPackageName(),
- mRealRequest,
- mReceiver.isListener(),
- mReceiver.isPendingIntent(),
- /* geofence= */ null,
- mAppForegroundHelper.isAppForeground(mReceiver.mCallerIdentity.getUid()));
-
- // remove from mRecordsByProvider
- ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
- if (globalRecords != null) {
- globalRecords.remove(this);
- }
-
- if (!removeReceiver) return; // the caller will handle the rest
-
- // remove from Receiver#mUpdateRecords
- HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
- receiverRecords.remove(this.mProvider);
-
- // and also remove the Receiver if it has no more update records
- if (receiverRecords.size() == 0) {
- removeUpdatesLocked(mReceiver);
- }
- }
-
- @Override
- public String toString() {
- StringBuilder b = new StringBuilder("UpdateRecord[");
- b.append(mProvider).append(" ");
- b.append(mReceiver.mCallerIdentity).append(" ");
- if (!mIsForegroundUid) {
- b.append("(background) ");
- }
- b.append(mRealRequest).append(" ").append(mReceiver.mWorkSource);
-
- if (mStackTrace != null) {
- ByteArrayOutputStream tmp = new ByteArrayOutputStream();
- mStackTrace.printStackTrace(new PrintStream(tmp));
- b.append("\n\n").append(tmp.toString()).append("\n");
- }
-
- b.append("]");
- return b.toString();
- }
- }
-
- @GuardedBy("mLock")
- private Receiver getReceiverLocked(ILocationListener listener, CallerIdentity identity,
- WorkSource workSource, boolean hideFromAppOps) {
- IBinder binder = listener.asBinder();
- Receiver receiver = mReceivers.get(binder);
- if (receiver == null && identity != null) {
- receiver = new Receiver(listener, null, identity, workSource,
- hideFromAppOps);
- if (!receiver.linkToListenerDeathNotificationLocked(
- receiver.getListener().asBinder())) {
- return null;
- }
- mReceivers.put(binder, receiver);
- }
- return receiver;
- }
-
- @GuardedBy("mLock")
- private Receiver getReceiverLocked(PendingIntent intent, CallerIdentity identity,
- WorkSource workSource, boolean hideFromAppOps) {
- Receiver receiver = mReceivers.get(intent);
- if (receiver == null && identity != null) {
- receiver = new Receiver(null, intent, identity, workSource,
- hideFromAppOps);
- mReceivers.put(intent, receiver);
- }
- return receiver;
- }
-
- /**
- * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
- * and consistency requirements.
- *
- * @param request the LocationRequest from which to create a sanitized version
- * @return a version of request that meets the given resolution and consistency requirements
- * @hide
- */
- private LocationRequest createSanitizedRequest(LocationRequest request,
- boolean callerHasLocationHardwarePermission, int permissionLevel) {
- LocationRequest sanitizedRequest = new LocationRequest(request);
- if (!callerHasLocationHardwarePermission) {
- // allow setting low power mode only for callers with location hardware permission
- sanitizedRequest.setLowPowerMode(false);
- }
- if (permissionLevel < PERMISSION_FINE) {
- sanitizedRequest.setCoarse(true);
- switch (sanitizedRequest.getQuality()) {
- case LocationRequest.ACCURACY_FINE:
- sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
- break;
- case LocationRequest.POWER_HIGH:
- sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
- break;
- }
- // throttle
- if (sanitizedRequest.getInterval() < FASTEST_COARSE_INTERVAL_MS) {
- sanitizedRequest.setInterval(FASTEST_COARSE_INTERVAL_MS);
- }
- if (sanitizedRequest.getFastestInterval() < FASTEST_COARSE_INTERVAL_MS) {
- sanitizedRequest.setFastestInterval(FASTEST_COARSE_INTERVAL_MS);
- }
- } else {
- sanitizedRequest.setCoarse(false);
- }
- // make getFastestInterval() the minimum of interval and fastest interval
- if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
- sanitizedRequest.setFastestInterval(request.getInterval());
- }
- return sanitizedRequest;
+ return mInjector.getSettingsHelper().getIgnoreSettingsPackageWhitelist().toArray(
+ new String[0]);
}
@Override
@@ -1930,45 +557,24 @@
String packageName, String attributionTag, String listenerId) {
CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
listenerId);
- int permissionLevel = LocationPermissions.getCallingOrSelfPermissionLevel(mContext);
- LocationPermissions.enforceLocationPermission(Binder.getCallingUid(), permissionLevel,
+ int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
+ identity.getPid());
+ LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
PERMISSION_COARSE);
- WorkSource workSource = request.getWorkSource();
- if (workSource != null && !workSource.isEmpty()) {
- mContext.enforceCallingOrSelfPermission(
- permission.UPDATE_DEVICE_STATS, null);
+ // clients in the system process should have an attribution tag set
+ if (identity.getPid() == Process.myPid() && attributionTag == null) {
+ Log.w(TAG, "system location request with no attribution tag",
+ new IllegalArgumentException());
}
- boolean hideFromAppOps = request.getHideFromAppOps();
- if (hideFromAppOps) {
- mContext.enforceCallingOrSelfPermission(
- permission.UPDATE_APP_OPS_STATS, null);
- }
- if (request.isLocationSettingsIgnored()) {
- mContext.enforceCallingOrSelfPermission(
- permission.WRITE_SECURE_SETTINGS, null);
- }
- boolean callerHasLocationHardwarePermission =
- mContext.checkCallingPermission(permission.LOCATION_HARDWARE)
- == PERMISSION_GRANTED;
- LocationRequest sanitizedRequest = createSanitizedRequest(request,
- callerHasLocationHardwarePermission,
- permissionLevel);
- mLocationUsageLogger.logLocationApiUsage(
- LocationStatsEnums.USAGE_STARTED,
- LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
- packageName, request, true, false,
- /* geofence= */ null,
- mAppForegroundHelper.isAppForeground(identity.getUid()));
+ request = validateAndSanitizeLocationRequest(request, permissionLevel);
- synchronized (mLock) {
- Receiver receiver = getReceiverLocked(Objects.requireNonNull(listener), identity,
- workSource, hideFromAppOps);
- if (receiver != null) {
- requestLocationUpdatesLocked(sanitizedRequest, receiver);
- }
- }
+ LocationProviderManager manager = getLocationProviderManager(request.getProvider());
+ Preconditions.checkArgument(manager != null,
+ "provider \"" + request.getProvider() + "\" does not exist");
+
+ manager.registerLocationRequest(request, identity, permissionLevel, listener);
}
@Override
@@ -1976,248 +582,154 @@
String packageName, String attributionTag) {
CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
AppOpsManager.toReceiverId(pendingIntent));
- int permissionLevel = LocationPermissions.getCallingOrSelfPermissionLevel(mContext);
- LocationPermissions.enforceLocationPermission(Binder.getCallingUid(), permissionLevel,
+ int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
+ identity.getPid());
+ LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
PERMISSION_COARSE);
+ // clients in the system process must have an attribution tag set
+ Preconditions.checkArgument(identity.getPid() != Process.myPid() || attributionTag != null);
+
+ request = validateAndSanitizeLocationRequest(request, permissionLevel);
+
+ LocationProviderManager manager = getLocationProviderManager(request.getProvider());
+ Preconditions.checkArgument(manager != null,
+ "provider \"" + request.getProvider() + "\" does not exist");
+
+ manager.registerLocationRequest(request, identity, permissionLevel, pendingIntent);
+ }
+
+ private LocationRequest validateAndSanitizeLocationRequest(LocationRequest request,
+ @PermissionLevel int permissionLevel) {
+ Objects.requireNonNull(request.getProvider());
+
WorkSource workSource = request.getWorkSource();
if (workSource != null && !workSource.isEmpty()) {
mContext.enforceCallingOrSelfPermission(
- permission.UPDATE_DEVICE_STATS, null);
+ permission.UPDATE_DEVICE_STATS,
+ "setting a work source requires " + permission.UPDATE_DEVICE_STATS);
}
- boolean hideFromAppOps = request.getHideFromAppOps();
- if (hideFromAppOps) {
+ if (request.getHideFromAppOps()) {
mContext.enforceCallingOrSelfPermission(
- permission.UPDATE_APP_OPS_STATS, null);
+ permission.UPDATE_APP_OPS_STATS,
+ "hiding from app ops requires " + permission.UPDATE_APP_OPS_STATS);
}
if (request.isLocationSettingsIgnored()) {
mContext.enforceCallingOrSelfPermission(
- permission.WRITE_SECURE_SETTINGS, null);
- }
- boolean callerHasLocationHardwarePermission =
- mContext.checkCallingPermission(permission.LOCATION_HARDWARE)
- == PERMISSION_GRANTED;
- LocationRequest sanitizedRequest = createSanitizedRequest(request,
- callerHasLocationHardwarePermission,
- permissionLevel);
-
- mLocationUsageLogger.logLocationApiUsage(
- LocationStatsEnums.USAGE_STARTED,
- LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
- packageName, request, true, false,
- /* geofence= */ null,
- mAppForegroundHelper.isAppForeground(identity.getUid()));
-
- synchronized (mLock) {
- Receiver receiver = getReceiverLocked(Objects.requireNonNull(pendingIntent), identity,
- workSource, hideFromAppOps);
- if (receiver != null) {
- requestLocationUpdatesLocked(sanitizedRequest, receiver);
- }
- }
- }
-
- @GuardedBy("mLock")
- private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver) {
- String provider = request.getProvider();
-
- LocationProviderManager manager = getLocationProviderManager(provider);
- if (manager == null) {
- throw new IllegalArgumentException("provider doesn't exist: " + provider);
+ permission.WRITE_SECURE_SETTINGS,
+ "ignoring location settings requires " + permission.WRITE_SECURE_SETTINGS);
}
- UpdateRecord record = new UpdateRecord(provider, request, receiver);
-
- UpdateRecord oldRecord = receiver.mUpdateRecords.put(provider, record);
- if (oldRecord != null) {
- oldRecord.disposeLocked(false);
+ LocationRequest sanitized = new LocationRequest(request);
+ if (mContext.checkCallingPermission(permission.LOCATION_HARDWARE) != PERMISSION_GRANTED) {
+ sanitized.setLowPowerMode(false);
}
-
- long identity = Binder.clearCallingIdentity();
- try {
- int userId = UserHandle.getUserId(receiver.mCallerIdentity.getUid());
- if (!manager.isEnabled(userId) && !isSettingsExempt(record)) {
- // Notify the listener that updates are currently disabled - but only if the request
- // does not ignore location settings
- receiver.callProviderEnabledLocked(provider, false, request);
+ if (permissionLevel < PERMISSION_FINE) {
+ switch (sanitized.getQuality()) {
+ case LocationRequest.ACCURACY_FINE:
+ sanitized.setQuality(LocationRequest.ACCURACY_BLOCK);
+ break;
+ case LocationRequest.POWER_HIGH:
+ sanitized.setQuality(LocationRequest.POWER_LOW);
+ break;
}
- applyRequirementsLocked(provider);
-
- // Update the monitoring here just in case multiple location requests were added to the
- // same receiver (this request may be high power and the initial might not have been).
- receiver.updateMonitoring(true);
- } finally {
- Binder.restoreCallingIdentity(identity);
+ if (sanitized.getInterval() < FASTEST_COARSE_INTERVAL_MS) {
+ sanitized.setInterval(FASTEST_COARSE_INTERVAL_MS);
+ }
+ if (sanitized.getFastestInterval() < FASTEST_COARSE_INTERVAL_MS) {
+ sanitized.setFastestInterval(FASTEST_COARSE_INTERVAL_MS);
+ }
}
+ if (sanitized.getFastestInterval() > sanitized.getInterval()) {
+ sanitized.setFastestInterval(request.getInterval());
+ }
+ if (sanitized.getWorkSource() != null) {
+ if (sanitized.getWorkSource().isEmpty()) {
+ sanitized.setWorkSource(null);
+ } else if (sanitized.getWorkSource().getPackageName(0) == null) {
+ Log.w(TAG, "received (and ignoring) illegal worksource with no package name");
+ sanitized.setWorkSource(null);
+ } else {
+ List<WorkChain> workChains = sanitized.getWorkSource().getWorkChains();
+ if (workChains != null && !workChains.isEmpty() && workChains.get(
+ 0).getAttributionTag() == null) {
+ Log.w(TAG,
+ "received (and ignoring) illegal worksource with no attribution tag");
+ sanitized.setWorkSource(null);
+ }
+ }
+ }
+
+ return sanitized;
}
@Override
public void unregisterLocationListener(ILocationListener listener) {
- synchronized (mLock) {
- Receiver receiver = getReceiverLocked(Objects.requireNonNull(listener), null, null,
- false);
- if (receiver != null) {
- removeUpdatesLocked(receiver);
- }
+ for (LocationProviderManager manager : mProviderManagers) {
+ manager.unregisterLocationRequest(listener);
}
}
@Override
public void unregisterLocationPendingIntent(PendingIntent pendingIntent) {
- synchronized (mLock) {
- Receiver receiver = getReceiverLocked(Objects.requireNonNull(pendingIntent), null, null,
- false);
- if (receiver != null) {
- removeUpdatesLocked(receiver);
- }
- }
- }
-
- @GuardedBy("mLock")
- private void removeUpdatesLocked(Receiver receiver) {
- if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
-
- if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
- receiver.unlinkFromListenerDeathNotificationLocked(
- receiver.getListener().asBinder());
- receiver.clearPendingBroadcastsLocked();
- }
-
- receiver.updateMonitoring(false);
-
- // Record which providers were associated with this listener
- HashSet<String> providers = new HashSet<>();
- HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
- if (oldRecords != null) {
- // Call dispose() on the obsolete update records.
- for (UpdateRecord record : oldRecords.values()) {
- // Update statistics for historical location requests by package/provider
- record.disposeLocked(false);
- }
- // Accumulate providers
- providers.addAll(oldRecords.keySet());
- }
-
- // update provider
- for (String provider : providers) {
- applyRequirementsLocked(provider);
+ for (LocationProviderManager manager : mProviderManagers) {
+ manager.unregisterLocationRequest(pendingIntent);
}
}
@Override
public Location getLastLocation(LocationRequest request, String packageName,
String attributionTag) {
- // unsafe is ok because app ops will verify the package name
- CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName, attributionTag);
- int permissionLevel = LocationPermissions.getCallingOrSelfPermissionLevel(mContext);
- LocationPermissions.enforceLocationPermission(Binder.getCallingUid(), permissionLevel,
+ CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag);
+ int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
+ identity.getPid());
+ LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
PERMISSION_COARSE);
- if (mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
- identity.getPackageName())) {
- return null;
- }
- if (!mUserInfoHelper.isCurrentUserId(identity.getUserId())) {
+ // clients in the system process must have an attribution tag set
+ Preconditions.checkArgument(identity.getPid() != Process.myPid() || attributionTag != null);
+
+ request = validateAndSanitizeLocationRequest(request, permissionLevel);
+
+ LocationProviderManager manager = getLocationProviderManager(request.getProvider());
+ if (manager == null) {
return null;
}
- synchronized (mLock) {
- LocationProviderManager manager = getLocationProviderManager(request.getProvider());
- if (manager == null) {
- return null;
- }
- if (!manager.isEnabled(identity.getUserId()) && !request.isLocationSettingsIgnored()) {
- return null;
- }
+ Location location = manager.getLastLocation(request, identity, permissionLevel);
- // appops check should always be right before delivery
- if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
- identity)) {
- return null;
- }
-
- Location location = manager.getLastLocation(identity.getUserId(), permissionLevel);
-
- // make a defensive copy - the client could be in the same process as us
- return location != null ? new Location(location) : null;
+ // lastly - note app ops
+ if (!mInjector.getAppOpsHelper().noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
+ identity)) {
+ return null;
}
+
+ return location;
}
@Override
public void getCurrentLocation(LocationRequest request,
- ICancellationSignal remoteCancellationSignal, ILocationCallback callback,
+ ICancellationSignal cancellationTransport, ILocationCallback consumer,
String packageName, String attributionTag, String listenerId) {
- // unsafe is ok because app ops will verify the package name
- CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName, attributionTag,
+ CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
listenerId);
- int permissionLevel = LocationPermissions.getCallingOrSelfPermissionLevel(mContext);
- LocationPermissions.enforceLocationPermission(Binder.getCallingUid(), permissionLevel,
+ int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
+ identity.getPid());
+ LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
PERMISSION_COARSE);
- request = createSanitizedRequest(request, false, permissionLevel);
- request.setNumUpdates(1);
- if (request.getExpireIn() > GET_CURRENT_LOCATION_MAX_TIMEOUT_MS) {
- request.setExpireIn(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS);
- }
+ // clients in the system process must have an attribution tag set
+ Preconditions.checkState(identity.getPid() != Process.myPid() || attributionTag != null);
- GetCurrentLocationTransport transport = new GetCurrentLocationTransport(callback);
+ request = validateAndSanitizeLocationRequest(request, permissionLevel);
- if (mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
- identity.getPackageName())) {
- transport.deliverResult(null);
- return;
- }
- if (!mUserInfoHelper.isCurrentUserId(identity.getUserId())) {
- transport.deliverResult(null);
- return;
- }
+ LocationProviderManager manager = getLocationProviderManager(request.getProvider());
+ Preconditions.checkArgument(manager != null,
+ "provider \"" + request.getProvider() + "\" does not exist");
- Location lastLocation;
- synchronized (mLock) {
- LocationProviderManager manager = getLocationProviderManager(request.getProvider());
- if (manager == null) {
- transport.deliverResult(null);
- return;
- }
- if (!manager.isEnabled(identity.getUserId()) && !request.isLocationSettingsIgnored()) {
- transport.deliverResult(null);
- return;
- }
-
- lastLocation = manager.getLastLocation(identity.getUserId(), permissionLevel);
- }
-
- if (lastLocation != null) {
- long locationAgeMs = NANOSECONDS.toMillis(
- SystemClock.elapsedRealtimeNanos() - lastLocation.getElapsedRealtimeNanos());
-
- if (locationAgeMs < MAX_CURRENT_LOCATION_AGE_MS) {
- // appops check should always be right before delivery
- if (mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
- identity)) {
- transport.deliverResult(lastLocation);
- } else {
- transport.deliverResult(null);
- }
- return;
- }
-
- if (!mAppForegroundHelper.isAppForeground(Binder.getCallingUid())) {
- if (locationAgeMs < mSettingsHelper.getBackgroundThrottleIntervalMs()) {
- // not allowed to request new locations, so we can't return anything
- transport.deliverResult(null);
- return;
- }
- }
- }
-
- registerLocationListener(request, transport, packageName, attributionTag, listenerId);
- CancellationSignal cancellationSignal = CancellationSignal.fromTransport(
- remoteCancellationSignal);
- if (cancellationSignal != null) {
- cancellationSignal.setOnCancelListener(() -> unregisterLocationListener(transport));
- }
+ manager.getCurrentLocation(request, identity, permissionLevel, cancellationTransport,
+ consumer);
}
@Override
@@ -2228,8 +740,13 @@
return null;
}
- Location location = gpsManager.getLastLocation(UserHandle.getCallingUserId(),
- PERMISSION_FINE);
+ // create a location request that works in almost all circumstances
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(GPS_PROVIDER, 0,
+ 0, true);
+
+ // use our own identity rather than the caller
+ CallerIdentity identity = CallerIdentity.fromContext(mContext);
+ Location location = gpsManager.getLastLocation(request, identity, PERMISSION_FINE);
if (location == null) {
return null;
}
@@ -2248,11 +765,9 @@
Preconditions.checkArgument(location.isComplete());
int userId = UserHandle.getCallingUserId();
- synchronized (mLock) {
- LocationProviderManager manager = getLocationProviderManager(location.getProvider());
- if (manager != null && manager.isEnabled(userId)) {
- manager.injectLastLocation(Objects.requireNonNull(location), userId);
- }
+ LocationProviderManager manager = getLocationProviderManager(location.getProvider());
+ if (manager != null && manager.isEnabled(userId)) {
+ manager.injectLastLocation(Objects.requireNonNull(location), userId);
}
}
@@ -2357,12 +872,11 @@
Objects.requireNonNull(command), extras);
}
- mLocationUsageLogger.logLocationApiUsage(
+ mInjector.getLocationUsageLogger().logLocationApiUsage(
LocationStatsEnums.USAGE_STARTED,
LocationStatsEnums.API_SEND_EXTRA_COMMAND,
provider);
-
- mLocationUsageLogger.logLocationApiUsage(
+ mInjector.getLocationUsageLogger().logLocationApiUsage(
LocationStatsEnums.USAGE_ENDED,
LocationStatsEnums.API_SEND_EXTRA_COMMAND,
provider);
@@ -2385,7 +899,7 @@
if (provider != null && !provider.equals(manager.getName())) {
continue;
}
- CallerIdentity identity = manager.getProviderIdentity();
+ CallerIdentity identity = manager.getIdentity();
if (identity == null) {
continue;
}
@@ -2406,7 +920,7 @@
return Collections.emptyList();
}
- CallerIdentity identity = manager.getProviderIdentity();
+ CallerIdentity identity = manager.getIdentity();
if (identity == null) {
return Collections.emptyList();
}
@@ -2454,164 +968,26 @@
mContext.enforceCallingOrSelfPermission(permission.WRITE_SECURE_SETTINGS, null);
- invalidateLocalLocationEnabledCaches();
- mSettingsHelper.setLocationEnabled(enabled, userId);
+ LocationManager.invalidateLocalLocationEnabledCaches();
+ mInjector.getSettingsHelper().setLocationEnabled(enabled, userId);
}
@Override
public boolean isLocationEnabledForUser(int userId) {
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, false, "isLocationEnabledForUser", null);
- return mSettingsHelper.isLocationEnabled(userId);
+ return mInjector.getSettingsHelper().isLocationEnabled(userId);
}
@Override
public boolean isProviderEnabledForUser(String provider, int userId) {
- // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
+ // fused provider is accessed indirectly via criteria rather than the provider-based APIs,
// so we discourage its use
if (FUSED_PROVIDER.equals(provider)) return false;
return mLocalService.isProviderEnabledForUser(provider, userId);
}
- @GuardedBy("mLock")
- private static boolean shouldBroadcastSafeLocked(
- Location loc, Location lastLoc, UpdateRecord record, long now) {
- // Always broadcast the first update
- if (lastLoc == null) {
- return true;
- }
-
- // Check whether sufficient time has passed
- long minTime = record.mRealRequest.getFastestInterval();
- long deltaMs = NANOSECONDS.toMillis(
- loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos());
- if (deltaMs < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
- return false;
- }
-
- // Check whether sufficient distance has been traveled
- double minDistance = record.mRealRequest.getSmallestDisplacement();
- if (minDistance > 0.0) {
- if (loc.distanceTo(lastLoc) <= minDistance) {
- return false;
- }
- }
-
- // Check whether sufficient number of udpates is left
- if (record.mRealRequest.getNumUpdates() <= 0) {
- return false;
- }
-
- // Check whether the expiry date has passed
- return record.mExpirationRealtimeMs >= now;
- }
-
- @GuardedBy("mLock")
- private void handleLocationChangedLocked(LocationProviderManager manager, Location fineLocation,
- Location coarseLocation) {
- if (!mProviderManagers.contains(manager)) {
- Log.w(TAG, "received location from unknown provider: " + manager.getName());
- return;
- }
-
- // notify passive provider
- if (manager != mPassiveManager) {
- mPassiveManager.updateLocation(fineLocation);
- }
-
- long now = SystemClock.elapsedRealtime();
-
- ArrayList<UpdateRecord> records = mRecordsByProvider.get(manager.getName());
- if (records == null || records.size() == 0) return;
-
- ArrayList<Receiver> deadReceivers = null;
- ArrayList<UpdateRecord> deadUpdateRecords = null;
-
- // Broadcast location to all listeners
- for (UpdateRecord r : records) {
- Receiver receiver = r.mReceiver;
- CallerIdentity identity = receiver.mCallerIdentity;
- boolean receiverDead = false;
-
-
- if (!manager.isEnabled(identity.getUserId()) && !isSettingsExempt(r)) {
- continue;
- }
-
- if (!mUserInfoHelper.isCurrentUserId(identity.getUserId())
- && !mLocalService.isProvider(null, identity)) {
- continue;
- }
-
- if (mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
- identity.getPackageName())) {
- continue;
- }
-
- int permissionLevel = r.mRequest.isCoarse() ? PERMISSION_COARSE : PERMISSION_FINE;
-
- Location location;
- switch (permissionLevel) {
- case PERMISSION_COARSE:
- location = coarseLocation;
- break;
- case PERMISSION_FINE:
- location = fineLocation;
- break;
- default:
- throw new AssertionError();
- }
-
- if (shouldBroadcastSafeLocked(location, r.mLastFixBroadcast, r, now)) {
- r.mLastFixBroadcast = location;
-
- // appops check should always be right before delivery
- if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
- receiver.mCallerIdentity)) {
- continue;
- }
-
- if (!receiver.callLocationChangedLocked(location, r.mRequest)) {
- receiverDead = true;
- }
- r.mRealRequest.decrementNumUpdates();
- }
-
- // track expired records
- if (r.mRealRequest.getNumUpdates() <= 0 || r.mExpirationRealtimeMs < now) {
- if (deadUpdateRecords == null) {
- deadUpdateRecords = new ArrayList<>();
- }
- deadUpdateRecords.add(r);
- }
- // track dead receivers
- if (receiverDead) {
- if (deadReceivers == null) {
- deadReceivers = new ArrayList<>();
- }
- if (!deadReceivers.contains(receiver)) {
- deadReceivers.add(receiver);
- }
- }
- }
-
- // remove dead records and receivers outside the loop
- if (deadReceivers != null) {
- for (Receiver receiver : deadReceivers) {
- removeUpdatesLocked(receiver);
- }
- }
- if (deadUpdateRecords != null) {
- for (UpdateRecord r : deadUpdateRecords) {
- r.disposeLocked(true);
- }
- applyRequirementsLocked(manager);
- }
- }
-
- // Geocoder
-
@Override
public boolean geocoderIsPresent() {
return mGeocodeProvider != null;
@@ -2637,7 +1013,6 @@
double lowerLeftLatitude, double lowerLeftLongitude,
double upperRightLatitude, double upperRightLongitude, int maxResults,
GeocoderParams params, IGeocodeListener listener) {
-
if (mGeocodeProvider != null) {
mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
@@ -2651,35 +1026,24 @@
}
}
- // Mock Providers
-
@Override
public void addTestProvider(String provider, ProviderProperties properties,
String packageName, String attributionTag) {
// unsafe is ok because app ops will verify the package name
- CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName,
- attributionTag);
- if (!mAppOpsHelper.noteOp(OP_MOCK_LOCATION, identity)) {
+ CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName, attributionTag);
+ if (!mInjector.getAppOpsHelper().noteOp(AppOpsManager.OP_MOCK_LOCATION, identity)) {
return;
}
- synchronized (mLock) {
- LocationProviderManager manager = getLocationProviderManager(provider);
- if (manager == null) {
- manager = new LocationProviderManager(provider);
- mProviderManagers.add(manager);
- }
-
- manager.setMockProvider(new MockProvider(properties, identity));
- }
+ getOrAddLocationProviderManager(provider).setMockProvider(
+ new MockProvider(properties, identity));
}
@Override
public void removeTestProvider(String provider, String packageName, String attributionTag) {
// unsafe is ok because app ops will verify the package name
- CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName,
- attributionTag);
- if (!mAppOpsHelper.noteOp(OP_MOCK_LOCATION, identity)) {
+ CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName, attributionTag);
+ if (!mInjector.getAppOpsHelper().noteOp(AppOpsManager.OP_MOCK_LOCATION, identity)) {
return;
}
@@ -2691,7 +1055,7 @@
manager.setMockProvider(null);
if (!manager.hasProvider()) {
- mProviderManagers.remove(manager);
+ removeLocationProviderManager(manager);
}
}
}
@@ -2702,7 +1066,7 @@
// unsafe is ok because app ops will verify the package name
CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName,
attributionTag);
- if (!mAppOpsHelper.noteOp(OP_MOCK_LOCATION, identity)) {
+ if (!mInjector.getAppOpsHelper().noteOp(AppOpsManager.OP_MOCK_LOCATION, identity)) {
return;
}
@@ -2723,7 +1087,7 @@
// unsafe is ok because app ops will verify the package name
CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName,
attributionTag);
- if (!mAppOpsHelper.noteOp(OP_MOCK_LOCATION, identity)) {
+ if (!mInjector.getAppOpsHelper().noteOp(AppOpsManager.OP_MOCK_LOCATION, identity)) {
return;
}
@@ -2777,57 +1141,32 @@
ipw.println("User Info:");
ipw.increaseIndent();
- mUserInfoHelper.dump(fd, ipw, args);
+ mInjector.getUserInfoHelper().dump(fd, ipw, args);
ipw.decreaseIndent();
ipw.println("Location Settings:");
ipw.increaseIndent();
- mSettingsHelper.dump(fd, ipw, args);
+ mInjector.getSettingsHelper().dump(fd, ipw, args);
ipw.decreaseIndent();
+ ipw.println("Historical Records by Provider:");
+ ipw.increaseIndent();
+ TreeMap<PackageProviderKey, PackageStatistics> sorted = new TreeMap<>(
+ mInjector.getLocationRequestStatistics().statistics);
+ for (Map.Entry<PackageProviderKey, PackageStatistics> entry
+ : sorted.entrySet()) {
+ ipw.println(entry.getKey() + ": " + entry.getValue());
+ }
+ ipw.decreaseIndent();
+
+ mInjector.getLocationRequestStatistics().history.dump(ipw);
+
synchronized (mLock) {
- ipw.println("Battery Saver Location Mode: "
- + locationPowerSaveModeToString(mBatterySaverMode));
-
- if (dumpFilter == null) {
- ipw.println("Location Listeners:");
- ipw.increaseIndent();
- for (Receiver receiver : mReceivers.values()) {
- ipw.println(receiver);
- }
- ipw.decreaseIndent();
-
- ipw.println("Active Records by Provider:");
- ipw.increaseIndent();
- for (Map.Entry<String, ArrayList<UpdateRecord>> entry :
- mRecordsByProvider.entrySet()) {
- ipw.println(entry.getKey() + ":");
- ipw.increaseIndent();
- for (UpdateRecord record : entry.getValue()) {
- ipw.println(record);
- }
- ipw.decreaseIndent();
- }
- ipw.decreaseIndent();
-
- ipw.println("Historical Records by Provider:");
- ipw.increaseIndent();
- TreeMap<PackageProviderKey, PackageStatistics> sorted = new TreeMap<>(
- mRequestStatistics.statistics);
- for (Map.Entry<PackageProviderKey, PackageStatistics> entry
- : sorted.entrySet()) {
- ipw.println(entry.getKey() + ": " + entry.getValue());
- }
- ipw.decreaseIndent();
-
- mRequestStatistics.history.dump(ipw);
-
- if (mExtraLocationControllerPackage != null) {
- ipw.println(
- "Location Controller Extra Package: " + mExtraLocationControllerPackage
- + (mExtraLocationControllerPackageEnabled ? " [enabled]"
- : "[disabled]"));
- }
+ if (mExtraLocationControllerPackage != null) {
+ ipw.println(
+ "Location Controller Extra Package: " + mExtraLocationControllerPackage
+ + (mExtraLocationControllerPackageEnabled ? " [enabled]"
+ : "[disabled]"));
}
}
@@ -2857,47 +1196,6 @@
}
}
- private class GetCurrentLocationTransport extends ILocationListener.Stub {
-
- private final Executor mExecutor;
- private final ILocationCallback mCallback;
-
- GetCurrentLocationTransport(ILocationCallback callback) {
- mExecutor = FgThread.getExecutor();
- mCallback = callback;
- }
-
- @Override
- public void onLocationChanged(Location location, IRemoteCallback onCompleteCallback) {
- mExecutor.execute(() -> {
- deliverResult(location);
- try {
- onCompleteCallback.sendResult(null);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- });
- unregisterLocationListener(this);
- }
-
- @Override
- public void onProviderEnabledChanged(String provider, boolean enabled)
- throws RemoteException {
- if (!enabled) {
- deliverResult(null);
- unregisterLocationListener(this);
- }
- }
-
- public void deliverResult(@Nullable Location location) {
- try {
- mCallback.onLocation(location);
- } catch (RemoteException e) {
- // do nothing
- }
- }
- }
-
private class LocalService extends LocationManagerInternal {
LocalService() {}
@@ -2916,17 +1214,28 @@
}
@Override
- public boolean isProvider(String provider, CallerIdentity identity) {
- for (LocationProviderManager manager : mProviderManagers) {
- if (provider != null && !provider.equals(manager.getName())) {
- continue;
- }
- if (identity.equals(manager.getProviderIdentity())) {
- return true;
- }
- }
+ public void addProviderEnabledListener(String provider, ProviderEnabledListener listener) {
+ LocationProviderManager manager = Objects.requireNonNull(
+ getLocationProviderManager(provider));
+ manager.addEnabledListener(listener);
+ }
- return false;
+ @Override
+ public void removeProviderEnabledListener(String provider,
+ ProviderEnabledListener listener) {
+ LocationProviderManager manager = Objects.requireNonNull(
+ getLocationProviderManager(provider));
+ manager.removeEnabledListener(listener);
+ }
+
+ @Override
+ public boolean isProvider(String provider, CallerIdentity identity) {
+ LocationProviderManager manager = getLocationProviderManager(provider);
+ if (manager == null) {
+ return false;
+ } else {
+ return identity.equals(manager.getIdentity());
+ }
}
@Override
@@ -2935,6 +1244,13 @@
mGnssManagerService.sendNiResponse(notifId, userResponse);
}
}
+
+ @Override
+ public void reportGnssBatchLocations(List<Location> locations) {
+ if (mGnssManagerService != null) {
+ mGnssManagerService.onReportLocation(locations);
+ }
+ }
}
private static class SystemInjector implements Injector {
diff --git a/services/core/java/com/android/server/location/LocationManagerServiceUtils.java b/services/core/java/com/android/server/location/LocationManagerServiceUtils.java
deleted file mode 100644
index b9d86c8..0000000
--- a/services/core/java/com/android/server/location/LocationManagerServiceUtils.java
+++ /dev/null
@@ -1,73 +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.server.location;
-
-import android.annotation.NonNull;
-import android.location.util.identity.CallerIdentity;
-import android.os.IBinder;
-import android.os.RemoteException;
-
-import java.util.NoSuchElementException;
-
-/**
- * Shared utilities for LocationManagerService and GnssManager.
- */
-public class LocationManagerServiceUtils {
-
- /**
- * Skeleton class of listener that can be linked to a binder.
- */
- public abstract static class LinkedListenerBase implements IBinder.DeathRecipient {
- protected final CallerIdentity mCallerIdentity;
-
- LinkedListenerBase(@NonNull CallerIdentity callerIdentity) {
- mCallerIdentity = callerIdentity;
- }
-
- @Override
- public String toString() {
- return mCallerIdentity.toString();
- }
-
- public CallerIdentity getCallerIdentity() {
- return mCallerIdentity;
- }
-
- /**
- * Link listener (i.e. callback) to a binder, so that it will be called upon binder's death.
- */
- public boolean linkToListenerDeathNotificationLocked(IBinder binder) {
- try {
- binder.linkToDeath(this, 0 /* flags */);
- return true;
- } catch (RemoteException e) {
- return false;
- }
- }
-
- /**
- * Unlink death listener (i.e. callback) from binder.
- */
- public void unlinkFromListenerDeathNotificationLocked(IBinder binder) {
- try {
- binder.unlinkToDeath(this, 0 /* flags */);
- } catch (NoSuchElementException e) {
- // ignore
- }
- }
- }
-}
diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java
new file mode 100644
index 0000000..d4f8c7e
--- /dev/null
+++ b/services/core/java/com/android/server/location/LocationProviderManager.java
@@ -0,0 +1,1951 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
+import static android.app.AlarmManager.WINDOW_EXACT;
+import static android.location.LocationManager.FUSED_PROVIDER;
+import static android.location.LocationManager.GPS_PROVIDER;
+import static android.location.LocationManager.KEY_LOCATION_CHANGED;
+import static android.location.LocationManager.KEY_PROVIDER_ENABLED;
+import static android.location.LocationManager.PASSIVE_PROVIDER;
+import static android.os.IPowerManager.LOCATION_MODE_NO_CHANGE;
+import static android.os.PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF;
+import static android.os.PowerManager.LOCATION_MODE_FOREGROUND_ONLY;
+import static android.os.PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF;
+import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
+
+import static com.android.server.location.LocationManagerService.D;
+import static com.android.server.location.LocationManagerService.TAG;
+import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
+import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
+import static com.android.server.location.LocationPermissions.PERMISSION_NONE;
+
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import android.annotation.Nullable;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.location.Criteria;
+import android.location.ILocationCallback;
+import android.location.ILocationListener;
+import android.location.Location;
+import android.location.LocationManager;
+import android.location.LocationManagerInternal;
+import android.location.LocationManagerInternal.ProviderEnabledListener;
+import android.location.LocationRequest;
+import android.location.util.identity.CallerIdentity;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.IBinder;
+import android.os.ICancellationSignal;
+import android.os.IRemoteCallback;
+import android.os.PowerManager;
+import android.os.PowerManager.LocationPowerSaveMode;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.WorkSource;
+import android.stats.location.LocationStatsEnums;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.EventLog;
+import android.util.IndentingPrintWriter;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.TimeUtils;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.location.ProviderProperties;
+import com.android.internal.location.ProviderRequest;
+import com.android.internal.util.Preconditions;
+import com.android.server.FgThread;
+import com.android.server.LocalServices;
+import com.android.server.PendingIntentUtils;
+import com.android.server.location.LocationPermissions.PermissionLevel;
+import com.android.server.location.listeners.ListenerMultiplexer;
+import com.android.server.location.listeners.RemovableListenerRegistration;
+import com.android.server.location.util.AppForegroundHelper;
+import com.android.server.location.util.AppForegroundHelper.AppForegroundListener;
+import com.android.server.location.util.AppOpsHelper;
+import com.android.server.location.util.Injector;
+import com.android.server.location.util.LocationAttributionHelper;
+import com.android.server.location.util.LocationPermissionsHelper;
+import com.android.server.location.util.LocationPermissionsHelper.LocationPermissionsListener;
+import com.android.server.location.util.LocationPowerSaveModeHelper;
+import com.android.server.location.util.LocationPowerSaveModeHelper.LocationPowerSaveModeChangedListener;
+import com.android.server.location.util.LocationUsageLogger;
+import com.android.server.location.util.ScreenInteractiveHelper;
+import com.android.server.location.util.ScreenInteractiveHelper.ScreenInteractiveChangedListener;
+import com.android.server.location.util.SettingsHelper;
+import com.android.server.location.util.SettingsHelper.GlobalSettingChangedListener;
+import com.android.server.location.util.SettingsHelper.UserSettingChangedListener;
+import com.android.server.location.util.UserInfoHelper;
+import com.android.server.location.util.UserInfoHelper.UserListener;
+
+import java.io.FileDescriptor;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+
+class LocationProviderManager extends
+ ListenerMultiplexer<Object, LocationRequest, LocationProviderManager.LocationTransport,
+ LocationProviderManager.Registration, ProviderRequest> implements
+ AbstractLocationProvider.Listener {
+
+ // fastest interval at which clients may receive coarse locations
+ public static final long FASTEST_COARSE_INTERVAL_MS = 10 * 60 * 1000;
+
+ private static final String WAKELOCK_TAG = "*location*";
+ private static final long WAKELOCK_TIMEOUT_MS = 30 * 1000;
+
+ // maximum interval to be considered "high power" request
+ private static final long MAX_HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
+
+ // maximum age of a location before it is no longer considered "current"
+ private static final long MAX_CURRENT_LOCATION_AGE_MS = 10 * 1000;
+
+ // max timeout allowed for getting the current location
+ private static final long GET_CURRENT_LOCATION_MAX_TIMEOUT_MS = 30 * 1000;
+
+ // maximum jitter allowed for fastest interval evaluation
+ private static final int MAX_FASTEST_INTERVAL_JITTER_MS = 100;
+
+ protected interface LocationTransport {
+
+ void deliverOnLocationChanged(Location location, @Nullable Runnable onCompleteCallback)
+ throws Exception;
+ }
+
+ protected interface ProviderTransport {
+
+ void deliverOnProviderEnabledChanged(String provider, boolean enabled) throws Exception;
+ }
+
+ protected static final class LocationListenerTransport implements LocationTransport,
+ ProviderTransport {
+
+ private final ILocationListener mListener;
+
+ protected LocationListenerTransport(ILocationListener listener) {
+ mListener = Objects.requireNonNull(listener);
+ }
+
+ @Override
+ public void deliverOnLocationChanged(Location location,
+ @Nullable Runnable onCompleteCallback)
+ throws RemoteException {
+ mListener.onLocationChanged(location,
+ onCompleteCallback == null ? null : new IRemoteCallback.Stub() {
+ @Override
+ public void sendResult(Bundle data) {
+ onCompleteCallback.run();
+ }
+ });
+ }
+
+ @Override
+ public void deliverOnProviderEnabledChanged(String provider, boolean enabled)
+ throws RemoteException {
+ mListener.onProviderEnabledChanged(provider, enabled);
+ }
+ }
+
+ protected static final class LocationPendingIntentTransport implements LocationTransport,
+ ProviderTransport {
+
+ private final Context mContext;
+ private final PendingIntent mPendingIntent;
+
+ public LocationPendingIntentTransport(Context context, PendingIntent pendingIntent) {
+ mContext = context;
+ mPendingIntent = pendingIntent;
+ }
+
+ @Override
+ public void deliverOnLocationChanged(Location location,
+ @Nullable Runnable onCompleteCallback)
+ throws PendingIntent.CanceledException {
+ mPendingIntent.send(mContext, 0, new Intent().putExtra(KEY_LOCATION_CHANGED, location),
+ onCompleteCallback != null ? (pI, i, rC, rD, rE) -> onCompleteCallback.run()
+ : null, null, null,
+ PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
+ }
+
+ @Override
+ public void deliverOnProviderEnabledChanged(String provider, boolean enabled)
+ throws PendingIntent.CanceledException {
+ mPendingIntent.send(mContext, 0, new Intent().putExtra(KEY_PROVIDER_ENABLED, enabled),
+ null, null, null,
+ PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
+ }
+ }
+
+ protected static final class GetCurrentLocationTransport implements LocationTransport {
+
+ private final ILocationCallback mCallback;
+
+ protected GetCurrentLocationTransport(ILocationCallback callback) {
+ mCallback = Objects.requireNonNull(callback);
+ }
+
+ @Override
+ public void deliverOnLocationChanged(Location location,
+ @Nullable Runnable onCompleteCallback)
+ throws RemoteException {
+ // ILocationCallback doesn't currently support completion callbacks
+ Preconditions.checkState(onCompleteCallback == null);
+ mCallback.onLocation(location);
+ }
+ }
+
+ protected abstract class Registration extends
+ RemovableListenerRegistration<LocationRequest, LocationTransport> {
+
+ @PermissionLevel protected final int mPermissionLevel;
+ private final WorkSource mWorkSource;
+
+ // we cache these values because checking/calculating on the fly is more expensive
+ private boolean mPermitted;
+ private boolean mForeground;
+ @Nullable private LocationRequest mProviderLocationRequest;
+ private boolean mIsUsingHighPower;
+
+ protected Registration(LocationRequest request, CallerIdentity identity,
+ LocationTransport transport, @PermissionLevel int permissionLevel) {
+ super(TAG, Objects.requireNonNull(request), identity, transport);
+
+ Preconditions.checkArgument(permissionLevel > PERMISSION_NONE);
+ mPermissionLevel = permissionLevel;
+
+ if (request.getWorkSource() != null && !request.getWorkSource().isEmpty()) {
+ mWorkSource = request.getWorkSource();
+ } else {
+ mWorkSource = identity.addToWorkSource(null);
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected final void onRemovableListenerRegister() {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ if (D) {
+ Log.d(TAG, mName + " provider added registration from " + getIdentity() + " -> "
+ + getRequest());
+ }
+
+ // initialization order is important as there are ordering dependencies
+ mPermitted = mLocationPermissionsHelper.hasLocationPermissions(mPermissionLevel,
+ getIdentity());
+ mForeground = mAppForegroundHelper.isAppForeground(getIdentity().getUid());
+ mProviderLocationRequest = calculateProviderLocationRequest();
+ mIsUsingHighPower = isUsingHighPower();
+
+ onProviderListenerRegister();
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected final void onRemovableListenerUnregister() {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ onProviderListenerUnregister();
+
+ if (D) {
+ Log.d(TAG, mName + " provider removed registration from " + getIdentity());
+ }
+ }
+
+ /**
+ * Subclasses may override this instead of {@link #onRemovableListenerRegister()}.
+ */
+ @GuardedBy("mLock")
+ protected void onProviderListenerRegister() {}
+
+ /**
+ * Subclasses may override this instead of {@link #onRemovableListenerUnregister()}.
+ */
+ @GuardedBy("mLock")
+ protected void onProviderListenerUnregister() {}
+
+ @Override
+ protected final ListenerOperation<LocationTransport> onActive() {
+ if (!getRequest().getHideFromAppOps()) {
+ mLocationAttributionHelper.reportLocationStart(getIdentity(), getName(), getKey());
+ }
+ onHighPowerUsageChanged();
+ return null;
+ }
+
+ @Override
+ protected final void onInactive() {
+ onHighPowerUsageChanged();
+ if (!getRequest().getHideFromAppOps()) {
+ mLocationAttributionHelper.reportLocationStop(getIdentity(), getName(), getKey());
+ }
+ }
+
+ @Override
+ public final LocationRequest getRequest() {
+ return Objects.requireNonNull(mProviderLocationRequest);
+ }
+
+ public final boolean isForeground() {
+ return mForeground;
+ }
+
+ public final boolean isPermitted() {
+ return mPermitted;
+ }
+
+ @Override
+ protected final LocationProviderManager getOwner() {
+ return LocationProviderManager.this;
+ }
+
+ protected final WorkSource getWorkSource() {
+ return mWorkSource;
+ }
+
+ @GuardedBy("mLock")
+ private void onHighPowerUsageChanged() {
+ boolean isUsingHighPower = isUsingHighPower();
+ if (isUsingHighPower != mIsUsingHighPower) {
+ mIsUsingHighPower = isUsingHighPower;
+
+ if (!getRequest().getHideFromAppOps()) {
+ if (mIsUsingHighPower) {
+ mLocationAttributionHelper.reportHighPowerLocationStart(
+ getIdentity(), getName(), getKey());
+ } else {
+ mLocationAttributionHelper.reportHighPowerLocationStop(
+ getIdentity(), getName(), getKey());
+ }
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
+ private boolean isUsingHighPower() {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ return isActive()
+ && getRequest().getInterval() < MAX_HIGH_POWER_INTERVAL_MS
+ && getProperties().mPowerRequirement == Criteria.POWER_HIGH;
+ }
+
+ @GuardedBy("mLock")
+ final boolean onLocationPermissionsChanged(String packageName) {
+ if (getIdentity().getPackageName().equals(packageName)) {
+ return onLocationPermissionsChanged();
+ }
+
+ return false;
+ }
+
+ @GuardedBy("mLock")
+ final boolean onLocationPermissionsChanged(int uid) {
+ if (getIdentity().getUid() == uid) {
+ return onLocationPermissionsChanged();
+ }
+
+ return false;
+ }
+
+ @GuardedBy("mLock")
+ private boolean onLocationPermissionsChanged() {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ boolean permitted = mLocationPermissionsHelper.hasLocationPermissions(mPermissionLevel,
+ getIdentity());
+ if (permitted != mPermitted) {
+ if (D) {
+ Log.v(TAG, mName + " provider package " + getIdentity().getPackageName()
+ + " permitted = " + permitted);
+ }
+
+ mPermitted = permitted;
+ return true;
+ }
+
+ return false;
+ }
+
+ @GuardedBy("mLock")
+ final boolean onForegroundChanged(int uid, boolean foreground) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ if (getIdentity().getUid() == uid && foreground != mForeground) {
+ if (D) {
+ Log.v(TAG, mName + " provider uid " + uid + " foreground = " + foreground);
+ }
+
+ mForeground = foreground;
+
+ // note that onProviderLocationRequestChanged() is always called
+ return onProviderLocationRequestChanged()
+ || mLocationPowerSaveModeHelper.getLocationPowerSaveMode()
+ == LOCATION_MODE_FOREGROUND_ONLY;
+ }
+
+ return false;
+ }
+
+ @GuardedBy("mLock")
+ final boolean onProviderLocationRequestChanged() {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ LocationRequest newRequest = calculateProviderLocationRequest();
+ if (!mProviderLocationRequest.equals(newRequest)) {
+ LocationRequest oldRequest = mProviderLocationRequest;
+ mProviderLocationRequest = newRequest;
+ onHighPowerUsageChanged();
+ updateService();
+
+ // if location settings ignored has changed then the active state may have changed
+ return oldRequest.isLocationSettingsIgnored()
+ != newRequest.isLocationSettingsIgnored();
+ }
+
+ return false;
+ }
+
+ private LocationRequest calculateProviderLocationRequest() {
+ LocationRequest newRequest = new LocationRequest(super.getRequest());
+
+ if (newRequest.isLocationSettingsIgnored()) {
+ // if we are not currently allowed use location settings ignored, disable it
+ if (!mSettingsHelper.getIgnoreSettingsPackageWhitelist().contains(
+ getIdentity().getPackageName()) && !mLocationManagerInternal.isProvider(
+ null, getIdentity())) {
+ newRequest.setLocationSettingsIgnored(false);
+ }
+ }
+
+ if (!newRequest.isLocationSettingsIgnored() && !isThrottlingExempt()) {
+ // throttle in the background
+ if (!mForeground) {
+ newRequest.setInterval(Math.max(newRequest.getInterval(),
+ mSettingsHelper.getBackgroundThrottleIntervalMs()));
+ }
+ }
+
+ return newRequest;
+ }
+
+ private boolean isThrottlingExempt() {
+ if (mSettingsHelper.getBackgroundThrottlePackageWhitelist().contains(
+ getIdentity().getPackageName())) {
+ return true;
+ }
+
+ return mLocationManagerInternal.isProvider(null, getIdentity());
+ }
+
+ @Nullable
+ abstract ListenerOperation<LocationTransport> acceptLocationChange(Location fineLocation);
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append(getIdentity());
+
+ ArraySet<String> flags = new ArraySet<>(2);
+ if (!isForeground()) {
+ flags.add("bg");
+ }
+ if (!isPermitted()) {
+ flags.add("na");
+ }
+ if (!flags.isEmpty()) {
+ builder.append(" ").append(flags);
+ }
+
+ if (mPermissionLevel == PERMISSION_COARSE) {
+ builder.append(" (COARSE)");
+ }
+
+ builder.append(" ").append(getRequest());
+ return builder.toString();
+ }
+ }
+
+ protected abstract class LocationRegistration extends Registration implements
+ AlarmManager.OnAlarmListener, ProviderEnabledListener {
+
+ private final PowerManager.WakeLock mWakeLock;
+
+ private volatile ProviderTransport mProviderTransport;
+ @Nullable private Location mLastLocation = null;
+ private int mNumLocationsDelivered = 0;
+ private long mExpirationRealtimeMs = Long.MAX_VALUE;
+
+ protected <TTransport extends LocationTransport & ProviderTransport> LocationRegistration(
+ LocationRequest request, CallerIdentity identity, TTransport transport,
+ @PermissionLevel int permissionLevel) {
+ super(request, identity, transport, permissionLevel);
+ mProviderTransport = transport;
+ mWakeLock = Objects.requireNonNull(mContext.getSystemService(PowerManager.class))
+ .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
+ mWakeLock.setReferenceCounted(true);
+ mWakeLock.setWorkSource(getWorkSource());
+ }
+
+ @Override
+ protected void onListenerUnregister() {
+ mProviderTransport = null;
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected final void onProviderListenerRegister() {
+ mExpirationRealtimeMs = getRequest().getExpirationRealtimeMs(
+ SystemClock.elapsedRealtime());
+
+ // add alarm for expiration
+ if (mExpirationRealtimeMs < SystemClock.elapsedRealtime()) {
+ remove();
+ } else if (mExpirationRealtimeMs < Long.MAX_VALUE) {
+ AlarmManager alarmManager = Objects.requireNonNull(
+ mContext.getSystemService(AlarmManager.class));
+ alarmManager.set(ELAPSED_REALTIME_WAKEUP, mExpirationRealtimeMs, WINDOW_EXACT,
+ 0, this, FgThread.getHandler(), getWorkSource());
+ }
+
+ // start listening for provider enabled/disabled events
+ addEnabledListener(this);
+
+ onLocationListenerRegister();
+
+ // if the provider is currently disabled, let the client know immediately
+ int userId = getIdentity().getUserId();
+ if (!isEnabled(userId)) {
+ onProviderEnabledChanged(mName, userId, false);
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected final void onProviderListenerUnregister() {
+ // stop listening for provider enabled/disabled events
+ removeEnabledListener(this);
+
+ // remove alarm for expiration
+ if (mExpirationRealtimeMs < Long.MAX_VALUE) {
+ AlarmManager alarmManager = Objects.requireNonNull(
+ mContext.getSystemService(AlarmManager.class));
+ alarmManager.cancel(this);
+ }
+
+ onLocationListenerUnregister();
+ }
+
+ /**
+ * Subclasses may override this instead of {@link #onRemovableListenerRegister()}.
+ */
+ @GuardedBy("mLock")
+ protected void onLocationListenerRegister() {}
+
+ /**
+ * Subclasses may override this instead of {@link #onRemovableListenerUnregister()}.
+ */
+ @GuardedBy("mLock")
+ protected void onLocationListenerUnregister() {}
+
+ @Override
+ public void onAlarm() {
+ if (D) {
+ Log.d(TAG, "removing " + getIdentity() + " from " + mName
+ + " provider due to expiration at " + TimeUtils.formatRealtime(
+ mExpirationRealtimeMs));
+ }
+
+ synchronized (mLock) {
+ remove();
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Nullable
+ @Override
+ ListenerOperation<LocationTransport> acceptLocationChange(Location fineLocation) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ // check expiration time - alarm is not guaranteed to go off at the right time,
+ // especially for short intervals
+ if (SystemClock.elapsedRealtime() >= mExpirationRealtimeMs) {
+ remove();
+ return null;
+ }
+
+ Location location;
+ switch (mPermissionLevel) {
+ case PERMISSION_FINE:
+ location = fineLocation;
+ break;
+ case PERMISSION_COARSE:
+ location = mLocationFudger.createCoarse(fineLocation);
+ break;
+ default:
+ // shouldn't be possible to have a client added without location permissions
+ throw new AssertionError();
+ }
+
+ if (mLastLocation != null) {
+ // check fastest interval
+ long deltaMs = NANOSECONDS.toMillis(
+ location.getElapsedRealtimeNanos()
+ - mLastLocation.getElapsedRealtimeNanos());
+ if (deltaMs < getRequest().getFastestInterval() - MAX_FASTEST_INTERVAL_JITTER_MS) {
+ return null;
+ }
+
+ // check smallest displacement
+ double smallestDisplacement = getRequest().getSmallestDisplacement();
+ if (smallestDisplacement > 0.0 && location.distanceTo(mLastLocation)
+ <= smallestDisplacement) {
+ return null;
+ }
+ }
+
+ // note app ops
+ if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(mPermissionLevel),
+ getIdentity())) {
+ if (D) {
+ Log.w(TAG, "noteOp denied for " + getIdentity());
+ }
+ return null;
+ }
+
+ // update last location
+ mLastLocation = location;
+
+ return new ListenerOperation<LocationTransport>() {
+ @Override
+ public void onPreExecute() {
+ // don't acquire a wakelock for mock locations to prevent abuse
+ if (!location.isFromMockProvider()) {
+ mWakeLock.acquire(WAKELOCK_TIMEOUT_MS);
+ }
+ }
+
+ @Override
+ public void operate(LocationTransport listener) throws Exception {
+ // if delivering to the same process, make a copy of the location first (since
+ // location is mutable)
+ Location deliveryLocation;
+ if (getIdentity().getPid() == Process.myPid()) {
+ deliveryLocation = new Location(location);
+ } else {
+ deliveryLocation = location;
+ }
+
+ listener.deliverOnLocationChanged(deliveryLocation,
+ location.isFromMockProvider() ? null : mWakeLock::release);
+ }
+
+ @Override
+ public void onPostExecute(boolean success) {
+ if (!success && !location.isFromMockProvider()) {
+ mWakeLock.release();
+ }
+
+ if (success) {
+ // check num updates - if successful then this function will always be run
+ // from the same thread, and no additional synchronization is necessary
+ boolean remove = ++mNumLocationsDelivered >= getRequest().getNumUpdates();
+ if (remove) {
+ if (D) {
+ Log.d(TAG, "removing " + getIdentity() + " from " + mName
+ + " provider due to number of updates");
+ }
+
+ synchronized (mLock) {
+ remove();
+ }
+ }
+ }
+ }
+ };
+ }
+
+ @Override
+ public void onProviderEnabledChanged(String provider, int userId, boolean enabled) {
+ Preconditions.checkState(mName.equals(provider));
+
+ if (userId != getIdentity().getUserId()) {
+ return;
+ }
+
+ // we choose not to hold a wakelock for provider enabled changed events
+ executeSafely(getExecutor(), () -> mProviderTransport,
+ listener -> listener.deliverOnProviderEnabledChanged(mName, enabled));
+ }
+ }
+
+ protected final class LocationListenerRegistration extends LocationRegistration implements
+ IBinder.DeathRecipient {
+
+ protected LocationListenerRegistration(LocationRequest request, CallerIdentity identity,
+ LocationListenerTransport transport, @PermissionLevel int permissionLevel) {
+ super(request, identity, transport, permissionLevel);
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void onLocationListenerRegister() {
+ try {
+ ((IBinder) getKey()).linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ remove();
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void onLocationListenerUnregister() {
+ ((IBinder) getKey()).unlinkToDeath(this, 0);
+ }
+
+ @Override
+ public void binderDied() {
+ try {
+ if (D) {
+ Log.d(TAG, mName + " provider client died: " + getIdentity());
+ }
+
+ synchronized (mLock) {
+ remove();
+ }
+ } catch (RuntimeException e) {
+ // the caller may swallow runtime exceptions, so we rethrow as assertion errors to
+ // ensure the crash is seen
+ throw new AssertionError(e);
+ }
+ }
+ }
+
+ protected final class LocationPendingIntentRegistration extends LocationRegistration implements
+ PendingIntent.CancelListener {
+
+ protected LocationPendingIntentRegistration(LocationRequest request,
+ CallerIdentity identity, LocationPendingIntentTransport transport,
+ @PermissionLevel int permissionLevel) {
+ super(request, identity, transport, permissionLevel);
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void onLocationListenerRegister() {
+ ((PendingIntent) getKey()).registerCancelListener(this);
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void onLocationListenerUnregister() {
+ ((PendingIntent) getKey()).unregisterCancelListener(this);
+ }
+
+ @Override
+ public void onCancelled(PendingIntent intent) {
+ synchronized (mLock) {
+ remove();
+ }
+ }
+ }
+
+ protected final class GetCurrentLocationListenerRegistration extends Registration implements
+ IBinder.DeathRecipient, ProviderEnabledListener, AlarmManager.OnAlarmListener {
+
+ private volatile LocationTransport mTransport;
+
+ private long mExpirationRealtimeMs = Long.MAX_VALUE;
+
+ protected GetCurrentLocationListenerRegistration(LocationRequest request,
+ CallerIdentity identity, LocationTransport transport, int permissionLevel) {
+ super(request, identity, transport, permissionLevel);
+ mTransport = transport;
+ }
+
+ @GuardedBy("mLock")
+ void deliverLocation(@Nullable Location location) {
+ executeSafely(getExecutor(), () -> mTransport, acceptLocationChange(location));
+ }
+
+ @Override
+ protected void onListenerUnregister() {
+ mTransport = null;
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void onProviderListenerRegister() {
+ mExpirationRealtimeMs = getRequest().getExpirationRealtimeMs(
+ SystemClock.elapsedRealtime());
+
+ // add alarm for expiration
+ if (mExpirationRealtimeMs < Long.MAX_VALUE) {
+ AlarmManager alarmManager = Objects.requireNonNull(
+ mContext.getSystemService(AlarmManager.class));
+ alarmManager.set(ELAPSED_REALTIME_WAKEUP, mExpirationRealtimeMs, WINDOW_EXACT,
+ 0, this, FgThread.getHandler(), getWorkSource());
+ }
+
+ try {
+ ((IBinder) getKey()).linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ remove();
+ }
+
+ // start listening for provider enabled/disabled events
+ addEnabledListener(this);
+
+ // if the provider is currently disabled fail immediately
+ int userId = getIdentity().getUserId();
+ if (!getRequest().isLocationSettingsIgnored() && !isEnabled(userId)) {
+ deliverLocation(null);
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void onProviderListenerUnregister() {
+ // stop listening for provider enabled/disabled events
+ removeEnabledListener(this);
+
+ // remove alarm for expiration
+ if (mExpirationRealtimeMs < Long.MAX_VALUE) {
+ AlarmManager alarmManager = Objects.requireNonNull(
+ mContext.getSystemService(AlarmManager.class));
+ alarmManager.cancel(this);
+ }
+
+ ((IBinder) getKey()).unlinkToDeath(this, 0);
+ }
+
+ @Override
+ public void onAlarm() {
+ if (D) {
+ Log.d(TAG, "removing " + getIdentity() + " from " + mName
+ + " provider due to expiration at " + TimeUtils.formatRealtime(
+ mExpirationRealtimeMs));
+ }
+
+ synchronized (mLock) {
+ deliverLocation(null);
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Nullable
+ @Override
+ ListenerOperation<LocationTransport> acceptLocationChange(@Nullable Location fineLocation) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ // lastly - note app ops
+ Location location;
+ if (fineLocation == null) {
+ location = null;
+ } else if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(mPermissionLevel),
+ getIdentity())) {
+ if (D) {
+ Log.w(TAG, "noteOp denied for " + getIdentity());
+ }
+ location = null;
+ } else {
+ switch (mPermissionLevel) {
+ case PERMISSION_FINE:
+ location = fineLocation;
+ break;
+ case PERMISSION_COARSE:
+ location = mLocationFudger.createCoarse(fineLocation);
+ break;
+ default:
+ // shouldn't be possible to have a client added without location permissions
+ throw new AssertionError();
+ }
+ }
+
+ return listener -> {
+ // if delivering to the same process, make a copy of the location first (since
+ // location is mutable)
+ Location deliveryLocation = location;
+ if (getIdentity().getPid() == Process.myPid() && location != null) {
+ deliveryLocation = new Location(location);
+ }
+
+ // we currently don't hold a wakelock for getCurrentLocation deliveries
+ listener.deliverOnLocationChanged(deliveryLocation, null);
+
+ synchronized (mLock) {
+ remove();
+ }
+ };
+ }
+
+ @Override
+ public void onProviderEnabledChanged(String provider, int userId, boolean enabled) {
+ Preconditions.checkState(mName.equals(provider));
+
+ if (userId != getIdentity().getUserId()) {
+ return;
+ }
+
+ // if the provider is disabled we give up on current location immediately
+ if (!getRequest().isLocationSettingsIgnored() && !enabled) {
+ synchronized (mLock) {
+ deliverLocation(null);
+ }
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ try {
+ if (D) {
+ Log.d(TAG, mName + " provider client died: " + getIdentity());
+ }
+
+ synchronized (mLock) {
+ remove();
+ }
+ } catch (RuntimeException e) {
+ // the caller may swallow runtime exceptions, so we rethrow as assertion errors to
+ // ensure the crash is seen
+ throw new AssertionError(e);
+ }
+ }
+ }
+
+ protected final Object mLock = new Object();
+
+ protected final String mName;
+ @Nullable private final PassiveLocationProviderManager mPassiveManager;
+
+ protected final Context mContext;
+
+ @GuardedBy("mLock")
+ private boolean mStarted;
+
+ // maps of user id to value
+ @GuardedBy("mLock")
+ private final SparseBooleanArray mEnabled; // null or not present means unknown
+ @GuardedBy("mLock")
+ private final SparseArray<LastLocation> mLastLocations;
+
+ @GuardedBy("mLock")
+ private final ArrayList<ProviderEnabledListener> mEnabledListeners;
+
+ protected final LocationManagerInternal mLocationManagerInternal;
+ protected final SettingsHelper mSettingsHelper;
+ protected final UserInfoHelper mUserInfoHelper;
+ protected final AppOpsHelper mAppOpsHelper;
+ protected final LocationPermissionsHelper mLocationPermissionsHelper;
+ protected final AppForegroundHelper mAppForegroundHelper;
+ protected final LocationPowerSaveModeHelper mLocationPowerSaveModeHelper;
+ protected final ScreenInteractiveHelper mScreenInteractiveHelper;
+ protected final LocationAttributionHelper mLocationAttributionHelper;
+ protected final LocationUsageLogger mLocationUsageLogger;
+ protected final LocationFudger mLocationFudger;
+ protected final LocationRequestStatistics mLocationRequestStatistics;
+
+ private final UserListener mUserChangedListener = this::onUserChanged;
+ private final UserSettingChangedListener mLocationEnabledChangedListener =
+ this::onLocationEnabledChanged;
+ private final GlobalSettingChangedListener mBackgroundThrottlePackageWhitelistChangedListener =
+ this::onBackgroundThrottlePackageWhitelistChanged;
+ private final UserSettingChangedListener mLocationPackageBlacklistChangedListener =
+ this::onLocationPackageBlacklistChanged;
+ private final LocationPermissionsListener mLocationPermissionsListener =
+ new LocationPermissionsListener() {
+ @Override
+ public void onLocationPermissionsChanged(String packageName) {
+ LocationProviderManager.this.onLocationPermissionsChanged(packageName);
+ }
+
+ @Override
+ public void onLocationPermissionsChanged(int uid) {
+ LocationProviderManager.this.onLocationPermissionsChanged(uid);
+ }
+ };
+ private final AppForegroundListener mAppForegroundChangedListener =
+ this::onAppForegroundChanged;
+ private final GlobalSettingChangedListener mBackgroundThrottleIntervalChangedListener =
+ this::onBackgroundThrottleIntervalChanged;
+ private final GlobalSettingChangedListener mIgnoreSettingsPackageWhitelistChangedListener =
+ this::onIgnoreSettingsWhitelistChanged;
+ private final LocationPowerSaveModeChangedListener mLocationPowerSaveModeChangedListener =
+ this::onLocationPowerSaveModeChanged;
+ private final ScreenInteractiveChangedListener mScreenInteractiveChangedListener =
+ this::onScreenInteractiveChanged;
+
+ // acquiring mLock makes operations on mProvider atomic, but is otherwise unnecessary
+ protected final MockableLocationProvider mProvider;
+
+ LocationProviderManager(Context context, Injector injector, String name,
+ @Nullable PassiveLocationProviderManager passiveManager) {
+ mContext = context;
+ mName = Objects.requireNonNull(name);
+ mPassiveManager = passiveManager;
+ mStarted = false;
+ mEnabled = new SparseBooleanArray(2);
+ mLastLocations = new SparseArray<>(2);
+
+ mEnabledListeners = new ArrayList<>();
+
+ mLocationManagerInternal = Objects.requireNonNull(
+ LocalServices.getService(LocationManagerInternal.class));
+ mSettingsHelper = injector.getSettingsHelper();
+ mUserInfoHelper = injector.getUserInfoHelper();
+ mAppOpsHelper = injector.getAppOpsHelper();
+ mLocationPermissionsHelper = injector.getLocationPermissionsHelper();
+ mAppForegroundHelper = injector.getAppForegroundHelper();
+ mLocationPowerSaveModeHelper = injector.getLocationPowerSaveModeHelper();
+ mScreenInteractiveHelper = injector.getScreenInteractiveHelper();
+ mLocationAttributionHelper = injector.getLocationAttributionHelper();
+ mLocationUsageLogger = injector.getLocationUsageLogger();
+ mLocationRequestStatistics = injector.getLocationRequestStatistics();
+ mLocationFudger = new LocationFudger(mSettingsHelper.getCoarseLocationAccuracyM());
+
+ // initialize last since this lets our reference escape
+ mProvider = new MockableLocationProvider(mLock, this);
+ }
+
+ public void startManager() {
+ synchronized (mLock) {
+ mStarted = true;
+
+ mUserInfoHelper.addListener(mUserChangedListener);
+ mSettingsHelper.addOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
+
+ // initialize enabled state
+ onUserStarted(UserHandle.USER_ALL);
+ }
+ }
+
+ public void stopManager() {
+ synchronized (mLock) {
+ mUserInfoHelper.removeListener(mUserChangedListener);
+ mSettingsHelper.removeOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
+
+ // notify and remove all listeners
+ onUserStopped(UserHandle.USER_ALL);
+ removeRegistrationIf(key -> true);
+ mEnabledListeners.clear();
+
+ mStarted = false;
+ }
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ @Nullable
+ public CallerIdentity getIdentity() {
+ return mProvider.getState().identity;
+ }
+
+ @Nullable
+ public ProviderProperties getProperties() {
+ return mProvider.getState().properties;
+ }
+
+ public boolean hasProvider() {
+ return mProvider.getProvider() != null;
+ }
+
+ public boolean isEnabled(int userId) {
+ if (userId == UserHandle.USER_NULL) {
+ return false;
+ }
+
+ Preconditions.checkArgument(userId >= 0);
+
+ synchronized (mLock) {
+ int index = mEnabled.indexOfKey(userId);
+ if (index < 0) {
+ // this generally shouldn't occur, but might be possible due to race conditions
+ // on when we are notified of new users
+ Log.w(TAG, mName + " provider saw user " + userId + " unexpectedly");
+ onEnabledChanged(userId);
+ index = mEnabled.indexOfKey(userId);
+ }
+
+ return mEnabled.valueAt(index);
+ }
+ }
+
+ public void addEnabledListener(ProviderEnabledListener listener) {
+ synchronized (mLock) {
+ Preconditions.checkState(mStarted);
+ mEnabledListeners.add(listener);
+ }
+ }
+
+ public void removeEnabledListener(ProviderEnabledListener listener) {
+ synchronized (mLock) {
+ Preconditions.checkState(mStarted);
+ mEnabledListeners.remove(listener);
+ }
+ }
+
+ public void setRealProvider(AbstractLocationProvider provider) {
+ synchronized (mLock) {
+ Preconditions.checkState(mStarted);
+ mProvider.setRealProvider(provider);
+ }
+ }
+
+ public void setMockProvider(@Nullable MockProvider provider) {
+ synchronized (mLock) {
+ Preconditions.checkState(mStarted);
+ mProvider.setMockProvider(provider);
+
+ // when removing a mock provider, also clear any mock last locations and reset the
+ // location fudger. the mock provider could have been used to infer the current
+ // location fudger offsets.
+ if (provider == null) {
+ final int lastLocationSize = mLastLocations.size();
+ for (int i = 0; i < lastLocationSize; i++) {
+ mLastLocations.valueAt(i).clearMock();
+ }
+
+ mLocationFudger.resetOffsets();
+ }
+ }
+ }
+
+ public void setMockProviderAllowed(boolean enabled) {
+ synchronized (mLock) {
+ if (!mProvider.isMock()) {
+ throw new IllegalArgumentException(mName + " provider is not a test provider");
+ }
+
+ mProvider.setMockProviderAllowed(enabled);
+ }
+ }
+
+ public void setMockProviderLocation(Location location) {
+ synchronized (mLock) {
+ if (!mProvider.isMock()) {
+ throw new IllegalArgumentException(mName + " provider is not a test provider");
+ }
+
+ String locationProvider = location.getProvider();
+ if (!TextUtils.isEmpty(locationProvider) && !mName.equals(locationProvider)) {
+ // The location has an explicit provider that is different from the mock
+ // provider name. The caller may be trying to fool us via b/33091107.
+ EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
+ mName + "!=" + locationProvider);
+ }
+
+ mProvider.setMockProviderLocation(location);
+ }
+ }
+
+ public List<LocationRequest> getMockProviderRequests() {
+ synchronized (mLock) {
+ if (!mProvider.isMock()) {
+ throw new IllegalArgumentException(mName + " provider is not a test provider");
+ }
+
+ return mProvider.getCurrentRequest().locationRequests;
+ }
+ }
+
+ @Nullable
+ public Location getLastLocation(LocationRequest request, CallerIdentity identity,
+ @PermissionLevel int permissionLevel) {
+ Preconditions.checkArgument(mName.equals(request.getProvider()));
+
+ if (mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
+ identity.getPackageName())) {
+ return null;
+ }
+ if (!mUserInfoHelper.isCurrentUserId(identity.getUserId())) {
+ return null;
+ }
+ if (!request.isLocationSettingsIgnored() && !isEnabled(identity.getUserId())) {
+ return null;
+ }
+
+ Location location = getLastLocation(identity.getUserId(), permissionLevel,
+ request.isLocationSettingsIgnored());
+
+ // we don't note op here because we don't know what the client intends to do with the
+ // location, the client is responsible for noting if necessary
+
+ if (identity.getPid() == Process.myPid() && location != null) {
+ // if delivering to the same process, make a copy of the location first (since
+ // location is mutable)
+ return new Location(location);
+ } else {
+ return location;
+ }
+ }
+
+ @Nullable
+ private Location getLastLocation(int userId, @PermissionLevel int permissionLevel,
+ boolean ignoreLocationSettings) {
+ synchronized (mLock) {
+ LastLocation lastLocation = mLastLocations.get(userId);
+ if (lastLocation == null) {
+ return null;
+ }
+ return lastLocation.get(permissionLevel, ignoreLocationSettings);
+ }
+ }
+
+ public void injectLastLocation(Location location, int userId) {
+ synchronized (mLock) {
+ if (getLastLocation(userId, PERMISSION_FINE, false) == null) {
+ setLastLocation(location, userId);
+ }
+ }
+ }
+
+ private void setLastLocation(Location location, int userId) {
+ if (userId == UserHandle.USER_ALL) {
+ final int[] runningUserIds = mUserInfoHelper.getRunningUserIds();
+ for (int i = 0; i < runningUserIds.length; i++) {
+ setLastLocation(location, runningUserIds[i]);
+ }
+ return;
+ }
+
+ Preconditions.checkArgument(userId >= 0);
+
+ synchronized (mLock) {
+ LastLocation lastLocation = mLastLocations.get(userId);
+ if (lastLocation == null) {
+ lastLocation = new LastLocation();
+ mLastLocations.put(userId, lastLocation);
+ }
+
+ Location coarseLocation = mLocationFudger.createCoarse(location);
+ if (isEnabled(userId)) {
+ lastLocation.set(location, coarseLocation);
+ }
+ lastLocation.setBypass(location, coarseLocation);
+ }
+ }
+
+ public void getCurrentLocation(LocationRequest request, CallerIdentity identity,
+ int permissionLevel, ICancellationSignal cancellationTransport,
+ ILocationCallback callback) {
+ Preconditions.checkArgument(mName.equals(request.getProvider()));
+
+ if (request.getExpireIn() > GET_CURRENT_LOCATION_MAX_TIMEOUT_MS) {
+ request.setExpireIn(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS);
+ }
+
+ GetCurrentLocationListenerRegistration registration =
+ new GetCurrentLocationListenerRegistration(
+ request,
+ identity,
+ new GetCurrentLocationTransport(callback),
+ permissionLevel);
+
+ synchronized (mLock) {
+ Location lastLocation = getLastLocation(request, identity, permissionLevel);
+ if (lastLocation != null) {
+ long locationAgeMs = NANOSECONDS.toMillis(
+ SystemClock.elapsedRealtimeNanos()
+ - lastLocation.getElapsedRealtimeNanos());
+ if (locationAgeMs < MAX_CURRENT_LOCATION_AGE_MS) {
+ registration.deliverLocation(lastLocation);
+ return;
+ }
+
+ if (!mAppForegroundHelper.isAppForeground(Binder.getCallingUid())
+ && locationAgeMs < mSettingsHelper.getBackgroundThrottleIntervalMs()) {
+ registration.deliverLocation(null);
+ return;
+ }
+ }
+
+ // if last location isn't good enough then we add a location request
+ addRegistration(callback.asBinder(), registration);
+ CancellationSignal cancellationSignal = CancellationSignal.fromTransport(
+ cancellationTransport);
+ if (cancellationSignal != null) {
+ cancellationSignal.setOnCancelListener(
+ () -> {
+ synchronized (mLock) {
+ removeRegistration(callback.asBinder(), registration);
+ }
+ });
+ }
+ }
+ }
+
+ public void sendExtraCommand(int uid, int pid, String command, Bundle extras) {
+ mProvider.sendExtraCommand(uid, pid, command, extras);
+ }
+
+ public void registerLocationRequest(LocationRequest request, CallerIdentity identity,
+ @PermissionLevel int permissionLevel, ILocationListener listener) {
+ Preconditions.checkArgument(mName.equals(request.getProvider()));
+
+ synchronized (mLock) {
+ addRegistration(
+ listener.asBinder(),
+ new LocationListenerRegistration(
+ request,
+ identity,
+ new LocationListenerTransport(listener),
+ permissionLevel));
+ }
+ }
+
+ public void registerLocationRequest(LocationRequest request, CallerIdentity identity,
+ @PermissionLevel int permissionLevel, PendingIntent pendingIntent) {
+ Preconditions.checkArgument(mName.equals(request.getProvider()));
+
+ synchronized (mLock) {
+ addRegistration(
+ pendingIntent,
+ new LocationPendingIntentRegistration(
+ request,
+ identity,
+ new LocationPendingIntentTransport(mContext, pendingIntent),
+ permissionLevel));
+ }
+ }
+
+ public void unregisterLocationRequest(ILocationListener listener) {
+ synchronized (mLock) {
+ removeRegistration(listener.asBinder());
+ }
+ }
+
+ public void unregisterLocationRequest(PendingIntent pendingIntent) {
+ synchronized (mLock) {
+ removeRegistration(pendingIntent);
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void onRegister() {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ mSettingsHelper.addOnBackgroundThrottleIntervalChangedListener(
+ mBackgroundThrottleIntervalChangedListener);
+ mSettingsHelper.addOnBackgroundThrottlePackageWhitelistChangedListener(
+ mBackgroundThrottlePackageWhitelistChangedListener);
+ mSettingsHelper.addOnLocationPackageBlacklistChangedListener(
+ mLocationPackageBlacklistChangedListener);
+ mSettingsHelper.addOnIgnoreSettingsPackageWhitelistChangedListener(
+ mIgnoreSettingsPackageWhitelistChangedListener);
+ mLocationPermissionsHelper.addListener(mLocationPermissionsListener);
+ mAppForegroundHelper.addListener(mAppForegroundChangedListener);
+ mLocationPowerSaveModeHelper.addListener(mLocationPowerSaveModeChangedListener);
+ mScreenInteractiveHelper.addListener(mScreenInteractiveChangedListener);
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void onUnregister() {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ mSettingsHelper.removeOnBackgroundThrottleIntervalChangedListener(
+ mBackgroundThrottleIntervalChangedListener);
+ mSettingsHelper.removeOnBackgroundThrottlePackageWhitelistChangedListener(
+ mBackgroundThrottlePackageWhitelistChangedListener);
+ mSettingsHelper.removeOnLocationPackageBlacklistChangedListener(
+ mLocationPackageBlacklistChangedListener);
+ mSettingsHelper.removeOnIgnoreSettingsPackageWhitelistChangedListener(
+ mIgnoreSettingsPackageWhitelistChangedListener);
+ mLocationPermissionsHelper.removeListener(mLocationPermissionsListener);
+ mAppForegroundHelper.removeListener(mAppForegroundChangedListener);
+ mLocationPowerSaveModeHelper.removeListener(mLocationPowerSaveModeChangedListener);
+ mScreenInteractiveHelper.removeListener(mScreenInteractiveChangedListener);
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void onRegistrationAdded(Object key, Registration registration) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ mLocationUsageLogger.logLocationApiUsage(
+ LocationStatsEnums.USAGE_STARTED,
+ LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
+ registration.getIdentity().getPackageName(),
+ registration.getRequest(),
+ key instanceof PendingIntent,
+ key instanceof IBinder,
+ /* geofence= */ null,
+ registration.isForeground());
+
+ mLocationRequestStatistics.startRequesting(
+ registration.getIdentity().getPackageName(),
+ registration.getIdentity().getAttributionTag(),
+ mName,
+ registration.getRequest().getInterval(),
+ registration.isForeground());
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void onRegistrationRemoved(Object key, Registration registration) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ mLocationRequestStatistics.stopRequesting(
+ registration.getIdentity().getPackageName(),
+ registration.getIdentity().getAttributionTag(),
+ mName);
+
+ mLocationUsageLogger.logLocationApiUsage(
+ LocationStatsEnums.USAGE_ENDED,
+ LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
+ registration.getIdentity().getPackageName(),
+ registration.getRequest(),
+ key instanceof PendingIntent,
+ key instanceof IBinder,
+ /* geofence= */ null,
+ registration.isForeground());
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected boolean registerWithService(ProviderRequest mergedRequest) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ mProvider.setRequest(mergedRequest);
+ return true;
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected boolean reregisterWithService(ProviderRequest oldRequest,
+ ProviderRequest newRequest) {
+ return registerWithService(newRequest);
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void unregisterWithService() {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+ mProvider.setRequest(ProviderRequest.EMPTY_REQUEST);
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected boolean isActive(Registration registration) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ CallerIdentity identity = registration.getIdentity();
+
+ if (!registration.isPermitted()) {
+ return false;
+ }
+
+ if (!registration.getRequest().isLocationSettingsIgnored()) {
+ if (!isEnabled(identity.getUserId())) {
+ return false;
+ }
+
+ switch (mLocationPowerSaveModeHelper.getLocationPowerSaveMode()) {
+ case LOCATION_MODE_FOREGROUND_ONLY:
+ if (!registration.isForeground()) {
+ return false;
+ }
+ break;
+ case LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF:
+ if (!GPS_PROVIDER.equals(mName)) {
+ break;
+ }
+ // fall through
+ case LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF:
+ // fall through
+ case LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF:
+ if (!mScreenInteractiveHelper.isInteractive()) {
+ return false;
+ }
+ break;
+ case LOCATION_MODE_NO_CHANGE:
+ // fall through
+ default:
+ break;
+ }
+ }
+
+ return !mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
+ identity.getPackageName());
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected ProviderRequest mergeRequests(Collection<Registration> registrations) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ ProviderRequest.Builder providerRequest = new ProviderRequest.Builder();
+ // initialize the low power mode to true and set to false if any of the records requires
+ providerRequest.setLowPowerMode(true);
+
+ ArrayList<Registration> providerRegistrations = new ArrayList<>(registrations.size());
+ for (Registration registration : registrations) {
+ LocationRequest locationRequest = registration.getRequest();
+
+ if (locationRequest.isLocationSettingsIgnored()) {
+ providerRequest.setLocationSettingsIgnored(true);
+ }
+ if (!locationRequest.isLowPowerMode()) {
+ providerRequest.setLowPowerMode(false);
+ }
+
+ providerRequest.setInterval(
+ Math.min(locationRequest.getInterval(), providerRequest.getInterval()));
+ providerRegistrations.add(registration);
+ }
+
+ // collect contributing location requests
+ ArrayList<LocationRequest> providerRequests = new ArrayList<>(providerRegistrations.size());
+ final int registrationsSize = providerRegistrations.size();
+ for (int i = 0; i < registrationsSize; i++) {
+ providerRequests.add(providerRegistrations.get(i).getRequest());
+ }
+
+ providerRequest.setLocationRequests(providerRequests);
+
+ // calculate who to blame for power in a somewhat arbitrary fashion. we pick a threshold
+ // interval slightly higher that the minimum interval, and spread the blame across all
+ // contributing registrations under that threshold.
+ long thresholdIntervalMs = (providerRequest.getInterval() + 1000) * 3 / 2;
+ if (thresholdIntervalMs < 0) {
+ // handle overflow
+ thresholdIntervalMs = Long.MAX_VALUE;
+ }
+ for (int i = 0; i < registrationsSize; i++) {
+ LocationRequest request = providerRegistrations.get(i).getRequest();
+ if (request.getInterval() <= thresholdIntervalMs) {
+ providerRequest.getWorkSource().add(providerRegistrations.get(i).getWorkSource());
+ }
+ }
+
+ return providerRequest.build();
+ }
+
+ private void onUserChanged(int userId, int change) {
+ synchronized (mLock) {
+ switch (change) {
+ case UserListener.CURRENT_USER_CHANGED:
+ onEnabledChanged(userId);
+ break;
+ case UserListener.USER_STARTED:
+ onUserStarted(userId);
+ break;
+ case UserListener.USER_STOPPED:
+ onUserStopped(userId);
+ break;
+ }
+ }
+ }
+
+ private void onLocationEnabledChanged(int userId) {
+ synchronized (mLock) {
+ onEnabledChanged(userId);
+ }
+ }
+
+ private void onScreenInteractiveChanged(boolean screenInteractive) {
+ synchronized (mLock) {
+ switch (mLocationPowerSaveModeHelper.getLocationPowerSaveMode()) {
+ case LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF:
+ if (!GPS_PROVIDER.equals(mName)) {
+ break;
+ }
+ // fall through
+ case LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF:
+ // fall through
+ case LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF:
+ updateService();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private void onBackgroundThrottlePackageWhitelistChanged() {
+ synchronized (mLock) {
+ updateRegistrations(Registration::onProviderLocationRequestChanged);
+ }
+ }
+
+ private void onBackgroundThrottleIntervalChanged() {
+ synchronized (mLock) {
+ updateRegistrations(Registration::onProviderLocationRequestChanged);
+ }
+ }
+
+ private void onLocationPowerSaveModeChanged(@LocationPowerSaveMode int locationPowerSaveMode) {
+ synchronized (mLock) {
+ // this is rare, just assume everything has changed to keep it simple
+ updateRegistrations(registration -> true);
+ }
+ }
+
+ private void onAppForegroundChanged(int uid, boolean foreground) {
+ synchronized (mLock) {
+ updateRegistrations(registration -> registration.onForegroundChanged(uid, foreground));
+ }
+ }
+
+ private void onIgnoreSettingsWhitelistChanged() {
+ synchronized (mLock) {
+ updateRegistrations(Registration::onProviderLocationRequestChanged);
+ }
+ }
+
+ private void onLocationPackageBlacklistChanged(int userId) {
+ synchronized (mLock) {
+ updateRegistrations(registration -> registration.getIdentity().getUserId() == userId);
+ }
+ }
+
+ private void onLocationPermissionsChanged(String packageName) {
+ synchronized (mLock) {
+ updateRegistrations(
+ registration -> registration.onLocationPermissionsChanged(packageName));
+ }
+ }
+
+ private void onLocationPermissionsChanged(int uid) {
+ synchronized (mLock) {
+ updateRegistrations(registration -> registration.onLocationPermissionsChanged(uid));
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ public void onStateChanged(
+ AbstractLocationProvider.State oldState, AbstractLocationProvider.State newState) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ if (oldState.allowed != newState.allowed) {
+ onEnabledChanged(UserHandle.USER_ALL);
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ public void onReportLocation(Location location) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ // don't validate mock locations
+ if (!location.isFromMockProvider()) {
+ if (location.getLatitude() == 0 && location.getLongitude() == 0) {
+ Log.w(TAG, "blocking 0,0 location from " + mName + " provider");
+ return;
+ }
+ }
+
+ if (!location.isComplete()) {
+ Log.w(TAG, "blocking incomplete location from " + mName + " provider");
+ return;
+ }
+
+ // update last location
+ setLastLocation(location, UserHandle.USER_ALL);
+
+ // notify passive provider
+ if (mPassiveManager != null) {
+ mPassiveManager.updateLocation(location);
+ }
+
+ // attempt listener delivery
+ deliverToListeners(registration -> {
+ return registration.acceptLocationChange(location);
+ });
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ public void onReportLocation(List<Location> locations) {
+ if (!GPS_PROVIDER.equals(mName)) {
+ return;
+ }
+
+ mLocationManagerInternal.reportGnssBatchLocations(locations);
+ }
+
+ @GuardedBy("mLock")
+ private void onUserStarted(int userId) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ if (userId == UserHandle.USER_NULL) {
+ return;
+ }
+
+ if (userId == UserHandle.USER_ALL) {
+ // clear the user's prior enabled state to prevent broadcast of enabled state change
+ mEnabled.clear();
+ onEnabledChanged(UserHandle.USER_ALL);
+ } else {
+ Preconditions.checkArgument(userId >= 0);
+
+ // clear the user's prior enabled state to prevent broadcast of enabled state change
+ mEnabled.delete(userId);
+ onEnabledChanged(userId);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void onUserStopped(int userId) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ if (userId == UserHandle.USER_NULL) {
+ return;
+ }
+
+ if (userId == UserHandle.USER_ALL) {
+ onEnabledChanged(UserHandle.USER_ALL);
+ mEnabled.clear();
+ mLastLocations.clear();
+ } else {
+ Preconditions.checkArgument(userId >= 0);
+
+ onEnabledChanged(userId);
+ mEnabled.delete(userId);
+ mLastLocations.remove(userId);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void onEnabledChanged(int userId) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ if (userId == UserHandle.USER_NULL) {
+ // used during initialization - ignore since many lower level operations (checking
+ // settings for instance) do not support the null user
+ return;
+ } else if (userId == UserHandle.USER_ALL) {
+ final int[] runningUserIds = mUserInfoHelper.getRunningUserIds();
+ for (int i = 0; i < runningUserIds.length; i++) {
+ onEnabledChanged(runningUserIds[i]);
+ }
+ return;
+ }
+
+ Preconditions.checkArgument(userId >= 0);
+
+ boolean enabled = mStarted
+ && mProvider.getState().allowed
+ && mUserInfoHelper.isCurrentUserId(userId)
+ && mSettingsHelper.isLocationEnabled(userId);
+
+ int index = mEnabled.indexOfKey(userId);
+ Boolean wasEnabled = index < 0 ? null : mEnabled.valueAt(index);
+ if (wasEnabled != null && wasEnabled == enabled) {
+ return;
+ }
+
+ mEnabled.put(userId, enabled);
+
+ if (D) {
+ Log.d(TAG, "[u" + userId + "] " + mName + " provider enabled = " + enabled);
+ }
+
+ // clear last locations if we become disabled
+ if (!enabled) {
+ LastLocation lastLocation = mLastLocations.get(userId);
+ if (lastLocation != null) {
+ lastLocation.clearLocations();
+ }
+ }
+
+ // do not send change notifications if we just saw this user for the first time
+ if (wasEnabled != null) {
+ // fused and passive provider never get public updates for legacy reasons
+ if (!FUSED_PROVIDER.equals(mName) && !PASSIVE_PROVIDER.equals(mName)) {
+ Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION)
+ .putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName)
+ .putExtra(LocationManager.EXTRA_PROVIDER_ENABLED, enabled)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
+ }
+
+ // send updates to internal listeners - since we expect listener changes to be more
+ // frequent than enabled changes, we use copy-on-read instead of copy-on-write
+ if (!mEnabledListeners.isEmpty()) {
+ ProviderEnabledListener[] listeners = mEnabledListeners.toArray(
+ new ProviderEnabledListener[0]);
+ FgThread.getHandler().post(() -> {
+ for (int i = 0; i < listeners.length; i++) {
+ listeners[i].onProviderEnabledChanged(mName, userId, enabled);
+ }
+ });
+ }
+ }
+
+ // update active state of affected registrations
+ updateRegistrations(registration -> registration.getIdentity().getUserId() == userId);
+ }
+
+ public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
+ synchronized (mLock) {
+ ipw.print(mName + " provider");
+ if (mProvider.isMock()) {
+ ipw.print(" [mock]");
+ }
+ ipw.println(":");
+ ipw.increaseIndent();
+
+ super.dump(fd, ipw, args);
+
+ int[] userIds = mUserInfoHelper.getRunningUserIds();
+ for (int userId : userIds) {
+ if (userIds.length != 1) {
+ ipw.println("user " + userId + ":");
+ ipw.increaseIndent();
+ }
+ ipw.println("last location=" + getLastLocation(userId, PERMISSION_FINE, false));
+ ipw.println("enabled=" + isEnabled(userId));
+ if (userIds.length != 1) {
+ ipw.decreaseIndent();
+ }
+ }
+ }
+
+ mProvider.dump(fd, ipw, args);
+
+ ipw.decreaseIndent();
+ }
+
+ private static class LastLocation {
+
+ @Nullable private Location mFineLocation;
+ @Nullable private Location mCoarseLocation;
+ @Nullable private Location mFineBypassLocation;
+ @Nullable private Location mCoarseBypassLocation;
+
+ public void clearMock() {
+ if (mFineLocation != null && mFineLocation.isFromMockProvider()) {
+ mFineLocation = null;
+ mCoarseLocation = null;
+ }
+ if (mFineBypassLocation != null && mFineBypassLocation.isFromMockProvider()) {
+ mFineBypassLocation = null;
+ mCoarseBypassLocation = null;
+ }
+ }
+
+ public void clearLocations() {
+ mFineLocation = null;
+ mCoarseLocation = null;
+ }
+
+ @Nullable
+ public Location get(@PermissionLevel int permissionLevel, boolean ignoreLocationSettings) {
+ switch (permissionLevel) {
+ case PERMISSION_FINE:
+ if (ignoreLocationSettings) {
+ return mFineBypassLocation;
+ } else {
+ return mFineLocation;
+ }
+ case PERMISSION_COARSE:
+ if (ignoreLocationSettings) {
+ return mCoarseBypassLocation;
+ } else {
+ return mCoarseLocation;
+ }
+ default:
+ // shouldn't be possible to have a client added without location permissions
+ throw new AssertionError();
+ }
+ }
+
+ public void set(Location location, Location coarseLocation) {
+ mFineLocation = location;
+ mCoarseLocation = calculateNextCoarse(mCoarseLocation, coarseLocation);
+ }
+
+ public void setBypass(Location location, Location coarseLocation) {
+ mFineBypassLocation = location;
+ mCoarseBypassLocation = calculateNextCoarse(mCoarseBypassLocation, coarseLocation);
+ }
+
+ private Location calculateNextCoarse(@Nullable Location oldCoarse, Location newCoarse) {
+ if (oldCoarse == null) {
+ return newCoarse;
+ }
+ // update last coarse interval only if enough time has passed
+ long timeDeltaMs = NANOSECONDS.toMillis(newCoarse.getElapsedRealtimeNanos())
+ - NANOSECONDS.toMillis(oldCoarse.getElapsedRealtimeNanos());
+ if (timeDeltaMs > FASTEST_COARSE_INTERVAL_MS) {
+ return newCoarse;
+ } else {
+ return oldCoarse;
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java
index c5bd5e6..fc88f14 100644
--- a/services/core/java/com/android/server/location/MockProvider.java
+++ b/services/core/java/com/android/server/location/MockProvider.java
@@ -40,9 +40,8 @@
public MockProvider(ProviderProperties properties, CallerIdentity identity) {
// using a direct executor is ok because this class has no locks that could deadlock
- super(DIRECT_EXECUTOR);
+ super(DIRECT_EXECUTOR, identity);
setProperties(properties);
- setIdentity(identity);
}
/** Sets the allowed state of this mock provider. */
diff --git a/services/core/java/com/android/server/location/MockableLocationProvider.java b/services/core/java/com/android/server/location/MockableLocationProvider.java
index 54af1c8..d8d435a 100644
--- a/services/core/java/com/android/server/location/MockableLocationProvider.java
+++ b/services/core/java/com/android/server/location/MockableLocationProvider.java
@@ -241,7 +241,6 @@
if (getState().properties != null) {
pw.println("properties=" + getState().properties);
}
- pw.println("request=" + mRequest);
}
if (provider != null) {
diff --git a/services/core/java/com/android/server/location/PassiveLocationProviderManager.java b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
new file mode 100644
index 0000000..d4999ab8
--- /dev/null
+++ b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.location.Location;
+import android.location.LocationManager;
+import android.os.Binder;
+
+import com.android.internal.util.Preconditions;
+import com.android.server.location.util.Injector;
+
+class PassiveLocationProviderManager extends LocationProviderManager {
+
+ PassiveLocationProviderManager(Context context, Injector injector) {
+ super(context, injector, LocationManager.PASSIVE_PROVIDER, null);
+ }
+
+ @Override
+ public void setRealProvider(AbstractLocationProvider provider) {
+ Preconditions.checkArgument(provider instanceof PassiveProvider);
+ super.setRealProvider(provider);
+ }
+
+ @Override
+ public void setMockProvider(@Nullable MockProvider provider) {
+ if (provider != null) {
+ throw new IllegalArgumentException("Cannot mock the passive provider");
+ }
+ }
+
+ public void updateLocation(Location location) {
+ synchronized (mLock) {
+ PassiveProvider passiveProvider = (PassiveProvider) mProvider.getProvider();
+ Preconditions.checkState(passiveProvider != null);
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ passiveProvider.updateLocation(location);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
index 0b7968b..1b599b0 100644
--- a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
@@ -16,17 +16,21 @@
package com.android.server.location.gnss;
+import static android.location.LocationManager.GPS_PROVIDER;
+
import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
import static com.android.server.location.gnss.GnssManagerService.TAG;
import android.annotation.Nullable;
import android.location.LocationManagerInternal;
+import android.location.LocationManagerInternal.ProviderEnabledListener;
import android.location.util.identity.CallerIdentity;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Process;
import android.util.ArraySet;
+import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.location.listeners.BinderListenerRegistration;
import com.android.server.location.listeners.ListenerMultiplexer;
@@ -161,8 +165,8 @@
protected final LocationManagerInternal mLocationManagerInternal;
private final UserListener mUserChangedListener = this::onUserChanged;
- private final SettingsHelper.UserSettingChangedListener mLocationEnabledChangedListener =
- this::onLocationEnabledChanged;
+ private final ProviderEnabledListener mProviderEnabledChangedListener =
+ this::onProviderEnabledChanged;
private final SettingsHelper.GlobalSettingChangedListener
mBackgroundThrottlePackageWhitelistChangedListener =
this::onBackgroundThrottlePackageWhitelistChanged;
@@ -233,12 +237,11 @@
}
CallerIdentity identity = registration.getIdentity();
- // TODO: this should be checking if the gps provider is enabled, not if location is enabled,
- // but this is the same for now.
return registration.isPermitted()
&& (registration.isForeground() || isBackgroundRestrictionExempt(identity))
&& mUserInfoHelper.isCurrentUserId(identity.getUserId())
- && mSettingsHelper.isLocationEnabled(identity.getUserId())
+ && mLocationManagerInternal.isProviderEnabledForUser(GPS_PROVIDER,
+ identity.getUserId())
&& !mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
identity.getPackageName());
}
@@ -263,7 +266,8 @@
}
mUserInfoHelper.addListener(mUserChangedListener);
- mSettingsHelper.addOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
+ mLocationManagerInternal.addProviderEnabledListener(GPS_PROVIDER,
+ mProviderEnabledChangedListener);
mSettingsHelper.addOnBackgroundThrottlePackageWhitelistChangedListener(
mBackgroundThrottlePackageWhitelistChangedListener);
mSettingsHelper.addOnLocationPackageBlacklistChangedListener(
@@ -279,7 +283,8 @@
}
mUserInfoHelper.removeListener(mUserChangedListener);
- mSettingsHelper.removeOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
+ mLocationManagerInternal.removeProviderEnabledListener(GPS_PROVIDER,
+ mProviderEnabledChangedListener);
mSettingsHelper.removeOnBackgroundThrottlePackageWhitelistChangedListener(
mBackgroundThrottlePackageWhitelistChangedListener);
mSettingsHelper.removeOnLocationPackageBlacklistChangedListener(
@@ -294,7 +299,8 @@
}
}
- private void onLocationEnabledChanged(int userId) {
+ private void onProviderEnabledChanged(String provider, int userId, boolean enabled) {
+ Preconditions.checkState(GPS_PROVIDER.equals(provider));
updateRegistrations(registration -> registration.getIdentity().getUserId() == userId);
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java b/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
index e17cca4..cea5a69 100644
--- a/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
+++ b/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
@@ -88,7 +88,7 @@
// Default time limit in milliseconds for the ConnectivityManager to find a suitable
// network with SUPL connectivity or report an error.
- private static final int SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS = 10 * 1000;
+ private static final int SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS = 20 * 1000;
private static final int HASH_MAP_INITIAL_CAPACITY_TO_TRACK_CONNECTED_NETWORKS = 5;
diff --git a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
index 528cf8a..f94de9b 100644
--- a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
@@ -104,18 +104,18 @@
* should return true if a matching call to {@link #unregisterWithService()} is required to
* unregister (ie, if registration succeeds).
*
- * @see #reregisterWithService(Object)
+ * @see #reregisterWithService(Object, Object)
*/
- protected abstract boolean registerWithService(TMergedRequest mergedRequest);
+ protected abstract boolean registerWithService(TMergedRequest newRequest);
/**
* Invoked when the service already has a request, and it is being replaced with a new request.
* The default implementation unregisters first, then registers with the new merged request, but
* this may be overridden by subclasses in order to reregister more efficiently.
*/
- protected boolean reregisterWithService(TMergedRequest mergedRequest) {
+ protected boolean reregisterWithService(TMergedRequest oldRequest, TMergedRequest newRequest) {
unregisterWithService();
- return registerWithService(mergedRequest);
+ return registerWithService(newRequest);
}
/**
@@ -368,6 +368,7 @@
mCurrentRequest = null;
if (mServiceRegistered) {
mServiceRegistered = false;
+ mCurrentRequest = null;
unregisterWithService();
}
return;
@@ -376,11 +377,15 @@
TMergedRequest merged = mergeRequests(actives);
if (!mServiceRegistered || !Objects.equals(merged, mCurrentRequest)) {
if (mServiceRegistered) {
- mServiceRegistered = reregisterWithService(merged);
+ mServiceRegistered = reregisterWithService(mCurrentRequest, merged);
} else {
mServiceRegistered = registerWithService(merged);
}
- mCurrentRequest = merged;
+ if (mServiceRegistered) {
+ mCurrentRequest = merged;
+ } else {
+ mCurrentRequest = null;
+ }
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -389,29 +394,6 @@
}
/**
- * Evaluates the given predicate for all registrations, and forces an {@link #updateService()}
- * if any predicate returns true for an active registration. The predicate will always be
- * evaluated for all registrations, even inactive registrations, or if it has already returned
- * true for a prior registration.
- */
- protected final void updateService(Predicate<TRegistration> predicate) {
- synchronized (mRegistrations) {
- boolean updateService = false;
- final int size = mRegistrations.size();
- for (int i = 0; i < size; i++) {
- TRegistration registration = mRegistrations.valueAt(i);
- if (predicate.test(registration) && registration.isActive()) {
- updateService = true;
- }
- }
-
- if (updateService) {
- updateService();
- }
- }
- }
-
- /**
* Begins buffering calls to {@link #updateService()} until {@link UpdateServiceLock#close()}
* is called. This is useful to prevent extra work when combining multiple calls (for example,
* buffering {@code updateService()} until after multiple adds/removes/updates occur.
diff --git a/services/core/java/com/android/server/location/listeners/ListenerRegistration.java b/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
index 0bdd131..ac56c51 100644
--- a/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
@@ -24,6 +24,7 @@
import android.location.util.identity.CallerIdentity;
import android.os.Process;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.listeners.ListenerExecutor;
import com.android.server.FgThread;
@@ -39,6 +40,9 @@
*/
public class ListenerRegistration<TRequest, TListener> implements ListenerExecutor {
+ @VisibleForTesting
+ public static final Executor IN_PROCESS_EXECUTOR = FgThread.getExecutor();
+
private final Executor mExecutor;
private final @Nullable TRequest mRequest;
private final CallerIdentity mIdentity;
@@ -55,9 +59,9 @@
// there's a slight loophole here for pending intents - pending intent callbacks can
// always be run on the direct executor since they're always asynchronous, but honestly
// you shouldn't be using pending intent callbacks within the same process anyways
- mExecutor = FgThread.getExecutor();
+ mExecutor = IN_PROCESS_EXECUTOR;
} else {
- mExecutor = DIRECT_EXECUTOR;
+ mExecutor = DIRECT_EXECUTOR;
}
mRequest = request;
@@ -73,7 +77,7 @@
/**
* Returns the request associated with this listener, or null if one wasn't supplied.
*/
- public final @Nullable TRequest getRequest() {
+ public @Nullable TRequest getRequest() {
return mRequest;
}
@@ -107,7 +111,7 @@
*/
protected void onInactive() {}
- final boolean isActive() {
+ public final boolean isActive() {
return mActive;
}
@@ -120,7 +124,7 @@
return false;
}
- final boolean isRegistered() {
+ public final boolean isRegistered() {
return mListener != null;
}
diff --git a/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java b/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java
index 6a815ea..0698cca 100644
--- a/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java
@@ -39,7 +39,7 @@
protected RemovableListenerRegistration(String tag, @Nullable TRequest request,
CallerIdentity callerIdentity, TListener listener) {
super(request, callerIdentity, listener);
- mTag = tag;
+ mTag = Objects.requireNonNull(tag);
}
/**
diff --git a/services/core/java/com/android/server/media/HandlerExecutor.java b/services/core/java/com/android/server/media/HandlerExecutor.java
new file mode 100644
index 0000000..7c9e72b
--- /dev/null
+++ b/services/core/java/com/android/server/media/HandlerExecutor.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.media;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+
+/**
+ * An adapter {@link Executor} that posts all executed tasks onto the given
+ * {@link Handler}.
+ *
+ * @hide
+ */
+public class HandlerExecutor implements Executor {
+ private final Handler mHandler;
+
+ public HandlerExecutor(@NonNull Handler handler) {
+ mHandler = Objects.requireNonNull(handler);
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ if (!mHandler.post(command)) {
+ throw new RejectedExecutionException(mHandler + " is shutting down");
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java
index 5d1b7491..162c388 100644
--- a/services/core/java/com/android/server/media/MediaSession2Record.java
+++ b/services/core/java/com/android/server/media/MediaSession2Record.java
@@ -20,7 +20,6 @@
import android.media.Session2CommandGroup;
import android.media.Session2Token;
import android.os.Handler;
-import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.ResultReceiver;
import android.os.UserHandle;
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 249b6801..07527c2 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -270,11 +270,12 @@
abstract boolean revertActiveSessions();
/**
- * Abandons the staged session with the given sessionId.
+ * Abandons the staged session with the given sessionId. Client should handle {@code false}
+ * return value carefully as failure here can leave device in inconsistent state.
*
- * @return {@code true} upon success, {@code false} if any remote exception occurs
+ * @return {@code true} upon success, {@code false} if any exception occurs
*/
- abstract boolean abortStagedSession(int sessionId) throws PackageManagerException;
+ abstract boolean abortStagedSession(int sessionId);
/**
* Uninstalls given {@code apexPackage}.
@@ -753,17 +754,13 @@
}
@Override
- boolean abortStagedSession(int sessionId) throws PackageManagerException {
+ boolean abortStagedSession(int sessionId) {
try {
waitForApexService().abortStagedSession(sessionId);
return true;
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to contact apexservice", re);
- return false;
} catch (Exception e) {
- throw new PackageManagerException(
- PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
- "Failed to abort staged session : " + e.getMessage());
+ Slog.e(TAG, e.getMessage(), e);
+ return false;
}
}
@@ -1122,7 +1119,7 @@
}
@Override
- boolean abortStagedSession(int sessionId) throws PackageManagerException {
+ boolean abortStagedSession(int sessionId) {
throw new UnsupportedOperationException();
}
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index fe6aad7..e48862e 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -14,16 +14,16 @@
per-file StagingManager.java = dariofreni@google.com, ioffe@google.com, olilan@google.com
# dex
-per-file AbstractStatsBase.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file BackgroundDexOptService.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file CompilerStats.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file DynamicCodeLoggingService.java = alanstokes@google.com, agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file InstructionSets.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file OtaDexoptService.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file OtaDexoptShellCommand.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file PackageDexOptimizer.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file PackageManagerServiceCompilerMapping.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file PackageUsage.java = agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file AbstractStatsBase.java = calin@google.com, ngeoffray@google.com
+per-file BackgroundDexOptService.java = calin@google.com, ngeoffray@google.com
+per-file CompilerStats.java = calin@google.com, ngeoffray@google.com
+per-file DynamicCodeLoggingService.java = alanstokes@google.com, calin@google.com, ngeoffray@google.com
+per-file InstructionSets.java = calin@google.com, ngeoffray@google.com
+per-file OtaDexoptService.java = calin@google.com, ngeoffray@google.com
+per-file OtaDexoptShellCommand.java = calin@google.com, ngeoffray@google.com
+per-file PackageDexOptimizer.java = calin@google.com, ngeoffray@google.com
+per-file PackageManagerServiceCompilerMapping.java = calin@google.com, ngeoffray@google.com
+per-file PackageUsage.java = calin@google.com, ngeoffray@google.com
# multi user / cross profile
per-file CrossProfileAppsServiceImpl.java = omakoto@google.com, yamasani@google.com
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 312dcdd..55e7ca8 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -1284,10 +1284,16 @@
int N = mSessions.size();
for (int i = 0; i < N; i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
- if (session.isStagedAndInTerminalState()) {
+
+ // Do not print finalized staged session as active install sessions
+ final PackageInstallerSession rootSession = session.hasParentSessionId()
+ ? getSession(session.getParentSessionId())
+ : session;
+ if (rootSession.isStagedAndInTerminalState()) {
finalizedSessions.add(session);
continue;
}
+
session.dump(pw);
pw.println();
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 7765f18..05026a0 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -169,7 +169,7 @@
private static final int MSG_STREAM_VALIDATE_AND_COMMIT = 2;
private static final int MSG_INSTALL = 3;
private static final int MSG_ON_PACKAGE_INSTALLED = 4;
- private static final int MSG_SESSION_VERIFICATION_FAILURE = 5;
+ private static final int MSG_SESSION_VALIDATION_FAILURE = 5;
/** XML constants used for persisting a session */
static final String TAG_SESSION = "session";
@@ -475,10 +475,10 @@
packageName, returnCode, message, extras);
break;
- case MSG_SESSION_VERIFICATION_FAILURE:
+ case MSG_SESSION_VALIDATION_FAILURE:
final int error = msg.arg1;
final String detailMessage = (String) msg.obj;
- onSessionVerificationFailure(error, detailMessage);
+ onSessionValidationFailure(error, detailMessage);
break;
}
@@ -1246,14 +1246,14 @@
// the parent
if (unrecoverableFailure != null) {
// {@link #streamValidateAndCommit()} calls
- // {@link #onSessionVerificationFailure(PackageManagerException)}, but we don't
+ // {@link #onSessionValidationFailure(PackageManagerException)}, but we don't
// expect it to ever do so for parent sessions. Call that on this parent to clean
// it up and notify listeners of the error.
- onSessionVerificationFailure(unrecoverableFailure);
+ onSessionValidationFailure(unrecoverableFailure);
// fail other child sessions that did not already fail
for (int i = nonFailingSessions.size() - 1; i >= 0; --i) {
PackageInstallerSession session = nonFailingSessions.get(i);
- session.onSessionVerificationFailure(unrecoverableFailure);
+ session.onSessionValidationFailure(unrecoverableFailure);
}
}
}
@@ -1575,11 +1575,11 @@
assertMultiPackageConsistencyLocked(childSessions);
}
} catch (PackageManagerException e) {
- throw onSessionVerificationFailure(e);
+ throw onSessionValidationFailure(e);
} catch (Throwable e) {
// Convert all exceptions into package manager exceptions as only those are handled
// in the code above.
- throw onSessionVerificationFailure(new PackageManagerException(e));
+ throw onSessionValidationFailure(new PackageManagerException(e));
}
}
@@ -1613,20 +1613,20 @@
}
return true;
} catch (PackageManagerException e) {
- throw onSessionVerificationFailure(e);
+ throw onSessionValidationFailure(e);
} catch (Throwable e) {
// Convert all exceptions into package manager exceptions as only those are handled
// in the code above.
- throw onSessionVerificationFailure(new PackageManagerException(e));
+ throw onSessionValidationFailure(new PackageManagerException(e));
}
}
- private PackageManagerException onSessionVerificationFailure(PackageManagerException e) {
- onSessionVerificationFailure(e.error, ExceptionUtils.getCompleteMessage(e));
+ private PackageManagerException onSessionValidationFailure(PackageManagerException e) {
+ onSessionValidationFailure(e.error, ExceptionUtils.getCompleteMessage(e));
return e;
}
- private void onSessionVerificationFailure(int error, String detailMessage) {
+ private void onSessionValidationFailure(int error, String detailMessage) {
// Session is sealed but could not be verified, we need to destroy it.
destroyInternal();
// Dispatch message to remove session from PackageInstallerService.
@@ -2091,7 +2091,7 @@
if (ps == null) {
return 0;
}
- final File apkDirOrPath = ps.codePath;
+ final File apkDirOrPath = ps.getCodePath();
if (apkDirOrPath == null) {
return 0;
}
@@ -2990,7 +2990,7 @@
synchronized (mLock) {
mDataLoaderFinished = true;
}
- dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
+ dispatchSessionValidationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
"Failure to obtain data loader");
return;
}
@@ -3040,7 +3040,7 @@
synchronized (mLock) {
mDataLoaderFinished = true;
}
- dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
+ dispatchSessionValidationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
"Failed to prepare image.");
if (manualStartAndDestroy) {
dataLoader.destroy(dataLoaderId);
@@ -3061,7 +3061,7 @@
synchronized (mLock) {
mDataLoaderFinished = true;
}
- dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
+ dispatchSessionValidationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
"DataLoader reported unrecoverable failure.");
break;
}
@@ -3117,7 +3117,7 @@
synchronized (mLock) {
mDataLoaderFinished = true;
}
- dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
+ dispatchSessionValidationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
"Image is missing pages required for installation.");
break;
}
@@ -3142,8 +3142,8 @@
return false;
}
- private void dispatchSessionVerificationFailure(int error, String detailMessage) {
- mHandler.obtainMessage(MSG_SESSION_VERIFICATION_FAILURE, error, -1,
+ private void dispatchSessionValidationFailure(int error, String detailMessage) {
+ mHandler.obtainMessage(MSG_SESSION_VALIDATION_FAILURE, error, -1,
detailMessage).sendToTarget();
}
@@ -3321,7 +3321,8 @@
/** {@hide} */
void setStagedSessionReady() {
synchronized (mLock) {
- if (mDestroyed) return; // Do not allow destroyed staged session to change state
+ // Do not allow destroyed/failed staged session to change state
+ if (mDestroyed || mStagedSessionFailed) return;
mStagedSessionReady = true;
mStagedSessionApplied = false;
mStagedSessionFailed = false;
@@ -3332,10 +3333,10 @@
}
/** {@hide} */
- void setStagedSessionFailed(@StagedSessionErrorCode int errorCode,
- String errorMessage) {
+ void setStagedSessionFailed(@StagedSessionErrorCode int errorCode, String errorMessage) {
synchronized (mLock) {
- if (mDestroyed) return; // Do not allow destroyed staged session to change state
+ // Do not allow destroyed/failed staged session to change state
+ if (mDestroyed || mStagedSessionFailed) return;
mStagedSessionReady = false;
mStagedSessionApplied = false;
mStagedSessionFailed = true;
@@ -3350,7 +3351,8 @@
/** {@hide} */
void setStagedSessionApplied() {
synchronized (mLock) {
- if (mDestroyed) return; // Do not allow destroyed staged session to change state
+ // Do not allow destroyed/failed staged session to change state
+ if (mDestroyed || mStagedSessionFailed) return;
mStagedSessionReady = false;
mStagedSessionApplied = true;
mStagedSessionFailed = false;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a726c8d..58a1648 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3010,7 +3010,7 @@
final int packageSettingCount = mSettings.mPackages.size();
for (int i = packageSettingCount - 1; i >= 0; i--) {
PackageSetting ps = mSettings.mPackages.valueAt(i);
- if (!isExternal(ps) && (ps.codePath == null || !ps.codePath.exists())
+ if (!isExternal(ps) && (ps.getCodePath() == null || !ps.getCodePath().exists())
&& mSettings.getDisabledSystemPkgLPr(ps.name) != null) {
mSettings.mPackages.removeAt(i);
mSettings.enableSystemPackageLPw(ps.name);
@@ -3175,11 +3175,11 @@
logCriticalInfo(Log.WARN,
"Expecting better updated system app for " + ps.name
+ "; removing system app. Last known"
- + " codePath=" + ps.codePathString
+ + " codePath=" + ps.getCodePathString()
+ ", versionCode=" + ps.versionCode
+ "; scanned versionCode=" + scannedPkg.getLongVersionCode());
removePackageLI(scannedPkg, true);
- mExpectingBetter.put(ps.name, ps.codePath);
+ mExpectingBetter.put(ps.name, ps.getCodePath());
}
continue;
@@ -3202,14 +3202,14 @@
// code path, but, changes the package name.
final PackageSetting disabledPs =
mSettings.getDisabledSystemPkgLPr(ps.name);
- if (disabledPs.codePath == null || !disabledPs.codePath.exists()
+ if (disabledPs.getCodePath() == null || !disabledPs.getCodePath().exists()
|| disabledPs.pkg == null) {
possiblyDeletedUpdatedSystemApps.add(ps.name);
} else {
// We're expecting that the system app should remain disabled, but add
// it to expecting better to recover in case the data version cannot
// be scanned.
- mExpectingBetter.put(disabledPs.name, disabledPs.codePath);
+ mExpectingBetter.put(disabledPs.name, disabledPs.getCodePath());
}
}
}
@@ -8551,6 +8551,15 @@
if (listUninstalled) {
list = new ArrayList<>(mSettings.mPackages.size());
for (PackageSetting ps : mSettings.mPackages.values()) {
+ if (listFactory) {
+ if (!ps.isSystem()) {
+ continue;
+ }
+ PackageSetting psDisabled = mSettings.getDisabledSystemPkgLPr(ps);
+ if (psDisabled != null) {
+ ps = psDisabled;
+ }
+ }
if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
continue;
}
@@ -8565,7 +8574,16 @@
} else {
list = new ArrayList<>(mPackages.size());
for (AndroidPackage p : mPackages.values()) {
- final PackageSetting ps = getPackageSetting(p.getPackageName());
+ PackageSetting ps = getPackageSetting(p.getPackageName());
+ if (listFactory) {
+ if (!p.isSystem()) {
+ continue;
+ }
+ PackageSetting psDisabled = mSettings.getDisabledSystemPkgLPr(ps);
+ if (psDisabled != null) {
+ ps = psDisabled;
+ }
+ }
if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
continue;
}
@@ -9150,7 +9168,7 @@
: getLastModifiedTime(parsedPackage);
final VersionInfo settingsVersionForPackage = getSettingsVersionForPackage(parsedPackage);
if (ps != null && !forceCollect
- && ps.codePathString.equals(parsedPackage.getCodePath())
+ && ps.getCodePathString().equals(parsedPackage.getCodePath())
&& ps.timeStamp == lastModifiedTime
&& !isCompatSignatureUpdateNeeded(settingsVersionForPackage)
&& !isRecoverSignatureUpdateNeeded(settingsVersionForPackage)) {
@@ -9383,8 +9401,8 @@
}
}
- final boolean newPkgChangedPaths =
- pkgAlreadyExists && !pkgSetting.codePathString.equals(parsedPackage.getCodePath());
+ final boolean newPkgChangedPaths = pkgAlreadyExists
+ && !pkgSetting.getCodePathString().equals(parsedPackage.getCodePath());
final boolean newPkgVersionGreater =
pkgAlreadyExists && parsedPackage.getLongVersionCode() > pkgSetting.versionCode;
final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated
@@ -9403,11 +9421,11 @@
"System package updated;"
+ " name: " + pkgSetting.name
+ "; " + pkgSetting.versionCode + " --> " + parsedPackage.getLongVersionCode()
- + "; " + pkgSetting.codePathString + " --> " + parsedPackage.getCodePath());
+ + "; " + pkgSetting.getCodePathString()
+ + " --> " + parsedPackage.getCodePath());
final InstallArgs args = createInstallArgsForExisting(
- pkgSetting.codePathString,
- pkgSetting.resourcePathString, getAppDexInstructionSets(
+ pkgSetting.getCodePathString(), getAppDexInstructionSets(
pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
args.cleanUpResourcesLI();
synchronized (mLock) {
@@ -9482,11 +9500,10 @@
+ " name: " + pkgSetting.name
+ "; " + pkgSetting.versionCode + " --> "
+ parsedPackage.getLongVersionCode()
- + "; " + pkgSetting.codePathString + " --> "
+ + "; " + pkgSetting.getCodePathString() + " --> "
+ parsedPackage.getCodePath());
InstallArgs args = createInstallArgsForExisting(
- pkgSetting.codePathString,
- pkgSetting.resourcePathString, getAppDexInstructionSets(
+ pkgSetting.getCodePathString(), getAppDexInstructionSets(
pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
synchronized (mInstallLock) {
args.cleanUpResourcesLI();
@@ -9499,7 +9516,7 @@
logCriticalInfo(Log.INFO,
"System package disabled;"
+ " name: " + pkgSetting.name
- + "; old: " + pkgSetting.codePathString + " @ "
+ + "; old: " + pkgSetting.getCodePathString() + " @ "
+ pkgSetting.versionCode
+ "; new: " + parsedPackage.getCodePath() + " @ "
+ parsedPackage.getCodePath());
@@ -11325,7 +11342,7 @@
if (changedAbiCodePath == null) {
changedAbiCodePath = new ArrayList<>();
}
- changedAbiCodePath.add(ps.codePathString);
+ changedAbiCodePath.add(ps.getCodePathString());
}
}
}
@@ -11421,7 +11438,6 @@
// Initialize package source and resource directories
final File destCodeFile = new File(parsedPackage.getCodePath());
- final File destResourceFile = new File(parsedPackage.getCodePath());
// We keep references to the derived CPU Abis from settings in oder to reuse
// them in the case where we're not upgrading or booting for the first time.
@@ -11479,7 +11495,7 @@
// REMOVE SharedUserSetting from method; update in a separate call
pkgSetting = Settings.createNewSetting(parsedPackage.getPackageName(),
originalPkgSetting, disabledPkgSetting, realPkgName, sharedUserSetting,
- destCodeFile, destResourceFile, parsedPackage.getNativeLibraryRootDir(),
+ destCodeFile, parsedPackage.getNativeLibraryRootDir(),
AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage),
AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage),
parsedPackage.getVersionCode(), pkgFlags, pkgPrivateFlags, user,
@@ -11497,7 +11513,7 @@
// secondaryCpuAbi are not known at this point so we always update them
// to null here, only to reset them at a later point.
Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, sharedUserSetting,
- destCodeFile, destResourceFile, parsedPackage.getNativeLibraryDir(),
+ destCodeFile, parsedPackage.getNativeLibraryDir(),
AndroidPackageUtils.getPrimaryCpuAbi(parsedPackage, pkgSetting),
AndroidPackageUtils.getSecondaryCpuAbi(parsedPackage, pkgSetting),
PackageInfoUtils.appInfoFlags(parsedPackage, pkgSetting),
@@ -12066,15 +12082,13 @@
if (known != null) {
if (DEBUG_PACKAGE_SCANNING) {
Log.d(TAG, "Examining " + pkg.getCodePath()
- + " and requiring known paths " + known.codePathString
- + " & " + known.resourcePathString);
+ + " and requiring known path " + known.getCodePathString());
}
- if (!pkg.getCodePath().equals(known.codePathString)
- || !pkg.getCodePath().equals(known.resourcePathString)) {
+ if (!pkg.getCodePath().equals(known.getCodePathString())) {
throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
"Application package " + pkg.getPackageName()
+ " found at " + pkg.getCodePath()
- + " but expected at " + known.codePathString
+ + " but expected at " + known.getCodePathString()
+ "; ignoring.");
}
} else {
@@ -15586,9 +15600,8 @@
* Create args that describe an existing installed package. Typically used
* when cleaning up old installs, or used as a move source.
*/
- private InstallArgs createInstallArgsForExisting(String codePath,
- String resourcePath, String[] instructionSets) {
- return new FileInstallArgs(codePath, resourcePath, instructionSets);
+ private InstallArgs createInstallArgsForExisting(String codePath, String[] instructionSets) {
+ return new FileInstallArgs(codePath, instructionSets);
}
static abstract class InstallArgs {
@@ -15669,10 +15682,8 @@
abstract boolean doRename(int status, ParsedPackage parsedPackage);
abstract int doPostInstall(int status, int uid);
- /** @see PackageSettingBase#codePathString */
+ /** @see PackageSettingBase#getCodePath() */
abstract String getCodePath();
- /** @see PackageSettingBase#resourcePathString */
- abstract String getResourcePath();
// Need installer lock especially for dex file removal.
abstract void cleanUpResourcesLI();
@@ -15743,14 +15754,13 @@
}
/** Existing install */
- FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
+ FileInstallArgs(String codePath, String[] instructionSets) {
super(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY,
null, null, instructionSets, null, null, null, MODE_DEFAULT, null, 0,
PackageParser.SigningDetails.UNKNOWN,
PackageManager.INSTALL_REASON_UNKNOWN, false,
DataLoaderType.NONE);
this.codeFile = (codePath != null) ? new File(codePath) : null;
- this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
}
int copyApk() {
@@ -15766,7 +15776,6 @@
if (origin.staged) {
if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
codeFile = origin.file;
- resourceFile = origin.file;
return PackageManager.INSTALL_SUCCEEDED;
}
@@ -15775,7 +15784,6 @@
final File tempDir =
mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
codeFile = tempDir;
- resourceFile = tempDir;
} catch (IOException e) {
Slog.w(TAG, "Failed to create copy file: " + e);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
@@ -15846,7 +15854,6 @@
// Reflect the rename internally
codeFile = afterCodeFile;
- resourceFile = afterCodeFile;
// Reflect the rename in scanned details
try {
@@ -15875,11 +15882,6 @@
return (codeFile != null) ? codeFile.getAbsolutePath() : null;
}
- @Override
- String getResourcePath() {
- return (resourceFile != null) ? resourceFile.getAbsolutePath() : null;
- }
-
private boolean cleanUp() {
if (codeFile == null || !codeFile.exists()) {
return false;
@@ -15892,10 +15894,6 @@
removeCodePathLI(codeFile);
- if (resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) {
- resourceFile.delete();
- }
-
return true;
}
@@ -15927,7 +15925,6 @@
*/
class MoveInstallArgs extends InstallArgs {
private File codeFile;
- private File resourceFile;
/** New install */
MoveInstallArgs(InstallParams params) {
@@ -15950,7 +15947,6 @@
final String toPathName = new File(move.fromCodePath).getName();
codeFile = new File(Environment.getDataAppDirectory(move.toUuid), toPathName);
- resourceFile = codeFile;
if (DEBUG_INSTALL) Slog.d(TAG, "codeFile after move is " + codeFile);
return PackageManager.INSTALL_SUCCEEDED;
@@ -15987,11 +15983,6 @@
return (codeFile != null) ? codeFile.getAbsolutePath() : null;
}
- @Override
- String getResourcePath() {
- return (resourceFile != null) ? resourceFile.getAbsolutePath() : null;
- }
-
private boolean cleanUp(String volumeUuid) {
final String toPathName = new File(move.fromCodePath).getName();
final File codeFile = new File(Environment.getDataAppDirectory(volumeUuid),
@@ -16777,7 +16768,6 @@
// installed. We need to make sure to delete the older one's .apk.
res.removedInfo.args = createInstallArgsForExisting(
oldPackage.getCodePath(),
- oldPackage.getCodePath(),
getAppDexInstructionSets(
AndroidPackageUtils.getPrimaryCpuAbi(oldPackage,
deletedPkgSetting),
@@ -18558,7 +18548,6 @@
// user handle installed state
int[] allUsers;
/** enabled state of the uninstalled application */
- final int origEnabledState;
synchronized (mLock) {
uninstalledPs = mSettings.mPackages.get(packageName);
if (uninstalledPs == null) {
@@ -18574,10 +18563,6 @@
}
disabledSystemPs = mSettings.getDisabledSystemPkgLPr(packageName);
- // Save the enabled state before we delete the package. When deleting a stub
- // application we always set the enabled state to 'disabled'.
- origEnabledState = uninstalledPs == null
- ? COMPONENT_ENABLED_STATE_DEFAULT : uninstalledPs.getEnabled(userId);
// Static shared libs can be declared by any package, so let us not
// allow removing a package if it provides a lib others depend on.
pkg = mPackages.get(packageName);
@@ -18656,20 +18641,32 @@
if (stubPkg != null && stubPkg.isStub()) {
final PackageSetting stubPs;
synchronized (mLock) {
- // restore the enabled state of the stub; the state is overwritten when
- // the stub is uninstalled
stubPs = mSettings.getPackageLPr(stubPkg.getPackageName());
- if (stubPs != null) {
- stubPs.setEnabled(origEnabledState, userId, "android");
- }
}
- if (origEnabledState == COMPONENT_ENABLED_STATE_DEFAULT
- || origEnabledState == COMPONENT_ENABLED_STATE_ENABLED) {
- if (DEBUG_COMPRESSION) {
- Slog.i(TAG, "Enabling system stub after removal; pkg: "
- + stubPkg.getPackageName());
+
+ if (stubPs != null) {
+ boolean enable = false;
+ for (int aUserId : allUsers) {
+ if (stubPs.getInstalled(aUserId)) {
+ int enabled = stubPs.getEnabled(aUserId);
+ if (enabled == COMPONENT_ENABLED_STATE_DEFAULT
+ || enabled == COMPONENT_ENABLED_STATE_ENABLED) {
+ enable = true;
+ break;
+ }
+ }
}
- enableCompressedPackage(stubPkg, stubPs);
+
+ if (enable) {
+ if (DEBUG_COMPRESSION) {
+ Slog.i(TAG, "Enabling system stub after removal; pkg: "
+ + stubPkg.getPackageName());
+ }
+ enableCompressedPackage(stubPkg, stubPs);
+ } else if (DEBUG_COMPRESSION) {
+ Slog.i(TAG, "System stub disabled for all users, leaving uncompressed "
+ + "after removal; pkg: " + stubPkg.getPackageName());
+ }
}
}
}
@@ -18998,7 +18995,7 @@
// Install the system package
if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
try {
- installPackageFromSystemLIF(disabledPs.codePathString, allUserHandles,
+ installPackageFromSystemLIF(disabledPs.getCodePathString(), allUserHandles,
outInfo == null ? null : outInfo.origUsers, deletedPs.getPermissionsState(),
writeSettings);
} catch (PackageManagerException e) {
@@ -19013,8 +19010,15 @@
// and re-enable it afterward.
final PackageSetting stubPs = mSettings.mPackages.get(deletedPkg.getPackageName());
if (stubPs != null) {
- stubPs.setEnabled(
- COMPONENT_ENABLED_STATE_DISABLED, UserHandle.USER_SYSTEM, "android");
+ int userId = action.user == null
+ ? UserHandle.USER_ALL : action.user.getIdentifier();
+ if (userId == UserHandle.USER_ALL) {
+ for (int aUserId : allUserHandles) {
+ stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, aUserId, "android");
+ }
+ } else if (userId >= UserHandle.USER_SYSTEM) {
+ stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, userId, "android");
+ }
}
}
}
@@ -19123,7 +19127,7 @@
// Delete application code and resources only for parent packages
if (deleteCodeAndResources && (outInfo != null)) {
outInfo.args = createInstallArgsForExisting(
- ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(
+ ps.getCodePathString(), getAppDexInstructionSets(
ps.primaryCpuAbiString, ps.secondaryCpuAbiString));
if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
}
@@ -19660,7 +19664,7 @@
final String[] packageNames = { packageName };
final long[] ceDataInodes = { ps.getCeDataInode(userId) };
- final String[] codePaths = { ps.codePathString };
+ final String[] codePaths = { ps.getCodePathString() };
try {
mInstaller.getAppSize(ps.volumeUuid, packageNames, userId, 0,
@@ -22582,11 +22586,11 @@
synchronized (mInstallLock) {
final AndroidPackage pkg;
try {
- pkg = scanPackageTracedLI(ps.codePath, parseFlags, SCAN_INITIAL, 0, null);
+ pkg = scanPackageTracedLI(ps.getCodePath(), parseFlags, SCAN_INITIAL, 0, null);
loaded.add(pkg);
} catch (PackageManagerException e) {
- Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage());
+ Slog.w(TAG, "Failed to scan " + ps.getCodePath() + ": " + e.getMessage());
}
if (!Build.FINGERPRINT.equals(ver.fingerprint)) {
@@ -22657,33 +22661,33 @@
final ArrayList<AndroidPackage> unloaded = new ArrayList<>();
synchronized (mInstallLock) {
- synchronized (mLock) {
- final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(volumeUuid);
- for (PackageSetting ps : packages) {
- if (ps.pkg == null) continue;
+ synchronized (mLock) {
+ final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(volumeUuid);
+ for (PackageSetting ps : packages) {
+ if (ps.pkg == null) continue;
- final AndroidPackage pkg = ps.pkg;
- final int deleteFlags = PackageManager.DELETE_KEEP_DATA;
- final PackageRemovedInfo outInfo = new PackageRemovedInfo(this);
+ final AndroidPackage pkg = ps.pkg;
+ final int deleteFlags = PackageManager.DELETE_KEEP_DATA;
+ final PackageRemovedInfo outInfo = new PackageRemovedInfo(this);
- try (PackageFreezer freezer = freezePackageForDelete(ps.name, deleteFlags,
- "unloadPrivatePackagesInner")) {
- if (deletePackageLIF(ps.name, null, false, null, deleteFlags, outInfo,
- false, null)) {
- unloaded.add(pkg);
- } else {
- Slog.w(TAG, "Failed to unload " + ps.codePath);
+ try (PackageFreezer freezer = freezePackageForDelete(ps.name, deleteFlags,
+ "unloadPrivatePackagesInner")) {
+ if (deletePackageLIF(ps.name, null, false, null, deleteFlags, outInfo,
+ false, null)) {
+ unloaded.add(pkg);
+ } else {
+ Slog.w(TAG, "Failed to unload " + ps.getCodePath());
+ }
}
+
+ // Try very hard to release any references to this package
+ // so we don't risk the system server being killed due to
+ // open FDs
+ AttributeCache.instance().removePackage(ps.name);
}
- // Try very hard to release any references to this package
- // so we don't risk the system server being killed due to
- // open FDs
- AttributeCache.instance().removePackage(ps.name);
+ mSettings.writeLPr();
}
-
- mSettings.writeLPr();
- }
}
if (DEBUG_INSTALL) Slog.d(TAG, "Unloaded packages " + unloaded);
@@ -22726,7 +22730,7 @@
final int packageCount = mSettings.mPackages.size();
for (int i = 0; i < packageCount; i++) {
final PackageSetting ps = mSettings.mPackages.valueAt(i);
- codePaths.add(ps.codePath.getAbsolutePath());
+ codePaths.add(ps.getCodePath().getAbsolutePath());
}
return codePaths;
}
@@ -23643,8 +23647,20 @@
}
}
- void onNewUserCreated(final int userId) {
- mPermissionManager.onNewUserCreated(userId);
+ void onNewUserCreated(@UserIdInt int userId, boolean convertedFromPreCreated) {
+ if (DEBUG_PERMISSIONS) {
+ Slog.d(TAG, "onNewUserCreated(id=" + userId
+ + ", convertedFromPreCreated=" + convertedFromPreCreated + ")");
+ }
+ if (!convertedFromPreCreated) {
+ mPermissionManager.onNewUserCreated(userId);
+ return;
+ }
+ if (!readPermissionStateForUser(userId)) {
+ // Could not read the existing permissions, re-grant them.
+ Slog.i(TAG, "re-granting permissions for pre-created user " + userId);
+ mPermissionManager.onNewUserCreated(userId);
+ }
}
boolean readPermissionStateForUser(@UserIdInt int userId) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 668f375..7aeec6d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -423,13 +423,15 @@
final List<ApplicationInfo> list;
if (packageName == null) {
final ParceledListSlice<ApplicationInfo> packages =
- mInterface.getInstalledApplications(
- PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
+ mInterface.getInstalledApplications(PackageManager.MATCH_SYSTEM_ONLY
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES,
+ UserHandle.USER_SYSTEM);
list = packages.getList();
} else {
list = new ArrayList<>(1);
- list.add(mInterface.getApplicationInfo(packageName,
- PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM));
+ list.add(mInterface.getApplicationInfo(packageName, PackageManager.MATCH_SYSTEM_ONLY
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES,
+ UserHandle.USER_SYSTEM));
}
for (ApplicationInfo info : list) {
if (info.isUpdatedSystemApp()) {
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 432d7f3..a3a7273 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -71,13 +71,13 @@
private PackageStateUnserialized pkgState = new PackageStateUnserialized();
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- public PackageSetting(String name, String realName, File codePath, File resourcePath,
+ public PackageSetting(String name, String realName, @NonNull File codePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString,
long pVersionCode, int pkgFlags, int privateFlags,
int sharedUserId, String[] usesStaticLibraries,
long[] usesStaticLibrariesVersions, Map<String, ArraySet<String>> mimeGroups) {
- super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString,
+ super(name, realName, codePath, legacyNativeLibraryPathString,
primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
pVersionCode, pkgFlags, privateFlags,
usesStaticLibraries, usesStaticLibrariesVersions);
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 834303c..6010344 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -64,10 +64,8 @@
* this is path to single base APK file; for cluster packages this is
* path to the cluster directory.
*/
- File codePath;
- String codePathString;
- File resourcePath;
- String resourcePathString;
+ private File mCodePath;
+ private String mCodePathString;
String[] usesStaticLibraries;
long[] usesStaticLibrariesVersions;
@@ -138,7 +136,7 @@
boolean forceQueryableOverride;
- PackageSettingBase(String name, String realName, File codePath, File resourcePath,
+ PackageSettingBase(String name, String realName, @NonNull File codePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString,
long pVersionCode, int pkgFlags, int pkgPrivateFlags,
@@ -148,10 +146,7 @@
this.realName = realName;
this.usesStaticLibraries = usesStaticLibraries;
this.usesStaticLibrariesVersions = usesStaticLibrariesVersions;
- this.codePath = codePath;
- this.codePathString = codePath.toString();
- this.resourcePath = resourcePath;
- this.resourcePathString = resourcePath.toString();
+ setCodePath(codePath);
this.legacyNativeLibraryPathString = legacyNativeLibraryPathString;
this.primaryCpuAbiString = primaryCpuAbiString;
this.secondaryCpuAbiString = secondaryCpuAbiString;
@@ -235,8 +230,7 @@
}
private void doCopy(PackageSettingBase orig) {
- codePath = orig.codePath;
- codePathString = orig.codePathString;
+ setCodePath(orig.getCodePath());
cpuAbiOverrideString = orig.cpuAbiOverrideString;
firstInstallTime = orig.firstInstallTime;
installPermissionsFixed = orig.installPermissionsFixed;
@@ -246,8 +240,6 @@
legacyNativeLibraryPathString = orig.legacyNativeLibraryPathString;
// Intentionally skip mOldCodePaths; it's not relevant for copies
primaryCpuAbiString = orig.primaryCpuAbiString;
- resourcePath = orig.resourcePath;
- resourcePathString = orig.resourcePathString;
secondaryCpuAbiString = orig.secondaryCpuAbiString;
signatures = orig.signatures;
timeStamp = orig.timeStamp;
@@ -705,6 +697,20 @@
return userState.harmfulAppWarning;
}
+ PackageSettingBase setCodePath(@NonNull File codePath) {
+ this.mCodePath = codePath;
+ this.mCodePathString = codePath.toString();
+ return this;
+ }
+
+ File getCodePath() {
+ return mCodePath;
+ }
+
+ String getCodePathString() {
+ return mCodePathString;
+ }
+
/**
* @see PackageUserState#overrideLabelAndIcon(ComponentName, String, Integer)
*
@@ -727,10 +733,7 @@
protected PackageSettingBase updateFrom(PackageSettingBase other) {
super.copyFrom(other);
- this.codePath = other.codePath;
- this.codePathString = other.codePathString;
- this.resourcePath = other.resourcePath;
- this.resourcePathString = other.resourcePathString;
+ setCodePath(other.getCodePath());
this.usesStaticLibraries = other.usesStaticLibraries;
this.usesStaticLibrariesVersions = other.usesStaticLibrariesVersions;
this.legacyNativeLibraryPathString = other.legacyNativeLibraryPathString;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 1805713..3e3e3c5 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -538,7 +538,7 @@
return null;
}
p.getPkgState().setUpdatedSystemApp(false);
- PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath,
+ PackageSetting ret = addPackageLPw(name, p.realName, p.getCodePath(),
p.legacyNativeLibraryPathString, p.primaryCpuAbiString,
p.secondaryCpuAbiString, p.cpuAbiOverrideString,
p.appId, p.versionCode, p.pkgFlags, p.pkgPrivateFlags,
@@ -558,7 +558,7 @@
mDisabledSysPackages.remove(name);
}
- PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
+ PackageSetting addPackageLPw(String name, String realName, File codePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString, int uid, long vc, int
pkgFlags, int pkgPrivateFlags, String[] usesStaticLibraries,
@@ -572,10 +572,9 @@
"Adding duplicate package, keeping first: " + name);
return null;
}
- p = new PackageSetting(name, realName, codePath, resourcePath,
- legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
- cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags,
- 0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames,
+ p = new PackageSetting(name, realName, codePath, legacyNativeLibraryPathString,
+ primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString, vc, pkgFlags,
+ pkgPrivateFlags, 0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames,
mimeGroups);
p.appId = uid;
if (registerExistingAppIdLPw(uid, p, name)) {
@@ -635,7 +634,7 @@
*/
static @NonNull PackageSetting createNewSetting(String pkgName, PackageSetting originalPkg,
PackageSetting disabledPkg, String realPkgName, SharedUserSetting sharedUser,
- File codePath, File resourcePath, String legacyNativeLibraryPath, String primaryCpuAbi,
+ File codePath, String legacyNativeLibraryPath, String primaryCpuAbi,
String secondaryCpuAbi, long versionCode, int pkgFlags, int pkgPrivateFlags,
UserHandle installUser, boolean allowInstall, boolean instantApp,
boolean virtualPreload, UserManagerService userManager,
@@ -646,12 +645,11 @@
if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "
+ pkgName + " is adopting original package " + originalPkg.name);
pkgSetting = new PackageSetting(originalPkg, pkgName /*realPkgName*/);
- pkgSetting.codePath = codePath;
+ pkgSetting.setCodePath(codePath);
pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath;
pkgSetting.pkgFlags = pkgFlags;
pkgSetting.pkgPrivateFlags = pkgPrivateFlags;
pkgSetting.primaryCpuAbiString = primaryCpuAbi;
- pkgSetting.resourcePath = resourcePath;
pkgSetting.secondaryCpuAbiString = secondaryCpuAbi;
// NOTE: Create a deeper copy of the package signatures so we don't
// overwrite the signatures in the original package setting.
@@ -662,7 +660,7 @@
// Update new package state.
pkgSetting.setTimeStamp(codePath.lastModified());
} else {
- pkgSetting = new PackageSetting(pkgName, realPkgName, codePath, resourcePath,
+ pkgSetting = new PackageSetting(pkgName, realPkgName, codePath,
legacyNativeLibraryPath, primaryCpuAbi, secondaryCpuAbi,
null /*cpuAbiOverrideString*/, versionCode, pkgFlags, pkgPrivateFlags,
0 /*sharedUserId*/, usesStaticLibraries,
@@ -756,10 +754,9 @@
*/
static void updatePackageSetting(@NonNull PackageSetting pkgSetting,
@Nullable PackageSetting disabledPkg, @Nullable SharedUserSetting sharedUser,
- @NonNull File codePath, File resourcePath,
- @Nullable String legacyNativeLibraryPath, @Nullable String primaryCpuAbi,
- @Nullable String secondaryCpuAbi, int pkgFlags, int pkgPrivateFlags,
- @NonNull UserManagerService userManager,
+ @NonNull File codePath, @Nullable String legacyNativeLibraryPath,
+ @Nullable String primaryCpuAbi, @Nullable String secondaryCpuAbi, int pkgFlags,
+ int pkgPrivateFlags, @NonNull UserManagerService userManager,
@Nullable String[] usesStaticLibraries, @Nullable long[] usesStaticLibrariesVersions,
@Nullable Set<String> mimeGroupNames)
throws PackageManagerException {
@@ -773,12 +770,12 @@
"Updating application package " + pkgName + " failed");
}
- if (!pkgSetting.codePath.equals(codePath)) {
+ if (!pkgSetting.getCodePath().equals(codePath)) {
final boolean isSystem = pkgSetting.isSystem();
Slog.i(PackageManagerService.TAG,
"Update" + (isSystem ? " system" : "")
+ " package " + pkgName
- + " code path from " + pkgSetting.codePathString
+ + " code path from " + pkgSetting.getCodePathString()
+ " to " + codePath.toString()
+ "; Retain data and using new");
if (!isSystem) {
@@ -800,19 +797,7 @@
// internal to external storage or vice versa.
pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath;
}
- pkgSetting.codePath = codePath;
- pkgSetting.codePathString = codePath.toString();
- }
- if (!pkgSetting.resourcePath.equals(resourcePath)) {
- final boolean isSystem = pkgSetting.isSystem();
- Slog.i(PackageManagerService.TAG,
- "Update" + (isSystem ? " system" : "")
- + " package " + pkgName
- + " resource path from " + pkgSetting.resourcePathString
- + " to " + resourcePath.toString()
- + "; Retain data and using new");
- pkgSetting.resourcePath = resourcePath;
- pkgSetting.resourcePathString = resourcePath.toString();
+ pkgSetting.setCodePath(codePath);
}
// If what we are scanning is a system (and possibly privileged) package,
// then make it so, regardless of whether it was previously installed only
@@ -2710,7 +2695,7 @@
private void writePackageListLPrInternal(int creatingUserId) {
// Only derive GIDs for active users (not dying)
- final List<UserInfo> users = getUsers(UserManagerService.getInstance(), true);
+ final List<UserInfo> users = getActiveUsers(UserManagerService.getInstance(), true);
int[] userIds = new int[users.size()];
for (int i = 0; i < userIds.length; i++) {
userIds[i] = users.get(i).id;
@@ -2812,14 +2797,11 @@
if (pkg.realName != null) {
serializer.attribute(null, "realName", pkg.realName);
}
- serializer.attribute(null, "codePath", pkg.codePathString);
+ serializer.attribute(null, "codePath", pkg.getCodePathString());
serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));
serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
- if (!pkg.resourcePathString.equals(pkg.codePathString)) {
- serializer.attribute(null, "resourcePath", pkg.resourcePathString);
- }
if (pkg.legacyNativeLibraryPathString != null) {
serializer.attribute(null, "nativeLibraryPath", pkg.legacyNativeLibraryPathString);
}
@@ -2857,10 +2839,7 @@
if (pkg.realName != null) {
serializer.attribute(null, "realName", pkg.realName);
}
- serializer.attribute(null, "codePath", pkg.codePathString);
- if (!pkg.resourcePathString.equals(pkg.codePathString)) {
- serializer.attribute(null, "resourcePath", pkg.resourcePathString);
- }
+ serializer.attribute(null, "codePath", pkg.getCodePathString());
if (pkg.legacyNativeLibraryPathString != null) {
serializer.attribute(null, "nativeLibraryPath", pkg.legacyNativeLibraryPathString);
@@ -3559,13 +3538,10 @@
String name = parser.getAttributeValue(null, ATTR_NAME);
String realName = parser.getAttributeValue(null, "realName");
String codePathStr = parser.getAttributeValue(null, "codePath");
- String resourcePathStr = parser.getAttributeValue(null, "resourcePath");
String legacyCpuAbiStr = parser.getAttributeValue(null, "requiredCpuAbi");
String legacyNativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
- String parentPackageName = parser.getAttributeValue(null, "parentPackageName");
-
String primaryCpuAbiStr = parser.getAttributeValue(null, "primaryCpuAbi");
String secondaryCpuAbiStr = parser.getAttributeValue(null, "secondaryCpuAbi");
String cpuAbiOverrideStr = parser.getAttributeValue(null, "cpuAbiOverride");
@@ -3574,9 +3550,6 @@
primaryCpuAbiStr = legacyCpuAbiStr;
}
- if (resourcePathStr == null) {
- resourcePathStr = codePathStr;
- }
String version = parser.getAttributeValue(null, "version");
long versionCode = 0;
if (version != null) {
@@ -3593,9 +3566,8 @@
pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
PackageSetting ps = new PackageSetting(name, realName, new File(codePathStr),
- new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiStr,
- secondaryCpuAbiStr, cpuAbiOverrideStr, versionCode, pkgFlags, pkgPrivateFlags,
- 0 /*sharedUserId*/, null, null, null);
+ legacyNativeLibraryPathStr, primaryCpuAbiStr, secondaryCpuAbiStr, cpuAbiOverrideStr,
+ versionCode, pkgFlags, pkgPrivateFlags, 0 /*sharedUserId*/, null, null, null);
String timeStampStr = parser.getAttributeValue(null, "ft");
if (timeStampStr != null) {
try {
@@ -3666,7 +3638,6 @@
String idStr = null;
String sharedIdStr = null;
String codePathStr = null;
- String resourcePathStr = null;
String legacyCpuAbiString = null;
String legacyNativeLibraryPathStr = null;
String primaryCpuAbiString = null;
@@ -3700,7 +3671,6 @@
uidError = parser.getAttributeValue(null, "uidError");
sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
codePathStr = parser.getAttributeValue(null, "codePath");
- resourcePathStr = parser.getAttributeValue(null, "resourcePath");
legacyCpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi");
@@ -3818,9 +3788,6 @@
+ " sharedUserId=" + sharedIdStr);
final int userId = idStr != null ? Integer.parseInt(idStr) : 0;
final int sharedUserId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
- if (resourcePathStr == null) {
- resourcePathStr = codePathStr;
- }
if (realName != null) {
realName = realName.intern();
}
@@ -3834,10 +3801,10 @@
+ parser.getPositionDescription());
} else if (userId > 0) {
packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
- new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString,
- secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags,
- pkgPrivateFlags, null /*usesStaticLibraries*/,
- null /*usesStaticLibraryVersions*/, null /*mimeGroups*/);
+ legacyNativeLibraryPathStr, primaryCpuAbiString, secondaryCpuAbiString,
+ cpuAbiOverrideString, userId, versionCode, pkgFlags, pkgPrivateFlags,
+ null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/,
+ null /*mimeGroups*/);
if (PackageManagerService.DEBUG_SETTINGS)
Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId="
+ userId + " pkg=" + packageSetting);
@@ -3852,8 +3819,8 @@
}
} else if (sharedIdStr != null) {
if (sharedUserId > 0) {
- packageSetting = new PackageSetting(name.intern(), realName, new File(
- codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr,
+ packageSetting = new PackageSetting(name.intern(), realName,
+ new File(codePathStr), legacyNativeLibraryPathStr,
primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
versionCode, pkgFlags, pkgPrivateFlags, sharedUserId,
null /*usesStaticLibraries*/,
@@ -4456,25 +4423,43 @@
}
/**
- * Return all users on the device, including partial or dying users.
+ * Returns all users on the device, including pre-created and dying users.
+ *
* @param userManager UserManagerService instance
* @return the list of users
*/
private static List<UserInfo> getAllUsers(UserManagerService userManager) {
- return getUsers(userManager, false);
+ return getUsers(userManager, /* excludeDying= */ false, /* excludePreCreated= */ false);
}
/**
- * Return the list of users on the device. Clear the calling identity before calling into
- * UserManagerService.
+ * Returns the list of users on the device, excluding pre-created ones.
+ *
* @param userManager UserManagerService instance
* @param excludeDying Indicates whether to exclude any users marked for deletion.
+ *
* @return the list of users
*/
- private static List<UserInfo> getUsers(UserManagerService userManager, boolean excludeDying) {
+ private static List<UserInfo> getActiveUsers(UserManagerService userManager,
+ boolean excludeDying) {
+ return getUsers(userManager, excludeDying, /* excludePreCreated= */ true);
+ }
+
+ /**
+ * Returns the list of users on the device.
+ *
+ * @param userManager UserManagerService instance
+ * @param excludeDying Indicates whether to exclude any users marked for deletion.
+ * @param excludePreCreated Indicates whether to exclude any pre-created users.
+ *
+ * @return the list of users
+ */
+ private static List<UserInfo> getUsers(UserManagerService userManager, boolean excludeDying,
+ boolean excludePreCreated) {
long id = Binder.clearCallingIdentity();
try {
- return userManager.getUsers(excludeDying);
+ return userManager.getUsers(/* excludePartial= */ true, excludeDying,
+ excludePreCreated);
} catch (NullPointerException npe) {
// packagemanager not yet initialized
} finally {
@@ -4657,9 +4642,9 @@
pw.print(prefix); pw.print(" sharedUser="); pw.println(ps.sharedUser);
}
pw.print(prefix); pw.print(" pkg="); pw.println(pkg);
- pw.print(prefix); pw.print(" codePath="); pw.println(ps.codePathString);
+ pw.print(prefix); pw.print(" codePath="); pw.println(ps.getCodePathString());
if (permissionNames == null) {
- pw.print(prefix); pw.print(" resourcePath="); pw.println(ps.resourcePathString);
+ pw.print(prefix); pw.print(" resourcePath="); pw.println(ps.getCodePathString());
pw.print(prefix); pw.print(" legacyNativeLibraryDir=");
pw.println(ps.legacyNativeLibraryPathString);
pw.print(prefix); pw.print(" primaryCpuAbi="); pw.println(ps.primaryCpuAbiString);
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 89ed3c7..700f7be 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -260,7 +260,8 @@
private static final int PACKAGE_MATCH_FLAGS =
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_UNINSTALLED_PACKAGES;
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_COMPONENTS;
private static final int SYSTEM_APP_MASK =
ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
@@ -278,12 +279,6 @@
}
};
- private static Predicate<ResolveInfo> ACTIVITY_NOT_SYSTEM_NOR_ENABLED = (ri) -> {
- final ApplicationInfo ai = ri.activityInfo.applicationInfo;
- final boolean isSystemApp = ai != null && (ai.flags & SYSTEM_APP_MASK) != 0;
- return !isSystemApp && !ri.activityInfo.enabled;
- };
-
private static Predicate<ResolveInfo> ACTIVITY_NOT_INSTALLED = (ri) ->
!isInstalled(ri.activityInfo);
@@ -3685,10 +3680,8 @@
final long start = getStatStartTime();
final long token = injectClearCallingIdentity();
try {
- return mIPackageManager.getPackageInfo(
- packageName, PACKAGE_MATCH_FLAGS | PackageManager.MATCH_DISABLED_COMPONENTS
- | (getSignatures ? PackageManager.GET_SIGNING_CERTIFICATES : 0),
- userId);
+ return mIPackageManager.getPackageInfo(packageName, PACKAGE_MATCH_FLAGS
+ | (getSignatures ? PackageManager.GET_SIGNING_CERTIFICATES : 0), userId);
} catch (RemoteException e) {
// Shouldn't happen.
Slog.wtf(TAG, "RemoteException", e);
@@ -3721,8 +3714,7 @@
final long start = getStatStartTime();
final long token = injectClearCallingIdentity();
try {
- return mIPackageManager.getApplicationInfo(packageName,
- PACKAGE_MATCH_FLAGS | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
+ return mIPackageManager.getApplicationInfo(packageName, PACKAGE_MATCH_FLAGS, userId);
} catch (RemoteException e) {
// Shouldn't happen.
Slog.wtf(TAG, "RemoteException", e);
@@ -3753,9 +3745,8 @@
final long start = getStatStartTime();
final long token = injectClearCallingIdentity();
try {
- return mIPackageManager.getActivityInfo(activity, (PACKAGE_MATCH_FLAGS
- | PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.GET_META_DATA),
- userId);
+ return mIPackageManager.getActivityInfo(activity,
+ PACKAGE_MATCH_FLAGS | PackageManager.GET_META_DATA, userId);
} catch (RemoteException e) {
// Shouldn't happen.
Slog.wtf(TAG, "RemoteException", e);
@@ -3800,8 +3791,7 @@
List<PackageInfo> injectGetPackagesWithUninstalled(@UserIdInt int userId)
throws RemoteException {
final ParceledListSlice<PackageInfo> parceledList =
- mIPackageManager.getInstalledPackages(
- PACKAGE_MATCH_FLAGS | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
+ mIPackageManager.getInstalledPackages(PACKAGE_MATCH_FLAGS, userId);
if (parceledList == null) {
return Collections.emptyList();
}
@@ -3836,6 +3826,41 @@
return (ai != null) && ((ai.flags & flags) == flags);
}
+ // Due to b/38267327, ActivityInfo.enabled may not reflect the current state of the component
+ // and we need to check the enabled state via PackageManager.getComponentEnabledSetting.
+ private boolean isEnabled(@Nullable ActivityInfo ai, int userId) {
+ if (ai == null) {
+ return false;
+ }
+
+ int enabledFlag;
+ final long token = injectClearCallingIdentity();
+ try {
+ enabledFlag = mIPackageManager.getComponentEnabledSetting(
+ ai.getComponentName(), userId);
+ } catch (RemoteException e) {
+ // Shouldn't happen.
+ Slog.wtf(TAG, "RemoteException", e);
+ return false;
+ } finally {
+ injectRestoreCallingIdentity(token);
+ }
+
+ if ((enabledFlag == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT && ai.enabled)
+ || enabledFlag == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+ return true;
+ }
+ return false;
+ }
+
+ private static boolean isSystem(@Nullable ActivityInfo ai) {
+ return (ai != null) && isSystem(ai.applicationInfo);
+ }
+
+ private static boolean isSystem(@Nullable ApplicationInfo ai) {
+ return (ai != null) && (ai.flags & SYSTEM_APP_MASK) != 0;
+ }
+
private static boolean isInstalled(@Nullable ApplicationInfo ai) {
return (ai != null) && ai.enabled && (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
}
@@ -3900,12 +3925,6 @@
return intent;
}
- private static boolean isSystemApp(@Nullable final ApplicationInfo ai) {
- final int systemAppMask =
- ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
- return ai != null && ((ai.flags & systemAppMask) != 0);
- }
-
/**
* Same as queryIntentActivitiesAsUser, except it makes sure the package is installed,
* and only returns exported activities.
@@ -3938,7 +3957,10 @@
}
// Make sure the package is installed.
resolved.removeIf(ACTIVITY_NOT_INSTALLED);
- resolved.removeIf(ACTIVITY_NOT_SYSTEM_NOR_ENABLED);
+ resolved.removeIf((ri) -> {
+ final ActivityInfo ai = ri.activityInfo;
+ return !isSystem(ai) && !isEnabled(ai, userId);
+ });
if (exportedOnly) {
resolved.removeIf(ACTIVITY_NOT_EXPORTED);
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 89bdb3e..f9bf54a 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -322,9 +322,6 @@
}
final long activeVersion = activePackage.applicationInfo.longVersionCode;
if (activeVersion != session.params.requiredInstalledVersionCode) {
- if (!mApexManager.abortStagedSession(session.sessionId)) {
- Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
- }
throw new PackageManagerException(
SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
"Installed version of APEX package " + activePackage.packageName
@@ -338,14 +335,11 @@
throws PackageManagerException {
final long activeVersion = activePackage.applicationInfo.longVersionCode;
final long newVersionCode = newPackage.applicationInfo.longVersionCode;
- boolean isAppDebuggable = (activePackage.applicationInfo.flags
+ final boolean isAppDebuggable = (activePackage.applicationInfo.flags
& ApplicationInfo.FLAG_DEBUGGABLE) != 0;
final boolean allowsDowngrade = PackageManagerServiceUtils.isDowngradePermitted(
session.params.installFlags, isAppDebuggable);
if (activeVersion > newVersionCode && !allowsDowngrade) {
- if (!mApexManager.abortStagedSession(session.sessionId)) {
- Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
- }
throw new PackageManagerException(
SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
"Downgrade of APEX package " + newPackage.packageName
@@ -835,37 +829,6 @@
return null;
}
- 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) -> {
- 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 + "]");
- session.setStagedSessionFailed(
- SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, errorMessage);
- mPreRebootVerificationHandler.onPreRebootVerificationComplete(
- session.sessionId);
- return;
- }
- mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete(
- session.sessionId);
- });
-
- apksToVerify.commit(receiver.getIntentSender(), false);
- }
-
private void installApksInSession(@NonNull PackageInstallerSession session)
throws PackageManagerException {
@@ -908,10 +871,21 @@
mPreRebootVerificationHandler.startPreRebootVerification(session.sessionId);
}
- private int parentOrOwnSessionId(PackageInstallerSession session) {
+ private int getSessionIdForParentOrSelf(PackageInstallerSession session) {
return session.hasParentSessionId() ? session.getParentSessionId() : session.sessionId;
}
+ private PackageInstallerSession getParentSessionOrSelf(PackageInstallerSession session) {
+ return session.hasParentSessionId()
+ ? getStagedSession(session.getParentSessionId())
+ : session;
+ }
+
+ private boolean isRollback(PackageInstallerSession session) {
+ final PackageInstallerSession root = getParentSessionOrSelf(session);
+ return root.params.installReason == PackageManager.INSTALL_REASON_ROLLBACK;
+ }
+
/**
* <p> Check if the session provided is non-overlapping with the active staged sessions.
*
@@ -937,6 +911,8 @@
boolean supportsCheckpoint = ((StorageManager) mContext.getSystemService(
Context.STORAGE_SERVICE)).isCheckpointSupported();
+ final boolean isRollback = isRollback(session);
+
synchronized (mStagedSessions) {
for (int i = 0; i < mStagedSessions.size(); i++) {
final PackageInstallerSession stagedSession = mStagedSessions.valueAt(i);
@@ -951,8 +927,8 @@
}
// Check if stagedSession has an active parent session or not
if (stagedSession.hasParentSessionId()) {
- int parentId = stagedSession.getParentSessionId();
- PackageInstallerSession parentSession = mStagedSessions.get(parentId);
+ final int parentId = stagedSession.getParentSessionId();
+ final PackageInstallerSession parentSession = mStagedSessions.get(parentId);
if (parentSession == null || parentSession.isStagedAndInTerminalState()
|| parentSession.isDestroyed()) {
// Parent session has been abandoned or terminated already
@@ -968,21 +944,37 @@
continue;
}
- // If session is not among the active sessions, then it cannot have same package
- // name as any of the active sessions.
+ // New session cannot have same package name as one of the active sessions
if (session.getPackageName().equals(stagedSession.getPackageName())) {
- throw new PackageManagerException(
- PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
- "Package: " + session.getPackageName() + " in session: "
- + session.sessionId + " has been staged already by session: "
- + stagedSession.sessionId, null);
+ if (isRollback) {
+ // If the new session is a rollback, then it gets priority. The existing
+ // session is failed to unblock rollback.
+ final PackageInstallerSession root = getParentSessionOrSelf(stagedSession);
+ if (!ensureActiveApexSessionIsAborted(root)) {
+ Slog.e(TAG, "Failed to abort apex session " + root.sessionId);
+ // Safe to ignore active apex session abort failure since session
+ // will be marked failed on next step and staging directory for session
+ // will be deleted.
+ }
+ root.setStagedSessionFailed(
+ SessionInfo.STAGED_SESSION_OTHER_ERROR,
+ "Session was blocking rollback session: " + session.sessionId);
+ Slog.i(TAG, "Session " + root.sessionId + " is marked failed due to "
+ + "blocking rollback session: " + session.sessionId);
+ } else {
+ throw new PackageManagerException(
+ PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
+ "Package: " + session.getPackageName() + " in session: "
+ + session.sessionId + " has been staged already by session:"
+ + " " + stagedSession.sessionId, null);
+ }
}
// Staging multiple root sessions is not allowed if device doesn't support
// checkpoint. If session and stagedSession do not have common ancestor, they are
// from two different root sessions.
- if (!supportsCheckpoint
- && parentOrOwnSessionId(session) != parentOrOwnSessionId(stagedSession)) {
+ if (!supportsCheckpoint && getSessionIdForParentOrSelf(session)
+ != getSessionIdForParentOrSelf(stagedSession)) {
throw new PackageManagerException(
PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
"Cannot stage multiple sessions without checkpoint support", null);
@@ -1042,23 +1034,11 @@
// A session could be marked ready once its pre-reboot verification ends
if (session.isStagedSessionReady()) {
- if (sessionContainsApex(session)) {
- try {
- ApexSessionInfo apexSession =
- mApexManager.getStagedSessionInfo(session.sessionId);
- if (apexSession == null || isApexSessionFinalized(apexSession)) {
- Slog.w(TAG,
- "Cannot abort session " + session.sessionId
- + " because it is not active.");
- } else {
- mApexManager.abortStagedSession(session.sessionId);
- }
- } catch (Exception e) {
- // Failed to contact apexd service. The apex might still be staged. We can still
- // safely cleanup the staged session since pre-reboot verification is complete.
- // Also, cleaning up the stageDir prevents the apex from being activated.
- Slog.w(TAG, "Could not contact apexd to abort staged session " + sessionId);
- }
+ if (!ensureActiveApexSessionIsAborted(session)) {
+ // Failed to ensure apex session is aborted, so it can still be staged. We can still
+ // safely cleanup the staged session since pre-reboot verification is complete.
+ // Also, cleaning up the stageDir prevents the apex from being activated.
+ Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
}
}
@@ -1068,6 +1048,22 @@
return true;
}
+ /**
+ * Ensure that there is no active apex session staged in apexd for the given session.
+ *
+ * @return returns true if it is ensured that there is no active apex session, otherwise false
+ */
+ private boolean ensureActiveApexSessionIsAborted(PackageInstallerSession session) {
+ if (!sessionContainsApex(session)) {
+ return true;
+ }
+ final ApexSessionInfo apexSession = mApexManager.getStagedSessionInfo(session.sessionId);
+ if (apexSession == null || isApexSessionFinalized(apexSession)) {
+ return true;
+ }
+ return mApexManager.abortStagedSession(session.sessionId);
+ }
+
private boolean isApexSessionFinalized(ApexSessionInfo session) {
/* checking if the session is in a final state, i.e., not active anymore */
return session.isUnknown || session.isActivationFailed || session.isSuccess
@@ -1294,8 +1290,8 @@
+ sessionId);
return;
}
- if (session.isDestroyed()) {
- // No point in running verification on a destroyed session
+ if (session.isDestroyed() || session.isStagedSessionFailed()) {
+ // No point in running verification on a destroyed/failed session
onPreRebootVerificationComplete(sessionId);
return;
}
@@ -1348,6 +1344,17 @@
obtainMessage(MSG_PRE_REBOOT_VERIFICATION_START, sessionId, 0).sendToTarget();
}
+ private void onPreRebootVerificationFailure(PackageInstallerSession session,
+ @SessionInfo.StagedSessionErrorCode int errorCode, String errorMessage) {
+ if (!ensureActiveApexSessionIsAborted(session)) {
+ Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
+ // Safe to ignore active apex session abortion failure since session will be marked
+ // failed on next step and staging directory for session will be deleted.
+ }
+ session.setStagedSessionFailed(errorCode, errorMessage);
+ onPreRebootVerificationComplete(session.sessionId);
+ }
+
// Things to do when pre-reboot verification completes for a particular sessionId
private void onPreRebootVerificationComplete(int sessionId) {
// Remove it from mVerificationRunning so that verification is considered complete
@@ -1432,8 +1439,7 @@
validateApexSignature(apexPackages.get(i));
}
} catch (PackageManagerException e) {
- session.setStagedSessionFailed(e.error, e.getMessage());
- onPreRebootVerificationComplete(session.sessionId);
+ onPreRebootVerificationFailure(session, e.error, e.getMessage());
return;
}
@@ -1460,16 +1466,42 @@
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);
- // TODO(b/118865310): abort the session on apexd.
} catch (PackageManagerException e) {
- session.setStagedSessionFailed(e.error, e.getMessage());
- onPreRebootVerificationComplete(session.sessionId);
+ 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);
+ }
+
/**
* Pre-reboot verification state for wrapping up:
* <p><ul>
@@ -1487,9 +1519,8 @@
} catch (Exception e) {
// Failed to get hold of StorageManager
Slog.e(TAG, "Failed to get hold of StorageManager", e);
- session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_UNKNOWN,
+ onPreRebootVerificationFailure(session, SessionInfo.STAGED_SESSION_UNKNOWN,
"Failed to get hold of StorageManager");
- onPreRebootVerificationComplete(session.sessionId);
return;
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 8f11fd5..e3bee72 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -3497,7 +3497,7 @@
}
t.traceBegin("PM.onNewUserCreated-" + userId);
- mPm.onNewUserCreated(userId);
+ mPm.onNewUserCreated(userId, /* convertedFromPreCreated= */ false);
t.traceEnd();
if (preCreate) {
// Must start user (which will be stopped right away, through
@@ -3570,10 +3570,7 @@
writeUserListLP();
}
updateUserIds();
- if (!mPm.readPermissionStateForUser(preCreatedUser.id)) {
- // Could not read the existing permissions, re-grant them.
- mPm.onNewUserCreated(preCreatedUser.id);
- }
+ mPm.onNewUserCreated(preCreatedUser.id, /* convertedFromPreCreated= */ true);
dispatchUserAdded(preCreatedUser);
return preCreatedUser;
}
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 6e0efb0..be93b8f 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -137,7 +137,6 @@
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.Watchdog;
-import com.android.server.am.ActivityManagerService;
import com.android.server.pm.ApexManager;
import com.android.server.pm.PackageManagerServiceUtils;
import com.android.server.pm.PackageSetting;
@@ -922,16 +921,6 @@
}
final int uid = UserHandle.getUid(userId, pkg.getUid());
-
- try {
- enforceCrossUserOrProfilePermission(Binder.getCallingUid(), UserHandle.getUserId(uid),
- false, false, "checkPermissionInternal");
- } catch (Exception e) {
- EventLog.writeEvent(0x534e4554, "153996875", "checkPermission", uid);
-
- throw e;
- }
-
final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
pkg.getPackageName());
if (ps == null) {
@@ -4399,7 +4388,7 @@
}
final int callingUserId = UserHandle.getUserId(callingUid);
if (hasCrossUserPermission(
- Binder.getCallingPid(), callingUid, callingUserId, userId, requireFullPermission,
+ callingUid, callingUserId, userId, requireFullPermission,
requirePermissionWhenSameUser)) {
return;
}
@@ -4426,54 +4415,37 @@
private void enforceCrossUserOrProfilePermission(int callingUid, int userId,
boolean requireFullPermission, boolean checkShell,
String message) {
- int callingPid = Binder.getCallingPid();
- final int callingUserId = UserHandle.getUserId(callingUid);
-
if (userId < 0) {
throw new IllegalArgumentException("Invalid userId " + userId);
}
-
- if (callingUserId == userId) {
+ if (checkShell) {
+ PackageManagerServiceUtils.enforceShellRestriction(mUserManagerInt,
+ UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
+ }
+ final int callingUserId = UserHandle.getUserId(callingUid);
+ if (hasCrossUserPermission(callingUid, callingUserId, userId, requireFullPermission,
+ /*requirePermissionWhenSameUser= */ false)) {
return;
}
-
- // Prevent endless loop between when checking permission while checking a permission
- if (callingPid == ActivityManagerService.MY_PID) {
+ final boolean isSameProfileGroup = isSameProfileGroup(callingUserId, userId);
+ if (isSameProfileGroup && PermissionChecker.checkPermissionForPreflight(
+ mContext,
+ android.Manifest.permission.INTERACT_ACROSS_PROFILES,
+ PermissionChecker.PID_UNKNOWN,
+ callingUid,
+ mPackageManagerInt.getPackage(callingUid).getPackageName())
+ == PermissionChecker.PERMISSION_GRANTED) {
return;
}
-
- long token = Binder.clearCallingIdentity();
- try {
- if (checkShell) {
- PackageManagerServiceUtils.enforceShellRestriction(mUserManagerInt,
- UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
- }
- if (hasCrossUserPermission(callingPid, callingUid, callingUserId, userId,
- requireFullPermission, /*requirePermissionWhenSameUser= */ false)) {
- return;
- }
- final boolean isSameProfileGroup = isSameProfileGroup(callingUserId, userId);
- if (isSameProfileGroup && PermissionChecker.checkPermissionForPreflight(
- mContext,
- android.Manifest.permission.INTERACT_ACROSS_PROFILES,
- PermissionChecker.PID_UNKNOWN,
- callingUid,
- mPackageManagerInt.getPackage(callingUid).getPackageName())
- == PermissionChecker.PERMISSION_GRANTED) {
- return;
- }
-
- String errorMessage = buildInvalidCrossUserOrProfilePermissionMessage(
- message, requireFullPermission, isSameProfileGroup);
- Slog.w(TAG, errorMessage);
- throw new SecurityException(errorMessage);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ String errorMessage = buildInvalidCrossUserOrProfilePermissionMessage(
+ message, requireFullPermission, isSameProfileGroup);
+ Slog.w(TAG, errorMessage);
+ throw new SecurityException(errorMessage);
}
- private boolean hasCrossUserPermission(int callingPid, int callingUid, int callingUserId,
- int userId, boolean requireFullPermission, boolean requirePermissionWhenSameUser) {
+ private boolean hasCrossUserPermission(
+ int callingUid, int callingUserId, int userId, boolean requireFullPermission,
+ boolean requirePermissionWhenSameUser) {
if (!requirePermissionWhenSameUser && userId == callingUserId) {
return true;
}
@@ -4481,11 +4453,15 @@
return true;
}
if (requireFullPermission) {
- return mContext.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
+ return hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL);
}
- return mContext.checkPermission(android.Manifest.permission.INTERACT_ACROSS_USERS,
- callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
+ return hasPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ || hasPermission(Manifest.permission.INTERACT_ACROSS_USERS);
+ }
+
+ private boolean hasPermission(String permission) {
+ return mContext.checkCallingOrSelfPermission(permission)
+ == PackageManager.PERMISSION_GRANTED;
}
private boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) {
diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
index 65dc320..c0d71ac 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -18,6 +18,14 @@
]
},
{
+ "name": "CtsAppSecurityHostTestCases",
+ "options": [
+ {
+ "include-filter": "android.appsecurity.cts.AppSecurityTests#rebootWithDuplicatePermission"
+ }
+ ]
+ },
+ {
"name": "CtsPermission2TestCases",
"options": [
{
@@ -29,17 +37,6 @@
]
},
{
- "name": "CtsPermissionHostTestCases"
- },
- {
- "name": "CtsAppSecurityHostTestCases",
- "options": [
- {
- "include-filter": "android.appsecurity.cts.AppSecurityTests#rebootWithDuplicatePermission"
- }
- ]
- },
- {
"name": "CtsStatsdHostTestCases",
"options": [
{
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index 3ec61fd..7467439 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -18,7 +18,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UserIdInt;
import android.app.timezonedetector.ITimeZoneConfigurationListener;
import android.app.timezonedetector.ITimeZoneDetectorService;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
@@ -38,6 +37,7 @@
import android.provider.Settings;
import android.util.IndentingPrintWriter;
import android.util.Slog;
+import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -60,7 +60,8 @@
* and making calls async, leaving the (consequently more testable) {@link TimeZoneDetectorStrategy}
* implementation to deal with the logic around time zone detection.
*/
-public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub {
+public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
+ implements IBinder.DeathRecipient {
private static final String TAG = "TimeZoneDetectorService";
@@ -104,9 +105,15 @@
@NonNull
private final TimeZoneDetectorStrategy mTimeZoneDetectorStrategy;
+ /**
+ * This sparse array acts as a map from userId to listeners running as that userId. User scoped
+ * as time zone detection configuration is partially user-specific, so different users can
+ * get different configuration.
+ */
@GuardedBy("mConfigurationListeners")
@NonNull
- private final ArrayList<ConfigListenerInfo> mConfigurationListeners = new ArrayList<>();
+ private final SparseArray<ArrayList<ITimeZoneConfigurationListener>> mConfigurationListeners =
+ new SparseArray<>();
private static TimeZoneDetectorService create(
@NonNull Context context, @NonNull Handler handler,
@@ -188,18 +195,23 @@
Objects.requireNonNull(listener);
int userId = UserHandle.getCallingUserId();
- ConfigListenerInfo listenerInfo = new ConfigListenerInfo(userId, listener);
-
synchronized (mConfigurationListeners) {
- if (mConfigurationListeners.contains(listenerInfo)) {
+ ArrayList<ITimeZoneConfigurationListener> listeners =
+ mConfigurationListeners.get(userId);
+ if (listeners != null && listeners.contains(listener)) {
return;
}
try {
- // Ensure the reference to the listener is removed if the client process dies.
- listenerInfo.linkToDeath();
+ if (listeners == null) {
+ listeners = new ArrayList<>(1);
+ mConfigurationListeners.put(userId, listeners);
+ }
+
+ // Ensure the reference to the listener will be removed if the client process dies.
+ listener.asBinder().linkToDeath(this, 0 /* flags */);
// Only add the listener if we can linkToDeath().
- mConfigurationListeners.add(listenerInfo);
+ listeners.add(listener);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to linkToDeath() for listener=" + listener, e);
}
@@ -213,21 +225,56 @@
int userId = UserHandle.getCallingUserId();
synchronized (mConfigurationListeners) {
- ConfigListenerInfo toRemove = new ConfigListenerInfo(userId, listener);
- Iterator<ConfigListenerInfo> listenerIterator = mConfigurationListeners.iterator();
- while (listenerIterator.hasNext()) {
- ConfigListenerInfo currentListenerInfo = listenerIterator.next();
- if (currentListenerInfo.equals(toRemove)) {
- listenerIterator.remove();
+ boolean removedListener = false;
+ ArrayList<ITimeZoneConfigurationListener> userListeners =
+ mConfigurationListeners.get(userId);
+ if (userListeners.remove(listener)) {
+ // Stop listening for the client process to die.
+ listener.asBinder().unlinkToDeath(this, 0 /* flags */);
+ removedListener = true;
+ }
+ if (!removedListener) {
+ Slog.w(TAG, "Client asked to remove listenener=" + listener
+ + ", but no listeners were removed."
+ + " mConfigurationListeners=" + mConfigurationListeners);
+ }
+ }
+ }
- // Stop listening for the client process to die.
- try {
- currentListenerInfo.unlinkToDeath();
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to unlinkToDeath() for listener=" + listener, e);
+ @Override
+ public void binderDied() {
+ // Should not be used as binderDied(IBinder who) is overridden.
+ Slog.wtf(TAG, "binderDied() called unexpectedly.");
+ }
+
+ /**
+ * Called when one of the ITimeZoneConfigurationListener processes dies before calling
+ * {@link #removeConfigurationListener(ITimeZoneConfigurationListener)}.
+ */
+ @Override
+ public void binderDied(IBinder who) {
+ synchronized (mConfigurationListeners) {
+ boolean removedListener = false;
+ final int userCount = mConfigurationListeners.size();
+ for (int i = 0; i < userCount; i++) {
+ ArrayList<ITimeZoneConfigurationListener> userListeners =
+ mConfigurationListeners.valueAt(i);
+ Iterator<ITimeZoneConfigurationListener> userListenerIterator =
+ userListeners.iterator();
+ while (userListenerIterator.hasNext()) {
+ ITimeZoneConfigurationListener userListener = userListenerIterator.next();
+ if (userListener.asBinder().equals(who)) {
+ userListenerIterator.remove();
+ removedListener = true;
+ break;
}
}
}
+ if (!removedListener) {
+ Slog.w(TAG, "Notified of binder death for who=" + who
+ + ", but did not remove any listeners."
+ + " mConfigurationListeners=" + mConfigurationListeners);
+ }
}
}
@@ -243,14 +290,24 @@
// problem.
synchronized (mConfigurationListeners) {
- for (ConfigListenerInfo listenerInfo : mConfigurationListeners) {
+ final int userCount = mConfigurationListeners.size();
+ for (int userIndex = 0; userIndex < userCount; userIndex++) {
+ int userId = mConfigurationListeners.keyAt(userIndex);
TimeZoneConfiguration configuration =
- mTimeZoneDetectorStrategy.getConfiguration(listenerInfo.getUserId());
- try {
- listenerInfo.getListener().onChange(configuration);
- } catch (RemoteException e) {
- Slog.w(TAG, "Unable to notify listener="
- + listenerInfo + " of updated configuration=" + configuration, e);
+ mTimeZoneDetectorStrategy.getConfiguration(userId);
+
+ ArrayList<ITimeZoneConfigurationListener> listeners =
+ mConfigurationListeners.valueAt(userIndex);
+ final int listenerCount = listeners.size();
+ for (int listenerIndex = 0; listenerIndex < listenerCount; listenerIndex++) {
+ ITimeZoneConfigurationListener listener = listeners.get(listenerIndex);
+ try {
+ listener.onChange(configuration);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to notify listener=" + listener
+ + " for userId=" + userId
+ + " of updated configuration=" + configuration, e);
+ }
}
}
}
@@ -338,66 +395,5 @@
(new TimeZoneDetectorShellCommand(this)).exec(
this, in, out, err, args, callback, resultReceiver);
}
-
- private class ConfigListenerInfo implements IBinder.DeathRecipient {
- private final @UserIdInt int mUserId;
- private final ITimeZoneConfigurationListener mListener;
-
- ConfigListenerInfo(
- @UserIdInt int userId, @NonNull ITimeZoneConfigurationListener listener) {
- this.mUserId = userId;
- this.mListener = Objects.requireNonNull(listener);
- }
-
- @UserIdInt int getUserId() {
- return mUserId;
- }
-
- ITimeZoneConfigurationListener getListener() {
- return mListener;
- }
-
- void linkToDeath() throws RemoteException {
- mListener.asBinder().linkToDeath(this, 0 /* flags */);
- }
-
- void unlinkToDeath() throws RemoteException {
- mListener.asBinder().unlinkToDeath(this, 0 /* flags */);
- }
-
- @Override
- public void binderDied() {
- synchronized (mConfigurationListeners) {
- Slog.i(TAG, "Configuration listener client died: " + this);
- mConfigurationListeners.remove(this);
- }
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- ConfigListenerInfo that = (ConfigListenerInfo) o;
- return mUserId == that.mUserId
- && mListener.equals(that.mListener);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mUserId, mListener);
- }
-
- @Override
- public String toString() {
- return "ConfigListenerInfo{"
- + "mUserId=" + mUserId
- + ", mListener=" + mListener
- + '}';
- }
- }
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index b72ff2d..1b4fac6 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -70,7 +70,7 @@
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
import static android.content.pm.ActivityInfo.PERSIST_ACROSS_REBOOTS;
import static android.content.pm.ActivityInfo.PERSIST_ROOT_ONLY;
@@ -168,7 +168,7 @@
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
-import static com.android.server.wm.ActivityTaskManagerService.getInputDispatchingTimeoutLocked;
+import static com.android.server.wm.ActivityTaskManagerService.getInputDispatchingTimeoutMillisLocked;
import static com.android.server.wm.IdentifierProto.HASH_CODE;
import static com.android.server.wm.IdentifierProto.TITLE;
import static com.android.server.wm.IdentifierProto.USER_ID;
@@ -587,8 +587,8 @@
*/
private boolean mOccludesParent;
- // The input dispatching timeout for this application token in nanoseconds.
- long mInputDispatchingTimeoutNanos;
+ // The input dispatching timeout for this application token in milliseconds.
+ long mInputDispatchingTimeoutMillis;
private boolean mShowWhenLocked;
private boolean mInheritShownWhenLocked;
@@ -1245,7 +1245,7 @@
if (oldParent == null && newParent != null) {
// First time we are adding the activity to the system.
mVoiceInteraction = newTask.voiceSession != null;
- mInputDispatchingTimeoutNanos = getInputDispatchingTimeoutLocked(this) * 1000000L;
+ mInputDispatchingTimeoutMillis = getInputDispatchingTimeoutMillisLocked(this);
// TODO(b/36505427): Maybe this call should be moved inside
// updateOverrideConfiguration()
@@ -1683,7 +1683,7 @@
if (options != null) {
final boolean useLockTask = options.getLockTaskMode();
if (useLockTask && lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_DEFAULT) {
- lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
+ lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
}
}
return lockTaskLaunchMode;
@@ -5651,8 +5651,9 @@
} else {
// In this case another process added windows using this activity token. So, we call the
// generic service input dispatch timed out method so that the right process is blamed.
- return mAtmService.mAmInternal.inputDispatchingTimedOut(
- windowPid, false /* aboveSystem */, reason) < 0;
+ long timeoutMillis = mAtmService.mAmInternal.inputDispatchingTimedOut(
+ windowPid, false /* aboveSystem */, reason);
+ return timeoutMillis <= 0;
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index ed1ea35..2c475e0 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -74,9 +74,9 @@
import static com.android.server.wm.Task.ActivityState.PAUSED;
import static com.android.server.wm.Task.ActivityState.PAUSING;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_ALLOWLISTED;
import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE;
import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_WHITELISTED;
import static com.android.server.wm.Task.REPARENT_KEEP_STACK_AT_FRONT;
import static com.android.server.wm.Task.TAG_CLEANUP;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
@@ -130,6 +130,7 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
+import android.view.Display;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -788,7 +789,7 @@
final LockTaskController lockTaskController = mService.getLockTaskController();
if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
|| task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV
- || (task.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED
+ || (task.mLockTaskAuth == LOCK_TASK_AUTH_ALLOWLISTED
&& lockTaskController.getLockTaskModeState()
== LOCK_TASK_MODE_LOCKED)) {
lockTaskController.startLockTaskMode(task, false, 0 /* blank UID */);
@@ -1090,9 +1091,9 @@
// Check if caller is already present on display
final boolean uidPresentOnDisplay = displayContent.isUidPresent(callingUid);
- final int displayOwnerUid = displayContent.mDisplay.getOwnerUid();
- if (displayContent.mDisplay.getType() == TYPE_VIRTUAL && displayOwnerUid != SYSTEM_UID) {
- // Limit launching on virtual displays, because their contents can be read from Surface
+ final Display display = displayContent.mDisplay;
+ if (!display.isTrusted()) {
+ // Limit launching on untrusted displays because their contents can be read from Surface
// by apps that created them.
if ((aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
@@ -1116,7 +1117,7 @@
}
// Check if the caller is the owner of the display.
- if (displayOwnerUid == callingUid) {
+ if (display.getOwnerUid() == callingUid) {
if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
+ " allow launch for owner of the display");
return true;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 777ddda..2dc22ec 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -528,8 +528,8 @@
public abstract void onActiveUidsCleared();
public abstract void onUidProcStateChanged(int uid, int procState);
- public abstract void onUidAddedToPendingTempWhitelist(int uid, String tag);
- public abstract void onUidRemovedFromPendingTempWhitelist(int uid);
+ public abstract void onUidAddedToPendingTempAllowlist(int uid, String tag);
+ public abstract void onUidRemovedFromPendingTempAllowlist(int uid);
/** Handle app crash event in {@link android.app.IActivityController} if there is one. */
public abstract boolean handleAppCrashInActivityController(String processName, int pid,
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 5534b8c..627361d 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -50,6 +50,7 @@
import static android.os.FactoryTest.FACTORY_TEST_HIGH_LEVEL;
import static android.os.FactoryTest.FACTORY_TEST_LOW_LEVEL;
import static android.os.FactoryTest.FACTORY_TEST_OFF;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.Process.FIRST_APPLICATION_UID;
import static android.os.Process.SYSTEM_UID;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
@@ -182,7 +183,6 @@
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
-import android.metrics.LogMaker;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -237,12 +237,9 @@
import com.android.internal.app.AssistUtils;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.ProcessMap;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.TransferPipe;
-import com.android.internal.os.logging.MetricsLoggerWrapper;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.KeyguardDismissCallback;
import com.android.internal.util.ArrayUtils;
@@ -314,10 +311,8 @@
private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
- // How long we wait until we timeout on key dispatching.
- public static final int KEY_DISPATCHING_TIMEOUT_MS = 5 * 1000;
// How long we wait until we timeout on key dispatching during instrumentation.
- static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS = 60 * 1000;
+ static final long INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS = 60 * 1000;
// How long we permit background activity starts after an activity in the process
// started or finished.
static final long ACTIVITY_BG_START_GRACE_PERIOD_MS = 10 * 1000;
@@ -385,7 +380,7 @@
private AppOpsManager mAppOpsManager;
/** All active uids in the system. */
private final MirrorActiveUids mActiveUids = new MirrorActiveUids();
- private final SparseArray<String> mPendingTempWhitelist = new SparseArray<>();
+ private final SparseArray<String> mPendingTempAllowlist = new SparseArray<>();
/** All processes currently running that might have a window organized by name. */
final ProcessMap<WindowProcessController> mProcessNames = new ProcessMap<>();
/** All processes we currently have running mapped by pid and uid */
@@ -1111,7 +1106,7 @@
@Override
public int startActivityIntentSender(IApplicationThread caller, IIntentSender target,
- IBinder whitelistToken, Intent fillInIntent, String resolvedType, IBinder resultTo,
+ IBinder allowlistToken, Intent fillInIntent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle bOptions) {
enforceNotIsolatedCaller("startActivityIntentSender");
// Refuse possible leaked file descriptors
@@ -1134,7 +1129,7 @@
mAppSwitchesAllowedTime = 0;
}
}
- return pir.sendInner(0, fillInIntent, resolvedType, whitelistToken, null, null,
+ return pir.sendInner(0, fillInIntent, resolvedType, allowlistToken, null, null,
resultTo, resultWho, requestCode, flagsMask, flagsValues, bOptions);
}
@@ -3038,7 +3033,7 @@
// system or a specific app.
// * System-initiated requests will only start the pinned mode (screen pinning)
// * App-initiated requests
- // - will put the device in fully locked mode (LockTask), if the app is whitelisted
+ // - will put the device in fully locked mode (LockTask), if the app is allowlisted
// - will start the pinned mode, otherwise
final int callingUid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
@@ -3078,7 +3073,7 @@
"updateLockTaskPackages()");
}
synchronized (mGlobalLock) {
- if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Whitelisting " + userId + ":"
+ if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Allowlisting " + userId + ":"
+ Arrays.toString(packages));
getLockTaskController().updateLockTaskPackages(userId, packages);
}
@@ -4096,10 +4091,6 @@
final Task stack = r.getRootTask();
stack.setPictureInPictureAspectRatio(aspectRatio);
stack.setPictureInPictureActions(actions);
- MetricsLoggerWrapper.logPictureInPictureEnter(mContext,
- r.info.applicationInfo.uid, r.shortComponentName,
- r.supportsEnterPipOnTaskSwitch);
- logPictureInPictureArgs(params);
}
};
@@ -4143,7 +4134,6 @@
r.pictureInPictureArgs.getAspectRatio());
stack.setPictureInPictureActions(r.pictureInPictureArgs.getActions());
}
- logPictureInPictureArgs(params);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -4157,18 +4147,6 @@
return 3;
}
- private void logPictureInPictureArgs(PictureInPictureParams params) {
- if (params.hasSetActions()) {
- MetricsLogger.histogram(mContext, "tron_varz_picture_in_picture_actions_count",
- params.getActions().size());
- }
- if (params.hasSetAspectRatio()) {
- LogMaker lm = new LogMaker(MetricsEvent.ACTION_PICTURE_IN_PICTURE_ASPECT_RATIO_CHANGED);
- lm.addTaggedData(MetricsEvent.PICTURE_IN_PICTURE_ASPECT_RATIO, params.getAspectRatio());
- MetricsLogger.action(lm);
- }
- }
-
/**
* Checks the state of the system and the activity associated with the given {@param token} to
* verify that picture-in-picture is supported for that activity.
@@ -5376,15 +5354,18 @@
}
}
- static long getInputDispatchingTimeoutLocked(ActivityRecord r) {
+ static long getInputDispatchingTimeoutMillisLocked(ActivityRecord r) {
if (r == null || !r.hasProcess()) {
- return KEY_DISPATCHING_TIMEOUT_MS;
+ return DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
}
- return getInputDispatchingTimeoutLocked(r.app);
+ return getInputDispatchingTimeoutMillisLocked(r.app);
}
- private static long getInputDispatchingTimeoutLocked(WindowProcessController r) {
- return r != null ? r.getInputDispatchingTimeout() : KEY_DISPATCHING_TIMEOUT_MS;
+ private static long getInputDispatchingTimeoutMillisLocked(WindowProcessController r) {
+ if (r == null) {
+ return DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+ }
+ return r.getInputDispatchingTimeoutMillis();
}
/**
@@ -5977,11 +5958,11 @@
}
/**
- * @return whitelist tag for a uid from mPendingTempWhitelist, null if not currently on
- * the whitelist
+ * @return allowlist tag for a uid from mPendingTempAllowlist, null if not currently on
+ * the allowlist
*/
- String getPendingTempWhitelistTagForUidLocked(int uid) {
- return mPendingTempWhitelist.get(uid);
+ String getPendingTempAllowlistTagForUidLocked(int uid) {
+ return mPendingTempAllowlist.get(uid);
}
void logAppTooSlow(WindowProcessController app, long startTime, String msg) {
@@ -7323,16 +7304,16 @@
}
@Override
- public void onUidAddedToPendingTempWhitelist(int uid, String tag) {
+ public void onUidAddedToPendingTempAllowlist(int uid, String tag) {
synchronized (mGlobalLockWithoutBoost) {
- mPendingTempWhitelist.put(uid, tag);
+ mPendingTempAllowlist.put(uid, tag);
}
}
@Override
- public void onUidRemovedFromPendingTempWhitelist(int uid) {
+ public void onUidRemovedFromPendingTempAllowlist(int uid) {
synchronized (mGlobalLockWithoutBoost) {
- mPendingTempWhitelist.remove(uid);
+ mPendingTempAllowlist.remove(uid);
}
}
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index f840d92..22dd1d3 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+
import static com.android.server.wm.DragDropController.MSG_ANIMATION_END;
import static com.android.server.wm.DragDropController.MSG_DRAG_END_TIMEOUT;
import static com.android.server.wm.DragDropController.MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT;
@@ -271,8 +273,7 @@
mDragApplicationHandle = new InputApplicationHandle(new Binder());
mDragApplicationHandle.name = "drag";
- mDragApplicationHandle.dispatchingTimeoutNanos =
- WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mDragApplicationHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle,
display.getDisplayId());
@@ -280,8 +281,7 @@
mDragWindowHandle.token = mServerChannel.getToken();
mDragWindowHandle.layoutParamsFlags = 0;
mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
- mDragWindowHandle.dispatchingTimeoutNanos =
- WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mDragWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
mDragWindowHandle.visible = true;
mDragWindowHandle.canReceiveKeys = false;
mDragWindowHandle.hasFocus = true;
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 852b3672..3b24584b 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
@@ -69,16 +71,14 @@
mApplicationHandle = new InputApplicationHandle(new Binder());
mApplicationHandle.name = name;
- mApplicationHandle.dispatchingTimeoutNanos =
- WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mApplicationHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
mWindowHandle = new InputWindowHandle(mApplicationHandle, displayId);
mWindowHandle.name = name;
mWindowHandle.token = mServerChannel.getToken();
mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
mWindowHandle.layoutParamsFlags = 0;
- mWindowHandle.dispatchingTimeoutNanos =
- WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
mWindowHandle.visible = true;
mWindowHandle.canReceiveKeys = false;
mWindowHandle.hasFocus = false;
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index 9c4ac89..e166bfc 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -10,6 +10,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.ON_POINTER_DOWN_OUTSIDE_FOCUS;
+import android.annotation.Nullable;
import android.os.Build;
import android.os.Debug;
import android.os.IBinder;
@@ -173,23 +174,23 @@
*/
@Override
public long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
- String reason) {
+ @Nullable Integer pid, String reason) {
final long startTime = SystemClock.uptimeMillis();
try {
- return notifyANRInner(inputApplicationHandle, token, reason);
+ return notifyANRInner(inputApplicationHandle, token, pid, reason);
} finally {
// Log the time because the method is called from InputDispatcher thread. It shouldn't
- // take too long that may affect input response time.
+ // take too long because it blocks input while executing.
Slog.d(TAG_WM, "notifyANR took " + (SystemClock.uptimeMillis() - startTime) + "ms");
}
}
private long notifyANRInner(InputApplicationHandle inputApplicationHandle, IBinder token,
- String reason) {
+ @Nullable Integer pid, String reason) {
ActivityRecord activity = null;
WindowState windowState = null;
boolean aboveSystem = false;
- int windowPid = INVALID_PID;
+ int windowPid = pid != null ? pid : INVALID_PID;
preDumpIfLockTooSlow();
@@ -258,18 +259,14 @@
if (!abort) {
// The activity manager declined to abort dispatching.
// Wait a bit longer and timeout again later.
- return activity.mInputDispatchingTimeoutNanos;
+ return TimeUnit.MILLISECONDS.toNanos(activity.mInputDispatchingTimeoutMillis);
}
} else if (windowState != null || windowPid != INVALID_PID) {
// Notify the activity manager about the timeout and let it decide whether
// to abort dispatching or keep waiting.
- long timeout = mService.mAmInternal.inputDispatchingTimedOut(windowPid, aboveSystem,
- reason);
- if (timeout >= 0) {
- // The activity manager declined to abort dispatching.
- // Wait a bit longer and timeout again later.
- return timeout * 1000000L; // nanoseconds
- }
+ long timeoutMillis =
+ mService.mAmInternal.inputDispatchingTimedOut(windowPid, aboveSystem, reason);
+ return TimeUnit.MILLISECONDS.toNanos(timeoutMillis);
}
return 0; // abort dispatching
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 20f1b9f..791f471 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -269,7 +269,7 @@
flags = child.getSurfaceTouchableRegion(inputWindowHandle, flags);
inputWindowHandle.layoutParamsFlags = flags;
inputWindowHandle.layoutParamsType = type;
- inputWindowHandle.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
+ inputWindowHandle.dispatchingTimeoutMillis = child.getInputDispatchingTimeoutMillis();
inputWindowHandle.visible = isVisible;
inputWindowHandle.canReceiveKeys = child.canReceiveKeys();
inputWindowHandle.hasFocus = hasFocus;
@@ -385,7 +385,7 @@
} else {
final InputApplicationHandle handle = newApp.mInputApplicationHandle;
handle.name = newApp.toString();
- handle.dispatchingTimeoutNanos = newApp.mInputDispatchingTimeoutNanos;
+ handle.dispatchingTimeoutMillis = newApp.mInputDispatchingTimeoutMillis;
mService.mInputManager.setFocusedApplication(mDisplayId, handle);
}
@@ -570,8 +570,7 @@
final String name, final int type, final boolean isVisible) {
inputWindowHandle.name = name;
inputWindowHandle.layoutParamsType = type;
- inputWindowHandle.dispatchingTimeoutNanos =
- WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ inputWindowHandle.dispatchingTimeoutMillis = 0; // it should never receive input
inputWindowHandle.visible = isVisible;
inputWindowHandle.canReceiveKeys = false;
inputWindowHandle.hasFocus = false;
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 28dcbcd..dccd3a6 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.view.SurfaceControl.HIDDEN;
import android.graphics.Point;
@@ -217,8 +218,7 @@
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
| WindowManager.LayoutParams.FLAG_SLIPPERY;
mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
- mWindowHandle.dispatchingTimeoutNanos =
- WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
mWindowHandle.visible = true;
mWindowHandle.ownerPid = Process.myPid();
mWindowHandle.ownerUid = Process.myUid();
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index c7a438d..8ef57f7 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -33,11 +33,11 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_ALLOWLISTED;
import static com.android.server.wm.Task.LOCK_TASK_AUTH_DONT_LOCK;
import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE;
import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
import static com.android.server.wm.Task.LOCK_TASK_AUTH_PINNABLE;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_WHITELISTED;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -264,12 +264,12 @@
}
/**
- * @return whether the requested task is allowed to be locked (either whitelisted, or declares
+ * @return whether the requested task is allowed to be locked (either allowlisted, or declares
* lockTaskMode="always" in the manifest).
*/
- boolean isTaskWhitelisted(Task task) {
+ boolean isTaskAllowlisted(Task task) {
switch(task.mLockTaskAuth) {
- case LOCK_TASK_AUTH_WHITELISTED:
+ case LOCK_TASK_AUTH_ALLOWLISTED:
case LOCK_TASK_AUTH_LAUNCHABLE:
case LOCK_TASK_AUTH_LAUNCHABLE_PRIV:
return true;
@@ -311,7 +311,7 @@
private boolean isLockTaskModeViolationInternal(Task task, boolean isNewClearTask) {
// TODO: Double check what's going on here. If the task is already in lock task mode, it's
- // likely whitelisted, so will return false below.
+ // likely allowlisted, so will return false below.
if (isTaskLocked(task) && !isNewClearTask) {
// If the task is already at the top and won't be cleared, then allow the operation
return false;
@@ -327,7 +327,7 @@
return false;
}
- return !(isTaskWhitelisted(task) || mLockTaskModeTasks.isEmpty());
+ return !(isTaskAllowlisted(task) || mLockTaskModeTasks.isEmpty());
}
private boolean isRecentsAllowed(int userId) {
@@ -356,7 +356,7 @@
return false;
default:
}
- return isPackageWhitelisted(userId, packageName);
+ return isPackageAllowlisted(userId, packageName);
}
private boolean isEmergencyCallTask(Task task) {
@@ -556,7 +556,7 @@
if (!isSystemCaller) {
task.mLockTaskUid = callingUid;
if (task.mLockTaskAuth == LOCK_TASK_AUTH_PINNABLE) {
- // startLockTask() called by app, but app is not part of lock task whitelist. Show
+ // startLockTask() called by app, but app is not part of lock task allowlist. Show
// app pinning request. We will come back here with isSystemCaller true.
if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Mode default, asking user");
StatusBarManagerInternal statusBarManager = LocalServices.getService(
@@ -649,8 +649,8 @@
/**
* Update packages that are allowed to be launched in lock task mode.
- * @param userId Which user this whitelist is associated with
- * @param packages The whitelist of packages allowed in lock task mode
+ * @param userId Which user this allowlist is associated with
+ * @param packages The allowlist of packages allowed in lock task mode
* @see #mLockTaskPackages
*/
void updateLockTaskPackages(int userId, String[] packages) {
@@ -659,19 +659,19 @@
boolean taskChanged = false;
for (int taskNdx = mLockTaskModeTasks.size() - 1; taskNdx >= 0; --taskNdx) {
final Task lockedTask = mLockTaskModeTasks.get(taskNdx);
- final boolean wasWhitelisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
- || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED;
+ final boolean wasAllowlisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
+ || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_ALLOWLISTED;
lockedTask.setLockTaskAuth();
- final boolean isWhitelisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
- || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED;
+ final boolean isAllowlisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
+ || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_ALLOWLISTED;
if (mLockTaskModeState != LOCK_TASK_MODE_LOCKED
|| lockedTask.mUserId != userId
- || !wasWhitelisted || isWhitelisted) {
+ || !wasAllowlisted || isAllowlisted) {
continue;
}
- // Terminate locked tasks that have recently lost whitelist authorization.
+ // Terminate locked tasks that have recently lost allowlist authorization.
if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "onLockTaskPackagesUpdated: removing " +
lockedTask + " mLockTaskAuth()=" + lockedTask.lockTaskAuthToString());
removeLockedTask(lockedTask);
@@ -697,17 +697,17 @@
}
}
- boolean isPackageWhitelisted(int userId, String pkg) {
+ boolean isPackageAllowlisted(int userId, String pkg) {
if (pkg == null) {
return false;
}
- String[] whitelist;
- whitelist = mLockTaskPackages.get(userId);
- if (whitelist == null) {
+ String[] allowlist;
+ allowlist = mLockTaskPackages.get(userId);
+ if (allowlist == null) {
return false;
}
- for (String whitelistedPkg : whitelist) {
- if (pkg.equals(whitelistedPkg)) {
+ for (String allowlistedPkg : allowlist) {
+ if (pkg.equals(allowlistedPkg)) {
return true;
}
}
diff --git a/services/core/java/com/android/server/wm/PolicyControl.java b/services/core/java/com/android/server/wm/PolicyControl.java
index 0f92bc8..61b6e0b 100644
--- a/services/core/java/com/android/server/wm/PolicyControl.java
+++ b/services/core/java/com/android/server/wm/PolicyControl.java
@@ -196,40 +196,40 @@
private static final String ALL = "*";
private static final String APPS = "apps";
- private final ArraySet<String> mWhitelist;
- private final ArraySet<String> mBlacklist;
+ private final ArraySet<String> mAllowlist;
+ private final ArraySet<String> mDenylist;
- private Filter(ArraySet<String> whitelist, ArraySet<String> blacklist) {
- mWhitelist = whitelist;
- mBlacklist = blacklist;
+ private Filter(ArraySet<String> allowlist, ArraySet<String> denylist) {
+ mAllowlist = allowlist;
+ mDenylist = denylist;
}
boolean matches(LayoutParams attrs) {
if (attrs == null) return false;
boolean isApp = attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
&& attrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
- if (isApp && mBlacklist.contains(APPS)) return false;
- if (onBlacklist(attrs.packageName)) return false;
- if (isApp && mWhitelist.contains(APPS)) return true;
- return onWhitelist(attrs.packageName);
+ if (isApp && mDenylist.contains(APPS)) return false;
+ if (onDenylist(attrs.packageName)) return false;
+ if (isApp && mAllowlist.contains(APPS)) return true;
+ return onAllowlist(attrs.packageName);
}
boolean matches(String packageName) {
- return !onBlacklist(packageName) && onWhitelist(packageName);
+ return !onDenylist(packageName) && onAllowlist(packageName);
}
- private boolean onBlacklist(String packageName) {
- return mBlacklist.contains(packageName) || mBlacklist.contains(ALL);
+ private boolean onDenylist(String packageName) {
+ return mDenylist.contains(packageName) || mDenylist.contains(ALL);
}
- private boolean onWhitelist(String packageName) {
- return mWhitelist.contains(ALL) || mWhitelist.contains(packageName);
+ private boolean onAllowlist(String packageName) {
+ return mAllowlist.contains(ALL) || mAllowlist.contains(packageName);
}
void dump(PrintWriter pw) {
pw.print("Filter[");
- dump("whitelist", mWhitelist, pw); pw.print(',');
- dump("blacklist", mBlacklist, pw); pw.print(']');
+ dump("allowlist", mAllowlist, pw); pw.print(',');
+ dump("denylist", mDenylist, pw); pw.print(']');
}
private void dump(String name, ArraySet<String> set, PrintWriter pw) {
@@ -253,18 +253,18 @@
// e.g. "com.package1", or "apps, com.android.keyguard" or "*"
static Filter parse(String value) {
if (value == null) return null;
- ArraySet<String> whitelist = new ArraySet<String>();
- ArraySet<String> blacklist = new ArraySet<String>();
+ ArraySet<String> allowlist = new ArraySet<String>();
+ ArraySet<String> denylist = new ArraySet<String>();
for (String token : value.split(",")) {
token = token.trim();
if (token.startsWith("-") && token.length() > 1) {
token = token.substring(1);
- blacklist.add(token);
+ denylist.add(token);
} else {
- whitelist.add(token);
+ allowlist.add(token);
}
}
- return new Filter(whitelist, blacklist);
+ return new Filter(allowlist, denylist);
}
}
}
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index ba2c0b6..df53563 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -655,7 +655,8 @@
}
for (int i = mTasks.size() - 1; i >= 0; --i) {
final Task task = mTasks.get(i);
- if (task.mUserId == userId && !mService.getLockTaskController().isTaskWhitelisted(task)) {
+ if (task.mUserId == userId
+ && !mService.getLockTaskController().isTaskAllowlisted(task)) {
remove(task);
}
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 526ec08..1cb483c 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2155,6 +2155,7 @@
// non-fullscreen bounds. Then when this new PIP task exits PIP, it can restore
// to its previous freeform bounds.
stack.setLastNonFullscreenBounds(task.mLastNonFullscreenBounds);
+ stack.setBounds(task.getBounds());
// There are multiple activities in the task and moving the top activity should
// reveal/leave the other activities in their original task.
@@ -2570,7 +2571,7 @@
mDisplayAccessUIDs.clear();
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent displayContent = getChildAt(displayNdx);
- // Only bother calculating the whitelist for private displays
+ // Only bother calculating the allowlist for private displays
if (displayContent.isPrivate()) {
mDisplayAccessUIDs.append(
displayContent.mDisplayId, displayContent.getPresentUIDs());
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index b71ecbb..ede6708 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -233,10 +233,10 @@
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
- // Check if someone tries to launch an unwhitelisted activity into LockTask mode.
+ // Check if someone tries to launch an unallowlisted activity into LockTask mode.
final boolean lockTaskMode = options.getLockTaskMode();
if (aInfo != null && lockTaskMode
- && !supervisor.mService.getLockTaskController().isPackageWhitelisted(
+ && !supervisor.mService.getLockTaskController().isPackageAllowlisted(
UserHandle.getUserId(callingUid), aInfo.packageName)) {
final String msg = "Permission Denial: starting " + getIntentString(intent)
+ " from " + callerApp + " (pid=" + callingPid
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index f362005..be0815b0 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -45,7 +45,7 @@
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
@@ -210,7 +210,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.os.logging.MetricsLoggerWrapper;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledFunction;
@@ -411,7 +410,7 @@
/** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
/** Can enter lockTask without user approval. Can start over existing lockTask task. */
- final static int LOCK_TASK_AUTH_WHITELISTED = 3;
+ final static int LOCK_TASK_AUTH_ALLOWLISTED = 3;
/** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
* lockTask task. */
final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
@@ -1686,7 +1685,7 @@
getDisplayArea().addStackReferenceIfNeeded((Task) child);
}
- // Make sure the list of display UID whitelists is updated
+ // Make sure the list of display UID allowlists is updated
// now that this record is in a new task.
mRootWindowContainer.updateUIDsPresentOnDisplay();
@@ -1903,7 +1902,7 @@
case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK";
case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
- case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED";
+ case LOCK_TASK_AUTH_ALLOWLISTED: return "LOCK_TASK_AUTH_ALLOWLISTED";
case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV";
default: return "unknown=" + mLockTaskAuth;
}
@@ -1923,8 +1922,8 @@
final LockTaskController lockTaskController = mAtmService.getLockTaskController();
switch (r.lockTaskLaunchMode) {
case LOCK_TASK_LAUNCH_MODE_DEFAULT:
- mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
- ? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
+ mLockTaskAuth = lockTaskController.isPackageAllowlisted(mUserId, pkg)
+ ? LOCK_TASK_AUTH_ALLOWLISTED : LOCK_TASK_AUTH_PINNABLE;
break;
case LOCK_TASK_LAUNCH_MODE_NEVER:
@@ -1935,8 +1934,8 @@
mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
break;
- case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
- mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
+ case LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED:
+ mLockTaskAuth = lockTaskController.isPackageAllowlisted(mUserId, pkg)
? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
break;
}
@@ -2366,7 +2365,6 @@
private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) {
if (mWmService.mDisableTransitionAnimation
|| !isVisible()
- || getDisplayContent().mAppTransition.isTransitionSet()
|| getSurfaceControl() == null
|| !isLeafTask()) {
return false;
@@ -7372,8 +7370,6 @@
getDisplayArea().positionChildAt(POSITION_TOP, this, false /* includingParents */);
mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, this);
- MetricsLoggerWrapper.logPictureInPictureFullScreen(mAtmService.mContext,
- task.effectiveUid, task.realActivity.flattenToString());
});
}
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index c68b660..3fbc037 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -18,6 +18,7 @@
import static android.app.ActivityTaskManager.RESIZE_MODE_USER;
import static android.app.ActivityTaskManager.RESIZE_MODE_USER_FORCED;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_BOTTOM;
@@ -230,8 +231,8 @@
mDragApplicationHandle = new InputApplicationHandle(new Binder());
mDragApplicationHandle.name = TAG;
- mDragApplicationHandle.dispatchingTimeoutNanos =
- WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mDragApplicationHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+
mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle,
displayContent.getDisplayId());
@@ -239,8 +240,7 @@
mDragWindowHandle.token = mServerChannel.getToken();
mDragWindowHandle.layoutParamsFlags = 0;
mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
- mDragWindowHandle.dispatchingTimeoutNanos =
- WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mDragWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
mDragWindowHandle.visible = true;
mDragWindowHandle.canReceiveKeys = false;
mDragWindowHandle.hasFocus = true;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index f3c7a5d..9b18ac8 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.graphics.Color.WHITE;
import static android.graphics.Color.alpha;
import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
@@ -142,6 +143,7 @@
private final Handler mHandler;
private boolean mSizeMismatch;
private final Paint mBackgroundPaint = new Paint();
+ private final int mActivityType;
private final int mStatusBarColor;
@VisibleForTesting final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
private final int mOrientationOnCreation;
@@ -173,6 +175,7 @@
final int windowFlags;
final int windowPrivateFlags;
final int currentOrientation;
+ final int activityType;
final InsetsState insetsState;
synchronized (service.mGlobalLock) {
final WindowState mainWindow = activity.findMainWindow();
@@ -241,6 +244,7 @@
taskBounds = new Rect();
task.getBounds(taskBounds);
currentOrientation = topFullscreenOpaqueWindow.getConfiguration().orientation;
+ activityType = activity.getActivityType();
final InsetsPolicy insetsPolicy = topFullscreenOpaqueWindow.getDisplayContent()
.getInsetsPolicy();
@@ -261,7 +265,8 @@
}
final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, sysUiVis,
- windowFlags, windowPrivateFlags, taskBounds, currentOrientation, insetsState);
+ windowFlags, windowPrivateFlags, taskBounds, currentOrientation, activityType,
+ insetsState);
window.setOuter(snapshotSurface);
try {
session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1,
@@ -282,7 +287,7 @@
TaskSnapshotSurface(WindowManagerService service, Window window, SurfaceControl surfaceControl,
TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription,
int sysUiVis, int windowFlags, int windowPrivateFlags, Rect taskBounds,
- int currentOrientation, InsetsState insetsState) {
+ int currentOrientation, int activityType, InsetsState insetsState) {
mService = service;
mSurface = service.mSurfaceFactory.get();
mHandler = new Handler(mService.mH.getLooper());
@@ -298,6 +303,7 @@
windowPrivateFlags, sysUiVis, taskDescription, 1f, insetsState);
mStatusBarColor = taskDescription.getStatusBarColor();
mOrientationOnCreation = currentOrientation;
+ mActivityType = activityType;
mTransaction = mService.mTransactionFactory.get();
}
@@ -305,7 +311,9 @@
public void remove() {
synchronized (mService.mGlobalLock) {
final long now = SystemClock.uptimeMillis();
- if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS) {
+ if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS
+ // Show the latest content as soon as possible for unlocking to home.
+ && mActivityType != ACTIVITY_TYPE_HOME) {
mHandler.postAtTime(this::remove, mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS);
ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
"Defer removing snapshot surface in %dms", (now - mShownTime));
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ede92f0..0b1d6bc 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -35,6 +35,7 @@
import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
import static android.content.pm.PackageManager.FEATURE_PC;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.Process.INVALID_UID;
import static android.os.Process.SYSTEM_UID;
import static android.os.Process.myPid;
@@ -366,9 +367,6 @@
// proceding with safe mode detection.
private static final int INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS = 1000;
- // Default input dispatching timeout in nanoseconds.
- static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L;
-
// Poll interval in milliseconds for watching boot animation finished.
// TODO(b/159045990) Migrate to SystemService.waitForState with dedicated thread.
private static final int BOOT_ANIMATION_POLL_INTERVAL = 50;
@@ -8090,7 +8088,7 @@
| LayoutParams.FLAG_SLIPPERY);
h.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | sanitizedFlags;
h.layoutParamsType = type;
- h.dispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ h.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
h.canReceiveKeys = false;
h.hasFocus = false;
h.hasWallpaper = false;
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index df59c56..a58c564 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -19,6 +19,7 @@
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.os.Build.VERSION_CODES.Q;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.view.Display.INVALID_DISPLAY;
import static com.android.server.am.ActivityManagerService.MY_PID;
@@ -30,8 +31,7 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskManagerService.ACTIVITY_BG_START_GRACE_PERIOD_MS;
-import static com.android.server.wm.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS;
-import static com.android.server.wm.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS;
+import static com.android.server.wm.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
import static com.android.server.wm.Task.ActivityState.DESTROYED;
import static com.android.server.wm.Task.ActivityState.DESTROYING;
@@ -41,6 +41,7 @@
import static com.android.server.wm.Task.ActivityState.STARTED;
import static com.android.server.wm.Task.ActivityState.STOPPING;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -1064,10 +1065,16 @@
return RELAUNCH_REASON_NONE;
}
- public long getInputDispatchingTimeout() {
+ /**
+ * Get the current dispatching timeout. If instrumentation is currently taking place, return
+ * a longer value. Shorter timeout is returned otherwise.
+ * @return The timeout in milliseconds
+ */
+ public long getInputDispatchingTimeoutMillis() {
synchronized (mAtm.mGlobalLock) {
return isInstrumenting() || isUsingWrapper()
- ? INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS : KEY_DISPATCHING_TIMEOUT_MS;
+ ? INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS :
+ DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index ef78420..ab78e74 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -25,6 +25,7 @@
import static android.app.WindowConfiguration.isSplitScreenWindowingMode;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.graphics.GraphicsProtos.dumpPointProto;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.PowerManager.DRAW_WAKE_LOCK;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.InsetsState.ITYPE_IME;
@@ -1635,10 +1636,10 @@
}
}
- public long getInputDispatchingTimeoutNanos() {
+ public long getInputDispatchingTimeoutMillis() {
return mActivityRecord != null
- ? mActivityRecord.mInputDispatchingTimeoutNanos
- : WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ ? mActivityRecord.mInputDispatchingTimeoutMillis
+ : DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
}
@Override
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 0e1b2f2..4b5f38c 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -99,6 +99,7 @@
"libpowermanager",
"libutils",
"libui",
+ "libvibratorservice",
"libinput",
"libinputflinger",
"libinputflinger_base",
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index 05aa359..74e2328 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -33,6 +33,8 @@
#include <inttypes.h>
#include <stdio.h>
+#include <vibratorservice/VibratorHalController.h>
+
using android::hardware::Return;
using android::hardware::Void;
using android::hardware::vibrator::V1_0::EffectStrength;
@@ -226,8 +228,24 @@
return val >= *iter.begin() && val <= *std::prev(iter.end());
}
-static void vibratorInit(JNIEnv *env, jclass clazz)
-{
+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));
+ return effect;
+}
+
+static void destroyVibratorController(void* rawVibratorController) {
+ vibrator::HalController* vibratorController =
+ reinterpret_cast<vibrator::HalController*>(rawVibratorController);
+ if (vibratorController) {
+ delete vibratorController;
+ }
+}
+
+static jlong vibratorInit(JNIEnv* /* env */, jclass /* clazz */) {
if (auto hal = getHal<aidl::IVibrator>()) {
// IBinder::pingBinder isn't accessible as a pointer function
// but getCapabilities can serve the same purpose
@@ -236,25 +254,26 @@
} else {
halCall(&V1_0::IVibrator::ping).isOk();
}
+ std::unique_ptr<vibrator::HalController> controller =
+ std::make_unique<vibrator::HalController>();
+ controller->init();
+ return reinterpret_cast<jlong>(controller.release());
}
-static jboolean vibratorExists(JNIEnv* /* env */, jclass /* clazz */)
-{
- bool ok;
+static jlong vibratorGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
+ return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyVibratorController));
+}
- if (auto hal = getHal<aidl::IVibrator>()) {
- // IBinder::pingBinder isn't accessible as a pointer function
- // but getCapabilities can serve the same purpose
- int32_t cap;
- ok = hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk();
- } else {
- ok = halCall(&V1_0::IVibrator::ping).isOk();
+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");
+ return JNI_FALSE;
}
- return ok ? JNI_TRUE : JNI_FALSE;
+ return controller->ping().isOk() ? JNI_TRUE : JNI_FALSE;
}
-static void vibratorOn(JNIEnv* /* env */, jclass /* clazz */, jlong timeout_ms)
-{
+static void vibratorOn(JNIEnv* /* env */, jclass /* clazz */, jlong timeout_ms) {
if (auto hal = getHal<aidl::IVibrator>()) {
auto status = hal->call(&aidl::IVibrator::on, timeout_ms, nullptr);
if (!status.isOk()) {
@@ -268,93 +287,53 @@
}
}
-static void vibratorOff(JNIEnv* /* env */, jclass /* clazz */)
-{
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::off);
- if (!status.isOk()) {
- ALOGE("vibratorOff command failed: %s", status.toString8().string());
- }
- } else {
- Status retStatus = halCall(&V1_0::IVibrator::off).withDefault(Status::UNKNOWN_ERROR);
- if (retStatus != Status::OK) {
- ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
- }
+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");
+ return;
}
+ controller->off();
}
-static jlong vibratorSupportsAmplitudeControl(JNIEnv*, jclass) {
- if (auto hal = getHal<aidl::IVibrator>()) {
- int32_t cap = 0;
- if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) {
- return false;
- }
- return (cap & aidl::IVibrator::CAP_AMPLITUDE_CONTROL) > 0;
- } else {
- return halCall(&V1_0::IVibrator::supportsAmplitudeControl).withDefault(false);
+static void vibratorSetAmplitude(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
+ jint amplitude) {
+ vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
+ if (controller == nullptr) {
+ ALOGE("vibratorSetAmplitude failed because controller was not initialized");
+ return;
}
+ controller->setAmplitude(static_cast<int32_t>(amplitude));
}
-static void vibratorSetAmplitude(JNIEnv*, jclass, jint amplitude) {
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::IVibrator::setAmplitude, static_cast<float>(amplitude) / UINT8_MAX);
- if (!status.isOk()) {
- ALOGE("Failed to set vibrator amplitude: %s", status.toString8().string());
- }
- } else {
- Status status = halCall(&V1_0::IVibrator::setAmplitude, static_cast<uint32_t>(amplitude))
- .withDefault(Status::UNKNOWN_ERROR);
- if (status != Status::OK) {
- ALOGE("Failed to set vibrator amplitude (%" PRIu32 ").",
- static_cast<uint32_t>(status));
- }
+static void vibratorSetExternalControl(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
+ jboolean enabled) {
+ vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
+ if (controller == nullptr) {
+ ALOGE("vibratorSetExternalControl failed because controller was not initialized");
+ return;
}
+ controller->setExternalControl(enabled);
}
-static jboolean vibratorSupportsExternalControl(JNIEnv*, jclass) {
- if (auto hal = getHal<aidl::IVibrator>()) {
- int32_t cap = 0;
- if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) {
- return false;
- }
- return (cap & aidl::IVibrator::CAP_EXTERNAL_CONTROL) > 0;
- } else {
- return halCall(&V1_3::IVibrator::supportsExternalControl).withDefault(false);
- }
-}
-
-static void vibratorSetExternalControl(JNIEnv*, jclass, jboolean enabled) {
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::IVibrator::setExternalControl, enabled);
- if (!status.isOk()) {
- ALOGE("Failed to set vibrator external control: %s", status.toString8().string());
- }
- } else {
- Status status = halCall(&V1_3::IVibrator::setExternalControl, static_cast<uint32_t>(enabled))
- .withDefault(Status::UNKNOWN_ERROR);
- if (status != Status::OK) {
- ALOGE("Failed to set vibrator external control (%" PRIu32 ").",
- static_cast<uint32_t>(status));
- }
- }
-}
-
-static jintArray vibratorGetSupportedEffects(JNIEnv *env, jclass) {
- if (auto hal = getHal<aidl::IVibrator>()) {
- std::vector<aidl::Effect> supportedEffects;
- if (!hal->call(&aidl::IVibrator::getSupportedEffects, &supportedEffects).isOk()) {
- return nullptr;
- }
- jintArray arr = env->NewIntArray(supportedEffects.size());
- env->SetIntArrayRegion(arr, 0, supportedEffects.size(),
- reinterpret_cast<jint*>(supportedEffects.data()));
- return arr;
- } else {
+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");
return nullptr;
}
+ auto result = controller->getSupportedEffects();
+ if (!result.isOk()) {
+ return nullptr;
+ }
+ std::vector<aidl::Effect> supportedEffects = result.value();
+ jintArray effects = env->NewIntArray(supportedEffects.size());
+ env->SetIntArrayRegion(effects, 0, supportedEffects.size(),
+ reinterpret_cast<jint*>(supportedEffects.data()));
+ return effects;
}
-static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jlong strength,
+static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong effect, jlong strength,
jobject vibration, jboolean withCallback) {
if (auto hal = getHal<aidl::IVibrator>()) {
int32_t lengthMs;
@@ -420,17 +399,8 @@
return -1;
}
-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<int>(env->GetIntField(primitive, gPrimitiveClassInfo.delay));
- return effect;
-}
-
-static void vibratorPerformComposedEffect(JNIEnv* env, jclass, jobjectArray composition,
- jobject vibration) {
+static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jobjectArray composition,
+ jobject vibration) {
auto hal = getHal<aidl::IVibrator>();
if (!hal) {
return;
@@ -451,65 +421,71 @@
}
}
-static jlong vibratorGetCapabilities(JNIEnv*, jclass) {
- if (auto hal = getHal<aidl::IVibrator>()) {
- int32_t cap = 0;
- if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) {
- return 0;
- }
- return cap;
+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");
+ return 0;
}
-
- return 0;
+ auto result = controller->getCapabilities();
+ return result.isOk() ? static_cast<jlong>(result.value()) : 0;
}
-static void vibratorAlwaysOnEnable(JNIEnv* env, jclass, jlong id, jlong effect, jlong strength) {
- auto status = halCall(&aidl::IVibrator::alwaysOnEnable, id,
- static_cast<aidl::Effect>(effect), static_cast<aidl::EffectStrength>(strength));
- if (!status.isOk()) {
- ALOGE("vibratortAlwaysOnEnable command failed (%s).", status.toString8().string());
+static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, 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");
+ return;
}
+ controller->alwaysOnEnable(static_cast<int32_t>(id), static_cast<aidl::Effect>(effect),
+ static_cast<aidl::EffectStrength>(strength));
}
-static void vibratorAlwaysOnDisable(JNIEnv* env, jclass, jlong id) {
- auto status = halCall(&aidl::IVibrator::alwaysOnDisable, id);
- if (!status.isOk()) {
- ALOGE("vibratorAlwaysOnDisable command failed (%s).", status.toString8().string());
+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");
+ return;
}
+ controller->alwaysOnDisable(static_cast<int32_t>(id));
}
static const JNINativeMethod method_table[] = {
- {"vibratorExists", "()Z", (void*)vibratorExists},
- {"vibratorInit", "()V", (void*)vibratorInit},
+ {"vibratorInit", "()J", (void*)vibratorInit},
+ {"vibratorGetFinalizer", "()J", (void*)vibratorGetFinalizer},
+ {"vibratorExists", "(J)Z", (void*)vibratorExists},
{"vibratorOn", "(J)V", (void*)vibratorOn},
- {"vibratorOff", "()V", (void*)vibratorOff},
- {"vibratorSupportsAmplitudeControl", "()Z", (void*)vibratorSupportsAmplitudeControl},
- {"vibratorSetAmplitude", "(I)V", (void*)vibratorSetAmplitude},
+ {"vibratorOff", "(J)V", (void*)vibratorOff},
+ {"vibratorSetAmplitude", "(JI)V", (void*)vibratorSetAmplitude},
{"vibratorPerformEffect", "(JJLcom/android/server/VibratorService$Vibration;Z)J",
(void*)vibratorPerformEffect},
{"vibratorPerformComposedEffect",
"([Landroid/os/VibrationEffect$Composition$PrimitiveEffect;Lcom/android/server/"
"VibratorService$Vibration;)V",
(void*)vibratorPerformComposedEffect},
- {"vibratorGetSupportedEffects", "()[I", (void*)vibratorGetSupportedEffects},
- {"vibratorSupportsExternalControl", "()Z", (void*)vibratorSupportsExternalControl},
- {"vibratorSetExternalControl", "(Z)V", (void*)vibratorSetExternalControl},
- {"vibratorGetCapabilities", "()J", (void*)vibratorGetCapabilities},
- {"vibratorAlwaysOnEnable", "(JJJ)V", (void*)vibratorAlwaysOnEnable},
- {"vibratorAlwaysOnDisable", "(J)V", (void*)vibratorAlwaysOnDisable},
+ {"vibratorGetSupportedEffects", "(J)[I", (void*)vibratorGetSupportedEffects},
+ {"vibratorSetExternalControl", "(JZ)V", (void*)vibratorSetExternalControl},
+ {"vibratorGetCapabilities", "(J)J", (void*)vibratorGetCapabilities},
+ {"vibratorAlwaysOnEnable", "(JJJJ)V", (void*)vibratorAlwaysOnEnable},
+ {"vibratorAlwaysOnDisable", "(JJ)V", (void*)vibratorAlwaysOnDisable},
};
int register_android_server_VibratorService(JNIEnv *env) {
- sMethodIdOnComplete = GetMethodIDOrDie(env,
- FindClassOrDie(env, "com/android/server/VibratorService$Vibration"),
- "onComplete", "()V");
- jclass primitiveClass = FindClassOrDie(env,
- "android/os/VibrationEffect$Composition$PrimitiveEffect");
+ sMethodIdOnComplete =
+ GetMethodIDOrDie(env,
+ FindClassOrDie(env, "com/android/server/VibratorService$Vibration"),
+ "onComplete", "()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");
- return jniRegisterNativeMethods(env, "com/android/server/VibratorService",
- method_table, NELEM(method_table));
+
+ return jniRegisterNativeMethods(env, "com/android/server/VibratorService", method_table,
+ NELEM(method_table));
}
-};
+}; // namespace android
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 7843663..0202c88 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -710,9 +710,8 @@
jobject tokenObj = javaObjectForIBinder(env, token);
jstring reasonObj = env->NewStringUTF(reason.c_str());
- jlong newTimeout = env->CallLongMethod(mServiceObj,
- gServiceClassInfo.notifyANR, inputApplicationHandleObj, tokenObj,
- reasonObj);
+ jlong newTimeout = env->CallLongMethod(mServiceObj, gServiceClassInfo.notifyANR,
+ inputApplicationHandleObj, tokenObj, reasonObj);
if (checkAndClearExceptionFromCallback(env, "notifyANR")) {
newTimeout = 0; // abort dispatch
} else {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ae6ccda..97ae505b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -121,9 +121,7 @@
import com.android.server.integrity.AppIntegrityManagerService;
import com.android.server.lights.LightsService;
import com.android.server.location.LocationManagerService;
-import com.android.server.media.MediaResourceMonitorService;
import com.android.server.media.MediaRouterService;
-import com.android.server.media.MediaSessionService;
import com.android.server.media.projection.MediaProjectionManagerService;
import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.net.NetworkStatsService;
@@ -152,6 +150,7 @@
import com.android.server.power.PowerManagerService;
import com.android.server.power.ShutdownThread;
import com.android.server.power.ThermalManagerService;
+import com.android.server.profcollect.ProfcollectForwardingService;
import com.android.server.recoverysystem.RecoverySystemService;
import com.android.server.restrictions.RestrictionsManagerService;
import com.android.server.role.RoleManagerService;
@@ -311,6 +310,10 @@
"com.android.server.rollback.RollbackManagerService";
private static final String ALARM_MANAGER_SERVICE_CLASS =
"com.android.server.alarm.AlarmManagerService";
+ private static final String MEDIA_SESSION_SERVICE_CLASS =
+ "com.android.server.media.MediaSessionService";
+ private static final String MEDIA_RESOURCE_MONITOR_SERVICE_CLASS =
+ "com.android.server.media.MediaResourceMonitorService";
private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
@@ -1229,6 +1232,12 @@
mSystemServiceManager.startService(IorapForwardingService.class);
t.traceEnd();
+ if (Build.IS_DEBUGGABLE) {
+ t.traceBegin("ProfcollectForwardingService");
+ mSystemServiceManager.startService(ProfcollectForwardingService.class);
+ t.traceEnd();
+ }
+
t.traceBegin("SignedConfigService");
SignedConfigService.registerUpdateReceiver(mSystemContext);
t.traceEnd();
@@ -1886,7 +1895,7 @@
t.traceEnd();
t.traceBegin("StartMediaSessionService");
- mSystemServiceManager.startService(MediaSessionService.class);
+ mSystemServiceManager.startService(MEDIA_SESSION_SERVICE_CLASS);
t.traceEnd();
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_HDMI_CEC)) {
@@ -1910,7 +1919,7 @@
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)) {
t.traceBegin("StartMediaResourceMonitor");
- mSystemServiceManager.startService(MediaResourceMonitorService.class);
+ mSystemServiceManager.startService(MEDIA_RESOURCE_MONITOR_SERVICE_CLASS);
t.traceEnd();
}
diff --git a/services/profcollect/Android.bp b/services/profcollect/Android.bp
new file mode 100644
index 0000000..68fba55
--- /dev/null
+++ b/services/profcollect/Android.bp
@@ -0,0 +1,35 @@
+// 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.
+
+filegroup {
+ name: "services.profcollect-javasources",
+ srcs: ["src/**/*.java"],
+ path: "src",
+ visibility: ["//frameworks/base/services"],
+}
+
+filegroup {
+ name: "services.profcollect-sources",
+ srcs: [
+ ":services.profcollect-javasources",
+ ":profcollectd_aidl",
+ ],
+ visibility: ["//frameworks/base/services:__subpackages__"],
+}
+
+java_library_static {
+ name: "services.profcollect",
+ srcs: [":services.profcollect-sources"],
+ libs: ["services.core"],
+}
diff --git a/services/profcollect/OWNERS b/services/profcollect/OWNERS
new file mode 100644
index 0000000..b380e39
--- /dev/null
+++ b/services/profcollect/OWNERS
@@ -0,0 +1,3 @@
+srhines@google.com
+yabinc@google.com
+yikong@google.com
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
new file mode 100644
index 0000000..bc75dcd
--- /dev/null
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -0,0 +1,196 @@
+/**
+ * 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.profcollect;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder.DeathRecipient;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import com.android.server.IoThread;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+import com.android.server.wm.ActivityMetricsLaunchObserver;
+import com.android.server.wm.ActivityMetricsLaunchObserverRegistry;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * System-server-local proxy into the {@code IProfcollectd} native service.
+ */
+public final class ProfcollectForwardingService extends SystemService {
+ public static final String LOG_TAG = "ProfcollectForwardingService";
+
+ private IProfCollectd mIProfcollect;
+ private ProfcollectForwardingService mSelfService;
+ private final Handler mHandler = new ProfcollectdHandler(IoThread.getHandler().getLooper());
+
+ public ProfcollectForwardingService(Context context) {
+ super(context);
+
+ if (mSelfService != null) {
+ throw new AssertionError("only one service instance allowed");
+ }
+ mSelfService = this;
+ }
+
+ @Override
+ public void onStart() {
+ Log.i(LOG_TAG, "Profcollect forwarding service start");
+ connectNativeService();
+ if (mIProfcollect == null) {
+ return;
+ }
+ if (serviceHasSupportedTraceProvider()) {
+ registerObservers();
+ }
+ }
+
+ private boolean serviceHasSupportedTraceProvider() {
+ if (mIProfcollect == null) {
+ return false;
+ }
+ try {
+ return !mIProfcollect.GetSupportedProvider().isEmpty();
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, e.getMessage());
+ return false;
+ }
+ }
+
+ private boolean tryConnectNativeService() {
+ if (connectNativeService()) {
+ return true;
+ }
+ // Cannot connect to the native service at this time, retry after a short delay.
+ mHandler.sendEmptyMessageDelayed(ProfcollectdHandler.MESSAGE_BINDER_CONNECT, 5000);
+ return false;
+ }
+
+ private boolean connectNativeService() {
+ try {
+ IProfCollectd profcollectd =
+ IProfCollectd.Stub.asInterface(
+ ServiceManager.getServiceOrThrow("profcollectd"));
+ profcollectd.asBinder().linkToDeath(new ProfcollectdDeathRecipient(), /*flags*/0);
+ mIProfcollect = profcollectd;
+ return true;
+ } catch (ServiceManager.ServiceNotFoundException | RemoteException e) {
+ Log.w(LOG_TAG, "Failed to connect profcollectd binder service.");
+ return false;
+ }
+ }
+
+ private class ProfcollectdHandler extends Handler {
+ public ProfcollectdHandler(Looper looper) {
+ super(looper);
+ }
+
+ public static final int MESSAGE_BINDER_CONNECT = 0;
+
+ @Override
+ public void handleMessage(android.os.Message message) {
+ switch (message.what) {
+ case MESSAGE_BINDER_CONNECT:
+ connectNativeService();
+ break;
+ default:
+ throw new AssertionError("Unknown message: " + message.toString());
+ }
+ }
+ }
+
+ private class ProfcollectdDeathRecipient implements DeathRecipient {
+ @Override
+ public void binderDied() {
+ Log.w(LOG_TAG, "profcollectd has died");
+
+ mIProfcollect = null;
+ tryConnectNativeService();
+ }
+ }
+
+ // Event observers
+ private void registerObservers() {
+ registerAppLaunchObserver();
+ }
+
+ private final AppLaunchObserver mAppLaunchObserver = new AppLaunchObserver();
+ private void registerAppLaunchObserver() {
+ ActivityTaskManagerInternal atmInternal =
+ LocalServices.getService(ActivityTaskManagerInternal.class);
+ ActivityMetricsLaunchObserverRegistry launchObserverRegistry =
+ atmInternal.getLaunchObserverRegistry();
+ launchObserverRegistry.registerLaunchObserver(mAppLaunchObserver);
+ }
+
+ private void traceOnAppStart(String packageName) {
+ if (mIProfcollect == null) {
+ return;
+ }
+
+ // Sample for a fraction of app launches.
+ int traceFrequency = SystemProperties.getInt("profcollectd.applaunch_trace_freq", 2);
+ int randomNum = ThreadLocalRandom.current().nextInt(100);
+ if (randomNum < traceFrequency) {
+ try {
+ Log.i(LOG_TAG, "Tracing on app launch event: " + packageName);
+ mIProfcollect.TraceOnce("applaunch");
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, e.getMessage());
+ }
+ }
+ }
+
+ private class AppLaunchObserver implements ActivityMetricsLaunchObserver {
+ @Override
+ public void onIntentStarted(Intent intent, long timestampNanos) {
+ traceOnAppStart(intent.getPackage());
+ }
+
+ @Override
+ public void onIntentFailed() {
+ // Ignored
+ }
+
+ @Override
+ public void onActivityLaunched(byte[] activity, int temperature) {
+ // Ignored
+ }
+
+ @Override
+ public void onActivityLaunchCancelled(byte[] abortingActivity) {
+ // Ignored
+ }
+
+ @Override
+ public void onActivityLaunchFinished(byte[] finalActivity, long timestampNanos) {
+ // Ignored
+ }
+
+ @Override
+ public void onReportFullyDrawn(byte[] activity, long timestampNanos) {
+ // Ignored
+ }
+ }
+}
diff --git a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
index ecdb30f..09552082 100644
--- a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
+++ b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
@@ -33,7 +33,6 @@
import com.android.server.pm.parsing.pkg.ParsedPackage
import com.android.server.pm.permission.PermissionManagerServiceInternal
import com.android.server.pm.test.override.PackageManagerComponentLabelIconOverrideTest.Companion.Params.AppType
-import com.android.server.pm.test.override.R
import com.android.server.testutils.TestHandler
import com.android.server.testutils.mock
import com.android.server.testutils.mockThrowOnUnmocked
@@ -266,7 +265,7 @@
.hideAsFinal()
private fun makePkgSetting(pkgName: String) = spy(PackageSetting(pkgName, null, File("/test"),
- File("/test"), null, null, null, null, 0, 0, 0, 0, null, null, null)) {
+ null, null, null, null, 0, 0, 0, 0, null, null, null)) {
this.pkgState.isUpdatedSystemApp = params.isUpdatedSystemApp
}
diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp
index 41dfade..cffcdd8 100644
--- a/services/tests/PackageManagerServiceTests/host/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/Android.bp
@@ -25,17 +25,28 @@
],
test_suites: ["general-tests"],
java_resources: [
- ":PackageManagerDummyAppVersion1",
- ":PackageManagerDummyAppVersion2",
- ":PackageManagerDummyAppVersion3",
- ":PackageManagerDummyAppVersion4",
- ":PackageManagerDummyAppOriginalOverride",
- ":PackageManagerServiceHostTestsResources",
- ]
+ ":PackageManagerTestAppStub",
+ ":PackageManagerTestAppVersion1",
+ ":PackageManagerTestAppVersion2",
+ ":PackageManagerTestAppVersion3",
+ ":PackageManagerTestAppVersion3Invalid",
+ ":PackageManagerTestAppVersion4",
+ ":PackageManagerTestAppOriginalOverride",
+ ],
}
-filegroup {
- name: "PackageManagerServiceHostTestsResources",
- srcs: [ "resources/*" ],
- path: "resources/"
+genrule {
+ name: "PackageManagerTestAppVersion3Invalid",
+ tools: [
+ "soong_zip",
+ "zipalign",
+ ],
+ srcs: [
+ ":PackageManagerTestAppVersion3",
+ ],
+ out: ["PackageManagerTestAppVersion3Invalid.apk"],
+ cmd: "mkdir -p $(genDir)/apk && unzip $(in) -d $(genDir)/apk" +
+ " && truncate -s 800 $(genDir)/apk/META-INF/CERT.RSA" +
+ " && $(location soong_zip) -o $(genDir)/temp.apk -L 0 -C $(genDir)/apk -D $(genDir)/apk" +
+ " && $(location zipalign) -f 4 $(genDir)/temp.apk $(out)",
}
diff --git a/services/tests/PackageManagerServiceTests/host/resources/PackageManagerDummyAppVersion3Invalid.apk b/services/tests/PackageManagerServiceTests/host/resources/PackageManagerDummyAppVersion3Invalid.apk
deleted file mode 100644
index 127886c..0000000
--- a/services/tests/PackageManagerServiceTests/host/resources/PackageManagerDummyAppVersion3Invalid.apk
+++ /dev/null
Binary files differ
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt
index 234fcf1..8dfefaf 100644
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt
@@ -21,8 +21,9 @@
import java.io.File
import java.io.FileOutputStream
-internal fun SystemPreparer.pushApk(file: String, partition: Partition) =
- pushResourceFile(file, HostUtils.makePathForApk(file, partition).toString())
+internal fun SystemPreparer.pushApk(javaResourceName: String, partition: Partition) =
+ pushResourceFile(javaResourceName, HostUtils.makePathForApk(javaResourceName, partition)
+ .toString())
internal fun SystemPreparer.deleteApkFolders(
partition: Partition,
@@ -58,4 +59,55 @@
}
return file
}
+
+ /**
+ * dumpsys package and therefore device.getAppPackageInfo doesn't work immediately after reboot,
+ * so the following methods parse the package dump directly to see if the path matches.
+ */
+ fun getCodePaths(device: ITestDevice, pkgName: String) =
+ device.executeShellCommand("pm dump $pkgName")
+ .lineSequence()
+ .map(String::trim)
+ .filter { it.startsWith("codePath=") }
+ .map { it.removePrefix("codePath=") }
+ .toList()
+
+ private fun userIdLineSequence(device: ITestDevice, pkgName: String) =
+ device.executeShellCommand("pm dump $pkgName")
+ .lineSequence()
+ .dropWhile { !it.startsWith("Packages:") }
+ .takeWhile {
+ !it.startsWith("Hidden system packages:") &&
+ !it.startsWith("Queries:")
+ }
+ .map(String::trim)
+ .filter { it.startsWith("User ") }
+
+ fun getUserIdToPkgEnabledState(device: ITestDevice, pkgName: String) =
+ userIdLineSequence(device, pkgName).associate {
+ val userId = it.removePrefix("User ")
+ .takeWhile(Char::isDigit)
+ .toInt()
+ val enabled = it.substringAfter("enabled=")
+ .takeWhile(Char::isDigit)
+ .toInt()
+ .let {
+ when (it) {
+ 0, 1 -> true
+ else -> false
+ }
+ }
+ userId to enabled
+ }
+
+ fun getUserIdToPkgInstalledState(device: ITestDevice, pkgName: String) =
+ userIdLineSequence(device, pkgName).associate {
+ val userId = it.removePrefix("User ")
+ .takeWhile(Char::isDigit)
+ .toInt()
+ val installed = it.substringAfter("installed=")
+ .takeWhile { !it.isWhitespace() }
+ .toBoolean()
+ userId to installed
+ }
}
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt
index 39b40d8..b7d1359 100644
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt
@@ -33,11 +33,11 @@
class InvalidNewSystemAppTest : BaseHostJUnit4Test() {
companion object {
- private const val TEST_PKG_NAME = "com.android.server.pm.test.dummy_app"
- private const val VERSION_ONE = "PackageManagerDummyAppVersion1.apk"
- private const val VERSION_TWO = "PackageManagerDummyAppVersion2.apk"
- private const val VERSION_THREE_INVALID = "PackageManagerDummyAppVersion3Invalid.apk"
- private const val VERSION_FOUR = "PackageManagerDummyAppVersion4.apk"
+ private const val TEST_PKG_NAME = "com.android.server.pm.test.test_app"
+ private const val VERSION_ONE = "PackageManagerTestAppVersion1.apk"
+ private const val VERSION_TWO = "PackageManagerTestAppVersion2.apk"
+ private const val VERSION_THREE_INVALID = "PackageManagerTestAppVersion3Invalid.apk"
+ private const val VERSION_FOUR = "PackageManagerTestAppVersion4.apk"
@get:ClassRule
val deviceRebootRule = SystemPreparer.TestRuleDelegate(true)
@@ -49,14 +49,14 @@
@get:Rule
val rules = RuleChain.outerRule(tempFolder).around(preparer)!!
- private val filePath = HostUtils.makePathForApk("PackageManagerDummyApp.apk", Partition.PRODUCT)
+ private val filePath = HostUtils.makePathForApk("PackageManagerTestApp.apk", Partition.PRODUCT)
@Before
@After
fun removeApk() {
device.uninstallPackage(TEST_PKG_NAME)
- device.deleteFile(filePath.parent.toString())
- device.reboot()
+ preparer.deleteFile(filePath.parent.toString())
+ .reboot()
}
@Test
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt
index fb0348c..4ae3ca5 100644
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt
@@ -33,11 +33,11 @@
class OriginalPackageMigrationTest : BaseHostJUnit4Test() {
companion object {
- private const val TEST_PKG_NAME = "com.android.server.pm.test.dummy_app"
- private const val VERSION_ONE = "PackageManagerDummyAppVersion1.apk"
- private const val VERSION_TWO = "PackageManagerDummyAppVersion2.apk"
- private const val VERSION_THREE = "PackageManagerDummyAppVersion3.apk"
- private const val NEW_PKG = "PackageManagerDummyAppOriginalOverride.apk"
+ private const val TEST_PKG_NAME = "com.android.server.pm.test.test_app"
+ private const val VERSION_ONE = "PackageManagerTestAppVersion1.apk"
+ private const val VERSION_TWO = "PackageManagerTestAppVersion2.apk"
+ private const val VERSION_THREE = "PackageManagerTestAppVersion3.apk"
+ private const val NEW_PKG = "PackageManagerTestAppOriginalOverride.apk"
@get:ClassRule
val deviceRebootRule = SystemPreparer.TestRuleDelegate(true)
@@ -55,6 +55,7 @@
fun deleteApkFolders() {
preparer.deleteApkFolders(Partition.SYSTEM, VERSION_ONE, VERSION_TWO, VERSION_THREE,
NEW_PKG)
+ .reboot()
}
@Test
@@ -99,9 +100,7 @@
}
private fun assertCodePath(apk: String) {
- // dumpsys package and therefore device.getAppPackageInfo doesn't work here for some reason,
- // so parse the package dump directly to see if the path matches.
- assertThat(device.executeShellCommand("pm dump $TEST_PKG_NAME"))
- .contains(HostUtils.makePathForApk(apk, Partition.SYSTEM).parent.toString())
+ assertThat(HostUtils.getCodePaths(device, TEST_PKG_NAME))
+ .containsExactly(HostUtils.makePathForApk(apk, Partition.SYSTEM).parent.toString())
}
}
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt
new file mode 100644
index 0000000..bc478b0
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt
@@ -0,0 +1,650 @@
+/*
+ * 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.pm.test
+
+import com.android.internal.util.test.SystemPreparer
+import com.android.tradefed.device.ITestDevice
+import com.android.tradefed.device.UserInfo
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test
+import com.google.common.truth.Truth.assertThat
+import org.junit.AfterClass
+import org.junit.Before
+import org.junit.ClassRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.RuleChain
+import org.junit.rules.TemporaryFolder
+import org.junit.runner.RunWith
+import java.io.File
+import java.util.zip.GZIPOutputStream
+
+@RunWith(DeviceJUnit4ClassRunner::class)
+class SystemStubMultiUserDisableUninstallTest : BaseHostJUnit4Test() {
+
+ companion object {
+ private const val TEST_PKG_NAME = "com.android.server.pm.test.test_app"
+ private const val VERSION_STUB = "PackageManagerTestAppStub.apk"
+ private const val VERSION_ONE = "PackageManagerTestAppVersion1.apk"
+
+ /**
+ * How many total users on device to test, including primary. This will clean up any
+ * users created specifically for this test.
+ */
+ private const val USER_COUNT = 3
+
+ /**
+ * Whether to manually reset state at each test method without rebooting
+ * for faster iterative development.
+ */
+ private const val DEBUG_NO_REBOOT = false
+
+ @get:ClassRule
+ val deviceRebootRule = SystemPreparer.TestRuleDelegate(true)
+
+ private val parentClassName = SystemStubMultiUserDisableUninstallTest::class.java.simpleName
+
+ private val deviceCompressedFile =
+ HostUtils.makePathForApk("$parentClassName.apk", Partition.PRODUCT).parent
+ .resolve("$parentClassName.apk.gz")
+
+ private val stubFile =
+ HostUtils.makePathForApk("$parentClassName-Stub.apk", Partition.PRODUCT)
+
+ private val secondaryUsers = mutableListOf<Int>()
+ private val usersToRemove = mutableListOf<Int>()
+ private var savedDevice: ITestDevice? = null
+ private var savedPreparer: SystemPreparer? = null
+
+ private fun setUpUsers(device: ITestDevice) {
+ if (this.savedDevice != null) return
+ this.savedDevice = device
+ secondaryUsers.clear()
+ secondaryUsers += device.userInfos.values.map(UserInfo::userId).filterNot { it == 0 }
+ while (secondaryUsers.size < USER_COUNT) {
+ secondaryUsers += device.createUser(parentClassName + secondaryUsers.size)
+ .also { usersToRemove += it }
+ }
+ }
+
+ @JvmStatic
+ @AfterClass
+ fun cleanUp() {
+ savedDevice ?: return
+
+ usersToRemove.forEach {
+ savedDevice?.removeUser(it)
+ }
+
+ savedDevice?.uninstallPackage(TEST_PKG_NAME)
+ savedDevice?.deleteFile(stubFile.parent.toString())
+ savedDevice?.deleteFile(deviceCompressedFile.parent.toString())
+ savedDevice?.reboot()
+ savedDevice = null
+
+ if (DEBUG_NO_REBOOT) {
+ savedPreparer?.after()
+ savedPreparer = null
+ }
+ }
+ }
+
+ private val tempFolder = TemporaryFolder()
+ private val preparer: SystemPreparer = SystemPreparer(tempFolder,
+ SystemPreparer.RebootStrategy.START_STOP, deviceRebootRule) { this.device }
+
+ @get:Rule
+ val rules = RuleChain.outerRule(tempFolder).let {
+ if (DEBUG_NO_REBOOT) {
+ it!!
+ } else {
+ it.around(preparer)!!
+ }
+ }
+
+ private var hostCompressedFile: File? = null
+
+ private val previousCodePaths = mutableListOf<String>()
+
+ @Before
+ fun ensureUserAndCompressStubAndInstall() {
+ setUpUsers(device)
+
+ val initialized = hostCompressedFile != null
+ if (!initialized) {
+ hostCompressedFile = tempFolder.newFile()
+ hostCompressedFile!!.outputStream().use {
+ javaClass.classLoader
+ .getResource(VERSION_ONE)!!
+ .openStream()
+ .use { input ->
+ GZIPOutputStream(it).use { output ->
+ input.copyTo(output)
+ }
+ }
+ }
+ }
+
+ device.uninstallPackage(TEST_PKG_NAME)
+
+ if (!initialized || !DEBUG_NO_REBOOT) {
+ savedPreparer = preparer
+ preparer.pushResourceFile(VERSION_STUB, stubFile.toString())
+ .pushFile(hostCompressedFile, deviceCompressedFile.toString())
+ .reboot()
+ }
+
+ // This test forces the state to installed/enabled for all users,
+ // since it only tests the uninstall/disable side.
+ installExisting(User.PRIMARY)
+ installExisting(User.SECONDARY)
+
+ ensureEnabled()
+
+ // Ensure data app isn't re-installed multiple times by comparing against the original path
+ val codePath = HostUtils.getCodePaths(device, TEST_PKG_NAME).first()
+ assertThat(codePath).contains("/data/app")
+ assertThat(codePath).contains(TEST_PKG_NAME)
+
+ previousCodePaths.clear()
+ previousCodePaths += codePath
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun disablePrimaryFirstAndUninstall() {
+ toggleEnabled(false, User.PRIMARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(false, User.SECONDARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = false,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+
+ device.uninstallPackage(TEST_PKG_NAME)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = false,
+ codePaths = listOf(CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun disableSecondaryFirstAndUninstall() {
+ toggleEnabled(false, User.SECONDARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = false,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(false, User.PRIMARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = false,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+
+ device.uninstallPackage(TEST_PKG_NAME)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = false,
+ codePaths = listOf(CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun disabledUninstalledEnablePrimaryFirst() {
+ toggleEnabled(false, User.PRIMARY)
+ toggleEnabled(false, User.SECONDARY)
+ device.uninstallPackage(TEST_PKG_NAME)
+
+ toggleEnabled(true, User.PRIMARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = false,
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.SECONDARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun disabledUninstalledEnableSecondaryFirst() {
+ toggleEnabled(false, User.PRIMARY)
+ toggleEnabled(false, User.SECONDARY)
+ device.uninstallPackage(TEST_PKG_NAME)
+
+ toggleEnabled(true, User.SECONDARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.PRIMARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun uninstallPrimaryFirstByUserAndInstallExistingPrimaryFirst() {
+ uninstall(User.PRIMARY)
+
+ assertState(
+ primaryInstalled = false, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ uninstall(User.SECONDARY)
+
+ assertState(
+ primaryInstalled = false, primaryEnabled = true,
+ secondaryInstalled = false, secondaryEnabled = true,
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ installExisting(User.PRIMARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = false, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+
+ installExisting(User.SECONDARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun uninstallSecondaryFirstByUserAndInstallExistingSecondaryFirst() {
+ uninstall(User.PRIMARY)
+
+ assertState(
+ primaryInstalled = false, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ uninstall(User.SECONDARY)
+
+ assertState(
+ primaryInstalled = false, primaryEnabled = true,
+ secondaryInstalled = false, secondaryEnabled = true,
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ installExisting(User.SECONDARY)
+
+ assertState(
+ primaryInstalled = false, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+
+ installExisting(User.PRIMARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun uninstallUpdatesAndEnablePrimaryFirst() {
+ device.executeShellCommand("pm uninstall-system-updates $TEST_PKG_NAME")
+
+ // Uninstall-system-updates always disables system user 0
+ // TODO: Is this intentional? There is no user argument for this command.
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = true,
+ // If any user is enabled when uninstalling updates, /data is re-uncompressed
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.PRIMARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+
+ // Test enabling secondary to ensure path does not change, even though it's already enabled
+ toggleEnabled(true, User.SECONDARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun uninstallUpdatesAndEnableSecondaryFirst() {
+ device.executeShellCommand("pm uninstall-system-updates $TEST_PKG_NAME")
+
+ // Uninstall-system-updates always disables system user 0
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = true,
+ // If any user is enabled when uninstalling updates, /data is re-uncompressed
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.SECONDARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.PRIMARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun disabledUninstallUpdatesAndEnablePrimaryFirst() {
+ toggleEnabled(false, User.PRIMARY)
+ toggleEnabled(false, User.SECONDARY)
+
+ device.executeShellCommand("pm uninstall-system-updates $TEST_PKG_NAME")
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = false,
+ codePaths = listOf(CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.PRIMARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = false,
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.SECONDARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun disabledUninstallUpdatesAndEnableSecondaryFirst() {
+ toggleEnabled(false, User.PRIMARY)
+ toggleEnabled(false, User.SECONDARY)
+
+ device.executeShellCommand("pm uninstall-system-updates $TEST_PKG_NAME")
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = false,
+ codePaths = listOf(CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.SECONDARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.PRIMARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun uninstalledUninstallUpdatesAndEnablePrimaryFirst() {
+ uninstall(User.PRIMARY)
+ uninstall(User.SECONDARY)
+
+ device.executeShellCommand("pm uninstall-system-updates $TEST_PKG_NAME")
+
+ // Uninstall-system-updates always disables system user 0
+ assertState(
+ primaryInstalled = false, primaryEnabled = false,
+ secondaryInstalled = false, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.PRIMARY)
+
+ assertState(
+ primaryInstalled = false, primaryEnabled = true,
+ secondaryInstalled = false, secondaryEnabled = true,
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.SECONDARY)
+
+ assertState(
+ primaryInstalled = false, primaryEnabled = true,
+ secondaryInstalled = false, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun uninstalledUninstallUpdatesAndEnableSecondaryFirst() {
+ uninstall(User.PRIMARY)
+ uninstall(User.SECONDARY)
+
+ device.executeShellCommand("pm uninstall-system-updates $TEST_PKG_NAME")
+
+ // Uninstall-system-updates always disables system user 0
+ assertState(
+ primaryInstalled = false, primaryEnabled = false,
+ secondaryInstalled = false, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.SECONDARY)
+
+ assertState(
+ primaryInstalled = false, primaryEnabled = false,
+ secondaryInstalled = false, secondaryEnabled = true,
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.PRIMARY)
+
+ assertState(
+ primaryInstalled = false, primaryEnabled = true,
+ secondaryInstalled = false, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ private fun ensureEnabled() {
+ toggleEnabled(true, User.PRIMARY)
+ toggleEnabled(true, User.SECONDARY)
+
+ assertThat(HostUtils.getUserIdToPkgEnabledState(device, TEST_PKG_NAME).all { it.value })
+ .isTrue()
+ }
+
+ private fun toggleEnabled(enabled: Boolean, user: User, pkgName: String = TEST_PKG_NAME) {
+ val command = if (enabled) "enable" else "disable"
+ @Suppress("UNUSED_VARIABLE") val exhaust: Any = when (user) {
+ User.PRIMARY -> {
+ device.executeShellCommand("pm $command --user 0 $pkgName")
+ }
+ User.SECONDARY -> {
+ secondaryUsers.forEach {
+ device.executeShellCommand("pm $command --user $it $pkgName")
+ }
+ }
+ }
+ }
+
+ private fun uninstall(user: User, pkgName: String = TEST_PKG_NAME) {
+ @Suppress("UNUSED_VARIABLE") val exhaust: Any = when (user) {
+ User.PRIMARY -> {
+ device.executeShellCommand("pm uninstall --user 0 $pkgName")
+ }
+ User.SECONDARY -> {
+ secondaryUsers.forEach {
+ device.executeShellCommand("pm uninstall --user $it $pkgName")
+ }
+ }
+ }
+ }
+
+ private fun installExisting(user: User, pkgName: String = TEST_PKG_NAME) {
+ @Suppress("UNUSED_VARIABLE") val exhaust: Any = when (user) {
+ User.PRIMARY -> {
+ device.executeShellCommand("pm install-existing --user 0 $pkgName")
+ }
+ User.SECONDARY -> {
+ secondaryUsers.forEach {
+ device.executeShellCommand("pm install-existing --user $it $pkgName")
+ }
+ }
+ }
+ }
+
+ private fun assertState(
+ primaryInstalled: Boolean,
+ primaryEnabled: Boolean,
+ secondaryInstalled: Boolean,
+ secondaryEnabled: Boolean,
+ codePaths: List<CodePath>
+ ) {
+ HostUtils.getUserIdToPkgInstalledState(device, TEST_PKG_NAME)
+ .forEach { (userId, installed) ->
+ if (userId == 0) {
+ assertThat(installed).isEqualTo(primaryInstalled)
+ } else {
+ assertThat(installed).isEqualTo(secondaryInstalled)
+ }
+ }
+
+ HostUtils.getUserIdToPkgEnabledState(device, TEST_PKG_NAME)
+ .forEach { (userId, enabled) ->
+ if (userId == 0) {
+ assertThat(enabled).isEqualTo(primaryEnabled)
+ } else {
+ assertThat(enabled).isEqualTo(secondaryEnabled)
+ }
+ }
+
+ assertCodePaths(codePaths.first(), codePaths.getOrNull(1))
+ }
+
+ private fun assertCodePaths(firstCodePath: CodePath, secondCodePath: CodePath? = null) {
+ val codePaths = HostUtils.getCodePaths(device, TEST_PKG_NAME)
+ assertThat(codePaths).hasSize(listOfNotNull(firstCodePath, secondCodePath).size)
+
+ when (firstCodePath) {
+ CodePath.SAME -> {
+ assertThat(codePaths[0]).contains("/data/app")
+ assertThat(codePaths[0]).contains(TEST_PKG_NAME)
+ assertThat(codePaths[0]).isEqualTo(previousCodePaths.last())
+ }
+ CodePath.DIFFERENT -> {
+ assertThat(codePaths[0]).contains("/data/app")
+ assertThat(codePaths[0]).contains(TEST_PKG_NAME)
+ assertThat(previousCodePaths).doesNotContain(codePaths[0])
+ previousCodePaths.add(codePaths[0])
+ }
+ CodePath.SYSTEM -> assertThat(codePaths[0]).isEqualTo(stubFile.parent.toString())
+ }
+
+ when (secondCodePath) {
+ CodePath.SAME, CodePath.DIFFERENT ->
+ throw AssertionError("secondDataPath cannot be a data path")
+ CodePath.SYSTEM -> assertThat(codePaths[1]).isEqualTo(stubFile.parent.toString())
+ }
+ }
+
+ enum class User {
+ /** The primary system user 0 */
+ PRIMARY,
+
+ /**
+ * All other users on the device that are not 0. This is split into an enum so that all
+ * methods that handle secondary act on all non-system users. Some behaviors only occur
+ * if a package state is marked for all non-primary users on the device, which can be
+ * more than just 1.
+ */
+ SECONDARY
+ }
+
+ enum class CodePath {
+ /** The data code path hasn't changed */
+ SAME,
+
+ /** New data code path */
+ DIFFERENT,
+
+ /** The static system code path */
+ SYSTEM
+ }
+}
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp
index c9b2927..4a3076e 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp
@@ -13,26 +13,32 @@
// limitations under the License.
android_test_helper_app {
- name: "PackageManagerDummyAppVersion1",
+ name: "PackageManagerTestAppStub",
+ manifest: "AndroidManifestVersion1.xml",
+ srcs: []
+}
+
+android_test_helper_app {
+ name: "PackageManagerTestAppVersion1",
manifest: "AndroidManifestVersion1.xml"
}
android_test_helper_app {
- name: "PackageManagerDummyAppVersion2",
+ name: "PackageManagerTestAppVersion2",
manifest: "AndroidManifestVersion2.xml"
}
android_test_helper_app {
- name: "PackageManagerDummyAppVersion3",
+ name: "PackageManagerTestAppVersion3",
manifest: "AndroidManifestVersion3.xml"
}
android_test_helper_app {
- name: "PackageManagerDummyAppVersion4",
+ name: "PackageManagerTestAppVersion4",
manifest: "AndroidManifestVersion4.xml"
}
android_test_helper_app {
- name: "PackageManagerDummyAppOriginalOverride",
+ name: "PackageManagerTestAppOriginalOverride",
manifest: "AndroidManifestOriginalOverride.xml"
}
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml
index f16e1bc..cba580e 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml
@@ -16,10 +16,10 @@
-->
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.pm.test.dummy_app.override"
+ package="com.android.server.pm.test.test_app.override"
android:versionCode="2"
>
- <original-package android:name="com.android.server.pm.test.dummy_app"/>
+ <original-package android:name="com.android.server.pm.test.test_app"/>
</manifest>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml
index b492a31..efc7372 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml
@@ -16,12 +16,12 @@
-->
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.pm.test.dummy_app"
+ package="com.android.server.pm.test.test_app"
android:versionCode="1"
>
<permission
- android:name="com.android.server.pm.test.dummy_app.TEST_PERMISSION"
+ android:name="com.android.server.pm.test.test_app.TEST_PERMISSION"
android:protectionLevel="normal"
/>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml
index 25e9f8e..620054c 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml
@@ -16,12 +16,12 @@
-->
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.pm.test.dummy_app"
+ package="com.android.server.pm.test.test_app"
android:versionCode="2"
>
<permission
- android:name="com.android.server.pm.test.dummy_app.TEST_PERMISSION"
+ android:name="com.android.server.pm.test.test_app.TEST_PERMISSION"
android:protectionLevel="normal"
/>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml
index 935f5e6..1997771 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml
@@ -16,12 +16,12 @@
-->
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.pm.test.dummy_app"
+ package="com.android.server.pm.test.test_app"
android:versionCode="3"
>
<permission
- android:name="com.android.server.pm.test.dummy_app.TEST_PERMISSION"
+ android:name="com.android.server.pm.test.test_app.TEST_PERMISSION"
android:protectionLevel="normal"
/>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion4.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion4.xml
index d0643cb..d6ade03 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion4.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion4.xml
@@ -16,12 +16,12 @@
-->
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.pm.test.dummy_app"
+ package="com.android.server.pm.test.test_app"
android:versionCode="4"
>
<permission
- android:name="com.android.server.pm.test.dummy_app.TEST_PERMISSION"
+ android:name="com.android.server.pm.test.test_app.TEST_PERMISSION"
android:protectionLevel="normal"
/>
diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml
index 44eb828..a398961 100644
--- a/services/tests/mockingservicestests/AndroidManifest.xml
+++ b/services/tests/mockingservicestests/AndroidManifest.xml
@@ -17,6 +17,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.frameworks.mockingservicestests">
+ <uses-sdk android:targetSdkVersion="30" />
+
<uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/>
<uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 2a267c4..1b2711d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -99,6 +99,7 @@
import org.junit.BeforeClass;
import org.junit.Test;
+import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
@@ -165,7 +166,7 @@
setFieldValue(ActivityManagerService.class, sService, "mHandler",
mock(ActivityManagerService.MainHandler.class));
setFieldValue(ActivityManagerService.class, sService, "mProcessStats",
- mock(ProcessStatsService.class));
+ new ProcessStatsService(sService, new File(sContext.getFilesDir(), "procstats")));
setFieldValue(ActivityManagerService.class, sService, "mBackupTargets",
mock(SparseArray.class));
setFieldValue(ActivityManagerService.class, sService, "mOomAdjProfiler",
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
index 0a61c44..7a3a950 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -130,7 +130,9 @@
}
@After
- public void resetStaticMocks() {
+ public void tearDown() {
+ mAppOpsService.shutdown();
+
mMockingSession.finishMocking();
}
@@ -216,9 +218,8 @@
false);
mAppOpsService.writeState();
- // Create a new app ops service, and initialize its state from XML.
+ // Create a new app ops service which will initialize its state from XML.
setupAppOpsService();
- mAppOpsService.readState();
// Query the state of the 2nd service.
List<PackageOps> loggedOps = getLoggedOps();
@@ -233,9 +234,8 @@
mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false);
mAppOpsService.shutdown();
- // Create a new app ops service, and initialize its state from XML.
+ // Create a new app ops service which will initialize its state from XML.
setupAppOpsService();
- mAppOpsService.readState();
// Query the state of the 2nd service.
List<PackageOps> loggedOps = getLoggedOps();
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
new file mode 100644
index 0000000..1cb004a
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
@@ -0,0 +1,971 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
+import static android.app.AlarmManager.WINDOW_EXACT;
+import static android.app.AppOpsManager.OP_FINE_LOCATION;
+import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
+import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
+import static android.location.Criteria.ACCURACY_COARSE;
+import static android.location.Criteria.ACCURACY_FINE;
+import static android.location.Criteria.POWER_HIGH;
+import static android.location.LocationManager.PASSIVE_PROVIDER;
+
+import static androidx.test.ext.truth.location.LocationSubject.assertThat;
+
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
+import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
+import static com.android.server.location.LocationUtils.createLocation;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.after;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import android.app.AlarmManager;
+import android.app.AlarmManager.OnAlarmListener;
+import android.content.Context;
+import android.location.ILocationCallback;
+import android.location.ILocationListener;
+import android.location.Location;
+import android.location.LocationManagerInternal;
+import android.location.LocationManagerInternal.ProviderEnabledListener;
+import android.location.LocationRequest;
+import android.location.util.identity.CallerIdentity;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.ICancellationSignal;
+import android.os.IRemoteCallback;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.WorkSource;
+import android.platform.test.annotations.Presubmit;
+import android.util.Log;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.location.ProviderProperties;
+import com.android.internal.location.ProviderRequest;
+import com.android.server.FgThread;
+import com.android.server.LocalServices;
+import com.android.server.location.listeners.ListenerRegistration;
+import com.android.server.location.util.FakeUserInfoHelper;
+import com.android.server.location.util.TestInjector;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Collections;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LocationProviderManagerTest {
+
+ private static final String TAG = "LocationProviderManagerTest";
+
+ private static final long TIMEOUT_MS = 1000;
+
+ private static final int CURRENT_USER = FakeUserInfoHelper.DEFAULT_USERID;
+ private static final int OTHER_USER = CURRENT_USER + 10;
+
+ private static final String NAME = "test";
+ private static final ProviderProperties PROPERTIES = new ProviderProperties(false, false, false,
+ false, true, true, true, POWER_HIGH, ACCURACY_FINE);
+ private static final CallerIdentity IDENTITY = CallerIdentity.forTest(CURRENT_USER, 1,
+ "mypackage",
+ "attribution");
+
+ private Random mRandom;
+
+ @Mock
+ private LocationManagerInternal mInternal;
+ @Mock
+ private Context mContext;
+ @Mock
+ private AlarmManager mAlarmManager;
+ @Mock
+ private PowerManager mPowerManager;
+ @Mock
+ private PowerManager.WakeLock mWakeLock;
+
+ private TestInjector mInjector;
+ private PassiveLocationProviderManager mPassive;
+ private TestProvider mProvider;
+
+ private LocationProviderManager mManager;
+
+ @Before
+ public void setUp() {
+ initMocks(this);
+
+ long seed = System.currentTimeMillis();
+ Log.i(TAG, "location random seed: " + seed);
+
+ mRandom = new Random(seed);
+
+ LocalServices.addService(LocationManagerInternal.class, mInternal);
+
+ doReturn("android").when(mContext).getPackageName();
+ doReturn(mAlarmManager).when(mContext).getSystemService(AlarmManager.class);
+ doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
+ doReturn(mWakeLock).when(mPowerManager).newWakeLock(anyInt(), anyString());
+
+ mInjector = new TestInjector();
+ mInjector.getUserInfoHelper().startUser(OTHER_USER);
+
+ mPassive = new PassiveLocationProviderManager(mContext, mInjector);
+ mPassive.startManager();
+ mPassive.setRealProvider(new PassiveProvider(mContext));
+
+ mProvider = new TestProvider(PROPERTIES, IDENTITY);
+ mProvider.setProviderAllowed(true);
+
+ mManager = new LocationProviderManager(mContext, mInjector, NAME, mPassive);
+ mManager.startManager();
+ mManager.setRealProvider(mProvider);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ LocalServices.removeServiceForTest(LocationManagerInternal.class);
+
+ // some test failures may leave the fg thread stuck, interrupt until we get out of it
+ CountDownLatch latch = new CountDownLatch(1);
+ FgThread.getExecutor().execute(latch::countDown);
+ int count = 0;
+ while (++count < 10 && !latch.await(10, TimeUnit.MILLISECONDS)) {
+ FgThread.get().getLooper().getThread().interrupt();
+ }
+ }
+
+ @Test
+ public void testProperties() {
+ assertThat(mManager.getName()).isEqualTo(NAME);
+ assertThat(mManager.getProperties()).isEqualTo(PROPERTIES);
+ assertThat(mManager.getIdentity()).isEqualTo(IDENTITY);
+ assertThat(mManager.hasProvider()).isTrue();
+
+ ProviderProperties newProperties = new ProviderProperties(true, true, true,
+ true, false, false, false, POWER_HIGH, ACCURACY_COARSE);
+ mProvider.setProperties(newProperties);
+ assertThat(mManager.getProperties()).isEqualTo(newProperties);
+
+ CallerIdentity newIdentity = CallerIdentity.forTest(OTHER_USER, 1, "otherpackage",
+ "otherattribution");
+ mProvider.setIdentity(newIdentity);
+ assertThat(mManager.getIdentity()).isEqualTo(newIdentity);
+
+ mManager.setRealProvider(null);
+ assertThat(mManager.hasProvider()).isFalse();
+ }
+
+ @Test
+ public void testRemoveProvider() {
+ mManager.setRealProvider(null);
+ assertThat(mManager.hasProvider()).isFalse();
+ }
+
+ @Test
+ public void testIsEnabled() {
+ assertThat(mManager.isEnabled(CURRENT_USER)).isTrue();
+
+ mInjector.getSettingsHelper().setLocationEnabled(false, CURRENT_USER);
+ assertThat(mManager.isEnabled(CURRENT_USER)).isFalse();
+
+ mInjector.getSettingsHelper().setLocationEnabled(true, CURRENT_USER);
+ mProvider.setAllowed(false);
+ assertThat(mManager.isEnabled(CURRENT_USER)).isFalse();
+
+ mProvider.setAllowed(true);
+ mInjector.getUserInfoHelper().setCurrentUserId(OTHER_USER);
+ assertThat(mManager.isEnabled(CURRENT_USER)).isFalse();
+ assertThat(mManager.isEnabled(OTHER_USER)).isTrue();
+
+ mInjector.getUserInfoHelper().setCurrentUserId(CURRENT_USER);
+ assertThat(mManager.isEnabled(CURRENT_USER)).isTrue();
+ assertThat(mManager.isEnabled(OTHER_USER)).isFalse();
+ }
+
+ @Test
+ public void testIsEnabledListener() {
+ ProviderEnabledListener listener = mock(ProviderEnabledListener.class);
+ mManager.addEnabledListener(listener);
+ verify(listener, never()).onProviderEnabledChanged(anyString(), anyInt(), anyBoolean());
+
+ mInjector.getSettingsHelper().setLocationEnabled(false, CURRENT_USER);
+ verify(listener, timeout(TIMEOUT_MS).times(1)).onProviderEnabledChanged(NAME, CURRENT_USER,
+ false);
+
+ mInjector.getSettingsHelper().setLocationEnabled(true, CURRENT_USER);
+ verify(listener, timeout(TIMEOUT_MS).times(1)).onProviderEnabledChanged(NAME, CURRENT_USER,
+ true);
+
+ mProvider.setAllowed(false);
+ verify(listener, timeout(TIMEOUT_MS).times(2)).onProviderEnabledChanged(NAME, CURRENT_USER,
+ false);
+
+ mProvider.setAllowed(true);
+ verify(listener, timeout(TIMEOUT_MS).times(2)).onProviderEnabledChanged(NAME, CURRENT_USER,
+ true);
+
+ mInjector.getUserInfoHelper().setCurrentUserId(OTHER_USER);
+ verify(listener, timeout(TIMEOUT_MS).times(3)).onProviderEnabledChanged(NAME, CURRENT_USER,
+ false);
+ verify(listener, timeout(TIMEOUT_MS).times(1)).onProviderEnabledChanged(NAME, OTHER_USER,
+ true);
+
+ mInjector.getUserInfoHelper().setCurrentUserId(CURRENT_USER);
+ verify(listener, timeout(TIMEOUT_MS).times(3)).onProviderEnabledChanged(NAME, CURRENT_USER,
+ true);
+ verify(listener, timeout(TIMEOUT_MS).times(1)).onProviderEnabledChanged(NAME, OTHER_USER,
+ false);
+
+ mManager.removeEnabledListener(listener);
+ mInjector.getSettingsHelper().setLocationEnabled(false, CURRENT_USER);
+ verifyNoMoreInteractions(listener);
+ }
+
+ @Test
+ public void testGetLastLocation_Fine() {
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+
+ Location loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
+ }
+
+ @Test
+ public void testGetLastLocation_Coarse() {
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+
+ Location loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ Location coarse = mManager.getLastLocation(request, IDENTITY, PERMISSION_COARSE);
+ assertThat(coarse).isNotEqualTo(loc);
+ assertThat(coarse).isNearby(loc, 5000);
+ }
+
+ @Test
+ public void testGetLastLocation_Bypass() {
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+ LocationRequest bypassRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false).setLocationSettingsIgnored(true);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+ assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isNull();
+
+ Location loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
+ assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+ loc);
+
+ mProvider.setProviderAllowed(false);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+ assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+ loc);
+
+ loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+ assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+ loc);
+
+ mProvider.setProviderAllowed(true);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+ assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+ loc);
+
+ loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
+ assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+ loc);
+ }
+
+ @Test
+ public void testGetLastLocation_ClearOnMockRemoval() {
+ MockProvider mockProvider = new MockProvider(PROPERTIES, IDENTITY);
+ mockProvider.setAllowed(true);
+ mManager.setMockProvider(mockProvider);
+
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+ Location loc = createLocation(NAME, mRandom);
+ mockProvider.setProviderLocation(loc);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
+
+ mManager.setMockProvider(null);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+ }
+
+ @Test
+ public void testInjectLastLocation() {
+ Location loc1 = createLocation(NAME, mRandom);
+ mManager.injectLastLocation(loc1, CURRENT_USER);
+
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc1);
+
+ Location loc2 = createLocation(NAME, mRandom);
+ mManager.injectLastLocation(loc2, CURRENT_USER);
+
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc1);
+ }
+
+ @Test
+ public void testPassive_Listener() throws Exception {
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(PASSIVE_PROVIDER, 0,
+ 0, false);
+ mPassive.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+ Location loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+
+ ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
+ verify(listener).onLocationChanged(locationCaptor.capture(),
+ nullable(IRemoteCallback.class));
+ assertThat(locationCaptor.getValue()).isEqualTo(loc);
+ }
+
+ @Test
+ public void testPassive_LastLocation() {
+ Location loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(PASSIVE_PROVIDER, 0,
+ 0, false);
+ assertThat(mPassive.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
+ }
+
+ @Test
+ public void testRegisterListener() throws Exception {
+ ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
+
+ ILocationListener listener = createMockLocationListener();
+ mManager.registerLocationRequest(
+ LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), IDENTITY,
+ PERMISSION_FINE, listener);
+
+ Location loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ verify(listener, times(1)).onLocationChanged(locationCaptor.capture(),
+ nullable(IRemoteCallback.class));
+ assertThat(locationCaptor.getValue()).isEqualTo(loc);
+
+ mInjector.getSettingsHelper().setLocationEnabled(false, CURRENT_USER);
+ verify(listener, timeout(TIMEOUT_MS).times(1)).onProviderEnabledChanged(NAME, false);
+ loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ verify(listener, times(1)).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+
+ mInjector.getSettingsHelper().setLocationEnabled(true, CURRENT_USER);
+ verify(listener, timeout(TIMEOUT_MS).times(1)).onProviderEnabledChanged(NAME, true);
+
+ mProvider.setAllowed(false);
+ verify(listener, timeout(TIMEOUT_MS).times(2)).onProviderEnabledChanged(NAME, false);
+ loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ verify(listener, times(1)).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+
+ mProvider.setAllowed(true);
+ verify(listener, timeout(TIMEOUT_MS).times(2)).onProviderEnabledChanged(NAME, true);
+
+ mInjector.getUserInfoHelper().setCurrentUserId(OTHER_USER);
+ verify(listener, timeout(TIMEOUT_MS).times(3)).onProviderEnabledChanged(NAME, false);
+ loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ verify(listener, times(1)).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+
+ mInjector.getUserInfoHelper().setCurrentUserId(CURRENT_USER);
+ verify(listener, timeout(TIMEOUT_MS).times(3)).onProviderEnabledChanged(NAME, true);
+
+ loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ verify(listener, times(2)).onLocationChanged(locationCaptor.capture(),
+ nullable(IRemoteCallback.class));
+ assertThat(locationCaptor.getValue()).isEqualTo(loc);
+ }
+
+ @Test
+ public void testRegisterListener_SameProcess() throws Exception {
+ ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
+
+ CallerIdentity identity = CallerIdentity.forTest(CURRENT_USER, Process.myPid(), "mypackage",
+ "attribution");
+
+ ILocationListener listener = createMockLocationListener();
+ mManager.registerLocationRequest(
+ LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), identity,
+ PERMISSION_FINE, listener);
+
+ Location loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ verify(listener, timeout(TIMEOUT_MS).times(1)).onLocationChanged(locationCaptor.capture(),
+ nullable(IRemoteCallback.class));
+ assertThat(locationCaptor.getValue()).isEqualTo(loc);
+ }
+
+ @Test
+ public void testRegisterListener_Unregister() throws Exception {
+ ILocationListener listener = createMockLocationListener();
+ mManager.registerLocationRequest(
+ LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), IDENTITY,
+ PERMISSION_FINE, listener);
+ mManager.unregisterLocationRequest(listener);
+
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ verify(listener, never()).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+
+ mInjector.getSettingsHelper().setLocationEnabled(false, CURRENT_USER);
+ verify(listener, after(TIMEOUT_MS).never()).onProviderEnabledChanged(NAME, false);
+ }
+
+ @Test
+ public void testRegisterListener_Unregister_SameProcess() throws Exception {
+ CallerIdentity identity = CallerIdentity.forTest(CURRENT_USER, Process.myPid(), "mypackage",
+ "attribution");
+
+ ILocationListener listener = createMockLocationListener();
+ mManager.registerLocationRequest(
+ LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), identity,
+ PERMISSION_FINE, listener);
+
+ CountDownLatch blocker = new CountDownLatch(1);
+ ListenerRegistration.IN_PROCESS_EXECUTOR.execute(() -> {
+ try {
+ blocker.await();
+ } catch (InterruptedException e) {
+ // do nothing
+ }
+ });
+
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ mManager.unregisterLocationRequest(listener);
+ blocker.countDown();
+ verify(listener, after(TIMEOUT_MS).never()).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+ }
+
+ @Test
+ public void testRegisterListener_NumUpdates() throws Exception {
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false).setNumUpdates(5);
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+
+ verify(listener, times(5)).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+ }
+
+ @Test
+ public void testRegisterListener_ExpiringAlarm() throws Exception {
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false).setExpireIn(5000);
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+ long baseTimeMs = SystemClock.elapsedRealtime();
+
+ ArgumentCaptor<Long> timeoutCapture = ArgumentCaptor.forClass(Long.class);
+ ArgumentCaptor<OnAlarmListener> listenerCapture = ArgumentCaptor.forClass(
+ OnAlarmListener.class);
+ verify(mAlarmManager).set(eq(ELAPSED_REALTIME_WAKEUP), timeoutCapture.capture(),
+ eq(WINDOW_EXACT), eq(0L), listenerCapture.capture(), any(Handler.class),
+ any(WorkSource.class));
+
+ assertThat(timeoutCapture.getValue()).isAtLeast(baseTimeMs + 4000);
+ assertThat(timeoutCapture.getValue()).isAtMost(baseTimeMs + 5000);
+ listenerCapture.getValue().onAlarm();
+
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ verify(listener, never()).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+ }
+
+ @Test
+ public void testRegisterListener_ExpiringNoAlarm() throws Exception {
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false).setExpireIn(25);
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+ Thread.sleep(25);
+
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ verify(listener, never()).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+ }
+
+ @Test
+ public void testRegisterListener_AlreadyExpired() throws Exception {
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false).setExpireIn(-1);
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ verify(listener, never()).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+ }
+
+ @Test
+ public void testRegisterListener_FastestInterval() throws Exception {
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 5000, 0,
+ false).setFastestInterval(5000);
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+
+ verify(listener, times(1)).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+ }
+
+ @Test
+ public void testRegisterListener_SmallestDisplacement() throws Exception {
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 5000, 0,
+ false).setSmallestDisplacement(1f);
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+ Location loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ mProvider.setProviderLocation(loc);
+
+ verify(listener, times(1)).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+ }
+
+ @Test
+ public void testRegisterListener_NoteOpFailure() throws Exception {
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+ mInjector.getAppOpsHelper().setAppOpAllowed(OP_FINE_LOCATION, IDENTITY.getPackageName(),
+ false);
+
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+
+ verify(listener, never()).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+ }
+
+ @Test
+ public void testRegisterListener_Wakelock() throws Exception {
+ CallerIdentity identity = CallerIdentity.forTest(CURRENT_USER, Process.myPid(), "mypackage",
+ "attribution");
+
+ ILocationListener listener = createMockLocationListener();
+ mManager.registerLocationRequest(
+ LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), identity,
+ PERMISSION_FINE, listener);
+
+ CountDownLatch blocker = new CountDownLatch(1);
+ ListenerRegistration.IN_PROCESS_EXECUTOR.execute(() -> {
+ try {
+ blocker.await();
+ } catch (InterruptedException e) {
+ // do nothing
+ }
+ });
+
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ verify(mWakeLock).acquire(anyLong());
+ verify(mWakeLock, never()).release();
+
+ blocker.countDown();
+ verify(listener, timeout(TIMEOUT_MS)).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+ verify(mWakeLock).acquire(anyLong());
+ verify(mWakeLock, timeout(TIMEOUT_MS)).release();
+ }
+
+ @Test
+ public void testGetCurrentLocation() throws Exception {
+ ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
+
+ ILocationCallback listener = createMockGetCurrentLocationListener();
+ LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false);
+ ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
+ mManager.getCurrentLocation(locationRequest, IDENTITY,
+ PERMISSION_FINE, cancellationSignal, listener);
+
+ Location loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+
+ verify(listener, times(1)).onLocation(locationCaptor.capture());
+ assertThat(locationCaptor.getValue()).isEqualTo(loc);
+ }
+
+ @Test
+ public void testGetCurrentLocation_Cancel() throws Exception {
+ ILocationCallback listener = createMockGetCurrentLocationListener();
+ LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false);
+ ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
+ mManager.getCurrentLocation(locationRequest, IDENTITY,
+ PERMISSION_FINE, cancellationSignal, listener);
+
+ cancellationSignal.cancel();
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+
+ verify(listener, never()).onLocation(nullable(Location.class));
+ }
+
+ @Test
+ public void testGetCurrentLocation_ProviderDisabled() throws Exception {
+ ILocationCallback listener = createMockGetCurrentLocationListener();
+ LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false);
+ ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
+ mManager.getCurrentLocation(locationRequest, IDENTITY,
+ PERMISSION_FINE, cancellationSignal, listener);
+
+ mProvider.setProviderAllowed(false);
+ mProvider.setProviderAllowed(true);
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ verify(listener, times(1)).onLocation(isNull());
+ }
+
+ @Test
+ public void testGetCurrentLocation_ProviderAlreadyDisabled() throws Exception {
+ mProvider.setProviderAllowed(false);
+
+ ILocationCallback listener = createMockGetCurrentLocationListener();
+ LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false);
+ ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
+ mManager.getCurrentLocation(locationRequest, IDENTITY,
+ PERMISSION_FINE, cancellationSignal, listener);
+
+ mProvider.setProviderAllowed(true);
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ verify(listener, times(1)).onLocation(isNull());
+ }
+
+ @Test
+ public void testGetCurrentLocation_LastLocation() throws Exception {
+ ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
+
+ Location loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+
+ ILocationCallback listener = createMockGetCurrentLocationListener();
+ LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false);
+ ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
+ mManager.getCurrentLocation(locationRequest, IDENTITY,
+ PERMISSION_FINE, cancellationSignal, listener);
+
+ verify(listener, times(1)).onLocation(locationCaptor.capture());
+ assertThat(locationCaptor.getValue()).isEqualTo(loc);
+ }
+
+ @Test
+ public void testGetCurrentLocation_Timeout() throws Exception {
+ ILocationCallback listener = createMockGetCurrentLocationListener();
+ LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false);
+ ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
+ mManager.getCurrentLocation(locationRequest, IDENTITY,
+ PERMISSION_FINE, cancellationSignal, listener);
+
+ ArgumentCaptor<OnAlarmListener> listenerCapture = ArgumentCaptor.forClass(
+ OnAlarmListener.class);
+ verify(mAlarmManager).set(eq(ELAPSED_REALTIME_WAKEUP), anyLong(),
+ eq(WINDOW_EXACT), eq(0L), listenerCapture.capture(), any(Handler.class),
+ any(WorkSource.class));
+ listenerCapture.getValue().onAlarm();
+
+ verify(listener, times(1)).onLocation(isNull());
+ }
+
+ @Test
+ public void testLocationMonitoring() {
+ assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_LOCATION,
+ IDENTITY.getPackageName())).isFalse();
+ assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_HIGH_POWER_LOCATION,
+ IDENTITY.getPackageName())).isFalse();
+
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+ assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_LOCATION,
+ IDENTITY.getPackageName())).isTrue();
+ assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_HIGH_POWER_LOCATION,
+ IDENTITY.getPackageName())).isTrue();
+
+ mInjector.getAppForegroundHelper().setAppForeground(IDENTITY.getUid(), false);
+
+ assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_LOCATION,
+ IDENTITY.getPackageName())).isTrue();
+ assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_HIGH_POWER_LOCATION,
+ IDENTITY.getPackageName())).isFalse();
+
+ mManager.unregisterLocationRequest(listener);
+
+ assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_LOCATION,
+ IDENTITY.getPackageName())).isFalse();
+ assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_HIGH_POWER_LOCATION,
+ IDENTITY.getPackageName())).isFalse();
+ }
+
+ @Test
+ public void testProviderRequest() {
+ assertThat(mProvider.getRequest().reportLocation).isFalse();
+ assertThat(mProvider.getRequest().locationRequests).isEmpty();
+
+ ILocationListener listener1 = createMockLocationListener();
+ LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0, false);
+ mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+ assertThat(mProvider.getRequest().reportLocation).isTrue();
+ assertThat(mProvider.getRequest().locationRequests).containsExactly(request1);
+ assertThat(mProvider.getRequest().locationSettingsIgnored).isFalse();
+ assertThat(mProvider.getRequest().interval).isEqualTo(5);
+ assertThat(mProvider.getRequest().lowPowerMode).isFalse();
+ assertThat(mProvider.getRequest().workSource).isNotNull();
+
+ ILocationListener listener2 = createMockLocationListener();
+ LocationRequest request2 = LocationRequest.createFromDeprecatedProvider(NAME, 1, 0,
+ false).setLowPowerMode(true);
+ mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
+
+ assertThat(mProvider.getRequest().reportLocation).isTrue();
+ assertThat(mProvider.getRequest().locationRequests).containsExactly(request1, request2);
+ assertThat(mProvider.getRequest().locationSettingsIgnored).isFalse();
+ assertThat(mProvider.getRequest().interval).isEqualTo(1);
+ assertThat(mProvider.getRequest().lowPowerMode).isFalse();
+ assertThat(mProvider.getRequest().workSource).isNotNull();
+
+ mManager.unregisterLocationRequest(listener1);
+
+ assertThat(mProvider.getRequest().reportLocation).isTrue();
+ assertThat(mProvider.getRequest().locationRequests).containsExactly(request2);
+ assertThat(mProvider.getRequest().locationSettingsIgnored).isFalse();
+ assertThat(mProvider.getRequest().interval).isEqualTo(1);
+ assertThat(mProvider.getRequest().lowPowerMode).isTrue();
+ assertThat(mProvider.getRequest().workSource).isNotNull();
+
+ mManager.unregisterLocationRequest(listener2);
+
+ assertThat(mProvider.getRequest().reportLocation).isFalse();
+ assertThat(mProvider.getRequest().locationRequests).isEmpty();
+ }
+
+ @Test
+ public void testProviderRequest_BackgroundThrottle() {
+ ILocationListener listener1 = createMockLocationListener();
+ LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0, false);
+ mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+ assertThat(mProvider.getRequest().interval).isEqualTo(5);
+
+ mInjector.getAppForegroundHelper().setAppForeground(IDENTITY.getUid(), false);
+ assertThat(mProvider.getRequest().interval).isEqualTo(
+ mInjector.getSettingsHelper().getBackgroundThrottleIntervalMs());
+ }
+
+ @Test
+ public void testProviderRequest_IgnoreLocationSettings() {
+ mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(
+ Collections.singleton(IDENTITY.getPackageName()));
+
+ ILocationListener listener1 = createMockLocationListener();
+ LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0, false);
+ mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+ assertThat(mProvider.getRequest().reportLocation).isTrue();
+ assertThat(mProvider.getRequest().interval).isEqualTo(5);
+ assertThat(mProvider.getRequest().locationSettingsIgnored).isFalse();
+
+ ILocationListener listener2 = createMockLocationListener();
+ LocationRequest request2 = LocationRequest.createFromDeprecatedProvider(NAME, 1, 0,
+ false).setLocationSettingsIgnored(true);
+ mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
+
+ assertThat(mProvider.getRequest().reportLocation).isTrue();
+ assertThat(mProvider.getRequest().interval).isEqualTo(1);
+ assertThat(mProvider.getRequest().locationSettingsIgnored).isTrue();
+ }
+
+ @Test
+ public void testProviderRequest_IgnoreLocationSettings_ProviderDisabled() {
+ mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(
+ Collections.singleton(IDENTITY.getPackageName()));
+
+ ILocationListener listener1 = createMockLocationListener();
+ LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 1, 0, false);
+ mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+ ILocationListener listener2 = createMockLocationListener();
+ LocationRequest request2 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0,
+ false).setLocationSettingsIgnored(true);
+ mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
+
+ mInjector.getSettingsHelper().setLocationEnabled(false, IDENTITY.getUserId());
+
+ assertThat(mProvider.getRequest().reportLocation).isTrue();
+ assertThat(mProvider.getRequest().locationRequests).containsExactly(request2);
+ assertThat(mProvider.getRequest().interval).isEqualTo(5);
+ assertThat(mProvider.getRequest().locationSettingsIgnored).isTrue();
+ }
+
+ @Test
+ public void testProviderRequest_IgnoreLocationSettings_NoAllowlist() {
+ mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(
+ Collections.singleton(IDENTITY.getPackageName()));
+
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 1, 0,
+ false).setLocationSettingsIgnored(true);
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+ mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(Collections.emptySet());
+
+ assertThat(mProvider.getRequest().reportLocation).isTrue();
+ assertThat(mProvider.getRequest().interval).isEqualTo(1);
+ assertThat(mProvider.getRequest().locationSettingsIgnored).isFalse();
+ }
+
+ @Test
+ public void testProviderRequest_BackgroundThrottle_IgnoreLocationSettings() {
+ mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(
+ Collections.singleton(IDENTITY.getPackageName()));
+
+ ILocationListener listener1 = createMockLocationListener();
+ LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0,
+ false).setLocationSettingsIgnored(true);
+ mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+ assertThat(mProvider.getRequest().interval).isEqualTo(5);
+
+ mInjector.getAppForegroundHelper().setAppForeground(IDENTITY.getUid(), false);
+ assertThat(mProvider.getRequest().interval).isEqualTo(5);
+ }
+
+ private ILocationListener createMockLocationListener() {
+ return spy(new ILocationListener.Stub() {
+ @Override
+ public void onLocationChanged(Location location, IRemoteCallback onCompleteCallback) {
+ if (onCompleteCallback != null) {
+ try {
+ onCompleteCallback.sendResult(null);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ @Override
+ public void onProviderEnabledChanged(String provider, boolean enabled) {
+ }
+ });
+ }
+
+ private ILocationCallback createMockGetCurrentLocationListener() {
+ return spy(new ILocationCallback.Stub() {
+ @Override
+ public void onLocation(Location location) {
+ }
+ });
+ }
+
+ private static class TestProvider extends AbstractLocationProvider {
+
+ private ProviderRequest mProviderRequest = ProviderRequest.EMPTY_REQUEST;
+
+ TestProvider(ProviderProperties properties, CallerIdentity identity) {
+ super(DIRECT_EXECUTOR, identity);
+ setProperties(properties);
+ }
+
+ public void setProviderAllowed(boolean allowed) {
+ setAllowed(allowed);
+ }
+
+ public void setProviderLocation(Location l) {
+ reportLocation(new Location(l));
+ }
+
+ public ProviderRequest getRequest() {
+ return mProviderRequest;
+ }
+
+ @Override
+ public void onSetRequest(ProviderRequest request) {
+ mProviderRequest = request;
+ }
+
+ @Override
+ protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
index c692253..1b6ac3c 100644
--- a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
@@ -183,13 +183,12 @@
@Test
public void hasAmplitudeControl_withAmplitudeControlSupport_returnsTrue() {
- when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
+ mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
assertTrue(createService().hasAmplitudeControl());
}
@Test
public void hasAmplitudeControl_withNoAmplitudeControlSupport_returnsFalse() {
- when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(false);
assertFalse(createService().hasAmplitudeControl());
}
@@ -270,7 +269,7 @@
@Test
public void vibrate_withOneShotAndAmplitudeControl_turnsVibratorOnAndSetsAmplitude() {
- when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
+ mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
VibratorService service = createService();
Mockito.clearInvocations(mNativeWrapperMock);
@@ -340,7 +339,7 @@
@Test
public void vibrate_withWaveform_controlsVibratorAmplitudeDuringTotalVibrationTime()
throws Exception {
- when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
+ mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
VibratorService service = createService();
Mockito.clearInvocations(mNativeWrapperMock);
@@ -511,7 +510,7 @@
setVibrationIntensityUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
Vibrator.VIBRATION_INTENSITY_OFF);
- when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
+ mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
VibratorService service = createService();
service.systemReady();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
index a9f2e4a..57bfbf3 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
@@ -27,6 +27,7 @@
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -95,12 +96,15 @@
ValueAnimator mMockValueAnimator;
ValueAnimator.AnimatorUpdateListener mTargetAnimationListener;
+ ValueAnimator.AnimatorListener mStateListener;
FullScreenMagnificationController mFullScreenMagnificationController;
+ Runnable mEndCallback;
@Before
public void setUp() {
Looper looper = InstrumentationRegistry.getContext().getMainLooper();
+ mEndCallback = Mockito.mock(Runnable.class);
// Pretending ID of the Thread associated with looper as main thread ID in controller
when(mMockContext.getMainLooper()).thenReturn(looper);
when(mMockControllerCtx.getContext()).thenReturn(mMockContext);
@@ -319,6 +323,7 @@
for (int i = 0; i < DISPLAY_COUNT; i++) {
setScaleAndCenter_animated_stateChangesAndAnimationHappens(i);
resetMockWindowManager();
+ Mockito.reset(mEndCallback);
}
}
@@ -331,7 +336,7 @@
MagnificationSpec endSpec = getMagnificationSpec(scale, offsets);
assertTrue(mFullScreenMagnificationController.setScaleAndCenter(displayId, scale,
- newCenter.x, newCenter.y, true, SERVICE_ID_1));
+ newCenter.x, newCenter.y, mEndCallback, SERVICE_ID_1));
mMessageCapturingHandler.sendAllMessages();
assertEquals(newCenter.x, mFullScreenMagnificationController.getCenterX(displayId), 0.5);
@@ -358,7 +363,33 @@
Mockito.reset(mMockWindowManager);
when(mMockValueAnimator.getAnimatedFraction()).thenReturn(1.0f);
mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
+ mStateListener.onAnimationEnd(mMockValueAnimator);
verify(mMockWindowManager).setMagnificationSpec(eq(displayId), argThat(closeTo(endSpec)));
+ verify(mEndCallback).run();
+ }
+
+ @Test
+ public void testSetScaleAndCenterWithAnimation_sameSpec_noAnimationButInvokeEndCallback() {
+ for (int i = 0; i < DISPLAY_COUNT; i++) {
+ setScaleAndCenter_sameSpec_noAnimationButInvokeEndCallback(i);
+ Mockito.reset(mEndCallback);
+ }
+ }
+
+ private void setScaleAndCenter_sameSpec_noAnimationButInvokeEndCallback(int displayId) {
+ register(displayId);
+ final PointF center = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
+ final float targetScale = 2.0f;
+ assertTrue(mFullScreenMagnificationController.setScaleAndCenter(displayId,
+ targetScale, center.x, center.y, false, SERVICE_ID_1));
+ mMessageCapturingHandler.sendAllMessages();
+
+ assertFalse(mFullScreenMagnificationController.setScaleAndCenter(displayId,
+ targetScale, center.x, center.y, mEndCallback, SERVICE_ID_1));
+ mMessageCapturingHandler.sendAllMessages();
+
+ verify(mMockValueAnimator, never()).start();
+ verify(mEndCallback).run();
}
@Test
@@ -639,6 +670,69 @@
}
@Test
+ public void testReset_notMagnifying_noStateChangeButInvokeCallback() {
+ for (int i = 0; i < DISPLAY_COUNT; i++) {
+ reset_notMagnifying_noStateChangeButInvokeCallback(i);
+ Mockito.reset(mEndCallback);
+ }
+ }
+
+ private void reset_notMagnifying_noStateChangeButInvokeCallback(int displayId) {
+ register(displayId);
+
+ assertFalse(mFullScreenMagnificationController.reset(displayId, mEndCallback));
+ mMessageCapturingHandler.sendAllMessages();
+
+ verify(mMockAms, never()).notifyMagnificationChanged(eq(displayId),
+ any(Region.class), anyFloat(), anyFloat(), anyFloat());
+ verify(mEndCallback).run();
+ }
+
+ @Test
+ public void testReset_Magnifying_resetsMagnificationAndInvokeLastEndCallback() {
+ for (int i = 0; i < DISPLAY_COUNT; i++) {
+ reset_Magnifying_resetsMagnificationAndInvokeLastEndCallback(i);
+ }
+ }
+
+ private void reset_Magnifying_resetsMagnificationAndInvokeLastEndCallback(int displayId) {
+ register(displayId);
+ float scale = 2.5f;
+ PointF firstCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
+ assertTrue(mFullScreenMagnificationController.setScaleAndCenter(displayId,
+ scale, firstCenter.x, firstCenter.y, mEndCallback, SERVICE_ID_1));
+ mMessageCapturingHandler.sendAllMessages();
+ Mockito.reset(mMockValueAnimator);
+ // Stubs the logic after the animation is started.
+ doAnswer(invocation -> {
+ mStateListener.onAnimationEnd(mMockValueAnimator);
+ return null;
+ }).when(mMockValueAnimator).cancel();
+ when(mMockValueAnimator.isRunning()).thenReturn(true);
+ // Intermediate point
+ float fraction = 0.33f;
+ when(mMockValueAnimator.getAnimatedFraction()).thenReturn(fraction);
+ mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
+ Runnable lastEndCallback = Mockito.mock(Runnable.class);
+
+ assertTrue(mFullScreenMagnificationController.reset(displayId, lastEndCallback));
+ mMessageCapturingHandler.sendAllMessages();
+
+ // Verify expected actions.
+ verify(mEndCallback, never()).run();
+ verify(mMockValueAnimator).start();
+ verify(mMockValueAnimator).cancel();
+
+ // Fast-forward the animation to the end.
+ when(mMockValueAnimator.getAnimatedFraction()).thenReturn(1.0f);
+ mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
+ mStateListener.onAnimationEnd(mMockValueAnimator);
+
+ assertFalse(mFullScreenMagnificationController.isMagnifying(DISPLAY_0));
+ verify(lastEndCallback).run();
+ }
+
+ @Test
public void testTurnScreenOff_resetsMagnification() {
register(DISPLAY_0);
register(DISPLAY_1);
@@ -1043,6 +1137,10 @@
ArgumentCaptor.forClass(ValueAnimator.AnimatorUpdateListener.class);
verify(mMockValueAnimator).addUpdateListener(listenerArgumentCaptor.capture());
mTargetAnimationListener = listenerArgumentCaptor.getValue();
+ ArgumentCaptor<ValueAnimator.AnimatorListener> animatorListenerArgumentCaptor =
+ ArgumentCaptor.forClass(ValueAnimator.AnimatorListener.class);
+ verify(mMockValueAnimator).addListener(animatorListenerArgumentCaptor.capture());
+ mStateListener = animatorListenerArgumentCaptor.getValue();
Mockito.reset(mMockValueAnimator); // Ignore other initialization
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index f991dff2..db56657 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -550,7 +550,6 @@
.setAppId(DUMMY_TARGET_APPID)
.setName("com.some.package")
.setCodePath("/")
- .setResourcePath("/")
.setPVersionCode(1L)
.build();
PackageSetting calling = simulateAddPackage(appsFilter,
@@ -874,7 +873,6 @@
.setAppId(appId)
.setName(newPkg.getPackageName())
.setCodePath("/")
- .setResourcePath("/")
.setPVersionCode(1L);
final PackageSetting setting =
(action == null ? settingBuilder : action.withBuilder(settingBuilder)).build();
diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
index 164bd72..90edaef 100644
--- a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
@@ -38,8 +38,7 @@
public PackageSetting generateFakePackageSetting(String name) {
return new PackageSetting(name, name, new File(mContext.getCacheDir(), "fakeCodePath"),
- new File(mContext.getCacheDir(), "fakeResPath"), "", "", "",
- "", 1, 0, 0, 0 /*sharedUserId*/, null /*usesStaticLibraries*/,
+ "", "", "", "", 1, 0, 0, 0 /*sharedUserId*/, null /*usesStaticLibraries*/,
null /*usesStaticLibrariesVersions*/, null /*mimeGroups*/);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index c4e25b5..80f145b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -86,8 +86,7 @@
// Create a real (non-null) PackageSetting and confirm that the removed
// users are copied properly
setting = new PackageSetting("name", "realName", new File("codePath"),
- new File("resourcePath"), "legacyNativeLibraryPathString",
- "primaryCpuAbiString", "secondaryCpuAbiString",
+ "legacyNativeLibraryPathString", "primaryCpuAbiString", "secondaryCpuAbiString",
"cpuAbiOverrideString", 0, 0, 0, 0,
null, null, null);
pri.populateUsers(new int[] {
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index aa92ba4..0bf06bb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -439,7 +439,6 @@
PACKAGE_NAME,
REAL_PACKAGE_NAME,
INITIAL_CODE_PATH /*codePath*/,
- INITIAL_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPathString*/,
"x86_64" /*primaryCpuAbiString*/,
"x86" /*secondaryCpuAbiString*/,
@@ -461,7 +460,6 @@
PACKAGE_NAME /*pkgName*/,
REAL_PACKAGE_NAME /*realPkgName*/,
INITIAL_CODE_PATH /*codePath*/,
- INITIAL_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPathString*/,
"x86_64" /*primaryCpuAbiString*/,
"x86" /*secondaryCpuAbiString*/,
@@ -477,7 +475,6 @@
PACKAGE_NAME /*pkgName*/,
REAL_PACKAGE_NAME /*realPkgName*/,
UPDATED_CODE_PATH /*codePath*/,
- UPDATED_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPathString*/,
null /*primaryCpuAbiString*/,
null /*secondaryCpuAbiString*/,
@@ -507,7 +504,6 @@
null /*disabledPkg*/,
null /*sharedUser*/,
UPDATED_CODE_PATH /*codePath*/,
- UPDATED_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPath*/,
"arm64-v8a" /*primaryCpuAbi*/,
"armeabi" /*secondaryCpuAbi*/,
@@ -541,7 +537,6 @@
null /*disabledPkg*/,
null /*sharedUser*/,
UPDATED_CODE_PATH /*codePath*/,
- UPDATED_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPath*/,
"arm64-v8a" /*primaryCpuAbi*/,
"armeabi" /*secondaryCpuAbi*/,
@@ -581,7 +576,6 @@
null /*disabledPkg*/,
testUserSetting01 /*sharedUser*/,
UPDATED_CODE_PATH /*codePath*/,
- null /*resourcePath*/,
null /*legacyNativeLibraryPath*/,
"arm64-v8a" /*primaryCpuAbi*/,
"armeabi" /*secondaryCpuAbi*/,
@@ -609,7 +603,6 @@
null /*realPkgName*/,
null /*sharedUser*/,
UPDATED_CODE_PATH /*codePath*/,
- UPDATED_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPath*/,
"arm64-v8a" /*primaryCpuAbi*/,
"armeabi" /*secondaryCpuAbi*/,
@@ -624,12 +617,11 @@
null /*usesStaticLibraries*/,
null /*usesStaticLibrariesVersions*/,
null /*mimeGroups*/);
- assertThat(testPkgSetting01.codePath, is(UPDATED_CODE_PATH));
+ assertThat(testPkgSetting01.getCodePath(), is(UPDATED_CODE_PATH));
assertThat(testPkgSetting01.name, is(PACKAGE_NAME));
assertThat(testPkgSetting01.pkgFlags, is(ApplicationInfo.FLAG_SYSTEM));
assertThat(testPkgSetting01.pkgPrivateFlags, is(ApplicationInfo.PRIVATE_FLAG_PRIVILEGED));
assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a"));
- assertThat(testPkgSetting01.resourcePath, is(UPDATED_CODE_PATH));
assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi"));
// signatures object must be different
assertNotSame(testPkgSetting01.signatures, originalSignatures);
@@ -649,7 +641,6 @@
null /*realPkgName*/,
null /*sharedUser*/,
INITIAL_CODE_PATH /*codePath*/,
- INITIAL_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPath*/,
"x86_64" /*primaryCpuAbiString*/,
"x86" /*secondaryCpuAbiString*/,
@@ -665,12 +656,11 @@
null /*usesStaticLibrariesVersions*/,
null /*mimeGroups*/);
assertThat(testPkgSetting01.appId, is(0));
- assertThat(testPkgSetting01.codePath, is(INITIAL_CODE_PATH));
+ assertThat(testPkgSetting01.getCodePath(), is(INITIAL_CODE_PATH));
assertThat(testPkgSetting01.name, is(PACKAGE_NAME));
assertThat(testPkgSetting01.pkgFlags, is(0));
assertThat(testPkgSetting01.pkgPrivateFlags, is(0));
assertThat(testPkgSetting01.primaryCpuAbiString, is("x86_64"));
- assertThat(testPkgSetting01.resourcePath, is(INITIAL_CODE_PATH));
assertThat(testPkgSetting01.secondaryCpuAbiString, is("x86"));
assertThat(testPkgSetting01.versionCode, is(INITIAL_VERSION_CODE));
// by default, the package is considered stopped
@@ -695,7 +685,6 @@
null /*realPkgName*/,
testUserSetting01 /*sharedUser*/,
INITIAL_CODE_PATH /*codePath*/,
- INITIAL_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPath*/,
"x86_64" /*primaryCpuAbiString*/,
"x86" /*secondaryCpuAbiString*/,
@@ -711,12 +700,11 @@
null /*usesStaticLibrariesVersions*/,
null /*mimeGroups*/);
assertThat(testPkgSetting01.appId, is(10064));
- assertThat(testPkgSetting01.codePath, is(INITIAL_CODE_PATH));
+ assertThat(testPkgSetting01.getCodePath(), is(INITIAL_CODE_PATH));
assertThat(testPkgSetting01.name, is(PACKAGE_NAME));
assertThat(testPkgSetting01.pkgFlags, is(0));
assertThat(testPkgSetting01.pkgPrivateFlags, is(0));
assertThat(testPkgSetting01.primaryCpuAbiString, is("x86_64"));
- assertThat(testPkgSetting01.resourcePath, is(INITIAL_CODE_PATH));
assertThat(testPkgSetting01.secondaryCpuAbiString, is("x86"));
assertThat(testPkgSetting01.versionCode, is(INITIAL_VERSION_CODE));
final PackageUserState userState = testPkgSetting01.readUserState(0);
@@ -738,7 +726,6 @@
null /*realPkgName*/,
null /*sharedUser*/,
UPDATED_CODE_PATH /*codePath*/,
- UPDATED_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPath*/,
"arm64-v8a" /*primaryCpuAbi*/,
"armeabi" /*secondaryCpuAbi*/,
@@ -754,12 +741,11 @@
null /*usesStaticLibrariesVersions*/,
null /*mimeGroups*/);
assertThat(testPkgSetting01.appId, is(10064));
- assertThat(testPkgSetting01.codePath, is(UPDATED_CODE_PATH));
+ assertThat(testPkgSetting01.getCodePath(), is(UPDATED_CODE_PATH));
assertThat(testPkgSetting01.name, is(PACKAGE_NAME));
assertThat(testPkgSetting01.pkgFlags, is(0));
assertThat(testPkgSetting01.pkgPrivateFlags, is(0));
assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a"));
- assertThat(testPkgSetting01.resourcePath, is(UPDATED_CODE_PATH));
assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi"));
assertNotSame(testPkgSetting01.signatures, disabledSignatures);
assertThat(testPkgSetting01.versionCode, is(UPDATED_VERSION_CODE));
@@ -806,10 +792,10 @@
private void verifySettingCopy(PackageSetting origPkgSetting, PackageSetting testPkgSetting) {
assertThat(origPkgSetting, is(not(testPkgSetting)));
assertThat(origPkgSetting.appId, is(testPkgSetting.appId));
- assertSame(origPkgSetting.codePath, testPkgSetting.codePath);
- assertThat(origPkgSetting.codePath, is(testPkgSetting.codePath));
- assertSame(origPkgSetting.codePathString, testPkgSetting.codePathString);
- assertThat(origPkgSetting.codePathString, is(testPkgSetting.codePathString));
+ assertSame(origPkgSetting.getCodePath(), testPkgSetting.getCodePath());
+ assertThat(origPkgSetting.getCodePath(), is(testPkgSetting.getCodePath()));
+ assertSame(origPkgSetting.getCodePathString(), testPkgSetting.getCodePathString());
+ assertThat(origPkgSetting.getCodePathString(), is(testPkgSetting.getCodePathString()));
assertSame(origPkgSetting.cpuAbiOverrideString, testPkgSetting.cpuAbiOverrideString);
assertThat(origPkgSetting.cpuAbiOverrideString, is(testPkgSetting.cpuAbiOverrideString));
assertThat(origPkgSetting.firstInstallTime, is(testPkgSetting.firstInstallTime));
@@ -823,7 +809,9 @@
testPkgSetting.legacyNativeLibraryPathString);
assertThat(origPkgSetting.legacyNativeLibraryPathString,
is(testPkgSetting.legacyNativeLibraryPathString));
- assertNotSame(origPkgSetting.mimeGroups, testPkgSetting.mimeGroups);
+ if (origPkgSetting.mimeGroups != null) {
+ assertNotSame(origPkgSetting.mimeGroups, testPkgSetting.mimeGroups);
+ }
assertThat(origPkgSetting.mimeGroups, is(testPkgSetting.mimeGroups));
assertNotSame(origPkgSetting.mPermissionsState, testPkgSetting.mPermissionsState);
assertThat(origPkgSetting.mPermissionsState, is(testPkgSetting.mPermissionsState));
@@ -839,10 +827,6 @@
assertSame(origPkgSetting.primaryCpuAbiString, testPkgSetting.primaryCpuAbiString);
assertThat(origPkgSetting.primaryCpuAbiString, is(testPkgSetting.primaryCpuAbiString));
assertThat(origPkgSetting.realName, is(testPkgSetting.realName));
- assertSame(origPkgSetting.resourcePath, testPkgSetting.resourcePath);
- assertThat(origPkgSetting.resourcePath, is(testPkgSetting.resourcePath));
- assertSame(origPkgSetting.resourcePathString, testPkgSetting.resourcePathString);
- assertThat(origPkgSetting.resourcePathString, is(testPkgSetting.resourcePathString));
assertSame(origPkgSetting.secondaryCpuAbiString, testPkgSetting.secondaryCpuAbiString);
assertThat(origPkgSetting.secondaryCpuAbiString, is(testPkgSetting.secondaryCpuAbiString));
assertSame(origPkgSetting.sharedUser, testPkgSetting.sharedUser);
@@ -874,7 +858,6 @@
PACKAGE_NAME,
REAL_PACKAGE_NAME,
INITIAL_CODE_PATH /*codePath*/,
- INITIAL_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPathString*/,
"x86_64" /*primaryCpuAbiString*/,
"x86" /*secondaryCpuAbiString*/,
@@ -893,7 +876,6 @@
packageName,
packageName,
INITIAL_CODE_PATH /*codePath*/,
- INITIAL_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPathString*/,
"x86_64" /*primaryCpuAbiString*/,
"x86" /*secondaryCpuAbiString*/,
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index b0b5386..2651cfa 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -312,8 +312,7 @@
private static PackageSetting mockPkgSetting(AndroidPackage pkg) {
return new PackageSetting(pkg.getPackageName(), pkg.getRealPackage(),
- new File(pkg.getCodePath()), new File(pkg.getCodePath()), null,
- pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi(),
+ new File(pkg.getCodePath()), null, pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi(),
null, pkg.getVersionCode(),
PackageInfoUtils.appInfoFlags(pkg, null),
PackageInfoUtils.appInfoPrivateFlags(pkg, null),
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
index d12ea894..f8e92ad 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
@@ -30,7 +30,6 @@
private String mName;
private String mRealName;
private String mCodePath;
- private String mResourcePath;
private String mLegacyNativeLibraryPathString;
private String mPrimaryCpuAbiString;
private String mSecondaryCpuAbiString;
@@ -74,11 +73,6 @@
return this;
}
- public PackageSettingBuilder setResourcePath(String resourcePath) {
- this.mResourcePath = resourcePath;
- return this;
- }
-
public PackageSettingBuilder setLegacyNativeLibraryPathString(
String legacyNativeLibraryPathString) {
this.mLegacyNativeLibraryPathString = legacyNativeLibraryPathString;
@@ -162,10 +156,10 @@
public PackageSetting build() {
final PackageSetting packageSetting = new PackageSetting(mName, mRealName,
- new File(mCodePath), new File(mResourcePath),
- mLegacyNativeLibraryPathString, mPrimaryCpuAbiString, mSecondaryCpuAbiString,
- mCpuAbiOverrideString, mPVersionCode, mPkgFlags, mPrivateFlags, mSharedUserId,
- mUsesStaticLibraries, mUsesStaticLibrariesVersions, mMimeGroups);
+ new File(mCodePath), mLegacyNativeLibraryPathString, mPrimaryCpuAbiString,
+ mSecondaryCpuAbiString, mCpuAbiOverrideString, mPVersionCode, mPkgFlags,
+ mPrivateFlags, mSharedUserId, mUsesStaticLibraries, mUsesStaticLibrariesVersions,
+ mMimeGroups);
packageSetting.signatures = mSigningDetails != null
? new PackageSignatures(mSigningDetails)
: new PackageSignatures();
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
index 55bc681..7108490 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
@@ -465,9 +465,9 @@
// Generic PackageSetting object with values from a test app installed on a device to be
// used to test the methods under the PackageSignatures signatures data member.
File appPath = new File("/data/app/app");
- PackageSetting result = new PackageSetting("test.app", null, appPath, appPath,
- "/data/app/app", null, null, null,
- 1, 940097092, 0, 0 /*userId*/, null, null, null /*mimeGroups*/);
+ PackageSetting result = new PackageSetting("test.app", null, appPath,
+ "/data/app/app", null, null, null, 1, 940097092, 0, 0 /*userId*/, null, null,
+ null /*mimeGroups*/);
return result;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index e7eff00..56dddb0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -484,8 +484,7 @@
private static PackageSettingBuilder createBasicPackageSettingBuilder(String packageName) {
return new PackageSettingBuilder()
.setName(packageName)
- .setCodePath(createCodePath(packageName))
- .setResourcePath(createCodePath(packageName));
+ .setCodePath(createCodePath(packageName));
}
private static ScanRequestBuilder createBasicScanRequestBuilder(ParsingPackage pkg) {
@@ -534,8 +533,7 @@
arrayContaining("some.static.library", "some.other.static.library"));
assertThat(pkgSetting.usesStaticLibrariesVersions, is(new long[]{234L, 456L}));
assertThat(pkgSetting.pkg, is(scanResult.request.parsedPackage));
- assertThat(pkgSetting.codePath, is(new File(createCodePath(packageName))));
- assertThat(pkgSetting.resourcePath, is(new File(createCodePath(packageName))));
+ assertThat(pkgSetting.getCodePath(), is(new File(createCodePath(packageName))));
assertThat(pkgSetting.versionCode, is(PackageInfo.composeLongVersionCode(1, 2345)));
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
index 1536345..8034cac 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
@@ -170,7 +170,7 @@
ITimeZoneConfigurationListener mockListener = mock(ITimeZoneConfigurationListener.class);
try {
mTimeZoneDetectorService.removeConfigurationListener(mockListener);
- fail();
+ fail("Expected a SecurityException");
} finally {
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 4040fa6..e3c795d 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -38,6 +38,7 @@
<uses-permission android:name="android.permission.REORDER_TASKS" />
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<uses-permission android:name="android.permission.STATUS_BAR" />
+ <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" />
<!-- TODO: Remove largeHeap hack when memory leak is fixed (b/123984854) -->
<application android:debuggable="true"
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index f69d7c3..1eb45d5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -59,7 +59,7 @@
@Presubmit
@RunWith(WindowTestRunner.class)
// TODO(b/144248496): Merge to DisplayContentTests
-public class ActivityDisplayTests extends ActivityTestsBase {
+public class ActivityDisplayTests extends WindowTestsBase {
@Test
public void testLastFocusedStackIsUpdatedWhenMovingStack() {
@@ -89,9 +89,9 @@
// Create a pinned stack and move to front.
final Task pinnedStack = mRootWindowContainer.getDefaultTaskDisplayArea()
.createStack(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP);
- final Task pinnedTask = new TaskBuilder(mService.mStackSupervisor)
+ final Task pinnedTask = new TaskBuilder(mAtm.mStackSupervisor)
.setStack(pinnedStack).build();
- new ActivityBuilder(mService).setActivityFlags(FLAG_ALWAYS_FOCUSABLE)
+ new ActivityBuilder(mAtm).setActivityFlags(FLAG_ALWAYS_FOCUSABLE)
.setTask(pinnedTask).build();
pinnedStack.moveToFront("movePinnedStackToFront");
@@ -140,7 +140,7 @@
// Create a display which supports system decoration and allows reparenting stacks to
// another display when the display is removed.
final DisplayContent display = new TestDisplayContent.Builder(
- mService, 1000, 1500).setSystemDecorations(true).build();
+ mAtm, 1000, 1500).setSystemDecorations(true).build();
doReturn(false).when(display).shouldDestroyContentOnRemove();
// Put home stack on the display.
@@ -162,9 +162,9 @@
private Task createFullscreenStackWithSimpleActivityAt(DisplayContent display) {
final Task fullscreenStack = display.getDefaultTaskDisplayArea().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP);
- final Task fullscreenTask = new TaskBuilder(mService.mStackSupervisor)
+ final Task fullscreenTask = new TaskBuilder(mAtm.mStackSupervisor)
.setStack(fullscreenStack).build();
- new ActivityBuilder(mService).setTask(fullscreenTask).build();
+ new ActivityBuilder(mAtm).setTask(fullscreenTask).build();
return fullscreenStack;
}
@@ -197,7 +197,7 @@
assertNull(display.topRunningActivity(true /* considerKeyguardState */));
// Add activity that should be shown on the keyguard.
- final ActivityRecord showWhenLockedActivity = new ActivityBuilder(mService)
+ final ActivityRecord showWhenLockedActivity = new ActivityBuilder(mAtm)
.setCreateTask(true)
.setStack(stack)
.setActivityFlags(FLAG_SHOW_WHEN_LOCKED)
@@ -226,7 +226,7 @@
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
final Task alwaysOnTopStack = taskDisplayArea.createStack(WINDOWING_MODE_FREEFORM,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true)
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true)
.setStack(alwaysOnTopStack).build();
alwaysOnTopStack.setAlwaysOnTop(true);
taskDisplayArea.positionChildAt(POSITION_TOP, alwaysOnTopStack,
@@ -322,10 +322,10 @@
ACTIVITY_TYPE_STANDARD, ON_TOP);
final Task stack4 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, ON_TOP);
- final Task task1 = new TaskBuilder(mService.mStackSupervisor).setStack(stack1).build();
- final Task task2 = new TaskBuilder(mService.mStackSupervisor).setStack(stack2).build();
- final Task task3 = new TaskBuilder(mService.mStackSupervisor).setStack(stack3).build();
- final Task task4 = new TaskBuilder(mService.mStackSupervisor).setStack(stack4).build();
+ final Task task1 = new TaskBuilder(mAtm.mStackSupervisor).setStack(stack1).build();
+ final Task task2 = new TaskBuilder(mAtm.mStackSupervisor).setStack(stack2).build();
+ final Task task3 = new TaskBuilder(mAtm.mStackSupervisor).setStack(stack3).build();
+ final Task task4 = new TaskBuilder(mAtm.mStackSupervisor).setStack(stack4).build();
// Reordering stacks while removing stacks.
doAnswer(invocation -> {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index feac6db..46c3e22 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -59,7 +59,7 @@
@SmallTest
@Presubmit
@RunWith(WindowTestRunner.class)
-public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase {
+public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
private ActivityMetricsLogger mActivityMetricsLogger;
private ActivityMetricsLogger.LaunchingState mLaunchingState;
private ActivityMetricsLaunchObserver mLaunchObserver;
@@ -81,11 +81,11 @@
// Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful.
// This seems to be the easiest way to create an ActivityRecord.
- mTrampolineActivity = new ActivityBuilder(mService)
+ mTrampolineActivity = new ActivityBuilder(mAtm)
.setCreateTask(true)
.setComponent(createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, "TrampolineActivity"))
.build();
- mTopActivity = new ActivityBuilder(mService)
+ mTopActivity = new ActivityBuilder(mAtm)
.setTask(mTrampolineActivity.getTask())
.setComponent(createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, "TopActivity"))
.build();
@@ -121,7 +121,7 @@
private <T> T verifyAsync(T mock) {
// With WindowTestRunner, all test methods are inside WM lock, so we have to unblock any
// messages that are waiting for the lock.
- waitHandlerIdle(mService.mH);
+ waitHandlerIdle(mAtm.mH);
// AMLO callbacks happen on a separate thread than AML calls, so we need to use a timeout.
return verify(mock, timeout(TimeUnit.SECONDS.toMillis(5)));
}
@@ -192,7 +192,7 @@
// Suppress resume when creating the record because we want to notify logger manually.
mSupervisor.beginDeferResume();
// Create an activity with different process that meets process switch.
- final ActivityRecord noDrawnActivity = new ActivityBuilder(mService)
+ final ActivityRecord noDrawnActivity = new ActivityBuilder(mAtm)
.setTask(mTopActivity.getTask())
.setProcessName("other")
.build();
@@ -321,7 +321,7 @@
onActivityLaunched(mTopActivity);
final ActivityMetricsLogger.LaunchingState previousState = mLaunchingState;
- final ActivityRecord otherActivity = new ActivityBuilder(mService)
+ final ActivityRecord otherActivity = new ActivityBuilder(mAtm)
.setComponent(createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, "OtherActivity"))
.setCreateTask(true)
.build();
@@ -345,7 +345,7 @@
.setDisplay(addNewDisplayContentAt(DisplayContent.POSITION_BOTTOM))
.setCreateActivity(false)
.build();
- final ActivityRecord activityOnNewDisplay = new ActivityBuilder(mService)
+ final ActivityRecord activityOnNewDisplay = new ActivityBuilder(mAtm)
.setStack(stack)
.setCreateTask(true)
.setProcessName("new")
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 2f02073..e3830f6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -67,7 +67,6 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
@@ -122,7 +121,7 @@
@MediumTest
@Presubmit
@RunWith(WindowTestRunner.class)
-public class ActivityRecordTests extends ActivityTestsBase {
+public class ActivityRecordTests extends WindowTestsBase {
private Task mStack;
private Task mTask;
private ActivityRecord mActivity;
@@ -133,7 +132,7 @@
mTask = mStack.getBottomMostTask();
mActivity = mTask.getTopNonFinishingActivity();
- setBooted(mService);
+ setBooted(mAtm);
}
@Test
@@ -152,16 +151,16 @@
public void testStackCleanupOnTaskRemoval() {
mStack.removeChild(mTask, null /*reason*/);
// Stack should be gone on task removal.
- assertNull(mService.mRootWindowContainer.getStack(mStack.mTaskId));
+ assertNull(mAtm.mRootWindowContainer.getStack(mStack.mTaskId));
}
@Test
public void testRemoveChildWithOverlayActivity() {
final ActivityRecord overlayActivity =
- new ActivityBuilder(mService).setTask(mTask).build();
+ new ActivityBuilder(mAtm).setTask(mTask).build();
overlayActivity.setTaskOverlay(true);
final ActivityRecord overlayActivity2 =
- new ActivityBuilder(mService).setTask(mTask).build();
+ new ActivityBuilder(mAtm).setTask(mTask).build();
overlayActivity2.setTaskOverlay(true);
mTask.removeChild(overlayActivity2, "test");
@@ -170,7 +169,7 @@
@Test
public void testNoCleanupMovingActivityInSameStack() {
- final Task newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
+ final Task newTask = new TaskBuilder(mAtm.mStackSupervisor).setStack(mStack).build();
mActivity.reparent(newTask, 0, null /*reason*/);
verify(mStack, times(0)).cleanUpActivityReferences(any());
}
@@ -213,7 +212,7 @@
// Make sure the state does not change if we are not the current top activity.
mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind");
- final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
mStack.mTranslucentActivityWaiting = topActivity;
mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
assertTrue(mActivity.isState(STARTED));
@@ -231,8 +230,8 @@
@Test
public void testCanBeLaunchedOnDisplay() {
- mService.mSupportsMultiWindow = true;
- final ActivityRecord activity = new ActivityBuilder(mService).build();
+ mAtm.mSupportsMultiWindow = true;
+ final ActivityRecord activity = new ActivityBuilder(mAtm).build();
// An activity can be launched on default display.
assertTrue(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY));
@@ -251,7 +250,7 @@
// Set options for two ActivityRecords in same Task. Apply one ActivityRecord options.
// Pending options should be cleared for both ActivityRecords
- ActivityRecord activity2 = new ActivityBuilder(mService).setTask(mTask).build();
+ ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(mTask).build();
activity2.updateOptionsLocked(activityOptions);
mActivity.updateOptionsLocked(activityOptions);
mActivity.applyOptionsLocked();
@@ -260,8 +259,8 @@
// Set options for two ActivityRecords in separate Tasks. Apply one ActivityRecord options.
// Pending options should be cleared for only ActivityRecord that was applied
- Task task2 = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
- activity2 = new ActivityBuilder(mService).setTask(task2).build();
+ Task task2 = new TaskBuilder(mAtm.mStackSupervisor).setStack(mStack).build();
+ activity2 = new ActivityBuilder(mAtm).setTask(task2).build();
activity2.updateOptionsLocked(activityOptions);
mActivity.updateOptionsLocked(activityOptions);
mActivity.applyOptionsLocked();
@@ -362,7 +361,7 @@
@Test
public void testSetRequestedOrientationUpdatesConfiguration() throws Exception {
- mActivity = new ActivityBuilder(mService)
+ mActivity = new ActivityBuilder(mAtm)
.setTask(mTask)
.setConfigChanges(CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT)
.build();
@@ -405,7 +404,7 @@
final ActivityConfigurationChangeItem expected =
ActivityConfigurationChangeItem.obtain(newConfig);
- verify(mService.getLifecycleManager()).scheduleTransaction(eq(mActivity.app.getThread()),
+ verify(mAtm.getLifecycleManager()).scheduleTransaction(eq(mActivity.app.getThread()),
eq(mActivity.appToken), eq(expected));
}
@@ -500,9 +499,9 @@
@Test
public void testShouldMakeActive_nonTopVisible() {
- ActivityRecord finishingActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ ActivityRecord finishingActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
finishingActivity.finishing = true;
- ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
mActivity.setState(Task.ActivityState.STOPPED, "Testing");
assertEquals(false, mActivity.shouldMakeActive(null /* activeActivity */));
@@ -528,7 +527,7 @@
mActivity.setState(Task.ActivityState.STOPPED, "Testing");
spyOn(mStack);
- ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
mActivity.addResultLocked(topActivity, "resultWho", 0, 0, new Intent());
topActivity.finishing = true;
@@ -539,7 +538,7 @@
@Test
public void testPushConfigurationWhenLaunchTaskBehind() throws Exception {
- mActivity = new ActivityBuilder(mService)
+ mActivity = new ActivityBuilder(mAtm)
.setTask(mTask)
.setLaunchTaskBehind(true)
.setConfigChanges(CONFIG_ORIENTATION)
@@ -574,7 +573,7 @@
final ActivityConfigurationChangeItem expected =
ActivityConfigurationChangeItem.obtain(newConfig);
- verify(mService.getLifecycleManager()).scheduleTransaction(
+ verify(mAtm.getLifecycleManager()).scheduleTransaction(
eq(mActivity.app.getThread()), eq(mActivity.appToken), eq(expected));
} finally {
stack.getDisplayArea().removeChild(stack);
@@ -583,7 +582,7 @@
@Test
public void testShouldStartWhenMakeClientActive() {
- ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
topActivity.setOccludesParent(false);
mActivity.setState(Task.ActivityState.STOPPED, "Testing");
mActivity.setVisibility(true);
@@ -621,7 +620,7 @@
public void testCanLaunchHomeActivityFromChooser() {
ComponentName chooserComponent = ComponentName.unflattenFromString(
Resources.getSystem().getString(R.string.config_chooserActivity));
- ActivityRecord chooserActivity = new ActivityBuilder(mService).setComponent(
+ ActivityRecord chooserActivity = new ActivityBuilder(mAtm).setComponent(
chooserComponent).build();
assertThat(mActivity.canLaunchHomeActivity(NOBODY_UID, chooserActivity)).isTrue();
}
@@ -736,7 +735,7 @@
// Put a visible activity on top, so the finishing activity doesn't have to wait until the
// next activity reports idle to destroy it.
- final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
topActivity.mVisibleRequested = true;
topActivity.nowVisible = true;
topActivity.setState(RESUMED, "test");
@@ -914,7 +913,7 @@
public void testFinishActivityIfPossible_nonVisibleNoAppTransition() {
// Put an activity on top of test activity to make it invisible and prevent us from
// accidentally resuming the topmost one again.
- new ActivityBuilder(mService).build();
+ new ActivityBuilder(mAtm).build();
mActivity.mVisibleRequested = false;
mActivity.setState(STOPPED, "test");
@@ -992,7 +991,7 @@
*/
@Test
public void testCompleteFinishing_waitForNextVisible() {
- final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
topActivity.mVisibleRequested = true;
topActivity.nowVisible = true;
topActivity.finishing = true;
@@ -1017,7 +1016,7 @@
*/
@Test
public void testCompleteFinishing_noWaitForNextVisible_alreadyInvisible() {
- final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
topActivity.mVisibleRequested = false;
topActivity.nowVisible = false;
topActivity.finishing = true;
@@ -1039,7 +1038,7 @@
*/
@Test
public void testCompleteFinishing_waitForIdle() {
- final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
topActivity.mVisibleRequested = true;
topActivity.nowVisible = true;
topActivity.finishing = true;
@@ -1060,7 +1059,7 @@
*/
@Test
public void testCompleteFinishing_noWaitForNextVisible_stopped() {
- final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
topActivity.mVisibleRequested = false;
topActivity.nowVisible = false;
topActivity.finishing = true;
@@ -1081,7 +1080,7 @@
*/
@Test
public void testCompleteFinishing_noWaitForNextVisible_nonFocusedStack() {
- final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
topActivity.mVisibleRequested = true;
topActivity.nowVisible = true;
topActivity.finishing = true;
@@ -1114,7 +1113,7 @@
// Make keyguard locked and set the top activity show-when-locked.
KeyguardController keyguardController = mActivity.mStackSupervisor.getKeyguardController();
doReturn(true).when(keyguardController).isKeyguardLocked();
- final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
topActivity.mVisibleRequested = true;
topActivity.nowVisible = true;
topActivity.setState(RESUMED, "true");
@@ -1143,18 +1142,18 @@
*/
@Test
public void testCompleteFinishing_ensureActivitiesVisible() {
- final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
firstActivity.mVisibleRequested = false;
firstActivity.nowVisible = false;
firstActivity.setState(STOPPED, "true");
- final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
secondActivity.mVisibleRequested = true;
secondActivity.nowVisible = true;
secondActivity.setState(PAUSED, "true");
final ActivityRecord translucentActivity =
- new ActivityBuilder(mService).setTask(mTask).build();
+ new ActivityBuilder(mAtm).setTask(mTask).build();
translucentActivity.mVisibleRequested = true;
translucentActivity.nowVisible = true;
translucentActivity.setState(RESUMED, "true");
@@ -1396,7 +1395,7 @@
final Task firstTaskRecord = mActivity.getTask();
final ActivityRecord secondActivityRecord =
- new ActivityBuilder(mService).setTask(firstTaskRecord).setUseProcess(wpc).build();
+ new ActivityBuilder(mAtm).setTask(firstTaskRecord).setUseProcess(wpc).build();
assertTrue(wpc.registeredForActivityConfigChanges());
assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
@@ -1409,7 +1408,7 @@
assertTrue(wpc.registeredForActivityConfigChanges());
final ActivityRecord secondActivityRecord =
- new ActivityBuilder(mService).setTask(mTask).setUseProcess(wpc).build();
+ new ActivityBuilder(mAtm).setTask(mTask).setUseProcess(wpc).build();
assertTrue(wpc.registeredForActivityConfigChanges());
assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
@@ -1505,7 +1504,7 @@
WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
params.width = params.height = WindowManager.LayoutParams.MATCH_PARENT;
final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState(
- mService.mWindowManager, mock(Session.class), new TestIWindow(), params, mActivity);
+ mAtm.mWindowManager, mock(Session.class), new TestIWindow(), params, mActivity);
mActivity.addWindow(w);
// Assume the activity is launching in different rotation, and there was an available
@@ -1526,7 +1525,7 @@
any() /* outContentInsets */, any() /* outStableInsets */,
any() /* outDisplayCutout */, any() /* outInputChannel */,
any() /* outInsetsState */, any() /* outActiveControls */);
- TaskSnapshotSurface.create(mService.mWindowManager, mActivity, snapshot);
+ TaskSnapshotSurface.create(mAtm.mWindowManager, mActivity, snapshot);
} catch (RemoteException ignored) {
} finally {
reset(session);
@@ -1602,7 +1601,7 @@
final Configuration initialConf =
new Configuration(mActivity.getMergedOverrideConfiguration());
final Task initialTask = mActivity.getTask();
- final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(initialTask)
+ final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(initialTask)
.setUseProcess(wpc).build();
assertTrue(wpc.registeredForActivityConfigChanges());
@@ -1696,12 +1695,12 @@
if (defaultDisplay) {
display = mRootWindowContainer.getDefaultDisplay();
} else {
- display = new TestDisplayContent.Builder(mService, 2000, 1000).setDensityDpi(300)
+ display = new TestDisplayContent.Builder(mAtm, 2000, 1000).setDensityDpi(300)
.setPosition(DisplayContent.POSITION_TOP).build();
}
final Task stack = display.getDefaultTaskDisplayArea()
.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
- return new ActivityBuilder(mService).setTask(task).setUseProcess(process).build();
+ return new ActivityBuilder(mAtm).setTask(task).setUseProcess(process).build();
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
index 197c89a..96b9700 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
@@ -38,7 +38,13 @@
import android.app.WaitResult;
import android.content.pm.ActivityInfo;
+import android.graphics.PixelFormat;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.media.ImageReader;
import android.platform.test.annotations.Presubmit;
+import android.view.Display;
+import android.view.DisplayInfo;
import androidx.test.filters.MediumTest;
@@ -55,7 +61,7 @@
@MediumTest
@Presubmit
@RunWith(WindowTestRunner.class)
-public class ActivityStackSupervisorTests extends ActivityTestsBase {
+public class ActivityStackSupervisorTests extends WindowTestsBase {
private Task mFullscreenStack;
@Before
@@ -69,7 +75,7 @@
*/
@Test
public void testStoppingActivityRemovedWhenResumed() {
- final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true)
.setStack(mFullscreenStack).build();
mSupervisor.mStoppingActivities.add(firstActivity);
@@ -83,7 +89,7 @@
*/
@Test
public void testReportWaitingActivityLaunchedIfNeeded() {
- final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true)
.setStack(mFullscreenStack).build();
final WaitResult taskToFrontWait = new WaitResult();
@@ -121,7 +127,7 @@
task.setResizeMode(unresizableActivity.info.resizeMode);
final TaskChangeNotificationController taskChangeNotifier =
- mService.getTaskChangeNotificationController();
+ mAtm.getTaskChangeNotificationController();
spyOn(taskChangeNotifier);
mSupervisor.handleNonResizableTaskIfNeeded(task, newDisplay.getWindowingMode(),
@@ -133,7 +139,7 @@
reset(taskChangeNotifier);
// Put a resizable activity on top of the unresizable task.
- final ActivityRecord resizableActivity = new ActivityBuilder(mService)
+ final ActivityRecord resizableActivity = new ActivityBuilder(mAtm)
.setTask(task).build();
resizableActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
@@ -150,27 +156,73 @@
*/
@Test
public void testNotifyTaskFocusChanged() {
- final ActivityRecord fullScreenActivityA = new ActivityBuilder(mService).setCreateTask(true)
+ final ActivityRecord fullScreenActivityA = new ActivityBuilder(mAtm).setCreateTask(true)
.setStack(mFullscreenStack).build();
final Task taskA = fullScreenActivityA.getTask();
final TaskChangeNotificationController taskChangeNotifier =
- mService.getTaskChangeNotificationController();
+ mAtm.getTaskChangeNotificationController();
spyOn(taskChangeNotifier);
- mService.setResumedActivityUncheckLocked(fullScreenActivityA, "resumeA");
+ mAtm.setResumedActivityUncheckLocked(fullScreenActivityA, "resumeA");
verify(taskChangeNotifier).notifyTaskFocusChanged(eq(taskA.mTaskId) /* taskId */,
eq(true) /* focused */);
reset(taskChangeNotifier);
- final ActivityRecord fullScreenActivityB = new ActivityBuilder(mService).setCreateTask(true)
+ final ActivityRecord fullScreenActivityB = new ActivityBuilder(mAtm).setCreateTask(true)
.setStack(mFullscreenStack).build();
final Task taskB = fullScreenActivityB.getTask();
- mService.setResumedActivityUncheckLocked(fullScreenActivityB, "resumeB");
+ mAtm.setResumedActivityUncheckLocked(fullScreenActivityB, "resumeB");
verify(taskChangeNotifier).notifyTaskFocusChanged(eq(taskA.mTaskId) /* taskId */,
eq(false) /* focused */);
verify(taskChangeNotifier).notifyTaskFocusChanged(eq(taskB.mTaskId) /* taskId */,
eq(true) /* focused */);
}
+
+ @Test
+ /** Ensures that a trusted virtual display can launch arbitrary activities. */
+ public void testTrustedVirtualDisplayCanLaunchActivities() {
+ final DisplayContent newDisplay = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
+ final Task stack = new StackBuilder(mRootWindowContainer)
+ .setDisplay(newDisplay).build();
+ final ActivityRecord unresizableActivity = stack.getTopNonFinishingActivity();
+ VirtualDisplay virtualDisplay = createVirtualDisplay(true);
+ final boolean allowed = mSupervisor.isCallerAllowedToLaunchOnDisplay(1234, 1234,
+ virtualDisplay.getDisplay().getDisplayId(), unresizableActivity.info);
+
+ assertThat(allowed).isTrue();
+ }
+
+ @Test
+ /** Ensures that an untrusted virtual display cannot launch arbitrary activities. */
+ public void testUntrustedVirtualDisplayCannotLaunchActivities() {
+ final DisplayContent newDisplay = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
+ final Task stack = new StackBuilder(mRootWindowContainer)
+ .setDisplay(newDisplay).build();
+ final ActivityRecord unresizableActivity = stack.getTopNonFinishingActivity();
+ VirtualDisplay virtualDisplay = createVirtualDisplay(false);
+ final boolean allowed = mSupervisor.isCallerAllowedToLaunchOnDisplay(1234, 1234,
+ virtualDisplay.getDisplay().getDisplayId(), unresizableActivity.info);
+
+ assertThat(allowed).isFalse();
+ }
+
+ private VirtualDisplay createVirtualDisplay(boolean trusted) {
+ final DisplayManager dm = mContext.getSystemService(DisplayManager.class);
+ final DisplayInfo displayInfo = new DisplayInfo();
+ final Display defaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY);
+ defaultDisplay.getDisplayInfo(displayInfo);
+ int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
+ if (trusted) {
+ flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
+ }
+
+ final ImageReader imageReader = ImageReader.newInstance(
+ displayInfo.logicalWidth, displayInfo.logicalHeight, PixelFormat.RGBA_8888, 2);
+
+ return dm.createVirtualDisplay("virtualDisplay", displayInfo.logicalWidth,
+ displayInfo.logicalHeight,
+ displayInfo.logicalDensityDpi, imageReader.getSurface(), flags);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index dfdf686..e2948a7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -89,7 +89,7 @@
@SmallTest
@Presubmit
@RunWith(WindowTestRunner.class)
-public class ActivityStackTests extends ActivityTestsBase {
+public class ActivityStackTests extends WindowTestsBase {
private TaskDisplayArea mDefaultTaskDisplayArea;
private Task mStack;
private Task mTask;
@@ -105,7 +105,7 @@
@Test
public void testResumedActivity() {
- final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord r = new ActivityBuilder(mAtm).setTask(mTask).build();
assertNull(mStack.getResumedActivity());
r.setState(RESUMED, "testResumedActivity");
assertEquals(r, mStack.getResumedActivity());
@@ -115,7 +115,7 @@
@Test
public void testResumedActivityFromTaskReparenting() {
- final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord r = new ActivityBuilder(mAtm).setTask(mTask).build();
// Ensure moving task between two stacks updates resumed activity
r.setState(RESUMED, "testResumedActivityFromTaskReparenting");
assertEquals(r, mStack.getResumedActivity());
@@ -133,7 +133,7 @@
@Test
public void testResumedActivityFromActivityReparenting() {
- final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord r = new ActivityBuilder(mAtm).setTask(mTask).build();
// Ensure moving task between two stacks updates resumed activity
r.setState(RESUMED, "testResumedActivityFromActivityReparenting");
assertEquals(r, mStack.getResumedActivity());
@@ -149,7 +149,7 @@
@Test
public void testPrimarySplitScreenMoveToBack() {
- TestSplitOrganizer organizer = new TestSplitOrganizer(mService);
+ TestSplitOrganizer organizer = new TestSplitOrganizer(mAtm);
// We're testing an edge case here where we have primary + fullscreen rather than secondary.
organizer.setMoveToSecondaryOnEnter(false);
@@ -177,7 +177,7 @@
@Test
public void testMoveToPrimarySplitScreenThenMoveToBack() {
- TestSplitOrganizer organizer = new TestSplitOrganizer(mService);
+ TestSplitOrganizer organizer = new TestSplitOrganizer(mAtm);
// This time, start with a fullscreen activitystack
final Task primarySplitScreen = mDefaultTaskDisplayArea.createStack(
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -202,7 +202,7 @@
@Test
public void testSplitScreenMoveToBack() {
- TestSplitOrganizer organizer = new TestSplitOrganizer(mService);
+ TestSplitOrganizer organizer = new TestSplitOrganizer(mAtm);
// Set up split-screen with primary on top and secondary containing the home task below
// another stack.
final Task primaryTask = mDefaultTaskDisplayArea.createStack(
@@ -241,12 +241,12 @@
@Test
public void testRemoveOrganizedTask_UpdateStackReference() {
final Task rootHomeTask = mDefaultTaskDisplayArea.getRootHomeTask();
- final ActivityRecord homeActivity = new ActivityBuilder(mService)
+ final ActivityRecord homeActivity = new ActivityBuilder(mAtm)
.setStack(rootHomeTask)
.setCreateTask(true)
.build();
final Task secondaryStack = (Task) WindowContainer.fromBinder(
- mService.mTaskOrganizerController.createRootTask(rootHomeTask.getDisplayId(),
+ mAtm.mTaskOrganizerController.createRootTask(rootHomeTask.getDisplayId(),
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token.asBinder());
rootHomeTask.reparent(secondaryStack, POSITION_TOP);
@@ -292,7 +292,7 @@
@Test
public void testStopActivityWhenActivityDestroyed() {
- final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord r = new ActivityBuilder(mAtm).setTask(mTask).build();
r.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
mStack.moveToFront("testStopActivityWithDestroy");
r.stopIfPossible();
@@ -302,14 +302,14 @@
@Test
public void testFindTaskWithOverlay() {
- final ActivityRecord r = new ActivityBuilder(mService)
+ final ActivityRecord r = new ActivityBuilder(mAtm)
.setCreateTask(true)
.setStack(mStack)
.setUid(0)
.build();
final Task task = r.getTask();
// Overlay must be for a different user to prevent recognizing a matching top activity
- final ActivityRecord taskOverlay = new ActivityBuilder(mService).setTask(task)
+ final ActivityRecord taskOverlay = new ActivityBuilder(mAtm).setTask(task)
.setUid(UserHandle.PER_USER_RANGE * 2).build();
taskOverlay.setTaskOverlay(true);
@@ -330,21 +330,21 @@
targetActivity);
final ComponentName alias = new ComponentName(DEFAULT_COMPONENT_PACKAGE_NAME,
aliasActivity);
- final Task task = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
+ final Task task = new TaskBuilder(mAtm.mStackSupervisor).setStack(mStack).build();
task.origActivity = alias;
task.realActivity = target;
- new ActivityBuilder(mService).setComponent(target).setTask(task).setTargetActivity(
+ new ActivityBuilder(mAtm).setComponent(target).setTask(task).setTargetActivity(
targetActivity).build();
// Using target activity to find task.
- final ActivityRecord r1 = new ActivityBuilder(mService).setComponent(
+ final ActivityRecord r1 = new ActivityBuilder(mAtm).setComponent(
target).setTargetActivity(targetActivity).build();
RootWindowContainer.FindTaskResult result = new RootWindowContainer.FindTaskResult();
result.process(r1, mStack);
assertThat(result.mRecord).isNotNull();
// Using alias activity to find task.
- final ActivityRecord r2 = new ActivityBuilder(mService).setComponent(
+ final ActivityRecord r2 = new ActivityBuilder(mAtm).setComponent(
alias).setTargetActivity(targetActivity).build();
result = new RootWindowContainer.FindTaskResult();
result.process(r2, mStack);
@@ -377,7 +377,7 @@
final Task pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Add an activity to the pinned stack so it isn't considered empty for visibility check.
- final ActivityRecord pinnedActivity = new ActivityBuilder(mService)
+ final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm)
.setCreateTask(true)
.setStack(pinnedStack)
.build();
@@ -676,7 +676,7 @@
assertEquals(STACK_VISIBILITY_VISIBLE,
translucentStack.getVisibility(null /* starting */));
// Add an activity to the pinned stack so it isn't considered empty for visibility check.
- final ActivityRecord pinnedActivity = new ActivityBuilder(mService)
+ final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm)
.setCreateTask(true)
.setStack(pinnedStack)
.build();
@@ -689,7 +689,7 @@
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
ActivityRecord topRunningHomeActivity = homeStack.topRunningActivity();
if (topRunningHomeActivity == null) {
- topRunningHomeActivity = new ActivityBuilder(mService)
+ topRunningHomeActivity = new ActivityBuilder(mAtm)
.setStack(homeStack)
.setCreateTask(true)
.build();
@@ -721,12 +721,12 @@
final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- final ActivityRecord firstActivity = new ActivityBuilder(mService)
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
.setStack(homeStack)
.setCreateTask(true)
.build();
final Task task = firstActivity.getTask();
- final ActivityRecord secondActivity = new ActivityBuilder(mService)
+ final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
.setTask(task)
.build();
@@ -991,7 +991,6 @@
TaskDisplayArea taskDisplayArea, int windowingMode, int activityType, boolean onTop) {
final Task task;
if (activityType == ACTIVITY_TYPE_HOME) {
- // Home stack and activity are created in ActivityTestsBase#setupActivityManagerService
task = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
mDefaultTaskDisplayArea.positionChildAt(onTop ? POSITION_TOP : POSITION_BOTTOM, task,
false /* includingParents */);
@@ -1009,8 +1008,8 @@
@Test
public void testFinishDisabledPackageActivities_FinishAliveActivities() {
- final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build();
- final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
+ final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
firstActivity.setState(STOPPED, "testFinishDisabledPackageActivities");
secondActivity.setState(RESUMED, "testFinishDisabledPackageActivities");
mStack.mResumedActivity = secondActivity;
@@ -1029,10 +1028,10 @@
@Test
public void testFinishDisabledPackageActivities_RemoveNonAliveActivities() {
- final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(mTask).build();
// The overlay activity is not in the disabled package but it is in the same task.
- final ActivityRecord overlayActivity = new ActivityBuilder(mService).setTask(mTask)
+ final ActivityRecord overlayActivity = new ActivityBuilder(mAtm).setTask(mTask)
.setComponent(new ComponentName("package.overlay", ".OverlayActivity")).build();
// If the task only remains overlay activity, the task should also be removed.
// See {@link ActivityStack#removeFromHistory}.
@@ -1058,8 +1057,8 @@
@Test
public void testHandleAppDied() {
- final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build();
- final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
+ final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
// Making the first activity a task overlay means it will be removed from the task's
// activities as well once second activity is removed as handleAppDied processes the
@@ -1080,7 +1079,7 @@
@Test
public void testHandleAppDied_RelaunchesAfterCrashDuringWindowingModeResize() {
- final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(mTask).build();
activity.mRelaunchReason = RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
activity.launchCount = 1;
@@ -1094,7 +1093,7 @@
@Test
public void testHandleAppDied_NotRelaunchAfterThreeCrashesDuringWindowingModeResize() {
- final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(mTask).build();
activity.mRelaunchReason = RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
activity.launchCount = 3;
@@ -1108,7 +1107,7 @@
@Test
public void testHandleAppDied_RelaunchesAfterCrashDuringFreeResize() {
- final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(mTask).build();
activity.mRelaunchReason = RELAUNCH_REASON_FREE_RESIZE;
activity.launchCount = 1;
@@ -1122,7 +1121,7 @@
@Test
public void testHandleAppDied_NotRelaunchAfterThreeCrashesDuringFreeResize() {
- final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(mTask).build();
activity.mRelaunchReason = RELAUNCH_REASON_FREE_RESIZE;
activity.launchCount = 3;
@@ -1136,11 +1135,11 @@
@Test
public void testCompletePauseOnResumeWhilePausingActivity() {
- final ActivityRecord bottomActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord bottomActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
doReturn(true).when(bottomActivity).attachedToProcess();
mStack.mPausingActivity = null;
mStack.mResumedActivity = bottomActivity;
- final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
topActivity.info.flags |= FLAG_RESUME_WHILE_PAUSING;
mStack.startPausingLocked(false /* userLeaving */, false /* uiSleeping */, topActivity);
@@ -1154,7 +1153,7 @@
ActivityRecord activity = homeStack.topRunningActivity();
if (activity == null) {
- activity = new ActivityBuilder(mService)
+ activity = new ActivityBuilder(mAtm)
.setStack(homeStack)
.setCreateTask(true)
.build();
@@ -1265,13 +1264,13 @@
public void testNavigateUpTo() {
final ActivityStartController controller = mock(ActivityStartController.class);
final ActivityStarter starter = new ActivityStarter(controller,
- mService, mService.mStackSupervisor, mock(ActivityStartInterceptor.class));
- doReturn(controller).when(mService).getActivityStartController();
+ mAtm, mAtm.mStackSupervisor, mock(ActivityStartInterceptor.class));
+ doReturn(controller).when(mAtm).getActivityStartController();
spyOn(starter);
doReturn(ActivityManager.START_SUCCESS).when(starter).execute();
- final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build();
- final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask)
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
+ final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(mTask)
.setUid(firstActivity.getUid() + 1).build();
doReturn(starter).when(controller).obtainStarter(eq(firstActivity.intent), anyString());
@@ -1297,7 +1296,7 @@
@Test
public void testShouldUpRecreateTaskLockedWithCorrectAffinityFormat() {
final String affinity = "affinity";
- final ActivityRecord activity = new ActivityBuilder(mService).setAffinity(affinity)
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setAffinity(affinity)
.setUid(Binder.getCallingUid()).setCreateTask(true).build();
activity.getTask().affinity = activity.taskAffinity;
@@ -1307,7 +1306,7 @@
@Test
public void testShouldUpRecreateTaskLockedWithWrongAffinityFormat() {
final String affinity = "affinity";
- final ActivityRecord activity = new ActivityBuilder(mService).setAffinity(affinity)
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setAffinity(affinity)
.setUid(Binder.getCallingUid()).setCreateTask(true).build();
activity.getTask().affinity = activity.taskAffinity;
final String fakeAffinity = activity.getUid() + activity.taskAffinity;
@@ -1318,12 +1317,12 @@
@Test
public void testResetTaskWithFinishingActivities() {
final ActivityRecord taskTop =
- new ActivityBuilder(mService).setStack(mStack).setCreateTask(true).build();
+ new ActivityBuilder(mAtm).setStack(mStack).setCreateTask(true).build();
// Make all activities in the task are finishing to simulate Task#getTopActivity
// returns null.
taskTop.finishing = true;
- final ActivityRecord newR = new ActivityBuilder(mService).build();
+ final ActivityRecord newR = new ActivityBuilder(mAtm).build();
final ActivityRecord result = mStack.resetTaskIfNeeded(taskTop, newR);
assertThat(result).isEqualTo(taskTop);
}
@@ -1333,9 +1332,9 @@
final ArrayList<ActivityRecord> occludedActivities = new ArrayList<>();
final Consumer<ActivityRecord> handleOccludedActivity = occludedActivities::add;
final ActivityRecord bottomActivity =
- new ActivityBuilder(mService).setStack(mStack).setTask(mTask).build();
+ new ActivityBuilder(mAtm).setStack(mStack).setTask(mTask).build();
final ActivityRecord topActivity =
- new ActivityBuilder(mService).setStack(mStack).setTask(mTask).build();
+ new ActivityBuilder(mAtm).setStack(mStack).setTask(mTask).build();
// Top activity occludes bottom activity.
doReturn(true).when(mStack).shouldBeVisible(any());
assertTrue(topActivity.shouldBeVisible());
@@ -1354,7 +1353,7 @@
// A finishing activity should not occlude other activities behind.
final ActivityRecord finishingActivity =
- new ActivityBuilder(mService).setStack(mStack).setTask(mTask).build();
+ new ActivityBuilder(mAtm).setStack(mStack).setTask(mTask).build();
finishingActivity.finishing = true;
doCallRealMethod().when(finishingActivity).occludesParent();
assertTrue(topActivity.shouldBeVisible());
@@ -1376,9 +1375,9 @@
final ActivityRecord[] activities = new ActivityRecord[2];
mSupervisor.beginDeferResume();
for (int i = 0; i < activities.length; i++) {
- final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord r = new ActivityBuilder(mAtm).setTask(mTask).build();
activities[i] = r;
- doReturn(null).when(mService).getProcessController(
+ doReturn(null).when(mAtm).getProcessController(
eq(r.processName), eq(r.info.applicationInfo.uid));
r.setState(Task.ActivityState.INITIALIZING, "test");
// Ensure precondition that the activity is opaque.
@@ -1388,7 +1387,7 @@
}
mSupervisor.endDeferResume();
- setBooted(mService);
+ setBooted(mAtm);
// 2 activities are started while keyguard is locked, so they are waiting to be resolved.
assertFalse(unknownAppVisibilityController.allResolved());
@@ -1405,8 +1404,8 @@
@Test
public void testNonTopVisibleActivityNotResume() {
final ActivityRecord nonTopVisibleActivity =
- new ActivityBuilder(mService).setTask(mTask).build();
- new ActivityBuilder(mService).setTask(mTask).build();
+ new ActivityBuilder(mAtm).setTask(mTask).build();
+ new ActivityBuilder(mAtm).setTask(mTask).build();
doReturn(false).when(nonTopVisibleActivity).attachedToProcess();
doReturn(true).when(nonTopVisibleActivity).shouldBeVisible(anyBoolean(), anyBoolean());
doNothing().when(mSupervisor).startSpecificActivity(any(), anyBoolean(),
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
index c9a9279..55afc70 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
@@ -51,7 +51,7 @@
@SmallTest
@Presubmit
@RunWith(WindowTestRunner.class)
-public class ActivityStartControllerTests extends ActivityTestsBase {
+public class ActivityStartControllerTests extends WindowTestsBase {
private ActivityStartController mController;
private Factory mFactory;
private ActivityStarter mStarter;
@@ -59,9 +59,9 @@
@Before
public void setUp() throws Exception {
mFactory = mock(Factory.class);
- mController = new ActivityStartController(mService, mService.mStackSupervisor, mFactory);
- mStarter = spy(new ActivityStarter(mController, mService,
- mService.mStackSupervisor, mock(ActivityStartInterceptor.class)));
+ mController = new ActivityStartController(mAtm, mAtm.mStackSupervisor, mFactory);
+ mStarter = spy(new ActivityStarter(mController, mAtm,
+ mAtm.mStackSupervisor, mock(ActivityStartInterceptor.class)));
doReturn(mStarter).when(mFactory).obtain();
}
@@ -72,15 +72,15 @@
public void testPendingActivityLaunches() {
final Random random = new Random();
- final ActivityRecord activity = new ActivityBuilder(mService).build();
- final ActivityRecord source = new ActivityBuilder(mService)
+ final ActivityRecord activity = new ActivityBuilder(mAtm).build();
+ final ActivityRecord source = new ActivityBuilder(mAtm)
.setCreateTask(true)
.build();
final int startFlags = random.nextInt();
- final Task stack = mService.mRootWindowContainer.getDefaultTaskDisplayArea()
+ final Task stack = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea()
.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final WindowProcessController wpc = new WindowProcessController(mService,
- mService.mContext.getApplicationInfo(), "name", 12345,
+ final WindowProcessController wpc = new WindowProcessController(mAtm,
+ mAtm.mContext.getApplicationInfo(), "name", 12345,
UserHandle.getUserId(12345), mock(Object.class),
mock(WindowProcessListener.class));
wpc.setThread(mock(IApplicationThread.class));
@@ -101,8 +101,8 @@
@Test
public void testRecycling() {
final Intent intent = new Intent();
- final ActivityStarter optionStarter = new ActivityStarter(mController, mService,
- mService.mStackSupervisor, mock(ActivityStartInterceptor.class));
+ final ActivityStarter optionStarter = new ActivityStarter(mController, mAtm,
+ mAtm.mStackSupervisor, mock(ActivityStartInterceptor.class));
optionStarter
.setIntent(intent)
.setReason("Test")
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index d07000f..e5c9ecc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -100,7 +100,7 @@
@SmallTest
@Presubmit
@RunWith(WindowTestRunner.class)
-public class ActivityStarterTests extends ActivityTestsBase {
+public class ActivityStarterTests extends WindowTestsBase {
private ActivityStartController mController;
private ActivityMetricsLogger mActivityMetricsLogger;
private PackageManagerInternal mMockPackageManager;
@@ -187,7 +187,7 @@
*/
private void verifyStartActivityPreconditionsUntracked(int preconditions, int launchFlags,
int expectedResult) {
- final ActivityTaskManagerService service = mService;
+ final ActivityTaskManagerService service = mAtm;
final IPackageManager packageManager = mock(IPackageManager.class);
final ActivityStartController controller = mock(ActivityStartController.class);
@@ -283,8 +283,8 @@
// Ensure that {@link ActivityOptions} are aborted with unsuccessful result.
if (expectedResult != START_SUCCESS) {
- final ActivityStarter optionStarter = new ActivityStarter(mController, mService,
- mService.mStackSupervisor, mock(ActivityStartInterceptor.class));
+ final ActivityStarter optionStarter = new ActivityStarter(mController, mAtm,
+ mAtm.mStackSupervisor, mock(ActivityStartInterceptor.class));
final ActivityOptions options = spy(ActivityOptions.makeBasic());
final int optionResult = optionStarter.setCaller(caller)
@@ -338,7 +338,7 @@
invocation -> {
throw new RuntimeException("Not stubbed");
});
- doReturn(mMockPackageManager).when(mService).getPackageManagerInternalLocked();
+ doReturn(mMockPackageManager).when(mAtm).getPackageManagerInternalLocked();
doReturn(false).when(mMockPackageManager).isInstantAppInstallerComponent(any());
doReturn(null).when(mMockPackageManager).resolveIntent(any(), any(), anyInt(), anyInt(),
anyInt(), anyBoolean(), anyInt());
@@ -359,8 +359,8 @@
info.applicationInfo = new ApplicationInfo();
info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName();
- return new ActivityStarter(mController, mService,
- mService.mStackSupervisor, mock(ActivityStartInterceptor.class))
+ return new ActivityStarter(mController, mAtm,
+ mAtm.mStackSupervisor, mock(ActivityStartInterceptor.class))
.setIntent(intent)
.setActivityInfo(info);
}
@@ -373,7 +373,7 @@
public void testCreateTaskLayout() {
// modifier for validating passed values.
final LaunchParamsModifier modifier = mock(LaunchParamsModifier.class);
- mService.mStackSupervisor.getLaunchParamsController().registerModifier(modifier);
+ mAtm.mStackSupervisor.getLaunchParamsController().registerModifier(modifier);
// add custom values to activity info to make unique.
final ActivityInfo info = new ActivityInfo();
@@ -414,9 +414,9 @@
final ActivityStarter starter = prepareStarter(
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false);
final ActivityRecord splitPrimaryFocusActivity =
- new ActivityBuilder(mService).setCreateTask(true).build();
+ new ActivityBuilder(mAtm).setCreateTask(true).build();
final ActivityRecord splitSecondReusableActivity =
- new ActivityBuilder(mService).setCreateTask(true).build();
+ new ActivityBuilder(mAtm).setCreateTask(true).build();
splitPrimaryFocusActivity.getRootTask()
.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
splitSecondReusableActivity.getRootTask()
@@ -443,11 +443,11 @@
final ActivityStarter starter = prepareStarter(
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false);
final ActivityRecord splitSecondReusableActivity =
- new ActivityBuilder(mService).setCreateTask(true).build();
+ new ActivityBuilder(mAtm).setCreateTask(true).build();
final ActivityRecord splitSecondTopActivity =
- new ActivityBuilder(mService).setCreateTask(true).build();
+ new ActivityBuilder(mAtm).setCreateTask(true).build();
final ActivityRecord splitPrimaryFocusActivity =
- new ActivityBuilder(mService).setCreateTask(true).build();
+ new ActivityBuilder(mAtm).setCreateTask(true).build();
splitPrimaryFocusActivity.getRootTask()
.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
splitSecondReusableActivity.getRootTask()
@@ -475,13 +475,13 @@
*/
@Test
public void testTaskModeViolation() {
- final DisplayContent display = mService.mRootWindowContainer.getDefaultDisplay();
+ final DisplayContent display = mAtm.mRootWindowContainer.getDefaultDisplay();
display.removeAllTasks();
assertNoTasks(display);
final ActivityStarter starter = prepareStarter(0);
- final LockTaskController lockTaskController = mService.getLockTaskController();
+ final LockTaskController lockTaskController = mAtm.getLockTaskController();
doReturn(true).when(lockTaskController).isLockTaskModeViolation(any());
final int result = starter.setReason("testTaskModeViolation").execute();
@@ -504,8 +504,8 @@
*/
@Test
public void testActivityStartsLogging_noLoggingWhenDisabled() {
- doReturn(false).when(mService).isActivityStartsLoggingEnabled();
- doReturn(mActivityMetricsLogger).when(mService.mStackSupervisor).getActivityMetricsLogger();
+ doReturn(false).when(mAtm).isActivityStartsLoggingEnabled();
+ doReturn(mActivityMetricsLogger).when(mAtm.mStackSupervisor).getActivityMetricsLogger();
ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK);
starter.setReason("testActivityStartsLogging_noLoggingWhenDisabled").execute();
@@ -521,8 +521,8 @@
@Test
public void testActivityStartsLogging_logsWhenEnabled() {
// note: conveniently this package doesn't have any activity visible
- doReturn(true).when(mService).isActivityStartsLoggingEnabled();
- doReturn(mActivityMetricsLogger).when(mService.mStackSupervisor).getActivityMetricsLogger();
+ doReturn(true).when(mAtm).isActivityStartsLoggingEnabled();
+ doReturn(mActivityMetricsLogger).when(mAtm.mStackSupervisor).getActivityMetricsLogger();
ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
.setCallingUid(FAKE_CALLING_UID)
@@ -544,7 +544,7 @@
*/
@Test
public void testBackgroundActivityStartsAllowed_noStartsAborted() {
- doReturn(true).when(mService).isBackgroundActivityStartsEnabled();
+ doReturn(true).when(mAtm).isBackgroundActivityStartsEnabled();
runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted", false,
UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
@@ -558,7 +558,7 @@
*/
@Test
public void testBackgroundActivityStartsDisallowed_unsupportedStartsAborted() {
- doReturn(false).when(mService).isBackgroundActivityStartsEnabled();
+ doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
runAndVerifyBackgroundActivityStartsSubtest(
"disallowed_unsupportedUsecase_aborted", true,
@@ -589,7 +589,7 @@
*/
@Test
public void testBackgroundActivityStartsDisallowed_supportedStartsNotAborted() {
- doReturn(false).when(mService).isBackgroundActivityStartsEnabled();
+ doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted", false,
Process.ROOT_UID, false, PROCESS_STATE_TOP + 1,
@@ -644,13 +644,13 @@
boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges,
boolean isCallingUidDeviceOwner) {
// window visibility
- doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
+ doReturn(callingUidHasVisibleWindow).when(mAtm.mWindowManager.mRoot)
.isAnyNonToastWindowVisibleForUid(callingUid);
- doReturn(realCallingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
+ doReturn(realCallingUidHasVisibleWindow).when(mAtm.mWindowManager.mRoot)
.isAnyNonToastWindowVisibleForUid(realCallingUid);
// process importance
- doReturn(callingUidProcState).when(mService).getUidState(callingUid);
- doReturn(realCallingUidProcState).when(mService).getUidState(realCallingUid);
+ doReturn(callingUidProcState).when(mAtm).getUidState(callingUid);
+ doReturn(realCallingUidProcState).when(mAtm).getUidState(realCallingUid);
// foreground activities
final IApplicationThread caller = mock(IApplicationThread.class);
final WindowProcessListener listener = mock(WindowProcessListener.class);
@@ -658,12 +658,12 @@
ai.uid = callingUid;
ai.packageName = "com.android.test.package";
final WindowProcessController callerApp =
- new WindowProcessController(mService, ai, null, callingUid, -1, null, listener);
+ new WindowProcessController(mAtm, ai, null, callingUid, -1, null, listener);
callerApp.setHasForegroundActivities(hasForegroundActivities);
- doReturn(callerApp).when(mService).getProcessController(caller);
+ doReturn(callerApp).when(mAtm).getProcessController(caller);
// caller is recents
RecentTasks recentTasks = mock(RecentTasks.class);
- mService.mStackSupervisor.setRecentTasks(recentTasks);
+ mAtm.mStackSupervisor.setRecentTasks(recentTasks);
doReturn(callerIsRecents).when(recentTasks).isCallerRecents(callingUid);
// caller is temp allowed
if (callerIsTempAllowed) {
@@ -673,7 +673,7 @@
callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges,
callerIsInstrumentingWithBackgroundActivityStartPrivileges);
// callingUid is the device owner
- doReturn(isCallingUidDeviceOwner).when(mService).isDeviceOwner(callingUid);
+ doReturn(isCallingUidDeviceOwner).when(mAtm).isDeviceOwner(callingUid);
final ActivityOptions options = spy(ActivityOptions.makeBasic());
ActivityRecord[] outActivity = new ActivityRecord[1];
@@ -706,14 +706,14 @@
@Test
public void testBringTaskToFrontWhenFocusedStackIsFinising() {
// Put 2 tasks in the same stack (simulate the behavior of home stack).
- final ActivityRecord activity = new ActivityBuilder(mService)
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
.setCreateTask(true).build();
- new ActivityBuilder(mService)
+ new ActivityBuilder(mAtm)
.setStack(activity.getRootTask())
.setCreateTask(true).build();
// Create a top finishing activity.
- final ActivityRecord finishingTopActivity = new ActivityBuilder(mService)
+ final ActivityRecord finishingTopActivity = new ActivityBuilder(mAtm)
.setCreateTask(true).build();
finishingTopActivity.getRootTask().moveToFront("finishingTopActivity");
@@ -741,7 +741,7 @@
// Create a secondary display at bottom.
final TestDisplayContent secondaryDisplay =
- new TestDisplayContent.Builder(mService, 1000, 1500)
+ new TestDisplayContent.Builder(mAtm, 1000, 1500)
.setPosition(POSITION_BOTTOM).build();
final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea();
final Task stack = secondaryTaskContainer.createStack(
@@ -751,7 +751,7 @@
final ActivityRecord topActivityOnSecondaryDisplay = createSingleTaskActivityOn(stack);
// Put an activity on default display as the top focused activity.
- new ActivityBuilder(mService).setCreateTask(true).build();
+ new ActivityBuilder(mAtm).setCreateTask(true).build();
// Start activity with the same intent as {@code topActivityOnSecondaryDisplay}
// on secondary display.
@@ -781,7 +781,7 @@
// Create a secondary display with an activity.
final TestDisplayContent secondaryDisplay =
- new TestDisplayContent.Builder(mService, 1000, 1500).build();
+ new TestDisplayContent.Builder(mAtm, 1000, 1500).build();
mRootWindowContainer.positionChildAt(POSITION_TOP, secondaryDisplay,
false /* includingParents */);
final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea();
@@ -793,7 +793,7 @@
final Task topStack = secondaryTaskContainer.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
final Task topTask = new TaskBuilder(mSupervisor).setStack(topStack).build();
- new ActivityBuilder(mService).setTask(topTask).build();
+ new ActivityBuilder(mAtm).setTask(topTask).build();
// Start activity with the same intent as {@code singleTaskActivity} on secondary display.
final ActivityOptions options = ActivityOptions.makeBasic()
@@ -815,16 +815,16 @@
final ActivityStarter starter = prepareStarter(
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false);
final ActivityRecord reusableActivity =
- new ActivityBuilder(mService).setCreateTask(true).build();
+ new ActivityBuilder(mAtm).setCreateTask(true).build();
final ActivityRecord topActivity =
- new ActivityBuilder(mService).setCreateTask(true).build();
+ new ActivityBuilder(mAtm).setCreateTask(true).build();
// Make sure topActivity is on top
topActivity.getRootTask().moveToFront("testWasVisibleInRestartAttempt");
reusableActivity.setVisible(false);
final TaskChangeNotificationController taskChangeNotifier =
- mService.getTaskChangeNotificationController();
+ mAtm.getTaskChangeNotificationController();
spyOn(taskChangeNotifier);
Task task = topActivity.getTask();
@@ -853,7 +853,7 @@
.setComponent(componentName)
.setStack(stack)
.build();
- return new ActivityBuilder(mService)
+ return new ActivityBuilder(mAtm)
.setComponent(componentName)
.setLaunchMode(LAUNCH_SINGLE_TASK)
.setTask(task)
@@ -876,7 +876,7 @@
true /* onTop */);
// Put an activity on default display as the top focused activity.
- final ActivityRecord topActivity = new ActivityBuilder(mService)
+ final ActivityRecord topActivity = new ActivityBuilder(mAtm)
.setCreateTask(true)
.setLaunchMode(LAUNCH_SINGLE_TASK)
.build();
@@ -900,7 +900,7 @@
@Test
public void testFreezeTaskListActivityOption() {
RecentTasks recentTasks = mock(RecentTasks.class);
- mService.mStackSupervisor.setRecentTasks(recentTasks);
+ mAtm.mStackSupervisor.setRecentTasks(recentTasks);
doReturn(true).when(recentTasks).isCallerRecents(anyInt());
final ActivityStarter starter = prepareStarter(0 /* flags */);
@@ -922,7 +922,7 @@
@Test
public void testFreezeTaskListActivityOptionFailedStart_expectResetFreezeTaskList() {
RecentTasks recentTasks = mock(RecentTasks.class);
- mService.mStackSupervisor.setRecentTasks(recentTasks);
+ mAtm.mStackSupervisor.setRecentTasks(recentTasks);
doReturn(true).when(recentTasks).isCallerRecents(anyInt());
final ActivityStarter starter = prepareStarter(0 /* flags */);
@@ -959,7 +959,7 @@
intent.setComponent(ActivityBuilder.getDefaultComponent());
doReturn(true).when(mMockPackageManager).isInstantAppInstallerComponent(any());
- starter.setIntent(intent).mRequest.resolveActivity(mService.mStackSupervisor);
+ starter.setIntent(intent).mRequest.resolveActivity(mAtm.mStackSupervisor);
// Make sure the client intent won't be modified.
assertThat(intent.getComponent()).isNotNull();
@@ -985,9 +985,9 @@
@Test
public void testRecycleTaskFromAnotherUser() {
final ActivityStarter starter = prepareStarter(0 /* flags */);
- starter.mStartActivity = new ActivityBuilder(mService).build();
- final Task task = new TaskBuilder(mService.mStackSupervisor)
- .setStack(mService.mRootWindowContainer.getDefaultTaskDisplayArea().createStack(
+ starter.mStartActivity = new ActivityBuilder(mAtm).build();
+ final Task task = new TaskBuilder(mAtm.mStackSupervisor)
+ .setStack(mAtm.mRootWindowContainer.getDefaultTaskDisplayArea().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */))
.setUserId(10)
.build();
@@ -1001,7 +1001,7 @@
public void testTargetStackInSplitScreen() {
final ActivityStarter starter =
prepareStarter(FLAG_ACTIVITY_LAUNCH_ADJACENT, false /* mockGetLaunchStack */);
- final ActivityRecord top = new ActivityBuilder(mService).setCreateTask(true).build();
+ final ActivityRecord top = new ActivityBuilder(mAtm).setCreateTask(true).build();
final ActivityOptions options = ActivityOptions.makeBasic();
final ActivityRecord[] outActivity = new ActivityRecord[1];
@@ -1012,7 +1012,7 @@
assertThat(outActivity[0].inSplitScreenWindowingMode()).isFalse();
// Move activity to split-screen-primary stack and make sure it has the focus.
- TestSplitOrganizer splitOrg = new TestSplitOrganizer(mService, top.getDisplayId());
+ TestSplitOrganizer splitOrg = new TestSplitOrganizer(mAtm, top.getDisplayId());
top.getRootTask().reparent(splitOrg.mPrimary, POSITION_BOTTOM);
top.getRootTask().moveToFront("testWindowingModeOptionsLaunchAdjacent");
@@ -1026,7 +1026,7 @@
@Test
public void testActivityStart_expectAddedToRecentTask() {
RecentTasks recentTasks = mock(RecentTasks.class);
- mService.mStackSupervisor.setRecentTasks(recentTasks);
+ mAtm.mStackSupervisor.setRecentTasks(recentTasks);
doReturn(true).when(recentTasks).isCallerRecents(anyInt());
final ActivityStarter starter = prepareStarter(0 /* flags */);
@@ -1044,10 +1044,10 @@
starter.setReason("testAllSplitScreenPrimaryActivitiesAreResumed");
- final ActivityRecord targetRecord = new ActivityBuilder(mService).build();
+ final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build();
targetRecord.setFocusable(false);
targetRecord.setVisibility(false);
- final ActivityRecord sourceRecord = new ActivityBuilder(mService).build();
+ final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).build();
final Task stack = spy(
mRootWindowContainer.getDefaultTaskDisplayArea()
@@ -1059,7 +1059,7 @@
doReturn(stack).when(mRootWindowContainer)
.getLaunchStack(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt());
- starter.mStartActivity = new ActivityBuilder(mService).build();
+ starter.mStartActivity = new ActivityBuilder(mAtm).build();
// When
starter.startActivityInner(
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index f8faae6..2e988af 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -60,14 +60,14 @@
@Presubmit
@MediumTest
@RunWith(WindowTestRunner.class)
-public class ActivityTaskManagerServiceTests extends ActivityTestsBase {
+public class ActivityTaskManagerServiceTests extends WindowTestsBase {
private final ArgumentCaptor<ClientTransaction> mClientTransactionCaptor =
ArgumentCaptor.forClass(ClientTransaction.class);
@Before
public void setUp() throws Exception {
- setBooted(mService);
+ setBooted(mAtm);
}
/** Verify that activity is finished correctly upon request. */
@@ -75,13 +75,13 @@
public void testActivityFinish() {
final Task stack = new StackBuilder(mRootWindowContainer).build();
final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
- assertTrue("Activity must be finished", mService.finishActivity(activity.appToken,
+ assertTrue("Activity must be finished", mAtm.finishActivity(activity.appToken,
0 /* resultCode */, null /* resultData */,
Activity.DONT_FINISH_TASK_WITH_ACTIVITY));
assertTrue(activity.finishing);
assertTrue("Duplicate activity finish request must also return 'true'",
- mService.finishActivity(activity.appToken, 0 /* resultCode */,
+ mAtm.finishActivity(activity.appToken, 0 /* resultCode */,
null /* resultData */, Activity.DONT_FINISH_TASK_WITH_ACTIVITY));
}
@@ -90,10 +90,10 @@
final Task stack = new StackBuilder(mRootWindowContainer).build();
final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
final ClientLifecycleManager mockLifecycleManager = mock(ClientLifecycleManager.class);
- doReturn(mockLifecycleManager).when(mService).getLifecycleManager();
+ doReturn(mockLifecycleManager).when(mAtm).getLifecycleManager();
doReturn(true).when(activity).checkEnterPictureInPictureState(anyString(), anyBoolean());
- mService.requestPictureInPictureMode(activity.token);
+ mAtm.requestPictureInPictureMode(activity.token);
verify(mockLifecycleManager).scheduleTransaction(mClientTransactionCaptor.capture());
final ClientTransaction transaction = mClientTransactionCaptor.getValue();
@@ -108,11 +108,11 @@
public void testOnPictureInPictureRequested_cannotEnterPip() throws RemoteException {
final Task stack = new StackBuilder(mRootWindowContainer).build();
final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
- ClientLifecycleManager lifecycleManager = mService.getLifecycleManager();
+ ClientLifecycleManager lifecycleManager = mAtm.getLifecycleManager();
doReturn(false).when(activity).inPinnedWindowingMode();
doReturn(false).when(activity).checkEnterPictureInPictureState(anyString(), anyBoolean());
- mService.requestPictureInPictureMode(activity.token);
+ mAtm.requestPictureInPictureMode(activity.token);
// Check enter no transactions with enter pip requests are made.
verify(lifecycleManager, times(0)).scheduleTransaction(any());
@@ -122,10 +122,10 @@
public void testOnPictureInPictureRequested_alreadyInPIPMode() throws RemoteException {
final Task stack = new StackBuilder(mRootWindowContainer).build();
final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
- ClientLifecycleManager lifecycleManager = mService.getLifecycleManager();
+ ClientLifecycleManager lifecycleManager = mAtm.getLifecycleManager();
doReturn(true).when(activity).inPinnedWindowingMode();
- mService.requestPictureInPictureMode(activity.token);
+ mAtm.requestPictureInPictureMode(activity.token);
// Check that no transactions with enter pip requests are made.
verify(lifecycleManager, times(0)).scheduleTransaction(any());
@@ -158,14 +158,14 @@
@Override
public void onFixedRotationFinished(int displayId) {}
};
- mService.mWindowManager.registerDisplayWindowListener(listener);
+ mAtm.mWindowManager.registerDisplayWindowListener(listener);
// Check that existing displays call added
assertEquals(1, added.size());
assertEquals(0, changed.size());
assertEquals(0, removed.size());
added.clear();
// Check adding a display
- DisplayContent newDisp1 = new TestDisplayContent.Builder(mService, 600, 800).build();
+ DisplayContent newDisp1 = new TestDisplayContent.Builder(mAtm, 600, 800).build();
assertEquals(1, added.size());
assertEquals(0, changed.size());
assertEquals(0, removed.size());
@@ -174,7 +174,7 @@
Configuration c = new Configuration(newDisp1.getRequestedOverrideConfiguration());
c.windowConfiguration.setBounds(new Rect(0, 0, 1000, 1300));
newDisp1.onRequestedOverrideConfigurationChanged(c);
- mService.mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */,
+ mAtm.mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */,
newDisp1.mDisplayId, false /* markFrozenIfConfigChanged */,
false /* deferResume */);
assertEquals(0, added.size());
@@ -214,13 +214,13 @@
//mock other operations
doReturn(true).when(record)
.checkEnterPictureInPictureState("enterPictureInPictureMode", false);
- doReturn(false).when(mService).isInPictureInPictureMode(any());
- doReturn(false).when(mService).isKeyguardLocked();
+ doReturn(false).when(mAtm).isInPictureInPictureMode(any());
+ doReturn(false).when(mAtm).isKeyguardLocked();
//to simulate NPE
doReturn(null).when(record).getParent();
- mService.enterPictureInPictureMode(token, params);
+ mAtm.enterPictureInPictureMode(token, params);
//if record's null parent is not handled gracefully, test will fail with NPE
mockSession.finishMocking();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
deleted file mode 100644
index 5be2f04..0000000
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ /dev/null
@@ -1,607 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
-
-import android.app.ActivityManager;
-import android.app.ActivityOptions;
-import android.app.IApplicationThread;
-import android.app.WindowConfiguration;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.res.Configuration;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.service.voice.IVoiceInteractionSession;
-import android.view.SurfaceControl;
-import android.window.ITaskOrganizer;
-import android.window.WindowContainerToken;
-
-import com.android.server.AttributeCache;
-
-import org.junit.Before;
-import org.junit.BeforeClass;
-
-/**
- * A base class to handle common operations in activity related unit tests.
- */
-class ActivityTestsBase extends SystemServiceTestsBase {
- final Context mContext = getInstrumentation().getTargetContext();
-
- ActivityTaskManagerService mService;
- RootWindowContainer mRootWindowContainer;
- ActivityStackSupervisor mSupervisor;
-
- // Default package name
- static final String DEFAULT_COMPONENT_PACKAGE_NAME = "com.foo";
-
- // Default base activity name
- private static final String DEFAULT_COMPONENT_CLASS_NAME = ".BarActivity";
-
- @BeforeClass
- public static void setUpOnceBase() {
- AttributeCache.init(getInstrumentation().getTargetContext());
- }
-
- @Before
- public void setUpBase() {
- mService = mSystemServicesTestRule.getActivityTaskManagerService();
- mSupervisor = mService.mStackSupervisor;
- mRootWindowContainer = mService.mRootWindowContainer;
- }
-
- /** Creates and adds a {@link TestDisplayContent} to supervisor at the given position. */
- TestDisplayContent addNewDisplayContentAt(int position) {
- return new TestDisplayContent.Builder(mService, 1000, 1500).setPosition(position).build();
- }
-
- /** Sets the default minimum task size to 1 so that tests can use small task sizes */
- public void removeGlobalMinSizeRestriction() {
- mService.mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp = 1;
- }
-
- /**
- * Builder for creating new activities.
- */
- protected static class ActivityBuilder {
- // An id appended to the end of the component name to make it unique
- private static int sCurrentActivityId = 0;
-
- private final ActivityTaskManagerService mService;
-
- private ComponentName mComponent;
- private String mTargetActivity;
- private Task mTask;
- private String mProcessName = "name";
- private String mAffinity;
- private int mUid = 12345;
- private boolean mCreateTask;
- private Task mStack;
- private int mActivityFlags;
- private int mLaunchMode;
- private int mResizeMode = RESIZE_MODE_RESIZEABLE;
- private float mMaxAspectRatio;
- private int mScreenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
- private boolean mLaunchTaskBehind;
- private int mConfigChanges;
- private int mLaunchedFromPid;
- private int mLaunchedFromUid;
- private WindowProcessController mWpc;
- private Bundle mIntentExtras;
-
- ActivityBuilder(ActivityTaskManagerService service) {
- mService = service;
- }
-
- ActivityBuilder setComponent(ComponentName component) {
- mComponent = component;
- return this;
- }
-
- ActivityBuilder setTargetActivity(String targetActivity) {
- mTargetActivity = targetActivity;
- return this;
- }
-
- ActivityBuilder setIntentExtras(Bundle extras) {
- mIntentExtras = extras;
- return this;
- }
-
- static ComponentName getDefaultComponent() {
- return ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
- DEFAULT_COMPONENT_PACKAGE_NAME);
- }
-
- ActivityBuilder setTask(Task task) {
- mTask = task;
- return this;
- }
-
- ActivityBuilder setActivityFlags(int flags) {
- mActivityFlags = flags;
- return this;
- }
-
- ActivityBuilder setLaunchMode(int launchMode) {
- mLaunchMode = launchMode;
- return this;
- }
-
- ActivityBuilder setStack(Task stack) {
- mStack = stack;
- return this;
- }
-
- ActivityBuilder setCreateTask(boolean createTask) {
- mCreateTask = createTask;
- return this;
- }
-
- ActivityBuilder setProcessName(String name) {
- mProcessName = name;
- return this;
- }
-
- ActivityBuilder setUid(int uid) {
- mUid = uid;
- return this;
- }
-
- ActivityBuilder setResizeMode(int resizeMode) {
- mResizeMode = resizeMode;
- return this;
- }
-
- ActivityBuilder setMaxAspectRatio(float maxAspectRatio) {
- mMaxAspectRatio = maxAspectRatio;
- return this;
- }
-
- ActivityBuilder setScreenOrientation(int screenOrientation) {
- mScreenOrientation = screenOrientation;
- return this;
- }
-
- ActivityBuilder setLaunchTaskBehind(boolean launchTaskBehind) {
- mLaunchTaskBehind = launchTaskBehind;
- return this;
- }
-
- ActivityBuilder setConfigChanges(int configChanges) {
- mConfigChanges = configChanges;
- return this;
- }
-
- ActivityBuilder setLaunchedFromPid(int pid) {
- mLaunchedFromPid = pid;
- return this;
- }
-
- ActivityBuilder setLaunchedFromUid(int uid) {
- mLaunchedFromUid = uid;
- return this;
- }
-
- ActivityBuilder setUseProcess(WindowProcessController wpc) {
- mWpc = wpc;
- return this;
- }
-
- ActivityBuilder setAffinity(String affinity) {
- mAffinity = affinity;
- return this;
- }
-
- ActivityRecord build() {
- SystemServicesTestRule.checkHoldsLock(mService.mGlobalLock);
- try {
- mService.deferWindowLayout();
- return buildInner();
- } finally {
- mService.continueWindowLayout();
- }
- }
-
- ActivityRecord buildInner() {
- if (mComponent == null) {
- final int id = sCurrentActivityId++;
- mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
- DEFAULT_COMPONENT_CLASS_NAME + id);
- }
-
- if (mCreateTask) {
- mTask = new TaskBuilder(mService.mStackSupervisor)
- .setComponent(mComponent)
- .setStack(mStack).build();
- } else if (mTask == null && mStack != null && DisplayContent.alwaysCreateStack(
- mStack.getWindowingMode(), mStack.getActivityType())) {
- // The stack can be the task root.
- mTask = mStack;
- }
-
- Intent intent = new Intent();
- intent.setComponent(mComponent);
- if (mIntentExtras != null) {
- intent.putExtras(mIntentExtras);
- }
- final ActivityInfo aInfo = new ActivityInfo();
- aInfo.applicationInfo = new ApplicationInfo();
- aInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
- aInfo.applicationInfo.packageName = mComponent.getPackageName();
- aInfo.applicationInfo.uid = mUid;
- aInfo.processName = mProcessName;
- aInfo.packageName = mComponent.getPackageName();
- aInfo.name = mComponent.getClassName();
- if (mTargetActivity != null) {
- aInfo.targetActivity = mTargetActivity;
- }
- aInfo.flags |= mActivityFlags;
- aInfo.launchMode = mLaunchMode;
- aInfo.resizeMode = mResizeMode;
- aInfo.maxAspectRatio = mMaxAspectRatio;
- aInfo.screenOrientation = mScreenOrientation;
- aInfo.configChanges |= mConfigChanges;
- aInfo.taskAffinity = mAffinity;
-
- ActivityOptions options = null;
- if (mLaunchTaskBehind) {
- options = ActivityOptions.makeTaskLaunchBehind();
- }
-
- final ActivityRecord activity = new ActivityRecord(mService, null /* caller */,
- mLaunchedFromPid /* launchedFromPid */, mLaunchedFromUid /* launchedFromUid */,
- null, null, intent, null, aInfo /*aInfo*/, new Configuration(),
- null /* resultTo */, null /* resultWho */, 0 /* reqCode */,
- false /*componentSpecified*/, false /* rootVoiceInteraction */,
- mService.mStackSupervisor, options, null /* sourceRecord */);
- spyOn(activity);
- if (mTask != null) {
- // fullscreen value is normally read from resources in ctor, so for testing we need
- // to set it somewhere else since we can't mock resources.
- doReturn(true).when(activity).occludesParent();
- doReturn(true).when(activity).fillsParent();
- mTask.addChild(activity);
- // Make visible by default...
- activity.setVisible(true);
- }
-
- final WindowProcessController wpc;
- if (mWpc != null) {
- wpc = mWpc;
- } else {
- wpc = new WindowProcessController(mService,
- aInfo.applicationInfo, mProcessName, mUid,
- UserHandle.getUserId(12345), mock(Object.class),
- mock(WindowProcessListener.class));
- wpc.setThread(mock(IApplicationThread.class));
- }
- wpc.setThread(mock(IApplicationThread.class));
- activity.setProcess(wpc);
- doReturn(wpc).when(mService).getProcessController(
- activity.processName, activity.info.applicationInfo.uid);
-
- // Resume top activities to make sure all other signals in the system are connected.
- mService.mRootWindowContainer.resumeFocusedStacksTopActivities();
- return activity;
- }
- }
-
- /**
- * Builder for creating new tasks.
- */
- protected static class TaskBuilder {
- private final ActivityStackSupervisor mSupervisor;
-
- private ComponentName mComponent;
- private String mPackage;
- private int mFlags = 0;
- // Task id 0 is reserved in ARC for the home app.
- private int mTaskId = SystemServicesTestRule.sNextTaskId++;
- private int mUserId = 0;
- private IVoiceInteractionSession mVoiceSession;
- private boolean mCreateStack = true;
-
- private Task mStack;
- private TaskDisplayArea mTaskDisplayArea;
-
- TaskBuilder(ActivityStackSupervisor supervisor) {
- mSupervisor = supervisor;
- }
-
- TaskBuilder setComponent(ComponentName component) {
- mComponent = component;
- return this;
- }
-
- TaskBuilder setPackage(String packageName) {
- mPackage = packageName;
- return this;
- }
-
- /**
- * Set to {@code true} by default, set to {@code false} to prevent the task from
- * automatically creating a parent stack.
- */
- TaskBuilder setCreateStack(boolean createStack) {
- mCreateStack = createStack;
- return this;
- }
-
- TaskBuilder setVoiceSession(IVoiceInteractionSession session) {
- mVoiceSession = session;
- return this;
- }
-
- TaskBuilder setFlags(int flags) {
- mFlags = flags;
- return this;
- }
-
- TaskBuilder setTaskId(int taskId) {
- mTaskId = taskId;
- return this;
- }
-
- TaskBuilder setUserId(int userId) {
- mUserId = userId;
- return this;
- }
-
- TaskBuilder setStack(Task stack) {
- mStack = stack;
- return this;
- }
-
- TaskBuilder setDisplay(DisplayContent display) {
- mTaskDisplayArea = display.getDefaultTaskDisplayArea();
- return this;
- }
-
- Task build() {
- SystemServicesTestRule.checkHoldsLock(mSupervisor.mService.mGlobalLock);
-
- if (mStack == null && mCreateStack) {
- TaskDisplayArea displayArea = mTaskDisplayArea != null ? mTaskDisplayArea
- : mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
- mStack = displayArea.createStack(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- spyOn(mStack);
- }
-
- final ActivityInfo aInfo = new ActivityInfo();
- aInfo.applicationInfo = new ApplicationInfo();
- aInfo.applicationInfo.packageName = mPackage;
-
- Intent intent = new Intent();
- if (mComponent == null) {
- mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
- DEFAULT_COMPONENT_CLASS_NAME);
- }
-
- intent.setComponent(mComponent);
- intent.setFlags(mFlags);
-
- final Task task = new Task(mSupervisor.mService, mTaskId, aInfo,
- intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/,
- null /*taskDescription*/, mStack);
- spyOn(task);
- task.mUserId = mUserId;
-
- if (mStack != null) {
- mStack.moveToFront("test");
- mStack.addChild(task, true, true);
- }
-
- return task;
- }
- }
-
- static class StackBuilder {
- private final RootWindowContainer mRootWindowContainer;
- private DisplayContent mDisplay;
- private TaskDisplayArea mTaskDisplayArea;
- private int mStackId = -1;
- private int mWindowingMode = WINDOWING_MODE_UNDEFINED;
- private int mActivityType = ACTIVITY_TYPE_STANDARD;
- private boolean mOnTop = true;
- private boolean mCreateActivity = true;
- private ActivityInfo mInfo;
- private Intent mIntent;
-
- StackBuilder(RootWindowContainer root) {
- mRootWindowContainer = root;
- mDisplay = mRootWindowContainer.getDefaultDisplay();
- mTaskDisplayArea = mDisplay.getDefaultTaskDisplayArea();
- }
-
- StackBuilder setWindowingMode(int windowingMode) {
- mWindowingMode = windowingMode;
- return this;
- }
-
- StackBuilder setActivityType(int activityType) {
- mActivityType = activityType;
- return this;
- }
-
- StackBuilder setStackId(int stackId) {
- mStackId = stackId;
- return this;
- }
-
- /**
- * Set the parent {@link DisplayContent} and use the default task display area. Overrides
- * the task display area, if was set before.
- */
- StackBuilder setDisplay(DisplayContent display) {
- mDisplay = display;
- mTaskDisplayArea = mDisplay.getDefaultTaskDisplayArea();
- return this;
- }
-
- /** Set the parent {@link TaskDisplayArea}. Overrides the display, if was set before. */
- StackBuilder setTaskDisplayArea(TaskDisplayArea taskDisplayArea) {
- mTaskDisplayArea = taskDisplayArea;
- mDisplay = mTaskDisplayArea.mDisplayContent;
- return this;
- }
-
- StackBuilder setOnTop(boolean onTop) {
- mOnTop = onTop;
- return this;
- }
-
- StackBuilder setCreateActivity(boolean createActivity) {
- mCreateActivity = createActivity;
- return this;
- }
-
- StackBuilder setActivityInfo(ActivityInfo info) {
- mInfo = info;
- return this;
- }
-
- StackBuilder setIntent(Intent intent) {
- mIntent = intent;
- return this;
- }
-
- Task build() {
- SystemServicesTestRule.checkHoldsLock(mRootWindowContainer.mWmService.mGlobalLock);
-
- final int stackId = mStackId >= 0 ? mStackId : mTaskDisplayArea.getNextStackId();
- final Task stack = mTaskDisplayArea.createStackUnchecked(
- mWindowingMode, mActivityType, stackId, mOnTop, mInfo, mIntent,
- false /* createdByOrganizer */);
- final ActivityStackSupervisor supervisor = mRootWindowContainer.mStackSupervisor;
-
- if (mCreateActivity) {
- new ActivityBuilder(supervisor.mService)
- .setCreateTask(true)
- .setStack(stack)
- .build();
- if (mOnTop) {
- // We move the task to front again in order to regain focus after activity
- // added to the stack. Or {@link DisplayContent#mPreferredTopFocusableStack}
- // could be other stacks (e.g. home stack).
- stack.moveToFront("createActivityStack");
- } else {
- stack.moveToBack("createActivityStack", null);
- }
- }
- spyOn(stack);
-
- doNothing().when(stack).startActivityLocked(
- any(), any(), anyBoolean(), anyBoolean(), any());
-
- return stack;
- }
-
- }
-
- static class TestSplitOrganizer extends ITaskOrganizer.Stub {
- final ActivityTaskManagerService mService;
- Task mPrimary;
- Task mSecondary;
- boolean mInSplit = false;
- // moves everything to secondary. Most tests expect this since sysui usually does it.
- boolean mMoveToSecondaryOnEnter = true;
- int mDisplayId;
- 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);
- WindowContainerToken primary = mService.mTaskOrganizerController.createRootTask(
- displayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).token;
- mPrimary = WindowContainer.fromBinder(primary.asBinder()).asTask();
- WindowContainerToken secondary = mService.mTaskOrganizerController.createRootTask(
- displayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token;
- mSecondary = WindowContainer.fromBinder(secondary.asBinder()).asTask();
- }
- TestSplitOrganizer(ActivityTaskManagerService service) {
- this(service,
- service.mStackSupervisor.mRootWindowContainer.getDefaultDisplay().mDisplayId);
- }
- public void setMoveToSecondaryOnEnter(boolean move) {
- mMoveToSecondaryOnEnter = move;
- }
- @Override
- public void onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash) {
- }
- @Override
- public void onTaskVanished(ActivityManager.RunningTaskInfo info) {
- }
- @Override
- public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
- if (mInSplit) {
- return;
- }
- if (info.topActivityType == ACTIVITY_TYPE_UNDEFINED) {
- // Not populated
- return;
- }
- if (info.configuration.windowConfiguration.getWindowingMode()
- != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- return;
- }
- mInSplit = true;
- if (!mMoveToSecondaryOnEnter) {
- return;
- }
- mService.mTaskOrganizerController.setLaunchRoot(mDisplayId,
- mSecondary.mRemoteToken.toWindowContainerToken());
- DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId);
- dc.forAllTaskDisplayAreas(taskDisplayArea -> {
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final Task stack = taskDisplayArea.getStackAt(sNdx);
- if (!WindowConfiguration.isSplitScreenWindowingMode(stack.getWindowingMode())) {
- stack.reparent(mSecondary, POSITION_BOTTOM);
- }
- }
- });
- }
- @Override
- public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
- }
- };
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 97a2ebe..888935e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -431,7 +431,7 @@
doCallRealMethod().when(mStack).startActivityLocked(
any(), any(), anyBoolean(), anyBoolean(), any());
// Make mVisibleSetFromTransferredStartingWindow true.
- final ActivityRecord middle = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+ final ActivityRecord middle = new ActivityBuilder(mWm.mAtmService)
.setTask(mTask).build();
mStack.startActivityLocked(middle, null /* focusedTopActivity */,
false /* newTask */, false /* keepCurTransition */, null /* options */);
@@ -440,7 +440,7 @@
assertNull(mActivity.startingWindow);
assertHasStartingWindow(middle);
- final ActivityRecord top = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+ final ActivityRecord top = new ActivityBuilder(mWm.mAtmService)
.setTask(mTask).build();
// Expect the visibility should be updated to true when transferring starting window from
// a visible activity.
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 edf1536..0cc6159 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -850,13 +850,13 @@
IWindowManager.FIXED_TO_USER_ROTATION_DISABLED);
final Task stack =
- new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootWindowContainer)
+ new StackBuilder(mWm.mAtmService.mRootWindowContainer)
.setDisplay(dc)
.build();
doReturn(true).when(stack).isVisible();
final Task freeformStack =
- new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootWindowContainer)
+ new StackBuilder(mWm.mAtmService.mRootWindowContainer)
.setDisplay(dc)
.setWindowingMode(WINDOWING_MODE_FREEFORM)
.build();
@@ -881,9 +881,8 @@
IWindowManager.FIXED_TO_USER_ROTATION_DISABLED);
final int newOrientation = getRotatedOrientation(dc);
- final Task stack =
- new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootWindowContainer)
- .setDisplay(dc).build();
+ final Task stack = new StackBuilder(mWm.mAtmService.mRootWindowContainer)
+ .setDisplay(dc).build();
final ActivityRecord activity = stack.getTopMostTask().getTopNonFinishingActivity();
activity.setRequestedOrientation(newOrientation);
@@ -901,9 +900,8 @@
IWindowManager.FIXED_TO_USER_ROTATION_ENABLED);
final int newOrientation = getRotatedOrientation(dc);
- final Task stack =
- new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootWindowContainer)
- .setDisplay(dc).build();
+ final Task stack = new StackBuilder(mWm.mAtmService.mRootWindowContainer)
+ .setDisplay(dc).build();
final ActivityRecord activity = stack.getTopMostTask().getTopNonFinishingActivity();
activity.setRequestedOrientation(newOrientation);
@@ -1213,7 +1211,7 @@
verify(t, never()).setPosition(any(), eq(0), eq(0));
// Launch another activity before the transition is finished.
- final ActivityRecord app2 = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+ final ActivityRecord app2 = new StackBuilder(mWm.mRoot)
.setDisplay(mDisplayContent).build().getTopMostActivity();
app2.setVisible(false);
mDisplayContent.mOpeningApps.add(app2);
@@ -1247,8 +1245,7 @@
final ActivityRecord app = createActivityRecord(mDisplayContent, WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD);
final Task task = app.getTask();
- final ActivityRecord app2 = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
- .setTask(task).build();
+ final ActivityRecord app2 = new ActivityBuilder(mWm.mAtmService).setTask(task).build();
mDisplayContent.setFixedRotationLaunchingApp(app2, (mDisplayContent.getRotation() + 1) % 4);
doReturn(true).when(task).isAppTransitioning();
// If the task is animating transition, this should be no-op.
@@ -1513,8 +1510,7 @@
@Test
public void testSetWindowingModeAtomicallyUpdatesWindoingModeAndDisplayWindowingMode() {
final DisplayContent dc = createNewDisplay();
- final Task stack =
- new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootWindowContainer)
+ final Task stack = new StackBuilder(mWm.mAtmService.mRootWindowContainer)
.setDisplay(dc)
.build();
doAnswer(invocation -> {
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
index a7a8505..820eca4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
@@ -68,14 +68,14 @@
@MediumTest
@Presubmit
@RunWith(WindowTestRunner.class)
-public class LaunchParamsControllerTests extends ActivityTestsBase {
+public class LaunchParamsControllerTests extends WindowTestsBase {
private LaunchParamsController mController;
private TestLaunchParamsPersister mPersister;
@Before
public void setUp() throws Exception {
mPersister = new TestLaunchParamsPersister();
- mController = new LaunchParamsController(mService, mPersister);
+ mController = new LaunchParamsController(mAtm, mPersister);
}
/**
@@ -87,8 +87,8 @@
positioner = mock(LaunchParamsModifier.class);
mController.registerModifier(positioner);
- final ActivityRecord record = new ActivityBuilder(mService).build();
- final ActivityRecord source = new ActivityBuilder(mService).build();
+ final ActivityRecord record = new ActivityBuilder(mAtm).build();
+ final ActivityRecord source = new ActivityBuilder(mAtm).build();
final WindowLayout layout = new WindowLayout(0, 0, 0, 0, 0, 0, 0);
final ActivityOptions options = mock(ActivityOptions.class);
@@ -108,7 +108,7 @@
final ComponentName name = new ComponentName("com.android.foo", ".BarActivity");
final int userId = 0;
- final ActivityRecord activity = new ActivityBuilder(mService).setComponent(name)
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setComponent(name)
.setUid(userId).build();
final LaunchParams expected = new LaunchParams();
expected.mPreferredTaskDisplayArea = mock(TaskDisplayArea.class);
@@ -228,10 +228,10 @@
@Test
public void testVrPreferredDisplay() {
final TestDisplayContent vrDisplay = createNewDisplayContent();
- mService.mVr2dDisplayId = vrDisplay.mDisplayId;
+ mAtm.mVr2dDisplayId = vrDisplay.mDisplayId;
final LaunchParams result = new LaunchParams();
- final ActivityRecord vrActivity = new ActivityBuilder(mService).build();
+ final ActivityRecord vrActivity = new ActivityBuilder(mAtm).build();
vrActivity.requestedVrComponent = vrActivity.mActivityComponent;
// VR activities should always land on default display.
@@ -241,7 +241,7 @@
result.mPreferredTaskDisplayArea);
// Otherwise, always lands on VR 2D display.
- final ActivityRecord vr2dActivity = new ActivityBuilder(mService).build();
+ final ActivityRecord vr2dActivity = new ActivityBuilder(mAtm).build();
mController.calculate(null /*task*/, null /*layout*/, vr2dActivity /*activity*/,
null /*source*/, null /*options*/, PHASE_BOUNDS, result);
assertEquals(vrDisplay.getDefaultTaskDisplayArea(), result.mPreferredTaskDisplayArea);
@@ -249,7 +249,7 @@
null /*options*/, PHASE_BOUNDS, result);
assertEquals(vrDisplay.getDefaultTaskDisplayArea(), result.mPreferredTaskDisplayArea);
- mService.mVr2dDisplayId = INVALID_DISPLAY;
+ mAtm.mVr2dDisplayId = INVALID_DISPLAY;
}
@@ -262,8 +262,8 @@
final LaunchParamsModifier positioner = mock(LaunchParamsModifier.class);
mController.registerModifier(positioner);
- final ActivityRecord record = new ActivityBuilder(mService).build();
- final ActivityRecord source = new ActivityBuilder(mService).build();
+ final ActivityRecord record = new ActivityBuilder(mAtm).build();
+ final ActivityRecord source = new ActivityBuilder(mAtm).build();
final WindowLayout layout = new WindowLayout(0, 0, 0, 0, 0, 0, 0);
final ActivityOptions options = mock(ActivityOptions.class);
@@ -284,7 +284,7 @@
final TaskDisplayArea preferredTaskDisplayArea = display.getDefaultTaskDisplayArea();
params.mPreferredTaskDisplayArea = preferredTaskDisplayArea;
final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
- final Task task = new TaskBuilder(mService.mStackSupervisor).build();
+ final Task task = new TaskBuilder(mAtm.mStackSupervisor).build();
mController.registerModifier(positioner);
@@ -305,7 +305,7 @@
final int windowingMode = WINDOWING_MODE_FREEFORM;
params.mWindowingMode = windowingMode;
final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
- final Task task = new TaskBuilder(mService.mStackSupervisor).build();
+ final Task task = new TaskBuilder(mAtm.mStackSupervisor).build();
mController.registerModifier(positioner);
@@ -330,7 +330,7 @@
params.mWindowingMode = WINDOWING_MODE_FREEFORM;
params.mBounds.set(expected);
final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
- final Task task = new TaskBuilder(mService.mStackSupervisor).build();
+ final Task task = new TaskBuilder(mAtm.mStackSupervisor).build();
mController.registerModifier(positioner);
@@ -355,7 +355,7 @@
params.mWindowingMode = WINDOWING_MODE_FULLSCREEN;
params.mBounds.set(expected);
final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
- final Task task = new TaskBuilder(mService.mStackSupervisor).build();
+ final Task task = new TaskBuilder(mAtm.mStackSupervisor).build();
mController.registerModifier(positioner);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index e389a53..18a2d13 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -65,7 +65,7 @@
@MediumTest
@Presubmit
@RunWith(WindowTestRunner.class)
-public class LaunchParamsPersisterTests extends ActivityTestsBase {
+public class LaunchParamsPersisterTests extends WindowTestsBase {
private static final int TEST_USER_ID = 3;
private static final int ALTERNATIVE_USER_ID = 0;
private static final ComponentName TEST_COMPONENT =
@@ -109,7 +109,7 @@
deleteRecursively(mFolder);
mDisplayUniqueId = "test:" + sNextUniqueId++;
- mTestDisplay = new TestDisplayContent.Builder(mService, 1000, 1500)
+ mTestDisplay = new TestDisplayContent.Builder(mAtm, 1000, 1500)
.setUniqueId(mDisplayUniqueId).build();
when(mRootWindowContainer.getDisplayContent(eq(mDisplayUniqueId)))
.thenReturn(mTestDisplay);
@@ -172,7 +172,7 @@
public void testFetchesSameResultWithActivity() {
mTarget.saveTask(mTestTask);
- final ActivityRecord activity = new ActivityBuilder(mService).setComponent(TEST_COMPONENT)
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setComponent(TEST_COMPONENT)
.setUid(TEST_USER_ID * UserHandle.PER_USER_RANGE).build();
mTarget.getLaunchParams(null, activity, mResult);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
index a137cde..044f819 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
@@ -168,8 +168,8 @@
@Test
public void testStartLockTaskMode_once() throws Exception {
- // GIVEN a task record with whitelisted auth
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN a task record with allowlisted auth
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
// WHEN calling setLockTaskMode for LOCKED mode without resuming
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
@@ -185,9 +185,9 @@
@Test
public void testStartLockTaskMode_twice() throws Exception {
- // GIVEN two task records with whitelisted auth
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
- Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN two task records with allowlisted auth
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
// WHEN calling setLockTaskMode for LOCKED mode on both tasks
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
@@ -205,7 +205,7 @@
@Test
public void testStartLockTaskMode_pinningRequest() {
- // GIVEN a task record that is not whitelisted, i.e. with pinned auth
+ // GIVEN a task record that is not allowlisted, i.e. with pinned auth
Task tr = getTask(Task.LOCK_TASK_AUTH_PINNABLE);
// WHEN calling startLockTaskMode
@@ -236,23 +236,23 @@
@Test
public void testLockTaskViolation() {
- // GIVEN one task record with whitelisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN one task record with allowlisted auth that is in lock task mode
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN it's not a lock task violation to try and launch this task without clearing
assertFalse(mLockTaskController.isLockTaskModeViolation(tr, false));
- // THEN it's a lock task violation to launch another task that is not whitelisted
+ // THEN it's a lock task violation to launch another task that is not allowlisted
assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(
Task.LOCK_TASK_AUTH_PINNABLE)));
// THEN it's a lock task violation to launch another task that is disallowed from lock task
assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(
Task.LOCK_TASK_AUTH_DONT_LOCK)));
- // THEN it's no a lock task violation to launch another task that is whitelisted
+ // THEN it's no a lock task violation to launch another task that is allowlisted
assertFalse(mLockTaskController.isLockTaskModeViolation(getTask(
- Task.LOCK_TASK_AUTH_WHITELISTED)));
+ Task.LOCK_TASK_AUTH_ALLOWLISTED)));
assertFalse(mLockTaskController.isLockTaskModeViolation(getTask(
Task.LOCK_TASK_AUTH_LAUNCHABLE)));
// THEN it's not a lock task violation to launch another task that is priv launchable
@@ -262,8 +262,8 @@
@Test
public void testLockTaskViolation_emergencyCall() {
- // GIVEN one task record with whitelisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN one task record with allowlisted auth that is in lock task mode
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// GIVEN tasks necessary for emergency calling
@@ -294,8 +294,8 @@
@Test
public void testStopLockTaskMode() throws Exception {
- // GIVEN one task record with whitelisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN one task record with allowlisted auth that is in lock task mode
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN the same caller calls stopLockTaskMode
@@ -311,8 +311,8 @@
@Test(expected = SecurityException.class)
public void testStopLockTaskMode_differentCaller() {
- // GIVEN one task record with whitelisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN one task record with allowlisted auth that is in lock task mode
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN a different caller calls stopLockTaskMode
@@ -323,8 +323,8 @@
@Test
public void testStopLockTaskMode_systemCaller() {
- // GIVEN one task record with whitelisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN one task record with allowlisted auth that is in lock task mode
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN system calls stopLockTaskMode
@@ -336,9 +336,9 @@
@Test
public void testStopLockTaskMode_twoTasks() throws Exception {
- // GIVEN two task records with whitelisted auth that is in lock task mode
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
- Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN two task records with allowlisted auth that is in lock task mode
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
@@ -357,9 +357,9 @@
@Test
public void testStopLockTaskMode_rootTask() throws Exception {
- // GIVEN two task records with whitelisted auth that is in lock task mode
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
- Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN two task records with allowlisted auth that is in lock task mode
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
@@ -405,9 +405,9 @@
@Test
public void testClearLockedTasks() throws Exception {
- // GIVEN two task records with whitelisted auth that is in lock task mode
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
- Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN two task records with allowlisted auth that is in lock task mode
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
@@ -434,7 +434,7 @@
.thenReturn(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
// AND there is a task record
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -454,7 +454,7 @@
.thenReturn(true);
// AND there is a task record
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -471,7 +471,7 @@
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, 1, mContext.getUserId());
// AND there is a task record
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -488,7 +488,7 @@
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, 0, mContext.getUserId());
// AND there is a task record
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -500,45 +500,45 @@
@Test
public void testUpdateLockTaskPackages() {
- String[] whitelist1 = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2};
- String[] whitelist2 = {TEST_PACKAGE_NAME};
+ String[] allowlist1 = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2};
+ String[] allowlist2 = {TEST_PACKAGE_NAME};
- // No package is whitelisted initially
- for (String pkg : whitelist1) {
- assertFalse("Package shouldn't be whitelisted: " + pkg,
- mLockTaskController.isPackageWhitelisted(TEST_USER_ID, pkg));
- assertFalse("Package shouldn't be whitelisted for user 0: " + pkg,
- mLockTaskController.isPackageWhitelisted(0, pkg));
+ // No package is allowlisted initially
+ for (String pkg : allowlist1) {
+ assertFalse("Package shouldn't be allowlisted: " + pkg,
+ mLockTaskController.isPackageAllowlisted(TEST_USER_ID, pkg));
+ assertFalse("Package shouldn't be allowlisted for user 0: " + pkg,
+ mLockTaskController.isPackageAllowlisted(0, pkg));
}
- // Apply whitelist
- mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist1);
+ // Apply allowlist
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist1);
- // Assert the whitelist is applied to the correct user
- for (String pkg : whitelist1) {
- assertTrue("Package should be whitelisted: " + pkg,
- mLockTaskController.isPackageWhitelisted(TEST_USER_ID, pkg));
- assertFalse("Package shouldn't be whitelisted for user 0: " + pkg,
- mLockTaskController.isPackageWhitelisted(0, pkg));
+ // Assert the allowlist is applied to the correct user
+ for (String pkg : allowlist1) {
+ assertTrue("Package should be allowlisted: " + pkg,
+ mLockTaskController.isPackageAllowlisted(TEST_USER_ID, pkg));
+ assertFalse("Package shouldn't be allowlisted for user 0: " + pkg,
+ mLockTaskController.isPackageAllowlisted(0, pkg));
}
- // Update whitelist
- mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist2);
+ // Update allowlist
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist2);
- // Assert the new whitelist is applied
- assertTrue("Package should remain whitelisted: " + TEST_PACKAGE_NAME,
- mLockTaskController.isPackageWhitelisted(TEST_USER_ID, TEST_PACKAGE_NAME));
- assertFalse("Package should no longer be whitelisted: " + TEST_PACKAGE_NAME_2,
- mLockTaskController.isPackageWhitelisted(TEST_USER_ID, TEST_PACKAGE_NAME_2));
+ // Assert the new allowlist is applied
+ assertTrue("Package should remain allowlisted: " + TEST_PACKAGE_NAME,
+ mLockTaskController.isPackageAllowlisted(TEST_USER_ID, TEST_PACKAGE_NAME));
+ assertFalse("Package should no longer be allowlisted: " + TEST_PACKAGE_NAME_2,
+ mLockTaskController.isPackageAllowlisted(TEST_USER_ID, TEST_PACKAGE_NAME_2));
}
@Test
public void testUpdateLockTaskPackages_taskRemoved() throws Exception {
- // GIVEN two tasks which are whitelisted initially
+ // GIVEN two tasks which are allowlisted initially
Task tr1 = getTaskForUpdate(TEST_PACKAGE_NAME, true);
Task tr2 = getTaskForUpdate(TEST_PACKAGE_NAME_2, false);
- String[] whitelist = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2};
- mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
+ String[] allowlist = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2};
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist);
// GIVEN the tasks are launched into LockTask mode
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
@@ -548,9 +548,9 @@
assertTrue(mLockTaskController.isTaskLocked(tr2));
verifyLockTaskStarted(STATUS_BAR_MASK_LOCKED, DISABLE2_MASK);
- // WHEN removing one package from whitelist
- whitelist = new String[] {TEST_PACKAGE_NAME};
- mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
+ // WHEN removing one package from allowlist
+ allowlist = new String[] {TEST_PACKAGE_NAME};
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist);
// THEN the task running that package should be stopped
verify(tr2).performClearTaskLocked();
@@ -560,9 +560,9 @@
assertTrue(mLockTaskController.isTaskLocked(tr1));
verifyLockTaskStarted(STATUS_BAR_MASK_LOCKED, DISABLE2_MASK);
- // WHEN removing the last package from whitelist
- whitelist = new String[] {};
- mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
+ // WHEN removing the last package from allowlist
+ allowlist = new String[] {};
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist);
// THEN the last task should be cleared, and the system should quit LockTask mode
verify(tr1).performClearTaskLocked();
@@ -574,7 +574,7 @@
@Test
public void testUpdateLockTaskFeatures() throws Exception {
// GIVEN a locked task
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN lock task mode should be started with default status bar masks
@@ -616,7 +616,7 @@
@Test
public void testUpdateLockTaskFeatures_differentUser() throws Exception {
// GIVEN a locked task
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN lock task mode should be started with default status bar masks
@@ -638,7 +638,7 @@
@Test
public void testUpdateLockTaskFeatures_keyguard() {
// GIVEN a locked task
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN keyguard should be disabled
@@ -704,7 +704,7 @@
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT));
// Start lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK is not enabled
@@ -719,15 +719,15 @@
assertTrue(mLockTaskController.isActivityAllowed(
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_ALWAYS));
- // unwhitelisted package should not be allowed
+ // unallowlisted package should not be allowed
assertFalse(mLockTaskController.isActivityAllowed(
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT));
- // update the whitelist
- String[] whitelist = new String[] { TEST_PACKAGE_NAME };
- mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
+ // update the allowlist
+ String[] allowlist = new String[] { TEST_PACKAGE_NAME };
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist);
- // whitelisted package should be allowed
+ // allowlisted package should be allowed
assertTrue(mLockTaskController.isActivityAllowed(
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT));
@@ -755,17 +755,17 @@
}
/**
- * @param isAppAware {@code true} if the app has marked if_whitelisted in its manifest
+ * @param isAppAware {@code true} if the app has marked if allowlisted in its manifest
*/
private Task getTaskForUpdate(String pkg, boolean isAppAware) {
- final int authIfWhitelisted = isAppAware
+ final int authIfAllowlisted = isAppAware
? Task.LOCK_TASK_AUTH_LAUNCHABLE
- : Task.LOCK_TASK_AUTH_WHITELISTED;
- Task tr = getTask(pkg, authIfWhitelisted);
+ : Task.LOCK_TASK_AUTH_ALLOWLISTED;
+ Task tr = getTask(pkg, authIfAllowlisted);
doAnswer((invocation) -> {
- boolean isWhitelisted =
- mLockTaskController.isPackageWhitelisted(TEST_USER_ID, pkg);
- tr.mLockTaskAuth = isWhitelisted ? authIfWhitelisted : Task.LOCK_TASK_AUTH_PINNABLE;
+ boolean isAllowlisted =
+ mLockTaskController.isPackageAllowlisted(TEST_USER_ID, pkg);
+ tr.mLockTaskAuth = isAllowlisted ? authIfAllowlisted : Task.LOCK_TASK_AUTH_PINNABLE;
return null;
}).when(tr).setLockTaskAuth();
return tr;
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 1724303..54c7f27 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -94,7 +94,7 @@
@MediumTest
@Presubmit
@RunWith(WindowTestRunner.class)
-public class RecentTasksTest extends ActivityTestsBase {
+public class RecentTasksTest extends WindowTestsBase {
private static final int TEST_USER_0_ID = 0;
private static final int TEST_USER_1_ID = 10;
private static final int TEST_QUIET_USER_ID = 20;
@@ -122,14 +122,14 @@
mTaskContainer = mRootWindowContainer.getDefaultTaskDisplayArea();
// Set the recent tasks we should use for testing in this class.
- mRecentTasks = new TestRecentTasks(mService, mTaskPersister);
+ mRecentTasks = new TestRecentTasks(mAtm, mTaskPersister);
spyOn(mRecentTasks);
- mService.setRecentTasks(mRecentTasks);
+ mAtm.setRecentTasks(mRecentTasks);
mRecentTasks.loadParametersFromResources(mContext.getResources());
// Set the running tasks we should use for testing in this class.
mRunningTasks = new TestRunningTasks();
- mService.mStackSupervisor.setRunningTasks(mRunningTasks);
+ mAtm.mStackSupervisor.setRunningTasks(mRunningTasks);
mStack = mTaskContainer.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -455,7 +455,7 @@
final Function<Boolean, Task> taskBuilder = visible -> {
final Task task = createTaskBuilder(className).build();
// Make the task non-empty.
- final ActivityRecord r = new ActivityBuilder(mService).setTask(task).build();
+ final ActivityRecord r = new ActivityBuilder(mAtm).setTask(task).build();
r.setVisibility(visible);
return task;
};
@@ -831,7 +831,7 @@
Task stack = mTasks.get(2).getRootTask();
stack.moveToFront("", mTasks.get(2));
- doReturn(stack).when(mService.mRootWindowContainer).getTopDisplayFocusedStack();
+ doReturn(stack).when(mAtm.mRootWindowContainer).getTopDisplayFocusedStack();
// Simulate the reset from the timeout
mRecentTasks.resetFreezeTaskListReorderingOnTimeout();
@@ -994,16 +994,16 @@
mStack.removeIfPossible();
// The following APIs should not restore task from recents to the active list.
- assertNotRestoreTask(() -> mService.setFocusedTask(taskId));
- assertNotRestoreTask(() -> mService.startSystemLockTaskMode(taskId));
- assertNotRestoreTask(() -> mService.cancelTaskWindowTransition(taskId));
+ assertNotRestoreTask(() -> mAtm.setFocusedTask(taskId));
+ assertNotRestoreTask(() -> mAtm.startSystemLockTaskMode(taskId));
+ assertNotRestoreTask(() -> mAtm.cancelTaskWindowTransition(taskId));
assertNotRestoreTask(
- () -> mService.resizeTask(taskId, null /* bounds */, 0 /* resizeMode */));
+ () -> mAtm.resizeTask(taskId, null /* bounds */, 0 /* resizeMode */));
assertNotRestoreTask(
- () -> mService.setTaskWindowingMode(taskId, WINDOWING_MODE_FULLSCREEN,
+ () -> mAtm.setTaskWindowingMode(taskId, WINDOWING_MODE_FULLSCREEN,
false/* toTop */));
assertNotRestoreTask(
- () -> mService.setTaskWindowingModeSplitScreenPrimary(taskId, false /* toTop */));
+ () -> mAtm.setTaskWindowingModeSplitScreenPrimary(taskId, false /* toTop */));
}
@Test
@@ -1014,7 +1014,7 @@
mRecentTasks.remove(task);
TaskChangeNotificationController controller =
- mService.getTaskChangeNotificationController();
+ mAtm.getTaskChangeNotificationController();
verify(controller, times(2)).notifyTaskListUpdated();
}
@@ -1027,7 +1027,7 @@
// 2 calls - Once for add and once for remove
TaskChangeNotificationController controller =
- mService.getTaskChangeNotificationController();
+ mAtm.getTaskChangeNotificationController();
verify(controller, times(2)).notifyTaskListUpdated();
}
@@ -1042,7 +1042,7 @@
// 4 calls - Twice for add and twice for remove
TaskChangeNotificationController controller =
- mService.getTaskChangeNotificationController();
+ mAtm.getTaskChangeNotificationController();
verify(controller, times(4)).notifyTaskListUpdated();
}
@@ -1054,7 +1054,7 @@
final Bundle data = new Bundle();
data.putInt("key", 100);
final Task task1 = createTaskBuilder(".Task").build();
- final ActivityRecord r1 = new ActivityBuilder(mService)
+ final ActivityRecord r1 = new ActivityBuilder(mAtm)
.setTask(task1)
.setIntentExtras(data)
.build();
@@ -1106,7 +1106,7 @@
@Test
public void testNotRecentsComponent_denyApiAccess() throws Exception {
- doReturn(PackageManager.PERMISSION_DENIED).when(mService)
+ doReturn(PackageManager.PERMISSION_DENIED).when(mAtm)
.checkGetTasksPermission(anyString(), anyInt(), anyInt());
// Expect the following methods to fail due to recents component not being set
mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.DENY_THROW_SECURITY_EXCEPTION);
@@ -1118,7 +1118,7 @@
@Test
public void testRecentsComponent_allowApiAccessWithoutPermissions() {
- doReturn(PackageManager.PERMISSION_DENIED).when(mService)
+ doReturn(PackageManager.PERMISSION_DENIED).when(mAtm)
.checkGetTasksPermission(anyString(), anyInt(), anyInt());
// Set the recents component and ensure that the following calls do not fail
mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.GRANT);
@@ -1127,50 +1127,50 @@
}
private void doTestRecentTasksApis(boolean expectCallable) {
- assertSecurityException(expectCallable, () -> mService.removeStack(INVALID_STACK_ID));
+ assertSecurityException(expectCallable, () -> mAtm.removeStack(INVALID_STACK_ID));
assertSecurityException(expectCallable,
- () -> mService.removeStacksInWindowingModes(
+ () -> mAtm.removeStacksInWindowingModes(
new int[]{WINDOWING_MODE_UNDEFINED}));
assertSecurityException(expectCallable,
- () -> mService.removeStacksWithActivityTypes(
+ () -> mAtm.removeStacksWithActivityTypes(
new int[]{ACTIVITY_TYPE_UNDEFINED}));
- assertSecurityException(expectCallable, () -> mService.removeTask(0));
+ assertSecurityException(expectCallable, () -> mAtm.removeTask(0));
assertSecurityException(expectCallable,
- () -> mService.setTaskWindowingMode(0, WINDOWING_MODE_UNDEFINED, true));
+ () -> mAtm.setTaskWindowingMode(0, WINDOWING_MODE_UNDEFINED, true));
assertSecurityException(expectCallable,
- () -> mService.moveTaskToStack(0, INVALID_STACK_ID, true));
+ () -> mAtm.moveTaskToStack(0, INVALID_STACK_ID, true));
assertSecurityException(expectCallable,
- () -> mService.setTaskWindowingModeSplitScreenPrimary(0, true));
+ () -> mAtm.setTaskWindowingModeSplitScreenPrimary(0, true));
assertSecurityException(expectCallable,
- () -> mService.moveTopActivityToPinnedStack(INVALID_STACK_ID, new Rect()));
- assertSecurityException(expectCallable, () -> mService.getAllStackInfos());
+ () -> mAtm.moveTopActivityToPinnedStack(INVALID_STACK_ID, new Rect()));
+ assertSecurityException(expectCallable, () -> mAtm.getAllStackInfos());
assertSecurityException(expectCallable,
- () -> mService.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED));
+ () -> mAtm.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED));
assertSecurityException(expectCallable, () -> {
try {
- mService.getFocusedStackInfo();
+ mAtm.getFocusedStackInfo();
} catch (RemoteException e) {
// Ignore
}
});
assertSecurityException(expectCallable,
- () -> mService.startActivityFromRecents(0, new Bundle()));
- assertSecurityException(expectCallable, () -> mService.getTaskSnapshot(0, true));
- assertSecurityException(expectCallable, () -> mService.registerTaskStackListener(null));
+ () -> mAtm.startActivityFromRecents(0, new Bundle()));
+ assertSecurityException(expectCallable, () -> mAtm.getTaskSnapshot(0, true));
+ assertSecurityException(expectCallable, () -> mAtm.registerTaskStackListener(null));
assertSecurityException(expectCallable,
- () -> mService.unregisterTaskStackListener(null));
- assertSecurityException(expectCallable, () -> mService.getTaskDescription(0));
- assertSecurityException(expectCallable, () -> mService.cancelTaskWindowTransition(0));
- assertSecurityException(expectCallable, () -> mService.startRecentsActivity(null, null,
+ () -> mAtm.unregisterTaskStackListener(null));
+ assertSecurityException(expectCallable, () -> mAtm.getTaskDescription(0));
+ assertSecurityException(expectCallable, () -> mAtm.cancelTaskWindowTransition(0));
+ assertSecurityException(expectCallable, () -> mAtm.startRecentsActivity(null, null,
null));
- assertSecurityException(expectCallable, () -> mService.cancelRecentsAnimation(true));
- assertSecurityException(expectCallable, () -> mService.stopAppSwitches());
- assertSecurityException(expectCallable, () -> mService.resumeAppSwitches());
+ assertSecurityException(expectCallable, () -> mAtm.cancelRecentsAnimation(true));
+ assertSecurityException(expectCallable, () -> mAtm.stopAppSwitches());
+ assertSecurityException(expectCallable, () -> mAtm.resumeAppSwitches());
}
private void testGetTasksApis(boolean expectCallable) {
- mService.getRecentTasks(MAX_VALUE, 0, TEST_USER_0_ID);
- mService.getTasks(MAX_VALUE);
+ mAtm.getRecentTasks(MAX_VALUE, 0, TEST_USER_0_ID);
+ mAtm.getTasks(MAX_VALUE);
if (expectCallable) {
assertTrue(mRecentTasks.mLastAllowed);
assertTrue(mRunningTasks.mLastAllowed);
@@ -1185,7 +1185,7 @@
}
private TaskBuilder createTaskBuilder(String packageName, String className) {
- return new TaskBuilder(mService.mStackSupervisor)
+ return new TaskBuilder(mAtm.mStackSupervisor)
.setComponent(new ComponentName(packageName, className))
.setStack(mStack)
.setUserId(TEST_USER_0_ID);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 8bc8c0b..7fb7d40 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -477,7 +477,7 @@
}
private ActivityRecord createHomeActivity() {
- final ActivityRecord homeActivity = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+ final ActivityRecord homeActivity = new ActivityBuilder(mWm.mAtmService)
.setStack(mRootHomeTask)
.setCreateTask(true)
.build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index e5d1e46..d821d38 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -66,7 +66,7 @@
@MediumTest
@Presubmit
@RunWith(WindowTestRunner.class)
-public class RecentsAnimationTest extends ActivityTestsBase {
+public class RecentsAnimationTest extends WindowTestsBase {
private static final int TEST_USER_ID = 100;
@@ -77,11 +77,11 @@
@Before
public void setUp() throws Exception {
mRecentsAnimationController = mock(RecentsAnimationController.class);
- mService.mWindowManager.setRecentsAnimationController(mRecentsAnimationController);
- doNothing().when(mService.mWindowManager).initializeRecentsAnimation(
+ mAtm.mWindowManager.setRecentsAnimationController(mRecentsAnimationController);
+ doNothing().when(mAtm.mWindowManager).initializeRecentsAnimation(
anyInt(), any(), any(), anyInt(), any(), any());
- final RecentTasks recentTasks = mService.getRecentTasks();
+ final RecentTasks recentTasks = mAtm.getRecentTasks();
spyOn(recentTasks);
doReturn(mRecentsComponent).when(recentTasks).getRecentsComponent();
}
@@ -91,12 +91,12 @@
TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
Task recentsStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_RECENTS, true /* onTop */);
- ActivityRecord recentActivity = new ActivityBuilder(mService)
+ ActivityRecord recentActivity = new ActivityBuilder(mAtm)
.setComponent(mRecentsComponent)
.setCreateTask(true)
.setStack(recentsStack)
.build();
- ActivityRecord topActivity = new ActivityBuilder(mService).setCreateTask(true).build();
+ ActivityRecord topActivity = new ActivityBuilder(mAtm).setCreateTask(true).build();
topActivity.getRootTask().moveToFront("testRecentsActivityVisiblility");
doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
@@ -123,7 +123,7 @@
false /* includingParents */);
ActivityRecord topRunningHomeActivity = homeStack.topRunningActivity();
if (topRunningHomeActivity == null) {
- topRunningHomeActivity = new ActivityBuilder(mService)
+ topRunningHomeActivity = new ActivityBuilder(mAtm)
.setStack(homeStack)
.setCreateTask(true)
.build();
@@ -139,15 +139,15 @@
anyInt() /* startFlags */, any() /* profilerInfo */);
// Assume its process is alive because the caller should be the recents service.
- WindowProcessController wpc = new WindowProcessController(mService, aInfo.applicationInfo,
+ WindowProcessController wpc = new WindowProcessController(mAtm, aInfo.applicationInfo,
aInfo.processName, aInfo.applicationInfo.uid, 0 /* userId */,
mock(Object.class) /* owner */, mock(WindowProcessListener.class));
wpc.setThread(mock(IApplicationThread.class));
- doReturn(wpc).when(mService).getProcessController(eq(wpc.mName), eq(wpc.mUid));
+ doReturn(wpc).when(mAtm).getProcessController(eq(wpc.mName), eq(wpc.mUid));
Intent recentsIntent = new Intent().setComponent(mRecentsComponent);
// Null animation indicates to preload.
- mService.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
+ mAtm.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
null /* recentsAnimationRunner */);
Task recentsStack = defaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN,
@@ -167,7 +167,7 @@
spyOn(recentsActivity);
// Start when the recents activity exists. It should ensure the configuration.
- mService.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
+ mAtm.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
null /* recentsAnimationRunner */);
verify(recentsActivity).ensureActivityConfiguration(anyInt() /* globalChanges */,
@@ -181,20 +181,20 @@
TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
Task recentsStack = defaultTaskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_RECENTS, true /* onTop */);
- ActivityRecord recentActivity = new ActivityBuilder(mService).setComponent(
+ ActivityRecord recentActivity = new ActivityBuilder(mAtm).setComponent(
mRecentsComponent).setCreateTask(true).setStack(recentsStack).build();
WindowProcessController app = recentActivity.app;
recentActivity.app = null;
// Start an activity on top.
- new ActivityBuilder(mService).setCreateTask(true).build().getRootTask().moveToFront(
+ new ActivityBuilder(mAtm).setCreateTask(true).build().getRootTask().moveToFront(
"testRestartRecentsActivity");
doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
any() /* starting */, anyInt() /* configChanges */,
anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
- doReturn(app).when(mService).getProcessController(eq(recentActivity.processName), anyInt());
- ClientLifecycleManager lifecycleManager = mService.getLifecycleManager();
+ doReturn(app).when(mAtm).getProcessController(eq(recentActivity.processName), anyInt());
+ ClientLifecycleManager lifecycleManager = mAtm.getLifecycleManager();
doNothing().when(lifecycleManager).scheduleTransaction(any());
startRecentsActivity();
@@ -212,20 +212,20 @@
// Assume the home activity support recents.
ActivityRecord targetActivity = homeStack.getTopNonFinishingActivity();
if (targetActivity == null) {
- targetActivity = new ActivityBuilder(mService)
+ targetActivity = new ActivityBuilder(mAtm)
.setCreateTask(true)
.setStack(homeStack)
.build();
}
// Put another home activity in home stack.
- ActivityRecord anotherHomeActivity = new ActivityBuilder(mService)
+ ActivityRecord anotherHomeActivity = new ActivityBuilder(mAtm)
.setComponent(new ComponentName(mContext.getPackageName(), "Home2"))
.setCreateTask(true)
.setStack(homeStack)
.build();
// Start an activity on top so the recents activity can be started.
- new ActivityBuilder(mService)
+ new ActivityBuilder(mAtm)
.setCreateTask(true)
.build()
.getRootTask()
@@ -252,21 +252,21 @@
TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
Task fullscreenStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
- new ActivityBuilder(mService)
+ new ActivityBuilder(mAtm)
.setComponent(new ComponentName(mContext.getPackageName(), "App1"))
.setCreateTask(true)
.setStack(fullscreenStack)
.build();
Task recentsStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_RECENTS, true /* onTop */);
- new ActivityBuilder(mService)
+ new ActivityBuilder(mAtm)
.setComponent(mRecentsComponent)
.setCreateTask(true)
.setStack(recentsStack)
.build();
Task fullscreenStack2 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
- new ActivityBuilder(mService)
+ new ActivityBuilder(mAtm)
.setComponent(new ComponentName(mContext.getPackageName(), "App2"))
.setCreateTask(true)
.setStack(fullscreenStack2)
@@ -293,21 +293,21 @@
TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
Task fullscreenStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
- new ActivityBuilder(mService)
+ new ActivityBuilder(mAtm)
.setComponent(new ComponentName(mContext.getPackageName(), "App1"))
.setCreateTask(true)
.setStack(fullscreenStack)
.build();
Task recentsStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_RECENTS, true /* onTop */);
- new ActivityBuilder(mService)
+ new ActivityBuilder(mAtm)
.setComponent(mRecentsComponent)
.setCreateTask(true)
.setStack(recentsStack)
.build();
Task fullscreenStack2 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
- new ActivityBuilder(mService)
+ new ActivityBuilder(mAtm)
.setComponent(new ComponentName(mContext.getPackageName(), "App2"))
.setCreateTask(true)
.setStack(fullscreenStack2)
@@ -319,7 +319,7 @@
fullscreenStack.removeIfPossible();
// Ensure that the recents animation was NOT canceled
- verify(mService.mWindowManager, times(0)).cancelRecentsAnimation(
+ verify(mAtm.mWindowManager, times(0)).cancelRecentsAnimation(
eq(REORDER_KEEP_IN_PLACE), any());
verify(mRecentsAnimationController, times(0)).setCancelOnNextTransitionStart();
}
@@ -330,7 +330,7 @@
.getDefaultTaskDisplayArea();
Task homeStack = taskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED,
ACTIVITY_TYPE_HOME);
- ActivityRecord otherUserHomeActivity = new ActivityBuilder(mService)
+ ActivityRecord otherUserHomeActivity = new ActivityBuilder(mAtm)
.setStack(homeStack)
.setCreateTask(true)
.setComponent(new ComponentName(mContext.getPackageName(), "Home2"))
@@ -339,13 +339,13 @@
Task fullscreenStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
- new ActivityBuilder(mService)
+ new ActivityBuilder(mAtm)
.setComponent(new ComponentName(mContext.getPackageName(), "App1"))
.setCreateTask(true)
.setStack(fullscreenStack)
.build();
- doReturn(TEST_USER_ID).when(mService).getCurrentUserId();
+ doReturn(TEST_USER_ID).when(mAtm).getCurrentUserId();
doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
any() /* starting */, anyInt() /* configChanges */,
anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
@@ -373,7 +373,7 @@
// The callback is actually RecentsAnimation.
recentsAnimation[0] = invocation.getArgument(2);
return null;
- }).when(mService.mWindowManager).initializeRecentsAnimation(
+ }).when(mAtm.mWindowManager).initializeRecentsAnimation(
anyInt() /* targetActivityType */, any() /* recentsAnimationRunner */,
any() /* callbacks */, anyInt() /* displayId */, any() /* recentTaskIds */,
any() /* targetActivity */);
@@ -381,7 +381,7 @@
Intent recentsIntent = new Intent();
recentsIntent.setComponent(recentsComponent);
- mService.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
+ mAtm.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
mock(IRecentsAnimationRunner.class));
return recentsAnimation[0];
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 74be2c9..1ec9bd2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -89,14 +89,14 @@
@MediumTest
@Presubmit
@RunWith(WindowTestRunner.class)
-public class RootActivityContainerTests extends ActivityTestsBase {
+public class RootActivityContainerTests extends WindowTestsBase {
private Task mFullscreenStack;
@Before
public void setUp() throws Exception {
mFullscreenStack = mRootWindowContainer.getDefaultTaskDisplayArea().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- doNothing().when(mService).updateSleepIfNeededLocked();
+ doNothing().when(mAtm).updateSleepIfNeededLocked();
}
/**
@@ -117,11 +117,11 @@
*/
@Test
public void testReplacingTaskInPinnedStack() {
- final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true)
.setStack(mFullscreenStack).build();
final Task task = firstActivity.getTask();
- final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(task)
+ final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(task)
.setStack(mFullscreenStack).build();
mFullscreenStack.moveToFront("testReplacingTaskInPinnedStack");
@@ -152,11 +152,11 @@
@Test
public void testMovingBottomMostStackActivityToPinnedStack() {
- final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true)
.setStack(mFullscreenStack).build();
final Task task = firstActivity.getTask();
- final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(task)
+ final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(task)
.setStack(mFullscreenStack).build();
mFullscreenStack.moveTaskToBack(task);
@@ -252,7 +252,7 @@
@Test
public void testAwakeFromSleepingWithAppConfiguration() {
final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
- final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
activity.moveFocusableActivityToTop("test");
assertTrue(activity.getStack().isFocusedStackOnDisplay());
ActivityRecordTests.setRotatedScreenOrientationSilently(activity);
@@ -264,13 +264,13 @@
// Assume the activity was shown in different orientation. For example, the top activity is
// landscape and the portrait lockscreen is shown.
activity.setLastReportedConfiguration(
- new MergedConfiguration(mService.getGlobalConfiguration(), rotatedConfig));
+ new MergedConfiguration(mAtm.getGlobalConfiguration(), rotatedConfig));
activity.setState(ActivityState.STOPPED, "sleep");
display.setIsSleeping(true);
doReturn(false).when(display).shouldSleep();
// Allow to resume when awaking.
- setBooted(mService);
+ setBooted(mAtm);
mRootWindowContainer.applySleepTokens(true);
// The display orientation should be changed by the activity so there is no relaunch.
@@ -288,7 +288,7 @@
final int originalStackCount = defaultTaskDisplayArea.getStackCount();
final Task stack = defaultTaskDisplayArea.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true)
.setStack(stack).build();
assertEquals(originalStackCount + 1, defaultTaskDisplayArea.getStackCount());
@@ -312,16 +312,16 @@
final int originalStackCount = defaultTaskDisplayArea.getStackCount();
final Task stack = defaultTaskDisplayArea.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true)
.setStack(stack).build();
assertEquals(originalStackCount + 1, defaultTaskDisplayArea.getStackCount());
final DisplayContent dc = defaultTaskDisplayArea.getDisplayContent();
- final TaskDisplayArea secondTaskDisplayArea = WindowTestsBase.createTaskDisplayArea(dc,
- mRootWindowContainer.mWmService, "TestTaskDisplayArea", FEATURE_VENDOR_FIRST);
+ final TaskDisplayArea secondTaskDisplayArea = WindowTestsBase.createTaskDisplayArea(
+ dc, mRootWindowContainer.mWmService, "TestTaskDisplayArea", FEATURE_VENDOR_FIRST);
final Task secondStack = secondTaskDisplayArea.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- new ActivityBuilder(mService).setCreateTask(true).setStack(secondStack)
+ new ActivityBuilder(mAtm).setCreateTask(true).setStack(secondStack)
.setUseProcess(firstActivity.app).build();
assertEquals(1, secondTaskDisplayArea.getStackCount());
@@ -340,7 +340,7 @@
.getDefaultTaskDisplayArea();
final Task stack = defaultTaskDisplayArea.createStack(
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true)
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true)
.setStack(stack).build();
// Created stacks are focusable by default.
@@ -354,7 +354,7 @@
final Task pinnedStack = defaultTaskDisplayArea.createStack(
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final ActivityRecord pinnedActivity = new ActivityBuilder(mService).setCreateTask(true)
+ final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm).setCreateTask(true)
.setStack(pinnedStack).build();
// We should not be focusable when in pinned mode
@@ -385,7 +385,7 @@
.createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
final Task task = new TaskBuilder(mSupervisor).setStack(primaryStack).build();
- final ActivityRecord r = new ActivityBuilder(mService).setTask(task).build();
+ final ActivityRecord r = new ActivityBuilder(mAtm).setTask(task).build();
// Find a launch stack for the top activity in split-screen primary, while requesting
// split-screen secondary.
@@ -439,7 +439,7 @@
final Task stack = secondDisplay.getDefaultTaskDisplayArea()
.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */);
final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
- new ActivityBuilder(mService).setTask(task).build();
+ new ActivityBuilder(mAtm).setTask(task).build();
final String reason = "findTaskToMoveToFront";
mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason,
@@ -459,7 +459,7 @@
final Task targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */));
final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
- final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
taskDisplayArea.positionChildAt(POSITION_BOTTOM, targetStack, false /*includingParents*/);
// Assume the stack is not at the topmost position (e.g. behind always-on-top stacks) but it
@@ -489,7 +489,7 @@
doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any());
- mService.setBooted(true);
+ mAtm.setBooted(true);
// Trigger resume on all displays
mRootWindowContainer.resumeFocusedStacksTopActivities();
@@ -515,11 +515,11 @@
final Task stack = secondDisplay.getDefaultTaskDisplayArea()
.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
- new ActivityBuilder(mService).setTask(task).build();
+ new ActivityBuilder(mAtm).setTask(task).build();
doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any());
- mService.setBooted(true);
+ mAtm.setBooted(true);
// Trigger resume on all displays
mRootWindowContainer.resumeFocusedStacksTopActivities();
@@ -539,7 +539,7 @@
final Task targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */));
final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
- final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
activity.setState(ActivityState.RESUMED, "test");
// Assume the stack is at the topmost position
@@ -559,7 +559,7 @@
final Task targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */));
final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
- final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
activity.setState(ActivityState.RESUMED, "test");
taskDisplayArea.positionChildAt(POSITION_BOTTOM, targetStack, false /*includingParents*/);
@@ -584,7 +584,7 @@
// Create secondary displays.
final TestDisplayContent secondDisplay =
- new TestDisplayContent.Builder(mService, 1000, 1500)
+ new TestDisplayContent.Builder(mAtm, 1000, 1500)
.setSystemDecorations(true).build();
doReturn(true).when(mRootWindowContainer)
@@ -605,16 +605,16 @@
@Test
public void testNotStartHomeBeforeBoot() {
final int displayId = 1;
- final boolean isBooting = mService.mAmInternal.isBooting();
- final boolean isBooted = mService.mAmInternal.isBooted();
+ final boolean isBooting = mAtm.mAmInternal.isBooting();
+ final boolean isBooted = mAtm.mAmInternal.isBooted();
try {
- mService.mAmInternal.setBooting(false);
- mService.mAmInternal.setBooted(false);
+ mAtm.mAmInternal.setBooting(false);
+ mAtm.mAmInternal.setBooted(false);
mRootWindowContainer.onDisplayAdded(displayId);
verify(mRootWindowContainer, never()).startHomeOnDisplay(anyInt(), any(), anyInt());
} finally {
- mService.mAmInternal.setBooting(isBooting);
- mService.mAmInternal.setBooted(isBooted);
+ mAtm.mAmInternal.setBooting(isBooting);
+ mAtm.mAmInternal.setBooted(isBooted);
}
}
@@ -626,7 +626,7 @@
final ActivityInfo info = new ActivityInfo();
info.applicationInfo = new ApplicationInfo();
final WindowProcessController app = mock(WindowProcessController.class);
- doReturn(app).when(mService).getProcessController(any(), anyInt());
+ doReturn(app).when(mAtm).getProcessController(any(), anyInt());
// Can not start home if we don't want to start home while home is being instrumented.
doReturn(true).when(app).isInstrumenting();
@@ -653,7 +653,7 @@
public void testStartSecondaryHomeOnDisplayWithUserKeyLocked() {
// Create secondary displays.
final TestDisplayContent secondDisplay =
- new TestDisplayContent.Builder(mService, 1000, 1500)
+ new TestDisplayContent.Builder(mAtm, 1000, 1500)
.setSystemDecorations(true).build();
// Use invalid user id to let StorageManager.isUserKeyUnlocked() return false.
@@ -678,7 +678,7 @@
public void testStartSecondaryHomeOnDisplayWithoutSysDecorations() {
// Create secondary displays.
final TestDisplayContent secondDisplay =
- new TestDisplayContent.Builder(mService, 1000, 1500)
+ new TestDisplayContent.Builder(mAtm, 1000, 1500)
.setSystemDecorations(false).build();
mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "testStartSecondaryHome",
@@ -712,7 +712,7 @@
@Test
public void testResolveSecondaryHomeActivityWhenPrimaryHomeNotSet() {
// Setup: primary home not set.
- final Intent primaryHomeIntent = mService.getHomeIntent();
+ final Intent primaryHomeIntent = mAtm.getHomeIntent();
final ActivityInfo aInfoPrimary = new ActivityInfo();
aInfoPrimary.name = ResolverActivity.class.getName();
doReturn(aInfoPrimary).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
@@ -740,7 +740,7 @@
// SetUp: set secondary home and force it.
mockResolveHomeActivity(false /* primaryHome */, true /* forceSystemProvided */);
final Intent secondaryHomeIntent =
- mService.getSecondaryHomeIntent(null /* preferredPackage */);
+ mAtm.getSecondaryHomeIntent(null /* preferredPackage */);
final List<ResolveInfo> resolutions = new ArrayList<>();
final ResolveInfo resolveInfo = new ResolveInfo();
final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/);
@@ -855,11 +855,11 @@
public void testGetLaunchStackWithRealCallerId() {
// Create a non-system owned virtual display.
final TestDisplayContent secondaryDisplay =
- new TestDisplayContent.Builder(mService, 1000, 1500)
+ new TestDisplayContent.Builder(mAtm, 1000, 1500)
.setType(TYPE_VIRTUAL).setOwnerUid(100).build();
// Create an activity with specify the original launch pid / uid.
- final ActivityRecord r = new ActivityBuilder(mService).setLaunchedFromPid(200)
+ final ActivityRecord r = new ActivityBuilder(mAtm).setLaunchedFromPid(200)
.setLaunchedFromUid(200).build();
// Simulate ActivityStarter to find a launch stack for requesting the activity to launch
@@ -882,12 +882,11 @@
@Test
public void testGetValidLaunchStackOnDisplayWithCandidateRootTask() {
// Create a root task with an activity on secondary display.
- final TestDisplayContent secondaryDisplay = new TestDisplayContent.Builder(mService, 300,
+ final TestDisplayContent secondaryDisplay = new TestDisplayContent.Builder(mAtm, 300,
600).build();
- final Task task = new ActivityTestsBase.StackBuilder(mRootWindowContainer).setDisplay(
- secondaryDisplay).build();
- final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(mService)
- .setTask(task).build();
+ final Task task = new StackBuilder(mRootWindowContainer)
+ .setDisplay(secondaryDisplay).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
// Make sure the root task is valid and can be reused on default display.
final Task stack = mRootWindowContainer.getValidLaunchStackInTaskDisplayArea(
@@ -923,7 +922,7 @@
DisplayContent.POSITION_TOP);
final Task stack = secondDisplay.getDefaultTaskDisplayArea()
.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final ActivityRecord activity = new ActivityBuilder(mService).setStack(stack).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setStack(stack).build();
spyOn(activity);
spyOn(stack);
@@ -946,7 +945,7 @@
ActivityInfo targetActivityInfo = getFakeHomeActivityInfo(primaryHome);
Intent targetIntent;
if (primaryHome) {
- targetIntent = mService.getHomeIntent();
+ targetIntent = mAtm.getHomeIntent();
} else {
Resources resources = mContext.getResources();
spyOn(resources);
@@ -954,7 +953,7 @@
com.android.internal.R.string.config_secondaryHomePackage);
doReturn(forceSystemProvided).when(resources).getBoolean(
com.android.internal.R.bool.config_useSystemProvidedLauncherForSecondary);
- targetIntent = mService.getSecondaryHomeIntent(null /* preferredPackage */);
+ targetIntent = mAtm.getSecondaryHomeIntent(null /* preferredPackage */);
}
doReturn(targetActivityInfo).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
refEq(targetIntent));
@@ -965,7 +964,7 @@
* activity info for test cases.
*/
private void mockResolveSecondaryHomeActivity() {
- final Intent secondaryHomeIntent = mService
+ final Intent secondaryHomeIntent = mAtm
.getSecondaryHomeIntent(null /* preferredPackage */);
final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false);
doReturn(Pair.create(aInfoSecondary, secondaryHomeIntent)).when(mRootWindowContainer)
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 d9d07d9b..72899e7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -133,10 +133,10 @@
@Test
public void testFindActivityByTargetComponent() {
final ComponentName aliasComponent = ComponentName.createRelative(
- ActivityTestsBase.DEFAULT_COMPONENT_PACKAGE_NAME, ".AliasActivity");
+ DEFAULT_COMPONENT_PACKAGE_NAME, ".AliasActivity");
final ComponentName targetComponent = ComponentName.createRelative(
aliasComponent.getPackageName(), ".TargetActivity");
- final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+ final ActivityRecord activity = new ActivityBuilder(mWm.mAtmService)
.setComponent(aliasComponent)
.setTargetActivity(targetComponent.getClassName())
.setLaunchMode(ActivityInfo.LAUNCH_SINGLE_INSTANCE)
@@ -174,15 +174,13 @@
@Test
public void testForceStopPackage() {
- final Task task = new ActivityTestsBase.StackBuilder(mWm.mRoot).build();
+ final Task task = new StackBuilder(mWm.mRoot).build();
final ActivityRecord activity = task.getTopMostActivity();
final WindowProcessController wpc = activity.app;
final ActivityRecord[] activities = {
activity,
- new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
- .setStack(task).setUseProcess(wpc).build(),
- new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
- .setStack(task).setUseProcess(wpc).build()
+ new ActivityBuilder(mWm.mAtmService).setStack(task).setUseProcess(wpc).build(),
+ new ActivityBuilder(mWm.mAtmService).setStack(task).setUseProcess(wpc).build()
};
activities[0].detachFromProcess();
activities[1].finishing = true;
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index e51a133..3415093 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -42,7 +42,7 @@
@MediumTest
@Presubmit
@RunWith(WindowTestRunner.class)
-public class RunningTasksTest extends ActivityTestsBase {
+public class RunningTasksTest extends WindowTestsBase {
private static final ArraySet<Integer> PROFILE_IDS = new ArraySet<>();
@@ -57,7 +57,7 @@
public void testCollectTasksByLastActiveTime() {
// Create a number of stacks with tasks (of incrementing active time)
final ArrayList<DisplayContent> displays = new ArrayList<>();
- final DisplayContent display = new TestDisplayContent.Builder(mService, 1000, 2500).build();
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2500).build();
displays.add(display);
final int numStacks = 2;
@@ -101,7 +101,7 @@
@Test
public void testTaskInfo_expectNoExtras() {
- final DisplayContent display = new TestDisplayContent.Builder(mService, 1000, 2500).build();
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2500).build();
final int numTasks = 10;
for (int i = 0; i < numTasks; i++) {
final Task stack = new StackBuilder(mRootWindowContainer)
@@ -132,13 +132,13 @@
*/
private Task createTask(Task stack, String className, int taskId,
int lastActiveTime, Bundle extras) {
- final Task task = new TaskBuilder(mService.mStackSupervisor)
+ final Task task = new TaskBuilder(mAtm.mStackSupervisor)
.setComponent(new ComponentName(mContext.getPackageName(), className))
.setTaskId(taskId)
.setStack(stack)
.build();
task.lastActiveTime = lastActiveTime;
- final ActivityRecord activity = new ActivityBuilder(mService)
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
.setTask(task)
.setComponent(new ComponentName(mContext.getPackageName(), ".TaskActivity"))
.setIntentExtras(extras)
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 250cf09..0e1d4dc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -64,7 +64,7 @@
@MediumTest
@Presubmit
@RunWith(WindowTestRunner.class)
-public class SizeCompatTests extends ActivityTestsBase {
+public class SizeCompatTests extends WindowTestsBase {
private Task mStack;
private Task mTask;
private ActivityRecord mActivity;
@@ -76,7 +76,7 @@
}
private void setUpDisplaySizeWithApp(int dw, int dh) {
- final TestDisplayContent.Builder builder = new TestDisplayContent.Builder(mService, dw, dh);
+ final TestDisplayContent.Builder builder = new TestDisplayContent.Builder(mAtm, dw, dh);
setUpApp(builder.build());
}
@@ -92,7 +92,7 @@
final Rect originalOverrideBounds = new Rect(mActivity.getBounds());
resizeDisplay(mStack.getDisplay(), 600, 1200);
// The visible activity should recompute configuration according to the last parent bounds.
- mService.restartActivityProcessIfVisible(mActivity.appToken);
+ mAtm.restartActivityProcessIfVisible(mActivity.appToken);
assertEquals(Task.ActivityState.RESTARTING_PROCESS, mActivity.getState());
assertNotEquals(originalOverrideBounds, mActivity.getBounds());
@@ -102,7 +102,7 @@
public void testKeepBoundsWhenChangingFromFreeformToFullscreen() {
removeGlobalMinSizeRestriction();
// create freeform display and a freeform app
- DisplayContent display = new TestDisplayContent.Builder(mService, 2000, 1000)
+ DisplayContent display = new TestDisplayContent.Builder(mAtm, 2000, 1000)
.setCanRotate(false)
.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM).build();
setUpApp(display);
@@ -135,7 +135,7 @@
@Test
public void testFixedAspectRatioBoundsWithDecorInSquareDisplay() {
final int notchHeight = 100;
- setUpApp(new TestDisplayContent.Builder(mService, 600, 800).setNotch(notchHeight).build());
+ setUpApp(new TestDisplayContent.Builder(mAtm, 600, 800).setNotch(notchHeight).build());
// Rotation is ignored so because the display size is close to square (700/600<1.333).
assertTrue(mActivity.mDisplayContent.ignoreRotationForApps());
@@ -186,10 +186,10 @@
// Make a new less-tall display with lower density
final DisplayContent newDisplay =
- new TestDisplayContent.Builder(mService, 1000, 2000)
+ new TestDisplayContent.Builder(mAtm, 1000, 2000)
.setDensityDpi(200).build();
- mActivity = new ActivityBuilder(mService)
+ mActivity = new ActivityBuilder(mAtm)
.setTask(mTask)
.setResizeMode(RESIZE_MODE_UNRESIZEABLE)
.setMaxAspectRatio(1.5f)
@@ -262,7 +262,7 @@
@Test
public void testAspectRatioMatchParentBoundsAndImeAttachable() {
- setUpApp(new TestDisplayContent.Builder(mService, 1000, 2000)
+ setUpApp(new TestDisplayContent.Builder(mAtm, 1000, 2000)
.setSystemDecorations(true).build());
prepareUnresizable(2f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED);
assertFitted();
@@ -293,7 +293,7 @@
final int origHeight = configBounds.height();
final int notchHeight = 100;
- final DisplayContent newDisplay = new TestDisplayContent.Builder(mService, 2000, 1000)
+ final DisplayContent newDisplay = new TestDisplayContent.Builder(mAtm, 2000, 1000)
.setCanRotate(false).setNotch(notchHeight).build();
// Move the non-resizable activity to the new display.
@@ -327,7 +327,7 @@
public void testFixedOrientRotateCutoutDisplay() {
// Create a display with a notch/cutout
final int notchHeight = 60;
- setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500)
+ setUpApp(new TestDisplayContent.Builder(mAtm, 1000, 2500)
.setNotch(notchHeight).build());
// Bounds=[0, 0 - 1000, 1460], AppBounds=[0, 60 - 1000, 1460].
prepareUnresizable(1.4f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
@@ -430,14 +430,14 @@
// Change display density
display.mBaseDisplayDensity = (int) (0.7f * display.mBaseDisplayDensity);
display.computeScreenConfiguration(rotatedConfig);
- mService.mAmInternal = mock(ActivityManagerInternal.class);
+ mAtm.mAmInternal = mock(ActivityManagerInternal.class);
display.onRequestedOverrideConfigurationChanged(rotatedConfig);
// The override configuration should be reset and the activity's process will be killed.
assertFitted();
verify(mActivity).restartProcessIfVisible();
- waitHandlerIdle(mService.mH);
- verify(mService.mAmInternal).killProcess(
+ waitHandlerIdle(mAtm.mH);
+ verify(mAtm.mAmInternal).killProcess(
eq(mActivity.app.mName), eq(mActivity.app.mUid), anyString());
}
@@ -454,7 +454,7 @@
assertFitted();
final ArrayList<IBinder> compatTokens = new ArrayList<>();
- mService.getTaskChangeNotificationController().registerTaskStackListener(
+ mAtm.getTaskChangeNotificationController().registerTaskStackListener(
new TaskStackListener() {
@Override
public void onSizeCompatModeActivityChanged(int displayId,
@@ -492,7 +492,7 @@
mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
// Create a size compat activity on the same task.
- final ActivityRecord activity = new ActivityBuilder(mService)
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
.setTask(mTask)
.setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE)
.setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
@@ -516,7 +516,7 @@
final int dw = 1000;
final int dh = 2500;
final int notchHeight = 200;
- setUpApp(new TestDisplayContent.Builder(mService, dw, dh).setNotch(notchHeight).build());
+ setUpApp(new TestDisplayContent.Builder(mAtm, dw, dh).setNotch(notchHeight).build());
addStatusBar(mActivity.mDisplayContent);
mActivity.setVisible(false);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
index 27a8fc3..3492556 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
@@ -219,8 +219,7 @@
final Task rootHomeTask = defaultTaskDisplayArea.getRootHomeTask();
rootHomeTask.mResizeMode = RESIZE_MODE_UNRESIZEABLE;
- final Task primarySplitTask =
- new ActivityTestsBase.StackBuilder(rootWindowContainer)
+ final Task primarySplitTask = new StackBuilder(rootWindowContainer)
.setTaskDisplayArea(defaultTaskDisplayArea)
.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
.setActivityType(ACTIVITY_TYPE_STANDARD)
@@ -234,7 +233,7 @@
ActivityRecord homeActivity = rootHomeTask.getTopNonFinishingActivity();
if (homeActivity == null) {
- homeActivity = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+ homeActivity = new ActivityBuilder(mWm.mAtmService)
.setStack(rootHomeTask).setCreateTask(true).build();
}
homeActivity.setVisible(false);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index a048526..42de5e6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -67,7 +67,7 @@
@SmallTest
@Presubmit
@RunWith(WindowTestRunner.class)
-public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
+public class TaskLaunchParamsModifierTests extends WindowTestsBase {
private static final Rect DISPLAY_BOUNDS = new Rect(/* left */ 0, /* top */ 0,
/* right */ 1920, /* bottom */ 1080);
private static final Rect DISPLAY_STABLE_BOUNDS = new Rect(/* left */ 100,
@@ -82,7 +82,7 @@
@Before
public void setUp() throws Exception {
- mActivity = new ActivityBuilder(mService).build();
+ mActivity = new ActivityBuilder(mAtm).build();
mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1;
mActivity.info.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
@@ -449,7 +449,7 @@
@Test
public void testForceMaximizesUnresizeableApp() {
- mService.mSizeCompatFreeform = false;
+ mAtm.mSizeCompatFreeform = false;
final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
@@ -472,7 +472,7 @@
@Test
public void testLaunchesAppInWindowOnFreeformDisplay() {
- mService.mSizeCompatFreeform = true;
+ mAtm.mSizeCompatFreeform = true;
final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
@@ -1318,18 +1318,18 @@
@Test
public void testNoMultiDisplaySupports() {
- final boolean orgValue = mService.mSupportsMultiDisplay;
+ final boolean orgValue = mAtm.mSupportsMultiDisplay;
final TestDisplayContent display = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
mCurrent.mPreferredTaskDisplayArea = display.getDefaultTaskDisplayArea();
try {
- mService.mSupportsMultiDisplay = false;
+ mAtm.mSupportsMultiDisplay = false;
assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
assertEquals(mRootWindowContainer.getDefaultTaskDisplayArea(),
mResult.mPreferredTaskDisplayArea);
} finally {
- mService.mSupportsMultiDisplay = orgValue;
+ mAtm.mSupportsMultiDisplay = orgValue;
}
}
@@ -1351,7 +1351,7 @@
private ActivityRecord createSourceActivity(TestDisplayContent display) {
final Task stack = display.getDefaultTaskDisplayArea()
.createStack(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true);
- return new ActivityBuilder(mService).setStack(stack).setCreateTask(true).build();
+ return new ActivityBuilder(mAtm).setStack(stack).setCreateTask(true).build();
}
private void addFreeformTaskTo(TestDisplayContent display, Rect bounds) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
index 0db3f94..27cae2f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
@@ -77,7 +77,7 @@
removeGlobalMinSizeRestriction();
final Task stack = createTaskStackOnDisplay(mDisplayContent);
- final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(stack.mAtmService)
+ final ActivityRecord activity = new ActivityBuilder(stack.mAtmService)
.setStack(stack)
// In real case, there is no additional level for freeform mode.
.setCreateTask(false)
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 bf76c8e..fc54e1d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -95,7 +95,7 @@
@MediumTest
@Presubmit
@RunWith(WindowTestRunner.class)
-public class TaskRecordTests extends ActivityTestsBase {
+public class TaskRecordTests extends WindowTestsBase {
private static final String TASK_TAG = "task";
@@ -172,7 +172,7 @@
@Test
public void testFitWithinBounds() {
final Rect parentBounds = new Rect(10, 10, 200, 200);
- TaskDisplayArea taskDisplayArea = mService.mRootWindowContainer.getDefaultTaskDisplayArea();
+ TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea();
Task stack = taskDisplayArea.createStack(WINDOWING_MODE_FREEFORM,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
@@ -210,7 +210,7 @@
/** Tests that the task bounds adjust properly to changes between FULLSCREEN and FREEFORM */
@Test
public void testBoundsOnModeChangeFreeformToFullscreen() {
- DisplayContent display = mService.mRootWindowContainer.getDefaultDisplay();
+ DisplayContent display = mAtm.mRootWindowContainer.getDefaultDisplay();
Task stack = new StackBuilder(mRootWindowContainer).setDisplay(display)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
Task task = stack.getBottomMostTask();
@@ -243,7 +243,7 @@
public void testFullscreenBoundsForcedOrientation() {
final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920);
- final DisplayContent display = new TestDisplayContent.Builder(mService,
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm,
fullScreenBounds.width(), fullScreenBounds.height()).setCanRotate(false).build();
assertTrue(mRootWindowContainer.getDisplayContent(display.mDisplayId) != null);
// Fix the display orientation to landscape which is the natural rotation (0) for the test
@@ -267,7 +267,7 @@
assertEquals(fullScreenBounds.height(), task.getBounds().height());
// Top activity gets used
- ActivityRecord top = new ActivityBuilder(mService).setTask(task).setStack(stack).build();
+ 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());
@@ -307,7 +307,7 @@
public void testIgnoresForcedOrientationWhenParentHandles() {
final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
DisplayContent display = new TestDisplayContent.Builder(
- mService, fullScreenBounds.width(), fullScreenBounds.height()).build();
+ mAtm, fullScreenBounds.width(), fullScreenBounds.height()).build();
display.getRequestedOverrideConfiguration().orientation =
Configuration.ORIENTATION_LANDSCAPE;
@@ -339,7 +339,7 @@
public void testComputeConfigResourceOverrides() {
final Rect fullScreenBounds = new Rect(0, 0, 1080, 1920);
TestDisplayContent display = new TestDisplayContent.Builder(
- mService, fullScreenBounds.width(), fullScreenBounds.height()).build();
+ 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();
@@ -438,11 +438,11 @@
@Test
public void testInsetDisregardedWhenFreeformOverlapsNavBar() {
- TaskDisplayArea taskDisplayArea = mService.mRootWindowContainer.getDefaultTaskDisplayArea();
+ TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea();
Task stack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
DisplayInfo displayInfo = new DisplayInfo();
- mService.mContext.getDisplay().getDisplayInfo(displayInfo);
+ mAtm.mContext.getDisplay().getDisplayInfo(displayInfo);
final int displayHeight = displayInfo.logicalHeight;
final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
final Configuration inOutConfig = new Configuration();
@@ -514,23 +514,23 @@
info.packageName = DEFAULT_COMPONENT_PACKAGE_NAME;
info.targetActivity = targetClassName;
- final Task task = new Task(mService, 1 /* taskId */, info, intent,
+ final Task task = new Task(mAtm, 1 /* taskId */, info, intent,
null /* voiceSession */, null /* voiceInteractor */, null /* taskDescriptor */,
null /*stack*/);
assertEquals("The alias activity component should be saved in task intent.", aliasClassName,
task.intent.getComponent().getClassName());
- ActivityRecord aliasActivity = new ActivityBuilder(mService).setComponent(
+ ActivityRecord aliasActivity = new ActivityBuilder(mAtm).setComponent(
aliasComponent).setTargetActivity(targetClassName).build();
assertEquals("Should be the same intent filter.", true,
task.isSameIntentFilter(aliasActivity));
- ActivityRecord targetActivity = new ActivityBuilder(mService).setComponent(
+ ActivityRecord targetActivity = new ActivityBuilder(mAtm).setComponent(
targetComponent).build();
assertEquals("Should be the same intent filter.", true,
task.isSameIntentFilter(targetActivity));
- ActivityRecord defaultActivity = new ActivityBuilder(mService).build();
+ ActivityRecord defaultActivity = new ActivityBuilder(mAtm).build();
assertEquals("Should not be the same intent filter.", false,
task.isSameIntentFilter(defaultActivity));
}
@@ -540,7 +540,7 @@
public void testFindRootIndex() {
final Task task = getTestTask();
// Add an extra activity on top of the root one
- new ActivityBuilder(mService).setTask(task).build();
+ new ActivityBuilder(mAtm).setTask(task).build();
assertEquals("The root activity in the task must be reported.", task.getChildAt(0),
task.getRootActivity(
@@ -557,9 +557,9 @@
// Add extra two activities and mark the two on the bottom as finishing.
final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.finishing = true;
- final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
activity1.finishing = true;
- new ActivityBuilder(mService).setTask(task).build();
+ new ActivityBuilder(mAtm).setTask(task).build();
assertEquals("The first non-finishing activity in the task must be reported.",
task.getChildAt(2), task.getRootActivity(
@@ -574,7 +574,7 @@
public void testFindRootIndex_effectiveRoot() {
final Task task = getTestTask();
// Add an extra activity on top of the root one
- new ActivityBuilder(mService).setTask(task).build();
+ new ActivityBuilder(mAtm).setTask(task).build();
assertEquals("The root activity in the task must be reported.",
task.getChildAt(0), task.getRootActivity(
@@ -592,9 +592,9 @@
// one above as finishing.
final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
- final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
activity1.finishing = true;
- new ActivityBuilder(mService).setTask(task).build();
+ new ActivityBuilder(mAtm).setTask(task).build();
assertEquals("The first non-finishing activity and non-relinquishing task identity "
+ "must be reported.", task.getChildAt(2), task.getRootActivity(
@@ -626,7 +626,7 @@
// Set relinquishTaskIdentity for all activities in the task
final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
- final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
assertEquals("The topmost activity in the task must be reported.",
@@ -639,7 +639,7 @@
public void testGetRootActivity() {
final Task task = getTestTask();
// Add an extra activity on top of the root one
- new ActivityBuilder(mService).setTask(task).build();
+ new ActivityBuilder(mAtm).setTask(task).build();
assertEquals("The root activity in the task must be reported.",
task.getBottomMostActivity(), task.getRootActivity());
@@ -652,7 +652,7 @@
public void testGetRootActivity_finishing() {
final Task task = getTestTask();
// Add an extra activity on top of the root one
- new ActivityBuilder(mService).setTask(task).build();
+ new ActivityBuilder(mAtm).setTask(task).build();
// Mark the root as finishing
task.getBottomMostActivity().finishing = true;
@@ -670,7 +670,7 @@
final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
// Add an extra activity on top of the root one.
- new ActivityBuilder(mService).setTask(task).build();
+ new ActivityBuilder(mAtm).setTask(task).build();
assertEquals("The root activity in the task must be reported.",
task.getBottomMostActivity(), task.getRootActivity());
@@ -687,7 +687,7 @@
final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.finishing = true;
// Add an extra activity on top of the root one and mark it as finishing
- final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
activity1.finishing = true;
assertNull("No activity must be reported if all are finishing", task.getRootActivity());
@@ -703,7 +703,7 @@
final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.finishing = true;
// Add an extra activity on top of the root one.
- final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
assertFalse("Finishing activity must not be the root of task", activity0.isRootOfTask());
assertTrue("Non-finishing activity must be the root of task", activity1.isRootOfTask());
@@ -720,7 +720,7 @@
final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.finishing = true;
// Add an extra activity on top of the root one and mark it as finishing
- final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
activity1.finishing = true;
assertTrue("Bottom activity must be the root of task", activity0.isRootOfTask());
@@ -756,9 +756,9 @@
final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.finishing = true;
// Add an extra activity on top - this will be the new root
- final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
// Add one more on top
- final ActivityRecord activity2 = new ActivityBuilder(mService).setTask(task).build();
+ final ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(task).build();
assertEquals(task.mTaskId,
ActivityRecord.getTaskForActivityLocked(activity0.appToken, true /* onlyRoot */));
@@ -779,9 +779,9 @@
final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
// Add an extra activity on top - this will be the new root
- final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
// Add one more on top
- final ActivityRecord activity2 = new ActivityBuilder(mService).setTask(task).build();
+ final ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(task).build();
assertEquals(task.mTaskId,
ActivityRecord.getTaskForActivityLocked(activity0.appToken, true /* onlyRoot */));
@@ -803,11 +803,11 @@
activity0.finishing = true;
// Add an extra activity on top of the root one and make it relinquish task identity
- final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
// Add one more activity on top
- final ActivityRecord activity2 = new ActivityBuilder(mService).setTask(task).build();
+ final ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(task).build();
assertEquals(task.mTaskId,
ActivityRecord.getTaskForActivityLocked(activity0.appToken, false /* onlyRoot */));
@@ -843,7 +843,7 @@
// Mark the bottom-most activity as finishing.
activity0.finishing = true;
// Add an extra activity on top of the root one
- final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
spyOn(task);
task.updateEffectiveIntent();
@@ -863,7 +863,7 @@
// Mark the bottom-most activity as finishing.
activity0.finishing = true;
// Add an extra activity on top of the root one and make it relinquish task identity
- final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
activity1.finishing = true;
// Task must still update the intent using the root activity (preserving legacy behavior).
@@ -874,7 +874,7 @@
@Test
public void testSaveLaunchingStateWhenConfigurationChanged() {
- LaunchParamsPersister persister = mService.mStackSupervisor.mLaunchParamsPersister;
+ LaunchParamsPersister persister = mAtm.mStackSupervisor.mLaunchParamsPersister;
spyOn(persister);
final Task task = getTestTask();
@@ -890,7 +890,7 @@
@Test
public void testSaveLaunchingStateWhenClearingParent() {
- LaunchParamsPersister persister = mService.mStackSupervisor.mLaunchParamsPersister;
+ LaunchParamsPersister persister = mAtm.mStackSupervisor.mLaunchParamsPersister;
spyOn(persister);
final Task task = getTestTask();
@@ -915,7 +915,7 @@
@Test
public void testNotSaveLaunchingStateNonFreeformDisplay() {
- LaunchParamsPersister persister = mService.mStackSupervisor.mLaunchParamsPersister;
+ LaunchParamsPersister persister = mAtm.mStackSupervisor.mLaunchParamsPersister;
spyOn(persister);
final Task task = getTestTask();
@@ -930,7 +930,7 @@
@Test
public void testNotSaveLaunchingStateWhenNotFullscreenOrFreeformWindow() {
- LaunchParamsPersister persister = mService.mStackSupervisor.mLaunchParamsPersister;
+ LaunchParamsPersister persister = mAtm.mStackSupervisor.mLaunchParamsPersister;
spyOn(persister);
final Task task = getTestTask();
@@ -983,7 +983,7 @@
private void testStackBoundsConfiguration(int windowingMode, Rect parentBounds, Rect bounds,
Rect expectedConfigBounds) {
- TaskDisplayArea taskDisplayArea = mService.mRootWindowContainer.getDefaultTaskDisplayArea();
+ TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea();
Task stack = taskDisplayArea.createStack(windowingMode, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
@@ -1019,12 +1019,12 @@
parser.setInput(reader);
assertEquals(XmlPullParser.START_TAG, parser.next());
assertEquals(TASK_TAG, parser.getName());
- return Task.restoreFromXml(parser, mService.mStackSupervisor);
+ return Task.restoreFromXml(parser, mAtm.mStackSupervisor);
}
}
private Task createTask(int taskId) {
- return new Task(mService, taskId, new Intent(), null, null, null,
+ return new Task(mAtm, taskId, new Intent(), null, null, null,
ActivityBuilder.getDefaultComponent(), null, false, false, false, 0, 10050, null,
0, false, null, 0, 0, 0, 0, null, null, 0, false, false, false, 0,
0, null /*ActivityInfo*/, null /*_voiceSession*/, null /*_voiceInteractor*/,
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index d950344..b4a1337 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
@@ -87,7 +88,7 @@
0 /* systemUiVisibility */, false /* isTranslucent */);
mSurface = new TaskSnapshotSurface(mWm, new Window(), new SurfaceControl(), snapshot, "Test",
createTaskDescription(Color.WHITE, Color.RED, Color.BLUE), sysuiVis, windowFlags, 0,
- taskBounds, ORIENTATION_PORTRAIT, new InsetsState());
+ taskBounds, ORIENTATION_PORTRAIT, ACTIVITY_TYPE_STANDARD, new InsetsState());
}
private static TaskDescription createTaskDescription(int background, int statusBar,
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 573e37a..ed9e270 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -295,7 +295,7 @@
}
private WindowState createWallpaperTargetWindow(DisplayContent dc) {
- final ActivityRecord homeActivity = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+ final ActivityRecord homeActivity = new ActivityBuilder(mWm.mAtmService)
.setStack(dc.getDefaultTaskDisplayArea().getRootHomeTask())
.setCreateTask(true)
.build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 3ebc288..8ac44f2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -830,7 +830,7 @@
final DisplayContent displayContent = createNewDisplay();
// Do not reparent activity to default display when removing the display.
doReturn(true).when(displayContent).shouldDestroyContentOnRemove();
- final ActivityRecord r = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+ final ActivityRecord r = new StackBuilder(mWm.mRoot)
.setDisplay(displayContent).build().getTopMostActivity();
// Add a window and make the activity animating so the removal of activity is deferred.
createWindow(null, TYPE_BASE_APPLICATION, r, "win");
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 800a5d4..8cfa4f0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -321,7 +321,7 @@
@Test
public void testTaskTransaction() {
removeGlobalMinSizeRestriction();
- final Task stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+ final Task stack = new StackBuilder(mWm.mRoot)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
final Task task = stack.getTopMostTask();
testTransaction(task);
@@ -330,7 +330,7 @@
@Test
public void testStackTransaction() {
removeGlobalMinSizeRestriction();
- final Task stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+ final Task stack = new StackBuilder(mWm.mRoot)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
StackInfo info =
mWm.mAtmService.getStackInfo(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
@@ -355,7 +355,7 @@
@Test
public void testSetWindowingMode() {
- final Task stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+ final Task stack = new StackBuilder(mWm.mRoot)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
testSetWindowingMode(stack);
@@ -389,7 +389,7 @@
@Test
public void testContainerFocusableChanges() {
removeGlobalMinSizeRestriction();
- final Task stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+ final Task stack = new StackBuilder(mWm.mRoot)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
final Task task = stack.getTopMostTask();
WindowContainerTransaction t = new WindowContainerTransaction();
@@ -405,7 +405,7 @@
@Test
public void testContainerHiddenChanges() {
removeGlobalMinSizeRestriction();
- final Task stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+ final Task stack = new StackBuilder(mWm.mRoot)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
WindowContainerTransaction t = new WindowContainerTransaction();
assertTrue(stack.shouldBeVisible(null));
@@ -420,7 +420,7 @@
@Test
public void testOverrideConfigSize() {
removeGlobalMinSizeRestriction();
- final Task stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+ final Task stack = new StackBuilder(mWm.mRoot)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
final Task task = stack.getTopMostTask();
WindowContainerTransaction t = new WindowContainerTransaction();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerMapTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerMapTests.java
index cb7bff3..c2ee079 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerMapTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerMapTests.java
@@ -31,6 +31,7 @@
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
/**
* Tests for the {@link WindowProcessControllerMap} class.
@@ -40,7 +41,8 @@
*/
@SmallTest
@Presubmit
-public class WindowProcessControllerMapTests extends ActivityTestsBase {
+@RunWith(WindowTestRunner.class)
+public class WindowProcessControllerMapTests extends WindowTestsBase {
private static final int FAKE_UID1 = 666;
private static final int FAKE_UID2 = 667;
@@ -60,23 +62,23 @@
public void setUp() throws Exception {
mProcessMap = new WindowProcessControllerMap();
pid1uid1 = new WindowProcessController(
- mService, mService.mContext.getApplicationInfo(), "fakepid1fakeuid1", FAKE_UID1,
+ mAtm, mAtm.mContext.getApplicationInfo(), "fakepid1fakeuid1", FAKE_UID1,
UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class));
pid1uid1.setPid(FAKE_PID1);
pid1uid2 = new WindowProcessController(
- mService, mService.mContext.getApplicationInfo(), "fakepid1fakeuid2", FAKE_UID2,
+ mAtm, mAtm.mContext.getApplicationInfo(), "fakepid1fakeuid2", FAKE_UID2,
UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class));
pid1uid2.setPid(FAKE_PID1);
pid2uid1 = new WindowProcessController(
- mService, mService.mContext.getApplicationInfo(), "fakepid2fakeuid1", FAKE_UID1,
+ mAtm, mAtm.mContext.getApplicationInfo(), "fakepid2fakeuid1", FAKE_UID1,
UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class));
pid2uid1.setPid(FAKE_PID2);
pid3uid1 = new WindowProcessController(
- mService, mService.mContext.getApplicationInfo(), "fakepid3fakeuid1", FAKE_UID1,
+ mAtm, mAtm.mContext.getApplicationInfo(), "fakepid3fakeuid1", FAKE_UID1,
UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class));
pid3uid1.setPid(FAKE_PID3);
pid4uid2 = new WindowProcessController(
- mService, mService.mContext.getApplicationInfo(), "fakepid4fakeuid2", FAKE_UID2,
+ mAtm, mAtm.mContext.getApplicationInfo(), "fakepid4fakeuid2", FAKE_UID2,
UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class));
pid4uid2.setPid(FAKE_PID4);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index cdf8eb4..2f73655 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -50,7 +50,7 @@
*/
@Presubmit
@RunWith(WindowTestRunner.class)
-public class WindowProcessControllerTests extends ActivityTestsBase {
+public class WindowProcessControllerTests extends WindowTestsBase {
WindowProcessController mWpc;
WindowProcessListener mMockListener;
@@ -62,7 +62,7 @@
ApplicationInfo info = mock(ApplicationInfo.class);
info.packageName = "test.package.name";
mWpc = new WindowProcessController(
- mService, info, null, 0, -1, null, mMockListener);
+ mAtm, info, null, 0, -1, null, mMockListener);
mWpc.setThread(mock(IApplicationThread.class));
}
@@ -108,7 +108,7 @@
public void testSetRunningRecentsAnimation() {
mWpc.setRunningRecentsAnimation(true);
mWpc.setRunningRecentsAnimation(false);
- waitHandlerIdle(mService.mH);
+ waitHandlerIdle(mAtm.mH);
InOrder orderVerifier = Mockito.inOrder(mMockListener);
orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(true));
@@ -119,7 +119,7 @@
public void testSetRunningRemoteAnimation() {
mWpc.setRunningRemoteAnimation(true);
mWpc.setRunningRemoteAnimation(false);
- waitHandlerIdle(mService.mH);
+ waitHandlerIdle(mAtm.mH);
InOrder orderVerifier = Mockito.inOrder(mMockListener);
orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(true));
@@ -133,7 +133,7 @@
mWpc.setRunningRecentsAnimation(false);
mWpc.setRunningRemoteAnimation(false);
- waitHandlerIdle(mService.mH);
+ waitHandlerIdle(mAtm.mH);
InOrder orderVerifier = Mockito.inOrder(mMockListener);
orderVerifier.verify(mMockListener, times(3)).setRunningRemoteAnimation(eq(true));
@@ -147,12 +147,12 @@
assertEquals(INVALID_DISPLAY, mWpc.getDisplayId());
// Register to a new display as a listener.
- final DisplayContent display = new TestDisplayContent.Builder(mService, 2000, 1000)
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm, 2000, 1000)
.setDensityDpi(300).setPosition(DisplayContent.POSITION_TOP).build();
mWpc.registerDisplayConfigurationListener(display);
assertEquals(display.mDisplayId, mWpc.getDisplayId());
- final Configuration expectedConfig = mService.mRootWindowContainer.getConfiguration();
+ final Configuration expectedConfig = mAtm.mRootWindowContainer.getConfiguration();
expectedConfig.updateFrom(display.getConfiguration());
assertEquals(expectedConfig, mWpc.getConfiguration());
}
@@ -184,15 +184,15 @@
@Test
public void testActivityNotOverridingSystemUiProcessConfig() {
- final ComponentName systemUiServiceComponent = mService.getSysUiServiceComponentLocked();
+ final ComponentName systemUiServiceComponent = mAtm.getSysUiServiceComponentLocked();
ApplicationInfo applicationInfo = mock(ApplicationInfo.class);
applicationInfo.packageName = systemUiServiceComponent.getPackageName();
WindowProcessController wpc = new WindowProcessController(
- mService, applicationInfo, null, 0, -1, null, mMockListener);
+ mAtm, applicationInfo, null, 0, -1, null, mMockListener);
wpc.setThread(mock(IApplicationThread.class));
- final ActivityRecord activity = new ActivityBuilder(mService)
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
.setCreateTask(true)
.setUseProcess(wpc)
.build();
@@ -209,7 +209,7 @@
// Notify WPC that this process has started an IME service.
mWpc.onServiceStarted(serviceInfo);
- final ActivityRecord activity = new ActivityBuilder(mService)
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
.setCreateTask(true)
.setUseProcess(mWpc)
.build();
@@ -226,7 +226,7 @@
// Notify WPC that this process has started an ally service.
mWpc.onServiceStarted(serviceInfo);
- final ActivityRecord activity = new ActivityBuilder(mService)
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
.setCreateTask(true)
.setUseProcess(mWpc)
.build();
@@ -243,7 +243,7 @@
// Notify WPC that this process has started an voice interaction service.
mWpc.onServiceStarted(serviceInfo);
- final ActivityRecord activity = new ActivityBuilder(mService)
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
.setCreateTask(true)
.setUseProcess(mWpc)
.build();
@@ -254,7 +254,7 @@
}
private TestDisplayContent createTestDisplayContentInContainer() {
- return new TestDisplayContent.Builder(mService, 1000, 1500).build();
+ return new TestDisplayContent.Builder(mAtm, 1000, 1500).build();
}
private static void invertOrientation(Configuration config) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index 2502932..0180d87 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -25,7 +25,7 @@
import android.view.IWindow;
import android.view.WindowManager;
-import com.android.server.wm.ActivityTestsBase.ActivityBuilder;
+import com.android.server.wm.WindowTestsBase.ActivityBuilder;
/**
* A collection of static functions that provide access to WindowManager related test functionality.
@@ -34,7 +34,7 @@
/** Creates a {@link Task} and adds it to the specified {@link Task}. */
static Task createTaskInStack(WindowManagerService service, Task stack, int userId) {
- final Task task = new ActivityTestsBase.TaskBuilder(stack.mStackSupervisor)
+ final Task task = new WindowTestsBase.TaskBuilder(stack.mStackSupervisor)
.setUserId(userId)
.setStack(stack)
.build();
@@ -49,7 +49,7 @@
}
static ActivityRecord createTestActivityRecord(Task stack) {
- final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(stack.mAtmService)
+ final ActivityRecord activity = new ActivityBuilder(stack.mAtmService)
.setStack(stack)
.setCreateTask(true)
.build();
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 dc38883..ec19a58 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -18,7 +18,13 @@
import static android.app.AppOpsManager.OP_NONE;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.os.Process.SYSTEM_UID;
import static android.view.View.VISIBLE;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
@@ -37,22 +43,44 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.mock;
import android.annotation.IntDef;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.IApplicationThread;
+import android.app.WindowConfiguration;
+import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.res.Configuration;
import android.hardware.display.DisplayManager;
+import android.os.Build;
+import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.service.voice.IVoiceInteractionSession;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.IDisplayWindowInsetsController;
import android.view.IWindow;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.View;
import android.view.WindowManager;
+import android.window.ITaskOrganizer;
+import android.window.WindowContainerToken;
import com.android.internal.util.ArrayUtils;
import com.android.server.AttributeCache;
@@ -68,11 +96,20 @@
/** Common base class for window manager unit test classes. */
class WindowTestsBase extends SystemServiceTestsBase {
+ final Context mContext = getInstrumentation().getTargetContext();
+ // Default package name
+ static final String DEFAULT_COMPONENT_PACKAGE_NAME = "com.foo";
+
+ // Default base activity name
+ private static final String DEFAULT_COMPONENT_CLASS_NAME = ".BarActivity";
+
+ ActivityTaskManagerService mAtm;
+ RootWindowContainer mRootWindowContainer;
+ ActivityStackSupervisor mSupervisor;
WindowManagerService mWm;
private final IWindow mIWindow = new TestIWindow();
private Session mMockSession;
- static int sNextStackId = 1000;
DisplayInfo mDisplayInfo = new DisplayInfo();
DisplayContent mDefaultDisplay;
@@ -107,6 +144,9 @@
@Before
public void setUpBase() {
+ mAtm = mSystemServicesTestRule.getActivityTaskManagerService();
+ mSupervisor = mAtm.mStackSupervisor;
+ mRootWindowContainer = mAtm.mRootWindowContainer;
mWm = mSystemServicesTestRule.getWindowManagerService();
SystemServicesTestRule.checkHoldsLock(mWm.mGlobalLock);
@@ -114,7 +154,7 @@
mTransaction = mSystemServicesTestRule.mTransaction;
mMockSession = mock(Session.class);
- getInstrumentation().getTargetContext().getSystemService(DisplayManager.class)
+ mContext.getSystemService(DisplayManager.class)
.getDisplay(Display.DEFAULT_DISPLAY).getDisplayInfo(mDisplayInfo);
// Only create an additional test display for annotated test class/method because it may
@@ -328,7 +368,7 @@
}
Task createTaskStackOnDisplay(int windowingMode, int activityType, DisplayContent dc) {
- return new ActivityTestsBase.StackBuilder(dc.mWmService.mRoot)
+ return new StackBuilder(dc.mWmService.mRoot)
.setDisplay(dc)
.setWindowingMode(windowingMode)
.setActivityType(activityType)
@@ -339,7 +379,7 @@
Task createTaskStackOnTaskDisplayArea(int windowingMode, int activityType,
TaskDisplayArea tda) {
- return new ActivityTestsBase.StackBuilder(tda.mWmService.mRoot)
+ return new StackBuilder(tda.mWmService.mRoot)
.setTaskDisplayArea(tda)
.setWindowingMode(windowingMode)
.setActivityType(activityType)
@@ -371,7 +411,7 @@
/** Creates a {@link DisplayContent} and adds it to the system. */
private DisplayContent createNewDisplay(DisplayInfo info, boolean supportIme) {
final DisplayContent display =
- new TestDisplayContent.Builder(mWm.mAtmService, info).build();
+ new TestDisplayContent.Builder(mAtm, info).build();
final DisplayContent dc = display.mDisplayContent;
// this display can show IME.
dc.mWmService.mDisplayWindowSettings.setShouldShowImeLocked(dc, supportIme);
@@ -435,11 +475,6 @@
};
}
- /** Sets the default minimum task size to 1 so that tests can use small task sizes */
- void removeGlobalMinSizeRestriction() {
- mWm.mAtmService.mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp = 1;
- }
-
/**
* Avoids rotating screen disturbed by some conditions. It is usually used for the default
* display that is not the instance of {@link TestDisplayContent} (it bypasses the conditions).
@@ -501,4 +536,523 @@
boolean addAllCommonWindows() default false;
@CommonTypes int[] addWindows() default {};
}
+
+ /** Creates and adds a {@link TestDisplayContent} to supervisor at the given position. */
+ TestDisplayContent addNewDisplayContentAt(int position) {
+ return new TestDisplayContent.Builder(mAtm, 1000, 1500).setPosition(position).build();
+ }
+
+ /** Sets the default minimum task size to 1 so that tests can use small task sizes */
+ public void removeGlobalMinSizeRestriction() {
+ mAtm.mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp = 1;
+ }
+
+ /**
+ * Builder for creating new activities.
+ */
+ protected static class ActivityBuilder {
+ // An id appended to the end of the component name to make it unique
+ private static int sCurrentActivityId = 0;
+
+ private final ActivityTaskManagerService mService;
+
+ private ComponentName mComponent;
+ private String mTargetActivity;
+ private Task mTask;
+ private String mProcessName = "name";
+ private String mAffinity;
+ private int mUid = 12345;
+ private boolean mCreateTask;
+ private Task mStack;
+ private int mActivityFlags;
+ private int mLaunchMode;
+ private int mResizeMode = RESIZE_MODE_RESIZEABLE;
+ private float mMaxAspectRatio;
+ private int mScreenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+ private boolean mLaunchTaskBehind;
+ private int mConfigChanges;
+ private int mLaunchedFromPid;
+ private int mLaunchedFromUid;
+ private WindowProcessController mWpc;
+ private Bundle mIntentExtras;
+
+ ActivityBuilder(ActivityTaskManagerService service) {
+ mService = service;
+ }
+
+ ActivityBuilder setComponent(ComponentName component) {
+ mComponent = component;
+ return this;
+ }
+
+ ActivityBuilder setTargetActivity(String targetActivity) {
+ mTargetActivity = targetActivity;
+ return this;
+ }
+
+ ActivityBuilder setIntentExtras(Bundle extras) {
+ mIntentExtras = extras;
+ return this;
+ }
+
+ static ComponentName getDefaultComponent() {
+ return ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
+ DEFAULT_COMPONENT_PACKAGE_NAME);
+ }
+
+ ActivityBuilder setTask(Task task) {
+ mTask = task;
+ return this;
+ }
+
+ ActivityBuilder setActivityFlags(int flags) {
+ mActivityFlags = flags;
+ return this;
+ }
+
+ ActivityBuilder setLaunchMode(int launchMode) {
+ mLaunchMode = launchMode;
+ return this;
+ }
+
+ ActivityBuilder setStack(Task stack) {
+ mStack = stack;
+ return this;
+ }
+
+ ActivityBuilder setCreateTask(boolean createTask) {
+ mCreateTask = createTask;
+ return this;
+ }
+
+ ActivityBuilder setProcessName(String name) {
+ mProcessName = name;
+ return this;
+ }
+
+ ActivityBuilder setUid(int uid) {
+ mUid = uid;
+ return this;
+ }
+
+ ActivityBuilder setResizeMode(int resizeMode) {
+ mResizeMode = resizeMode;
+ return this;
+ }
+
+ ActivityBuilder setMaxAspectRatio(float maxAspectRatio) {
+ mMaxAspectRatio = maxAspectRatio;
+ return this;
+ }
+
+ ActivityBuilder setScreenOrientation(int screenOrientation) {
+ mScreenOrientation = screenOrientation;
+ return this;
+ }
+
+ ActivityBuilder setLaunchTaskBehind(boolean launchTaskBehind) {
+ mLaunchTaskBehind = launchTaskBehind;
+ return this;
+ }
+
+ ActivityBuilder setConfigChanges(int configChanges) {
+ mConfigChanges = configChanges;
+ return this;
+ }
+
+ ActivityBuilder setLaunchedFromPid(int pid) {
+ mLaunchedFromPid = pid;
+ return this;
+ }
+
+ ActivityBuilder setLaunchedFromUid(int uid) {
+ mLaunchedFromUid = uid;
+ return this;
+ }
+
+ ActivityBuilder setUseProcess(WindowProcessController wpc) {
+ mWpc = wpc;
+ return this;
+ }
+
+ ActivityBuilder setAffinity(String affinity) {
+ mAffinity = affinity;
+ return this;
+ }
+
+ ActivityRecord build() {
+ SystemServicesTestRule.checkHoldsLock(mService.mGlobalLock);
+ try {
+ mService.deferWindowLayout();
+ return buildInner();
+ } finally {
+ mService.continueWindowLayout();
+ }
+ }
+
+ ActivityRecord buildInner() {
+ if (mComponent == null) {
+ final int id = sCurrentActivityId++;
+ mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
+ DEFAULT_COMPONENT_CLASS_NAME + id);
+ }
+
+ if (mCreateTask) {
+ mTask = new TaskBuilder(mService.mStackSupervisor)
+ .setComponent(mComponent)
+ .setStack(mStack).build();
+ } else if (mTask == null && mStack != null && DisplayContent.alwaysCreateStack(
+ mStack.getWindowingMode(), mStack.getActivityType())) {
+ // The stack can be the task root.
+ mTask = mStack;
+ }
+
+ Intent intent = new Intent();
+ intent.setComponent(mComponent);
+ if (mIntentExtras != null) {
+ intent.putExtras(mIntentExtras);
+ }
+ final ActivityInfo aInfo = new ActivityInfo();
+ aInfo.applicationInfo = new ApplicationInfo();
+ aInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+ aInfo.applicationInfo.packageName = mComponent.getPackageName();
+ aInfo.applicationInfo.uid = mUid;
+ aInfo.processName = mProcessName;
+ aInfo.packageName = mComponent.getPackageName();
+ aInfo.name = mComponent.getClassName();
+ if (mTargetActivity != null) {
+ aInfo.targetActivity = mTargetActivity;
+ }
+ aInfo.flags |= mActivityFlags;
+ aInfo.launchMode = mLaunchMode;
+ aInfo.resizeMode = mResizeMode;
+ aInfo.maxAspectRatio = mMaxAspectRatio;
+ aInfo.screenOrientation = mScreenOrientation;
+ aInfo.configChanges |= mConfigChanges;
+ aInfo.taskAffinity = mAffinity;
+
+ ActivityOptions options = null;
+ if (mLaunchTaskBehind) {
+ options = ActivityOptions.makeTaskLaunchBehind();
+ }
+
+ final ActivityRecord activity = new ActivityRecord(mService, null /* caller */,
+ mLaunchedFromPid /* launchedFromPid */, mLaunchedFromUid /* launchedFromUid */,
+ null, null, intent, null, aInfo /*aInfo*/, new Configuration(),
+ null /* resultTo */, null /* resultWho */, 0 /* reqCode */,
+ false /*componentSpecified*/, false /* rootVoiceInteraction */,
+ mService.mStackSupervisor, options, null /* sourceRecord */);
+ spyOn(activity);
+ if (mTask != null) {
+ // fullscreen value is normally read from resources in ctor, so for testing we need
+ // to set it somewhere else since we can't mock resources.
+ doReturn(true).when(activity).occludesParent();
+ doReturn(true).when(activity).fillsParent();
+ mTask.addChild(activity);
+ // Make visible by default...
+ activity.setVisible(true);
+ }
+
+ final WindowProcessController wpc;
+ if (mWpc != null) {
+ wpc = mWpc;
+ } else {
+ wpc = new WindowProcessController(mService,
+ aInfo.applicationInfo, mProcessName, mUid,
+ UserHandle.getUserId(12345), mock(Object.class),
+ mock(WindowProcessListener.class));
+ wpc.setThread(mock(IApplicationThread.class));
+ }
+ wpc.setThread(mock(IApplicationThread.class));
+ activity.setProcess(wpc);
+ doReturn(wpc).when(mService).getProcessController(
+ activity.processName, activity.info.applicationInfo.uid);
+
+ // Resume top activities to make sure all other signals in the system are connected.
+ mService.mRootWindowContainer.resumeFocusedStacksTopActivities();
+ return activity;
+ }
+ }
+
+ /**
+ * Builder for creating new tasks.
+ */
+ protected static class TaskBuilder {
+ private final ActivityStackSupervisor mSupervisor;
+
+ private ComponentName mComponent;
+ private String mPackage;
+ private int mFlags = 0;
+ // Task id 0 is reserved in ARC for the home app.
+ private int mTaskId = SystemServicesTestRule.sNextTaskId++;
+ private int mUserId = 0;
+ private IVoiceInteractionSession mVoiceSession;
+ private boolean mCreateStack = true;
+
+ private Task mStack;
+ private TaskDisplayArea mTaskDisplayArea;
+
+ TaskBuilder(ActivityStackSupervisor supervisor) {
+ mSupervisor = supervisor;
+ }
+
+ TaskBuilder setComponent(ComponentName component) {
+ mComponent = component;
+ return this;
+ }
+
+ TaskBuilder setPackage(String packageName) {
+ mPackage = packageName;
+ return this;
+ }
+
+ /**
+ * Set to {@code true} by default, set to {@code false} to prevent the task from
+ * automatically creating a parent stack.
+ */
+ TaskBuilder setCreateStack(boolean createStack) {
+ mCreateStack = createStack;
+ return this;
+ }
+
+ TaskBuilder setVoiceSession(IVoiceInteractionSession session) {
+ mVoiceSession = session;
+ return this;
+ }
+
+ TaskBuilder setFlags(int flags) {
+ mFlags = flags;
+ return this;
+ }
+
+ TaskBuilder setTaskId(int taskId) {
+ mTaskId = taskId;
+ return this;
+ }
+
+ TaskBuilder setUserId(int userId) {
+ mUserId = userId;
+ return this;
+ }
+
+ TaskBuilder setStack(Task stack) {
+ mStack = stack;
+ return this;
+ }
+
+ TaskBuilder setDisplay(DisplayContent display) {
+ mTaskDisplayArea = display.getDefaultTaskDisplayArea();
+ return this;
+ }
+
+ Task build() {
+ SystemServicesTestRule.checkHoldsLock(mSupervisor.mService.mGlobalLock);
+
+ if (mStack == null && mCreateStack) {
+ TaskDisplayArea displayArea = mTaskDisplayArea != null ? mTaskDisplayArea
+ : mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
+ mStack = displayArea.createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ spyOn(mStack);
+ }
+
+ final ActivityInfo aInfo = new ActivityInfo();
+ aInfo.applicationInfo = new ApplicationInfo();
+ aInfo.applicationInfo.packageName = mPackage;
+
+ Intent intent = new Intent();
+ if (mComponent == null) {
+ mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
+ DEFAULT_COMPONENT_CLASS_NAME);
+ }
+
+ intent.setComponent(mComponent);
+ intent.setFlags(mFlags);
+
+ final Task task = new Task(mSupervisor.mService, mTaskId, aInfo,
+ intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/,
+ null /*taskDescription*/, mStack);
+ spyOn(task);
+ task.mUserId = mUserId;
+
+ if (mStack != null) {
+ mStack.moveToFront("test");
+ mStack.addChild(task, true, true);
+ }
+
+ return task;
+ }
+ }
+
+ static class StackBuilder {
+ private final RootWindowContainer mRootWindowContainer;
+ private DisplayContent mDisplay;
+ private TaskDisplayArea mTaskDisplayArea;
+ private int mStackId = -1;
+ private int mWindowingMode = WINDOWING_MODE_UNDEFINED;
+ private int mActivityType = ACTIVITY_TYPE_STANDARD;
+ private boolean mOnTop = true;
+ private boolean mCreateActivity = true;
+ private ActivityInfo mInfo;
+ private Intent mIntent;
+
+ StackBuilder(RootWindowContainer root) {
+ mRootWindowContainer = root;
+ mDisplay = mRootWindowContainer.getDefaultDisplay();
+ mTaskDisplayArea = mDisplay.getDefaultTaskDisplayArea();
+ }
+
+ StackBuilder setWindowingMode(int windowingMode) {
+ mWindowingMode = windowingMode;
+ return this;
+ }
+
+ StackBuilder setActivityType(int activityType) {
+ mActivityType = activityType;
+ return this;
+ }
+
+ StackBuilder setStackId(int stackId) {
+ mStackId = stackId;
+ return this;
+ }
+
+ /**
+ * Set the parent {@link DisplayContent} and use the default task display area. Overrides
+ * the task display area, if was set before.
+ */
+ StackBuilder setDisplay(DisplayContent display) {
+ mDisplay = display;
+ mTaskDisplayArea = mDisplay.getDefaultTaskDisplayArea();
+ return this;
+ }
+
+ /** Set the parent {@link TaskDisplayArea}. Overrides the display, if was set before. */
+ StackBuilder setTaskDisplayArea(TaskDisplayArea taskDisplayArea) {
+ mTaskDisplayArea = taskDisplayArea;
+ mDisplay = mTaskDisplayArea.mDisplayContent;
+ return this;
+ }
+
+ StackBuilder setOnTop(boolean onTop) {
+ mOnTop = onTop;
+ return this;
+ }
+
+ StackBuilder setCreateActivity(boolean createActivity) {
+ mCreateActivity = createActivity;
+ return this;
+ }
+
+ StackBuilder setActivityInfo(ActivityInfo info) {
+ mInfo = info;
+ return this;
+ }
+
+ StackBuilder setIntent(Intent intent) {
+ mIntent = intent;
+ return this;
+ }
+
+ Task build() {
+ SystemServicesTestRule.checkHoldsLock(mRootWindowContainer.mWmService.mGlobalLock);
+
+ final int stackId = mStackId >= 0 ? mStackId : mTaskDisplayArea.getNextStackId();
+ final Task stack = mTaskDisplayArea.createStackUnchecked(
+ mWindowingMode, mActivityType, stackId, mOnTop, mInfo, mIntent,
+ false /* createdByOrganizer */);
+ final ActivityStackSupervisor supervisor = mRootWindowContainer.mStackSupervisor;
+
+ if (mCreateActivity) {
+ new ActivityBuilder(supervisor.mService)
+ .setCreateTask(true)
+ .setStack(stack)
+ .build();
+ if (mOnTop) {
+ // We move the task to front again in order to regain focus after activity
+ // added to the stack. Or {@link DisplayContent#mPreferredTopFocusableStack}
+ // could be other stacks (e.g. home stack).
+ stack.moveToFront("createActivityStack");
+ } else {
+ stack.moveToBack("createActivityStack", null);
+ }
+ }
+ spyOn(stack);
+
+ doNothing().when(stack).startActivityLocked(
+ any(), any(), anyBoolean(), anyBoolean(), any());
+
+ return stack;
+ }
+
+ }
+
+ static class TestSplitOrganizer extends ITaskOrganizer.Stub {
+ final ActivityTaskManagerService mService;
+ Task mPrimary;
+ Task mSecondary;
+ boolean mInSplit = false;
+ // moves everything to secondary. Most tests expect this since sysui usually does it.
+ boolean mMoveToSecondaryOnEnter = true;
+ int mDisplayId;
+ 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);
+ WindowContainerToken primary = mService.mTaskOrganizerController.createRootTask(
+ displayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).token;
+ mPrimary = WindowContainer.fromBinder(primary.asBinder()).asTask();
+ WindowContainerToken secondary = mService.mTaskOrganizerController.createRootTask(
+ displayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token;
+ mSecondary = WindowContainer.fromBinder(secondary.asBinder()).asTask();
+ }
+ TestSplitOrganizer(ActivityTaskManagerService service) {
+ this(service,
+ service.mStackSupervisor.mRootWindowContainer.getDefaultDisplay().mDisplayId);
+ }
+ public void setMoveToSecondaryOnEnter(boolean move) {
+ mMoveToSecondaryOnEnter = move;
+ }
+ @Override
+ public void onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash) {
+ }
+ @Override
+ public void onTaskVanished(ActivityManager.RunningTaskInfo info) {
+ }
+ @Override
+ public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
+ if (mInSplit) {
+ return;
+ }
+ if (info.topActivityType == ACTIVITY_TYPE_UNDEFINED) {
+ // Not populated
+ return;
+ }
+ if (info.configuration.windowConfiguration.getWindowingMode()
+ != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+ return;
+ }
+ mInSplit = true;
+ if (!mMoveToSecondaryOnEnter) {
+ return;
+ }
+ mService.mTaskOrganizerController.setLaunchRoot(mDisplayId,
+ mSecondary.mRemoteToken.toWindowContainerToken());
+ DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId);
+ dc.forAllTaskDisplayAreas(taskDisplayArea -> {
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final Task stack = taskDisplayArea.getStackAt(sNdx);
+ if (!WindowConfiguration.isSplitScreenWindowingMode(stack.getWindowingMode())) {
+ stack.reparent(mSecondary, POSITION_BOTTOM);
+ }
+ }
+ });
+ }
+ @Override
+ public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
+ }
+ }
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index ee564a9..0ea84da 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -1281,27 +1281,25 @@
attributesBuilder.setInternalCapturePreset(MediaRecorder.AudioSource.HOTWORD);
AudioAttributes attributes = attributesBuilder.build();
- // Use same AudioFormat processing as in RecognitionEvent.fromParcel
AudioFormat originalFormat = event.getCaptureFormat();
- AudioFormat captureFormat = (new AudioFormat.Builder())
- .setChannelMask(originalFormat.getChannelMask())
- .setEncoding(originalFormat.getEncoding())
- .setSampleRate(originalFormat.getSampleRate())
- .build();
-
- int bufferSize = AudioRecord.getMinBufferSize(
- captureFormat.getSampleRate() == AudioFormat.SAMPLE_RATE_UNSPECIFIED
- ? AudioFormat.SAMPLE_RATE_HZ_MAX
- : captureFormat.getSampleRate(),
- captureFormat.getChannelCount() == 2
- ? AudioFormat.CHANNEL_IN_STEREO
- : AudioFormat.CHANNEL_IN_MONO,
- captureFormat.getEncoding());
sEventLogger.log(new SoundTriggerLogger.StringEvent("createAudioRecordForEvent"));
- return new AudioRecord(attributes, captureFormat, bufferSize,
- event.getCaptureSession());
+ try {
+ return (new AudioRecord.Builder())
+ .setAudioAttributes(attributes)
+ .setAudioFormat((new AudioFormat.Builder())
+ .setChannelMask(originalFormat.getChannelMask())
+ .setEncoding(originalFormat.getEncoding())
+ .setSampleRate(originalFormat.getSampleRate())
+ .build())
+ .setSessionId(event.getCaptureSession())
+ .build();
+ } catch (IllegalArgumentException | UnsupportedOperationException e) {
+ Slog.w(TAG, mPuuid + ": createAudioRecordForEvent(" + event
+ + "), failed to create AudioRecord");
+ return null;
+ }
}
@Override
@@ -1331,8 +1329,10 @@
// Currently we need to start and release the audio record to reset
// the DSP even if we don't want to process the event
- capturedData.startRecording();
- capturedData.release();
+ if (capturedData != null) {
+ capturedData.startRecording();
+ capturedData.release();
+ }
}
}));
}
diff --git a/startop/OWNERS b/startop/OWNERS
index 3394be9..2d1eb38 100644
--- a/startop/OWNERS
+++ b/startop/OWNERS
@@ -1,7 +1,7 @@
# mailing list: startop-eng@google.com
+calin@google.com
chriswailes@google.com
eholk@google.com
iam@google.com
mathieuc@google.com
-sehr@google.com
yawanng@google.com
diff --git a/telephony/api/system-current.txt b/telephony/api/system-current.txt
index ef94c76..09c1659 100644
--- a/telephony/api/system-current.txt
+++ b/telephony/api/system-current.txt
@@ -316,6 +316,7 @@
method @Deprecated public int getDataConnectionApnTypeBitMask();
method @Deprecated public int getDataConnectionFailCause();
method @Deprecated public int getDataConnectionState();
+ method public int getId();
}
public final class PreciseDisconnectCause {
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
index aee8617..fd9f460 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -28,11 +28,15 @@
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import android.telephony.AccessNetworkConstants.TransportType;
import android.telephony.Annotation.ApnType;
import android.telephony.Annotation.DataFailureCause;
import android.telephony.Annotation.DataState;
import android.telephony.Annotation.NetworkType;
import android.telephony.data.ApnSetting;
+import android.telephony.data.DataCallResponse;
+
+import com.android.internal.telephony.util.TelephonyUtils;
import java.util.Objects;
@@ -53,6 +57,8 @@
*
*/
public final class PreciseDataConnectionState implements Parcelable {
+ private final @TransportType int mTransportType;
+ private final int mId;
private final @DataState int mState;
private final @NetworkType int mNetworkType;
private final @DataFailureCause int mFailCause;
@@ -74,16 +80,20 @@
@ApnType int apnTypes, @NonNull String apn,
@Nullable LinkProperties linkProperties,
@DataFailureCause int failCause) {
- this(state, networkType, linkProperties, failCause, new ApnSetting.Builder()
- .setApnTypeBitmask(apnTypes)
- .setApnName(apn)
- .build());
+ this(AccessNetworkConstants.TRANSPORT_TYPE_INVALID, -1, state, networkType,
+ linkProperties, failCause, new ApnSetting.Builder()
+ .setApnTypeBitmask(apnTypes)
+ .setApnName(apn)
+ .setEntryName(apn)
+ .build());
}
/**
* Constructor of PreciseDataConnectionState
*
+ * @param transportType The transport of the data connection
+ * @param id The id of the data connection
* @param state The state of the data connection
* @param networkType The access network that is/would carry this data connection
* @param linkProperties If the data connection is connected, the properties of the connection
@@ -92,11 +102,12 @@
* @param apnSetting If there is a valid APN for this Data Connection, then the APN Settings;
* if there is no valid APN setting for the specific type, then this will be null
*/
- private PreciseDataConnectionState(@DataState int state,
- @NetworkType int networkType,
- @Nullable LinkProperties linkProperties,
- @DataFailureCause int failCause,
- @Nullable ApnSetting apnSetting) {
+ private PreciseDataConnectionState(@TransportType int transportType, int id,
+ @DataState int state, @NetworkType int networkType,
+ @Nullable LinkProperties linkProperties, @DataFailureCause int failCause,
+ @Nullable ApnSetting apnSetting) {
+ mTransportType = transportType;
+ mId = id;
mState = state;
mNetworkType = networkType;
mLinkProperties = linkProperties;
@@ -110,6 +121,8 @@
* @hide
*/
private PreciseDataConnectionState(Parcel in) {
+ mTransportType = in.readInt();
+ mId = in.readInt();
mState = in.readInt();
mNetworkType = in.readInt();
mLinkProperties = in.readParcelable(LinkProperties.class.getClassLoader());
@@ -144,7 +157,29 @@
}
/**
- * Returns the high-level state of this data connection.
+ * @return The transport type of this data connection.
+ */
+ public @TransportType int getTransportType() {
+ return mTransportType;
+ }
+
+ /**
+ * @return The unique id of the data connection
+ *
+ * Note this is the id assigned in {@link DataCallResponse}.
+ * The id remains the same for data connection handover between
+ * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN} and
+ * {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN}
+ *
+ * @hide
+ */
+ @SystemApi
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * @return The high-level state of this data connection.
*/
public @DataState int getState() {
return mState;
@@ -222,7 +257,9 @@
/**
* Return the APN Settings for this data connection.
*
- * @return the ApnSetting that was used to configure this data connection.
+ * @return the ApnSetting that was used to configure this data connection. Note that a data
+ * connection cannot be established without a valid {@link ApnSetting}. The return value would
+ * never be {@code null} even though it has {@link Nullable} annotation.
*/
public @Nullable ApnSetting getApnSetting() {
return mApnSetting;
@@ -235,6 +272,8 @@
@Override
public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeInt(mTransportType);
+ out.writeInt(mId);
out.writeInt(mState);
out.writeInt(mNetworkType);
out.writeParcelable(mLinkProperties, flags);
@@ -256,7 +295,8 @@
@Override
public int hashCode() {
- return Objects.hash(mState, mNetworkType, mFailCause, mLinkProperties, mApnSetting);
+ return Objects.hash(mTransportType, mId, mState, mNetworkType, mFailCause,
+ mLinkProperties, mApnSetting);
}
@@ -265,7 +305,9 @@
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PreciseDataConnectionState that = (PreciseDataConnectionState) o;
- return mState == that.mState
+ return mTransportType == that.mTransportType
+ && mId == that.mId
+ && mState == that.mState
&& mNetworkType == that.mNetworkType
&& mFailCause == that.mFailCause
&& Objects.equals(mLinkProperties, that.mLinkProperties)
@@ -277,14 +319,14 @@
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append("Data Connection state: " + mState);
- sb.append(", Network type: " + mNetworkType);
- sb.append(", APN types: " + ApnSetting.getApnTypesStringFromBitmask(
- getDataConnectionApnTypeBitMask()));
- sb.append(", APN: " + getDataConnectionApn());
- sb.append(", Link properties: " + mLinkProperties);
- sb.append(", Fail cause: " + DataFailCause.toString(mFailCause));
- sb.append(", Apn Setting: " + mApnSetting);
+ sb.append(" state: " + TelephonyUtils.dataStateToString(mState));
+ sb.append(", transport: "
+ + AccessNetworkConstants.transportTypeToString(mTransportType));
+ sb.append(", id: " + mId);
+ sb.append(", network type: " + TelephonyManager.getNetworkTypeName(mNetworkType));
+ sb.append(", APN Setting: " + mApnSetting);
+ sb.append(", link properties: " + mLinkProperties);
+ sb.append(", fail cause: " + DataFailCause.toString(mFailCause));
return sb.toString();
}
@@ -295,6 +337,15 @@
* @hide
*/
public static final class Builder {
+ /** The transport type of the data connection */
+ private @TransportType int mTransportType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
+
+ /**
+ * The unique ID of the data connection. This is the id assigned in
+ * {@link DataCallResponse)}.
+ */
+ private int mId = -1;
+
/** The state of the data connection */
private @DataState int mState = TelephonyManager.DATA_UNKNOWN;
@@ -314,12 +365,34 @@
private @Nullable ApnSetting mApnSetting = null;
/**
+ * Set the transport type of the data connection.
+ *
+ * @param transportType The transport type of the data connection
+ * @return The builder
+ */
+ public @NonNull Builder setTransportType(@TransportType int transportType) {
+ mTransportType = transportType;
+ return this;
+ }
+
+ /**
+ * Set the id of the data connection.
+ *
+ * @param id The id of the data connection
+ * @return The builder
+ */
+ public @NonNull Builder setId(int id) {
+ mId = id;
+ return this;
+ }
+
+ /**
* Set the state of the data connection.
*
* @param state The state of the data connection
* @return The builder
*/
- public Builder setState(@DataState int state) {
+ public @NonNull Builder setState(@DataState int state) {
mState = state;
return this;
}
@@ -330,7 +403,7 @@
* @param networkType The network type
* @return The builder
*/
- public Builder setNetworkType(@NetworkType int networkType) {
+ public @NonNull Builder setNetworkType(@NetworkType int networkType) {
mNetworkType = networkType;
return this;
}
@@ -341,7 +414,7 @@
* @param linkProperties Link properties
* @return The builder
*/
- public Builder setLinkProperties(@NonNull LinkProperties linkProperties) {
+ public @NonNull Builder setLinkProperties(LinkProperties linkProperties) {
mLinkProperties = linkProperties;
return this;
}
@@ -353,7 +426,7 @@
* error code indicating the cause of the failure.
* @return The builder
*/
- public Builder setFailCause(@DataFailureCause int failCause) {
+ public @NonNull Builder setFailCause(@DataFailureCause int failCause) {
mFailCause = failCause;
return this;
}
@@ -364,7 +437,7 @@
* @param apnSetting APN setting
* @return This builder
*/
- public Builder setApnSetting(@NonNull ApnSetting apnSetting) {
+ public @NonNull Builder setApnSetting(@NonNull ApnSetting apnSetting) {
mApnSetting = apnSetting;
return this;
}
@@ -375,8 +448,8 @@
* @return The {@link PreciseDataConnectionState} instance
*/
public PreciseDataConnectionState build() {
- return new PreciseDataConnectionState(mState, mNetworkType, mLinkProperties, mFailCause,
- mApnSetting);
+ return new PreciseDataConnectionState(mTransportType, mId, mState, mNetworkType,
+ mLinkProperties, mFailCause, mApnSetting);
}
}
}
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index e60ae89..ff9329e 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1214,12 +1214,16 @@
return false;
}
- // TODO - if we have this function we should also have hashCode.
- // Also should handle changes in type order and perhaps case-insensitivity.
+ @Override
+ public int hashCode() {
+ return Objects.hash(mApnName, mProxyAddress, mProxyPort, mMmsc, mMmsProxyAddress,
+ mMmsProxyPort, mUser, mPassword, mAuthType, mApnTypeBitmask, mId, mOperatorNumeric,
+ mProtocol, mRoamingProtocol, mMtu, mCarrierEnabled, mNetworkTypeBitmask, mProfileId,
+ mPersistent, mMaxConns, mWaitTime, mMaxConnsTime, mMvnoType, mMvnoMatchData,
+ mApnSetId, mCarrierId, mSkip464Xlat);
+ }
- /**
- * @hide
- */
+ @Override
public boolean equals(Object o) {
if (o instanceof ApnSetting == false) {
return false;
diff --git a/test-runner/src/android/test/AndroidTestRunner.java b/test-runner/src/android/test/AndroidTestRunner.java
index f898516..b2fdc50 100644
--- a/test-runner/src/android/test/AndroidTestRunner.java
+++ b/test-runner/src/android/test/AndroidTestRunner.java
@@ -125,7 +125,7 @@
} catch (IllegalArgumentException e) {
runFailed("Illegal argument passed to constructor. Class: " + testClass.getName());
} catch (InvocationTargetException e) {
- runFailed("Constructor thew an exception. Class: " + testClass.getName());
+ runFailed("Constructor threw an exception. Class: " + testClass.getName());
}
return null;
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index 2e4d390..c0658fe 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -84,7 +84,7 @@
navBarLayerIsAlwaysVisible(bugId = 140855415)
statusBarLayerIsAlwaysVisible(bugId = 140855415)
noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false)
- navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0)
+ navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0, bugId = 140855415)
statusBarLayerRotatesScales(rotation, Surface.ROTATION_0)
imeLayerBecomesInvisible(bugId = 141458352)
imeAppLayerBecomesInvisible(testApp, bugId = 153739621)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index 1c0da4f..dcf3085 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -92,7 +92,7 @@
navBarLayerIsAlwaysVisible(bugId = 140855415)
statusBarLayerIsAlwaysVisible(bugId = 140855415)
noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false)
- navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0)
+ navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0, bugId = 140855415)
statusBarLayerRotatesScales(rotation, Surface.ROTATION_0)
imeLayerBecomesInvisible(bugId = 153739621)
imeAppLayerBecomesInvisible(testApp, bugId = 153739621)
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 e078f26..91ec211 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
@@ -90,7 +90,7 @@
navBarLayerIsAlwaysVisible()
statusBarLayerIsAlwaysVisible()
noUncoveredRegions(rotation)
- navBarLayerRotatesAndScales(rotation)
+ navBarLayerRotatesAndScales(rotation, bugId = 140855415)
statusBarLayerRotatesScales(rotation)
all("dividerLayerBecomesVisible") {
@@ -102,7 +102,8 @@
eventLog {
focusChanges(testApp.`package`,
- "recents_animation_input_consumer", "NexusLauncherActivity")
+ "recents_animation_input_consumer", "NexusLauncherActivity",
+ bugId = 151179149)
}
}
}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
index 51bae3a..08144c8 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
@@ -60,7 +60,7 @@
static final String sSkSL =
"uniform float param1;\n"
- + "void main(float x, float y, inout half4 color) {\n"
+ + "void main(float2 xy, inout half4 color) {\n"
+ "color = half4(color.r, half(param1), color.b, 1.0);\n"
+ "}\n";
diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp
new file mode 100644
index 0000000..9d35cbc
--- /dev/null
+++ b/tests/Input/Android.bp
@@ -0,0 +1,12 @@
+android_test {
+ name: "InputTests",
+ srcs: ["src/**/*.kt"],
+ platform_apis: true,
+ certificate: "platform",
+ static_libs: [
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+ "android-support-test",
+ "ub-uiautomator",
+ ],
+}
diff --git a/tests/Input/AndroidManifest.xml b/tests/Input/AndroidManifest.xml
new file mode 100644
index 0000000..4195df7
--- /dev/null
+++ b/tests/Input/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.input">
+ <uses-permission android:name="android.permission.MONITOR_INPUT"/>
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
+ <uses-permission android:name="android.permission.INJECT_EVENTS"/>
+
+ <application android:label="InputTest">
+
+ <activity android:name=".UnresponsiveGestureMonitorActivity"
+ android:label="Unresponsive gesture monitor"
+ android:process=":externalProcess">
+ </activity>
+
+
+ </application>
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.test.input"
+ android:label="Input Tests"/>
+</manifest>
diff --git a/tests/Input/AndroidTest.xml b/tests/Input/AndroidTest.xml
new file mode 100644
index 0000000..c62db1ea
--- /dev/null
+++ b/tests/Input/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright 2020 Google Inc. All Rights Reserved.
+ -->
+<configuration description="Runs Input Tests">
+ <option name="test-tag" value="InputTests" />
+ <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" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true"/>
+ <option name="test-file-name" value="InputTests.apk"/>
+
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.test.input"/>
+ <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
+ <option name="shell-timeout" value="660s" />
+ <option name="test-timeout" value="600s" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
diff --git a/tests/Input/src/com/android/test/input/AnrTest.kt b/tests/Input/src/com/android/test/input/AnrTest.kt
new file mode 100644
index 0000000..4da3eca
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/AnrTest.kt
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.input
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.filters.MediumTest
+
+import android.graphics.Rect
+import android.os.SystemClock
+import android.provider.Settings
+import android.provider.Settings.Global.HIDE_ERROR_DIALOGS
+import android.support.test.uiautomator.By
+import android.support.test.uiautomator.UiDevice
+import android.support.test.uiautomator.UiObject2
+import android.support.test.uiautomator.Until
+import android.view.InputDevice
+import android.view.MotionEvent
+
+import org.junit.After
+import org.junit.Assert.fail
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * This test makes sure that an unresponsive gesture monitor gets an ANR.
+ *
+ * The gesture monitor must be registered from a different process than the instrumented process.
+ * Otherwise, when the test runs, you will get:
+ * Test failed to run to completion.
+ * Reason: 'Instrumentation run failed due to 'keyDispatchingTimedOut''.
+ * Check device logcat for details
+ * RUNNER ERROR: Instrumentation run failed due to 'keyDispatchingTimedOut'
+ */
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class AnrTest {
+ companion object {
+ private const val TAG = "AnrTest"
+ }
+
+ val mInstrumentation = InstrumentationRegistry.getInstrumentation()
+ var mHideErrorDialogs = 0
+
+ @Before
+ fun setUp() {
+ val contentResolver = mInstrumentation.targetContext.contentResolver
+ mHideErrorDialogs = Settings.Global.getInt(contentResolver, HIDE_ERROR_DIALOGS, 0)
+ Settings.Global.putInt(contentResolver, HIDE_ERROR_DIALOGS, 0)
+ }
+
+ @After
+ fun tearDown() {
+ val contentResolver = mInstrumentation.targetContext.contentResolver
+ Settings.Global.putInt(contentResolver, HIDE_ERROR_DIALOGS, mHideErrorDialogs)
+ }
+
+ @Test
+ fun testGestureMonitorAnr() {
+ startUnresponsiveActivity()
+ val uiDevice: UiDevice = UiDevice.getInstance(mInstrumentation)
+ val obj: UiObject2? = uiDevice.wait(Until.findObject(
+ By.text("Unresponsive gesture monitor")), 10000)
+
+ if (obj == null) {
+ fail("Could not find unresponsive activity")
+ return
+ }
+
+ val rect: Rect = obj.visibleBounds
+ val downTime = SystemClock.uptimeMillis()
+ val downEvent = MotionEvent.obtain(downTime, downTime,
+ MotionEvent.ACTION_DOWN, rect.left.toFloat(), rect.top.toFloat(), 0 /* metaState */)
+ downEvent.source = InputDevice.SOURCE_TOUCHSCREEN
+
+ mInstrumentation.uiAutomation.injectInputEvent(downEvent, false /* sync*/)
+
+ // Todo: replace using timeout from android.hardware.input.IInputManager
+ SystemClock.sleep(5000) // default ANR timeout for gesture monitors
+
+ clickCloseAppOnAnrDialog()
+ }
+
+ private fun clickCloseAppOnAnrDialog() {
+ // Find anr dialog and kill app
+ val uiDevice: UiDevice = UiDevice.getInstance(mInstrumentation)
+ val closeAppButton: UiObject2? =
+ uiDevice.wait(Until.findObject(By.res("android:id/aerr_close")), 20000)
+ if (closeAppButton == null) {
+ fail("Could not find anr dialog")
+ return
+ }
+ closeAppButton.click()
+ }
+
+ private fun startUnresponsiveActivity() {
+ val flags = " -W -n "
+ val startCmd = "am start $flags com.android.test.input/.UnresponsiveGestureMonitorActivity"
+ mInstrumentation.uiAutomation.executeShellCommand(startCmd)
+ }
+}
\ No newline at end of file
diff --git a/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt b/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt
new file mode 100644
index 0000000..d83a457
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.input
+
+import android.app.Activity
+import android.hardware.input.InputManager
+import android.os.Bundle
+import android.os.Looper
+import android.util.Log
+import android.view.InputChannel
+import android.view.InputEvent
+import android.view.InputEventReceiver
+import android.view.InputMonitor
+
+class UnresponsiveReceiver(channel: InputChannel, looper: Looper) :
+ InputEventReceiver(channel, looper) {
+ companion object {
+ const val TAG = "UnresponsiveReceiver"
+ }
+ override fun onInputEvent(event: InputEvent) {
+ Log.i(TAG, "Received $event")
+ // Not calling 'finishInputEvent' in order to trigger the ANR
+ }
+}
+
+class UnresponsiveGestureMonitorActivity : Activity() {
+ companion object {
+ const val MONITOR_NAME = "unresponsive gesture monitor"
+ }
+ private lateinit var mInputEventReceiver: InputEventReceiver
+ private lateinit var mInputMonitor: InputMonitor
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ mInputMonitor = InputManager.getInstance().monitorGestureInput(MONITOR_NAME, displayId)
+ mInputEventReceiver = UnresponsiveReceiver(
+ mInputMonitor.getInputChannel(), Looper.myLooper())
+ }
+}
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index da6018e..530d0e4 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -29,6 +29,7 @@
"compatibility-tradefed",
"frameworks-base-hostutils",
"module_test_util",
+ "cts-install-lib-host",
],
data: [
":com.android.apex.cts.shim.v2_prebuilt",
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 7cfbdc2..5285b04 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -22,6 +22,7 @@
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
+import com.android.cts.install.lib.host.InstallUtilsHost;
import com.android.ddmlib.Log;
import com.android.tests.rollback.host.AbandonSessionsRule;
import com.android.tests.util.ModuleTestUtils;
@@ -49,6 +50,7 @@
private static final String APK_A = "TestAppAv1.apk";
private final ModuleTestUtils mTestUtils = new ModuleTestUtils(this);
+ private final InstallUtilsHost mHostUtils = new InstallUtilsHost(this);
/**
* Runs the given phase of a test by calling into the device.
@@ -93,7 +95,7 @@
@Test
public void testAdbStagedInstallWaitForReadyFlagWorks() throws Exception {
assumeTrue("Device does not support updating APEX",
- mTestUtils.isApexUpdateSupported());
+ mHostUtils.isApexUpdateSupported());
File apexFile = mTestUtils.getTestFile(SHIM_V2);
String output = getDevice().executeAdbCommand("install", "--staged",
@@ -107,7 +109,7 @@
@Test
public void testAdbStagedInstallNoWaitFlagWorks() throws Exception {
assumeTrue("Device does not support updating APEX",
- mTestUtils.isApexUpdateSupported());
+ mHostUtils.isApexUpdateSupported());
File apexFile = mTestUtils.getTestFile(SHIM_V2);
String output = getDevice().executeAdbCommand("install", "--staged",
@@ -122,7 +124,7 @@
@Test
public void testAdbInstallMultiPackageCommandWorks() throws Exception {
assumeTrue("Device does not support updating APEX",
- mTestUtils.isApexUpdateSupported());
+ mHostUtils.isApexUpdateSupported());
File apexFile = mTestUtils.getTestFile(SHIM_V2);
File apkFile = mTestUtils.getTestFile(APK_A);
diff --git a/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
index f30c35a..c2a5459 100644
--- a/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
+++ b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
@@ -34,6 +34,8 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import javax.annotation.Nullable;
@@ -49,7 +51,7 @@
public class SystemPreparer extends ExternalResource {
private static final long OVERLAY_ENABLE_TIMEOUT_MS = 30000;
- // The paths of the files pushed onto the device through this rule.
+ // The paths of the files pushed onto the device through this rule to be removed after.
private ArrayList<String> mPushedFiles = new ArrayList<>();
// The package names of packages installed through this rule.
@@ -81,7 +83,7 @@
final ITestDevice device = mDeviceProvider.getDevice();
remount();
assertTrue(device.pushFile(copyResourceToTemp(filePath), outputPath));
- mPushedFiles.add(outputPath);
+ addPushedFile(device, outputPath);
return this;
}
@@ -91,10 +93,23 @@
final ITestDevice device = mDeviceProvider.getDevice();
remount();
assertTrue(device.pushFile(file, outputPath));
- mPushedFiles.add(outputPath);
+ addPushedFile(device, outputPath);
return this;
}
+ private void addPushedFile(ITestDevice device, String outputPath)
+ throws DeviceNotAvailableException {
+ Path pathCreated = Paths.get(outputPath);
+
+ // Find the top most parent that is new to the device
+ while (pathCreated.getParent() != null
+ && !device.doesFileExist(pathCreated.getParent().toString())) {
+ pathCreated = pathCreated.getParent();
+ }
+
+ mPushedFiles.add(pathCreated.toString());
+ }
+
/** Deletes the given path from the device */
public SystemPreparer deleteFile(String file) throws DeviceNotAvailableException {
final ITestDevice device = mDeviceProvider.getDevice();
@@ -203,7 +218,7 @@
/** Removes installed packages and files that were pushed to the device. */
@Override
- protected void after() {
+ public void after() {
final ITestDevice device = mDeviceProvider.getDevice();
try {
remount();
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index d210184..2830249 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -15,8 +15,6 @@
#include "native_writer.h"
#include "utils.h"
-using namespace google::protobuf;
-
namespace android {
namespace stats_log_api_gen {
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 3cdfb00..e493789 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -122,7 +122,7 @@
DhcpInfo getDhcpInfo();
- void setScanAlwaysAvailable(boolean isAvailable);
+ void setScanAlwaysAvailable(boolean isAvailable, String packageName);
boolean isScanAlwaysAvailable();
@@ -142,9 +142,9 @@
void updateInterfaceIpState(String ifaceName, int mode);
- boolean startSoftAp(in WifiConfiguration wifiConfig);
+ boolean startSoftAp(in WifiConfiguration wifiConfig, String packageName);
- boolean startTetheredHotspot(in SoftApConfiguration softApConfig);
+ boolean startTetheredHotspot(in SoftApConfiguration softApConfig, String packageName);
boolean stopSoftAp();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index ae834f9..b28b902 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2802,7 +2802,7 @@
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void setScanAlwaysAvailable(boolean isAvailable) {
try {
- mService.setScanAlwaysAvailable(isAvailable);
+ mService.setScanAlwaysAvailable(isAvailable, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3035,7 +3035,7 @@
})
public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) {
try {
- return mService.startSoftAp(wifiConfig);
+ return mService.startSoftAp(wifiConfig, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3059,7 +3059,7 @@
})
public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig) {
try {
- return mService.startTetheredHotspot(softApConfig);
+ return mService.startTetheredHotspot(softApConfig, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index cba1690..e7f1916c 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -218,10 +218,10 @@
*/
@Test
public void testStartSoftApCallsServiceWithWifiConfig() throws Exception {
- when(mWifiService.startSoftAp(eq(mApConfig))).thenReturn(true);
+ when(mWifiService.startSoftAp(mApConfig, TEST_PACKAGE_NAME)).thenReturn(true);
assertTrue(mWifiManager.startSoftAp(mApConfig));
- when(mWifiService.startSoftAp(eq(mApConfig))).thenReturn(false);
+ when(mWifiService.startSoftAp(mApConfig, TEST_PACKAGE_NAME)).thenReturn(false);
assertFalse(mWifiManager.startSoftAp(mApConfig));
}
@@ -231,10 +231,10 @@
*/
@Test
public void testStartSoftApCallsServiceWithNullConfig() throws Exception {
- when(mWifiService.startSoftAp(eq(null))).thenReturn(true);
+ when(mWifiService.startSoftAp(null, TEST_PACKAGE_NAME)).thenReturn(true);
assertTrue(mWifiManager.startSoftAp(null));
- when(mWifiService.startSoftAp(eq(null))).thenReturn(false);
+ when(mWifiService.startSoftAp(null, TEST_PACKAGE_NAME)).thenReturn(false);
assertFalse(mWifiManager.startSoftAp(null));
}
@@ -257,10 +257,12 @@
@Test
public void testStartTetheredHotspotCallsServiceWithSoftApConfig() throws Exception {
SoftApConfiguration softApConfig = generatorTestSoftApConfig();
- when(mWifiService.startTetheredHotspot(eq(softApConfig))).thenReturn(true);
+ when(mWifiService.startTetheredHotspot(softApConfig, TEST_PACKAGE_NAME))
+ .thenReturn(true);
assertTrue(mWifiManager.startTetheredHotspot(softApConfig));
- when(mWifiService.startTetheredHotspot(eq(softApConfig))).thenReturn(false);
+ when(mWifiService.startTetheredHotspot(softApConfig, TEST_PACKAGE_NAME))
+ .thenReturn(false);
assertFalse(mWifiManager.startTetheredHotspot(softApConfig));
}
@@ -270,10 +272,10 @@
*/
@Test
public void testStartTetheredHotspotCallsServiceWithNullConfig() throws Exception {
- when(mWifiService.startTetheredHotspot(eq(null))).thenReturn(true);
+ when(mWifiService.startTetheredHotspot(null, TEST_PACKAGE_NAME)).thenReturn(true);
assertTrue(mWifiManager.startTetheredHotspot(null));
- when(mWifiService.startTetheredHotspot(eq(null))).thenReturn(false);
+ when(mWifiService.startTetheredHotspot(null, TEST_PACKAGE_NAME)).thenReturn(false);
assertFalse(mWifiManager.startTetheredHotspot(null));
}
@@ -2375,7 +2377,7 @@
@Test
public void testScanAvailable() throws Exception {
mWifiManager.setScanAlwaysAvailable(true);
- verify(mWifiService).setScanAlwaysAvailable(true);
+ verify(mWifiService).setScanAlwaysAvailable(true, TEST_PACKAGE_NAME);
when(mWifiService.isScanAlwaysAvailable()).thenReturn(false);
assertFalse(mWifiManager.isScanAlwaysAvailable());