Merge "Add inline actions to the response to IME. Use inline style from the IME request in the response."
diff --git a/Android.bp b/Android.bp
index 5796fb1..12bc906 100644
--- a/Android.bp
+++ b/Android.bp
@@ -653,6 +653,33 @@
output_extension: "srcjar",
}
+gensrcs {
+ name: "framework-cppstream-protos",
+ depfile: true,
+
+ tools: [
+ "aprotoc",
+ "protoc-gen-cppstream",
+ ],
+
+ cmd: "mkdir -p $(genDir) " +
+ "&& $(location aprotoc) " +
+ " --plugin=$(location protoc-gen-cppstream) " +
+ " --dependency_out=$(depfile) " +
+ " --cppstream_out=$(genDir) " +
+ " -Iexternal/protobuf/src " +
+ " -I . " +
+ " $(in)",
+
+ srcs: [
+ ":ipconnectivity-proto-src",
+ "core/proto/**/*.proto",
+ "libs/incident/**/*.proto",
+ ],
+
+ output_extension: "proto.h",
+}
+
filegroup {
name: "framework-annotations",
srcs: [
@@ -1010,43 +1037,6 @@
},
}
-gensrcs {
- name: "gen-platform-proto-constants",
- depfile: true,
-
- tools: [
- "aprotoc",
- "protoc-gen-cppstream",
- ],
-
- srcs: [
- "core/proto/android/os/backtrace.proto",
- "core/proto/android/os/batterytype.proto",
- "core/proto/android/os/cpufreq.proto",
- "core/proto/android/os/cpuinfo.proto",
- "core/proto/android/os/data.proto",
- "core/proto/android/os/kernelwake.proto",
- "core/proto/android/os/pagetypeinfo.proto",
- "core/proto/android/os/procrank.proto",
- "core/proto/android/os/ps.proto",
- "core/proto/android/os/system_properties.proto",
- "core/proto/android/util/event_log_tags.proto",
- "core/proto/android/util/log.proto",
- ],
-
- // Append protoc-gen-cppstream tool's PATH otherwise aprotoc can't find the plugin tool
- cmd: "mkdir -p $(genDir) " +
- "&& $(location aprotoc) " +
- " --plugin=$(location protoc-gen-cppstream) " +
- " --dependency_out=$(depfile) " +
- " --cppstream_out=$(genDir) " +
- " -Iexternal/protobuf/src " +
- " -I . " +
- " $(in)",
-
- output_extension: "proto.h",
-}
-
subdirs = [
"cmds/*",
diff --git a/apct-tests/perftests/blobstore/Android.bp b/apct-tests/perftests/blobstore/Android.bp
new file mode 100644
index 0000000..be5072c
--- /dev/null
+++ b/apct-tests/perftests/blobstore/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "BlobStorePerfTests",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "BlobStoreTestUtils",
+ "androidx.test.rules",
+ "androidx.annotation_annotation",
+ "apct-perftests-utils",
+ "ub-uiautomator",
+ ],
+ platform_apis: true,
+ test_suites: ["device-tests"],
+ certificate: "platform",
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/blobstore/AndroidManifest.xml b/apct-tests/perftests/blobstore/AndroidManifest.xml
new file mode 100644
index 0000000..21d0726
--- /dev/null
+++ b/apct-tests/perftests/blobstore/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.perftests.blob">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.perftests.blob"/>
+
+</manifest>
\ No newline at end of file
diff --git a/apct-tests/perftests/blobstore/AndroidTest.xml b/apct-tests/perftests/blobstore/AndroidTest.xml
new file mode 100644
index 0000000..19456c6
--- /dev/null
+++ b/apct-tests/perftests/blobstore/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs BlobStorePerfTests 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="BlobStorePerfTests.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.perftests.blob" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/AtraceUtils.java b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/AtraceUtils.java
new file mode 100644
index 0000000..0208dab
--- /dev/null
+++ b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/AtraceUtils.java
@@ -0,0 +1,120 @@
+/*
+ * 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.perftests.blob;
+
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.os.ParcelFileDescriptor;
+import android.perftests.utils.TraceMarkParser;
+import android.perftests.utils.TraceMarkParser.TraceMarkSlice;
+import android.support.test.uiautomator.UiDevice;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.List;
+import java.util.function.BiConsumer;
+
+// Copy of com.android.frameworks.perftests.am.util.AtraceUtils. TODO: avoid this duplication.
+public class AtraceUtils {
+ private static final String TAG = "AtraceUtils";
+ private static final boolean VERBOSE = true;
+
+ private static final String ATRACE_START = "atrace --async_start -b %d -c %s";
+ private static final String ATRACE_DUMP = "atrace --async_dump";
+ private static final String ATRACE_STOP = "atrace --async_stop";
+ private static final int DEFAULT_ATRACE_BUF_SIZE = 1024;
+
+ private UiAutomation mAutomation;
+ private static AtraceUtils sUtils = null;
+ private boolean mStarted = false;
+
+ private AtraceUtils(Instrumentation instrumentation) {
+ mAutomation = instrumentation.getUiAutomation();
+ }
+
+ public static AtraceUtils getInstance(Instrumentation instrumentation) {
+ if (sUtils == null) {
+ sUtils = new AtraceUtils(instrumentation);
+ }
+ return sUtils;
+ }
+
+ /**
+ * @param categories The list of the categories to trace, separated with space.
+ */
+ public void startTrace(String categories) {
+ synchronized (this) {
+ if (mStarted) {
+ throw new IllegalStateException("atrace already started");
+ }
+ runShellCommand(String.format(
+ ATRACE_START, DEFAULT_ATRACE_BUF_SIZE, categories));
+ mStarted = true;
+ }
+ }
+
+ public void stopTrace() {
+ synchronized (this) {
+ mStarted = false;
+ runShellCommand(ATRACE_STOP);
+ }
+ }
+
+ private String runShellCommand(String cmd) {
+ try {
+ return UiDevice.getInstance(
+ InstrumentationRegistry.getInstrumentation()).executeShellCommand(cmd);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * @param parser The function that can accept the buffer of atrace dump and parse it.
+ * @param handler The parse result handler
+ */
+ public void performDump(TraceMarkParser parser,
+ BiConsumer<String, List<TraceMarkSlice>> handler) {
+ parser.reset();
+ try {
+ if (VERBOSE) {
+ Log.i(TAG, "Collecting atrace dump...");
+ }
+ writeDataToBuf(mAutomation.executeShellCommand(ATRACE_DUMP), parser);
+ } catch (IOException e) {
+ Log.e(TAG, "Error in reading dump", e);
+ }
+ parser.forAllSlices(handler);
+ }
+
+ // The given file descriptor here will be closed by this function
+ private void writeDataToBuf(ParcelFileDescriptor pfDescriptor,
+ TraceMarkParser parser) throws IOException {
+ InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfDescriptor);
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ parser.visit(line);
+ }
+ }
+ }
+}
diff --git a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java
new file mode 100644
index 0000000..8e0ea98
--- /dev/null
+++ b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java
@@ -0,0 +1,146 @@
+/*
+ * 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.perftests.blob;
+
+import android.app.blob.BlobStoreManager;
+import android.content.Context;
+import android.perftests.utils.ManualBenchmarkState;
+import android.perftests.utils.PerfManualStatusReporter;
+import android.perftests.utils.TraceMarkParser;
+import android.perftests.utils.TraceMarkParser.TraceMarkSlice;
+import android.support.test.uiautomator.UiDevice;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.utils.blob.DummyBlobData;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+@LargeTest
+@RunWith(Parameterized.class)
+public class BlobStorePerfTests {
+ // From frameworks/native/cmds/atrace/atrace.cpp
+ private static final String ATRACE_CATEGORY_SYSTEM_SERVER = "ss";
+ // From f/b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
+ private static final String ATRACE_COMPUTE_DIGEST_PREFIX = "computeBlobDigest-";
+
+ private Context mContext;
+ private BlobStoreManager mBlobStoreManager;
+ private AtraceUtils mAtraceUtils;
+ private ManualBenchmarkState mState;
+
+ @Rule
+ public PerfManualStatusReporter mPerfManualStatusReporter = new PerfManualStatusReporter();
+
+ @Parameterized.Parameter(0)
+ public int fileSizeInMb;
+
+ @Parameterized.Parameters(name = "{0}MB")
+ public static Collection<Object[]> getParameters() {
+ return Arrays.asList(new Object[][] {
+ { 25 },
+ { 50 },
+ { 100 },
+ { 200 },
+ });
+ }
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ mBlobStoreManager = (BlobStoreManager) mContext.getSystemService(
+ Context.BLOB_STORE_SERVICE);
+ mAtraceUtils = AtraceUtils.getInstance(InstrumentationRegistry.getInstrumentation());
+ mState = mPerfManualStatusReporter.getBenchmarkState();
+ }
+
+ @After
+ public void tearDown() {
+ // TODO: Add a blob_store shell command to trigger idle maintenance to avoid hardcoding
+ // job id like this.
+ // From BlobStoreConfig.IDLE_JOB_ID = 191934935.
+ runShellCommand("cmd jobscheduler run -f android 191934935");
+ }
+
+ @Test
+ public void testComputeDigest() throws Exception {
+ mAtraceUtils.startTrace(ATRACE_CATEGORY_SYSTEM_SERVER);
+ try {
+ final List<Long> durations = new ArrayList<>();
+ final DummyBlobData blobData = prepareDataBlob(fileSizeInMb);
+ final TraceMarkParser parser = new TraceMarkParser(
+ line -> line.name.startsWith(ATRACE_COMPUTE_DIGEST_PREFIX));
+ while (mState.keepRunning(durations)) {
+ commitBlob(blobData);
+
+ durations.clear();
+ collectDigestDurationsFromTrace(parser, durations);
+ // TODO: get and delete blobId before next iteration.
+ }
+ } finally {
+ mAtraceUtils.stopTrace();
+ }
+ }
+
+ private void collectDigestDurationsFromTrace(TraceMarkParser parser, List<Long> durations) {
+ mAtraceUtils.performDump(parser, (key, slices) -> {
+ for (TraceMarkSlice slice : slices) {
+ durations.add(TimeUnit.MICROSECONDS.toNanos(slice.getDurationInMicroseconds()));
+ }
+ });
+ }
+
+ private DummyBlobData prepareDataBlob(int fileSizeInMb) throws Exception {
+ final DummyBlobData blobData = new DummyBlobData(mContext,
+ fileSizeInMb * 1024 * 1024 /* bytes */);
+ blobData.prepare();
+ return blobData;
+ }
+
+ private void commitBlob(DummyBlobData blobData) throws Exception {
+ final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
+ try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
+ blobData.writeToSession(session);
+ final CompletableFuture<Integer> callback = new CompletableFuture<>();
+ session.commit(mContext.getMainExecutor(), callback::complete);
+ // Ignore commit callback result.
+ callback.get();
+ }
+ }
+
+ private String runShellCommand(String cmd) {
+ try {
+ return UiDevice.getInstance(
+ InstrumentationRegistry.getInstrumentation()).executeShellCommand(cmd);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassificationManagerPerfTest.java b/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassificationManagerPerfTest.java
index bd3b673..f61ea85 100644
--- a/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassificationManagerPerfTest.java
+++ b/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassificationManagerPerfTest.java
@@ -18,35 +18,60 @@
import android.content.Context;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
-import android.perftests.utils.SettingsHelper;
-import android.provider.Settings;
+import android.provider.DeviceConfig;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
@LargeTest
public class TextClassificationManagerPerfTest {
+ private static final String WRITE_DEVICE_CONFIG_PERMISSION =
+ "android.permission.WRITE_DEVICE_CONFIG";
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ private String mOriginalSystemTextclassifierStatus;
+
+ @BeforeClass
+ public static void setUpClass() {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity(
+ WRITE_DEVICE_CONFIG_PERMISSION);
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ InstrumentationRegistry
+ .getInstrumentation()
+ .getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+
+ @Before
+ public void setUp() {
+ // Saves config original value.
+ mOriginalSystemTextclassifierStatus = DeviceConfig.getProperty(
+ DeviceConfig.NAMESPACE_TEXTCLASSIFIER, "system_textclassifier_enabled");
+ }
+
@After
public void tearDown() {
- SettingsHelper.delete(
- SettingsHelper.NAMESPACE_GLOBAL, Settings.Global.TEXT_CLASSIFIER_CONSTANTS);
+ // Restores config original value.
+ enableSystemTextclassifier(mOriginalSystemTextclassifierStatus);
}
@Test
public void testGetTextClassifier_systemTextClassifierDisabled() {
Context context = InstrumentationRegistry.getTargetContext();
- SettingsHelper.set(
- SettingsHelper.NAMESPACE_GLOBAL,
- Settings.Global.TEXT_CLASSIFIER_CONSTANTS,
- "system_textclassifier_enabled=false");
+ enableSystemTextclassifier(String.valueOf(false));
TextClassificationManager textClassificationManager =
context.getSystemService(TextClassificationManager.class);
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
@@ -59,10 +84,7 @@
@Test
public void testGetTextClassifier_systemTextClassifierEnabled() {
Context context = InstrumentationRegistry.getTargetContext();
- SettingsHelper.set(
- SettingsHelper.NAMESPACE_GLOBAL,
- Settings.Global.TEXT_CLASSIFIER_CONSTANTS,
- "system_textclassifier_enabled=true");
+ enableSystemTextclassifier(String.valueOf(true));
TextClassificationManager textClassificationManager =
context.getSystemService(TextClassificationManager.class);
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
@@ -71,4 +93,9 @@
textClassificationManager.invalidateForTesting();
}
}
+
+ private void enableSystemTextclassifier(String enabled) {
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ "system_textclassifier_enabled", enabled, /* makeDefault */ false);
+ }
}
diff --git a/apex/blobstore/TEST_MAPPING b/apex/blobstore/TEST_MAPPING
index cfe19a5..25a1537 100644
--- a/apex/blobstore/TEST_MAPPING
+++ b/apex/blobstore/TEST_MAPPING
@@ -4,7 +4,7 @@
"name": "CtsBlobStoreTestCases"
},
{
- "name": "FrameworksServicesTests",
+ "name": "FrameworksMockingServicesTests",
"options": [
{
"include-filter": "com.android.server.blob"
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
index f110b36..d339afa 100644
--- a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
+++ b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
@@ -257,6 +257,11 @@
return Base64.encodeToString(digest, Base64.NO_WRAP);
}
+ /** @hide */
+ public boolean isExpired() {
+ return expiryTimeMillis != 0 && expiryTimeMillis < System.currentTimeMillis();
+ }
+
public static final @NonNull Creator<BlobHandle> CREATOR = new Creator<BlobHandle>() {
@Override
public @NonNull BlobHandle createFromParcel(@NonNull Parcel source) {
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
index aba3e8c..c12e0ec 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
@@ -64,9 +64,9 @@
private final Context mContext;
- public final long blobId;
- public final BlobHandle blobHandle;
- public final int userId;
+ private final long mBlobId;
+ private final BlobHandle mBlobHandle;
+ private final int mUserId;
@GuardedBy("mMetadataLock")
private final ArraySet<Committer> mCommitters = new ArraySet<>();
@@ -90,9 +90,21 @@
BlobMetadata(Context context, long blobId, BlobHandle blobHandle, int userId) {
mContext = context;
- this.blobId = blobId;
- this.blobHandle = blobHandle;
- this.userId = userId;
+ this.mBlobId = blobId;
+ this.mBlobHandle = blobHandle;
+ this.mUserId = userId;
+ }
+
+ long getBlobId() {
+ return mBlobId;
+ }
+
+ BlobHandle getBlobHandle() {
+ return mBlobHandle;
+ }
+
+ int getUserId() {
+ return mUserId;
}
void addCommitter(@NonNull Committer committer) {
@@ -159,7 +171,7 @@
boolean hasLeases() {
synchronized (mMetadataLock) {
- return mLeasees.isEmpty();
+ return !mLeasees.isEmpty();
}
}
@@ -196,7 +208,7 @@
File getBlobFile() {
if (mBlobFile == null) {
- mBlobFile = BlobStoreConfig.getBlobFile(blobId);
+ mBlobFile = BlobStoreConfig.getBlobFile(mBlobId);
}
return mBlobFile;
}
@@ -244,7 +256,7 @@
void dump(IndentingPrintWriter fout, DumpArgs dumpArgs) {
fout.println("blobHandle:");
fout.increaseIndent();
- blobHandle.dump(fout, dumpArgs.shouldDumpFull());
+ mBlobHandle.dump(fout, dumpArgs.shouldDumpFull());
fout.decreaseIndent();
fout.println("Committers:");
@@ -274,11 +286,11 @@
void writeToXml(XmlSerializer out) throws IOException {
synchronized (mMetadataLock) {
- XmlUtils.writeLongAttribute(out, ATTR_ID, blobId);
- XmlUtils.writeIntAttribute(out, ATTR_USER_ID, userId);
+ XmlUtils.writeLongAttribute(out, ATTR_ID, mBlobId);
+ XmlUtils.writeIntAttribute(out, ATTR_USER_ID, mUserId);
out.startTag(null, TAG_BLOB_HANDLE);
- blobHandle.writeToXml(out);
+ mBlobHandle.writeToXml(out);
out.endTag(null, TAG_BLOB_HANDLE);
for (int i = 0, count = mCommitters.size(); i < count; ++i) {
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
index eb414b0..ba2e559 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
@@ -18,12 +18,15 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Environment;
+import android.util.Log;
import android.util.Slog;
import java.io.File;
+import java.util.concurrent.TimeUnit;
class BlobStoreConfig {
public static final String TAG = "BlobStore";
+ public static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE);
public static final int CURRENT_XML_VERSION = 1;
@@ -32,6 +35,20 @@
private static final String SESSIONS_INDEX_FILE_NAME = "sessions_index.xml";
private static final String BLOBS_INDEX_FILE_NAME = "blobs_index.xml";
+ /**
+ * Job Id for idle maintenance job ({@link BlobStoreIdleJobService}).
+ */
+ public static final int IDLE_JOB_ID = 0xB70B1D7; // 191934935L
+ /**
+ * Max time period (in millis) between each idle maintenance job run.
+ */
+ public static final long IDLE_JOB_PERIOD_MILLIS = TimeUnit.DAYS.toMillis(1);
+
+ /**
+ * Timeout in millis after which sessions with no updates will be deleted.
+ */
+ public static final long SESSION_EXPIRY_TIMEOUT_MILLIS = TimeUnit.DAYS.toMillis(7);
+
@Nullable
public static File prepareBlobFile(long sessionId) {
final File blobsDir = prepareBlobsDir();
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreIdleJobService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreIdleJobService.java
new file mode 100644
index 0000000..460e776
--- /dev/null
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreIdleJobService.java
@@ -0,0 +1,70 @@
+/*
+ * 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.blob;
+
+import static com.android.server.blob.BlobStoreConfig.IDLE_JOB_ID;
+import static com.android.server.blob.BlobStoreConfig.IDLE_JOB_PERIOD_MILLIS;
+import static com.android.server.blob.BlobStoreConfig.LOGV;
+import static com.android.server.blob.BlobStoreConfig.TAG;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.AsyncTask;
+import android.util.Slog;
+
+import com.android.server.LocalServices;
+
+/**
+ * Maintenance job to clean up stale sessions and blobs.
+ */
+public class BlobStoreIdleJobService extends JobService {
+ @Override
+ public boolean onStartJob(final JobParameters params) {
+ AsyncTask.execute(() -> {
+ final BlobStoreManagerInternal blobStoreManagerInternal = LocalServices.getService(
+ BlobStoreManagerInternal.class);
+ blobStoreManagerInternal.onIdleMaintenance();
+ jobFinished(params, false);
+ });
+ return false;
+ }
+
+ @Override
+ public boolean onStopJob(final JobParameters params) {
+ Slog.d(TAG, "Idle maintenance job is stopped; id=" + params.getJobId()
+ + ", reason=" + JobParameters.getReasonCodeDescription(params.getStopReason()));
+ return false;
+ }
+
+ static void schedule(Context context) {
+ final JobScheduler jobScheduler = (JobScheduler) context.getSystemService(
+ Context.JOB_SCHEDULER_SERVICE);
+ final JobInfo job = new JobInfo.Builder(IDLE_JOB_ID,
+ new ComponentName(context, BlobStoreIdleJobService.class))
+ .setRequiresDeviceIdle(true)
+ .setRequiresCharging(true)
+ .setPeriodic(IDLE_JOB_PERIOD_MILLIS)
+ .build();
+ jobScheduler.schedule(job);
+ if (LOGV) {
+ Slog.v(TAG, "Scheduling the idle maintenance job");
+ }
+ }
+}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerInternal.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerInternal.java
new file mode 100644
index 0000000..5358245
--- /dev/null
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerInternal.java
@@ -0,0 +1,28 @@
+/*
+ * 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.blob;
+
+/**
+ * BlobStoreManager local system service interface.
+ *
+ * Only for use within the system server.
+ */
+public abstract class BlobStoreManagerInternal {
+ /**
+ * Triggered from idle maintenance job to cleanup stale blobs and sessions.
+ */
+ public abstract void onIdleMaintenance();
+}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index 13f095e..0ba34ca 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -28,6 +28,8 @@
import static android.os.UserHandle.USER_NULL;
import static com.android.server.blob.BlobStoreConfig.CURRENT_XML_VERSION;
+import static com.android.server.blob.BlobStoreConfig.LOGV;
+import static com.android.server.blob.BlobStoreConfig.SESSION_EXPIRY_TIMEOUT_MILLIS;
import static com.android.server.blob.BlobStoreConfig.TAG;
import static com.android.server.blob.BlobStoreSession.STATE_ABANDONED;
import static com.android.server.blob.BlobStoreSession.STATE_COMMITTED;
@@ -61,6 +63,7 @@
import android.os.UserHandle;
import android.os.UserManagerInternal;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.ExceptionUtils;
import android.util.LongSparseArray;
@@ -94,8 +97,10 @@
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
/**
* Service responsible for maintaining and facilitating access to data blobs published by apps.
@@ -115,6 +120,10 @@
@GuardedBy("mBlobsLock")
private final SparseArray<ArrayMap<BlobHandle, BlobMetadata>> mBlobsMap = new SparseArray<>();
+ // Contains all ids that are currently in use.
+ @GuardedBy("mBlobsLock")
+ private final ArraySet<Long> mKnownBlobIds = new ArraySet<>();
+
private final Context mContext;
private final Handler mHandler;
private final Injector mInjector;
@@ -151,6 +160,7 @@
@Override
public void onStart() {
publishBinderService(Context.BLOB_STORE_SERVICE, new Stub());
+ LocalServices.addService(BlobStoreManagerInternal.class, new LocalService());
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
registerReceivers();
@@ -164,6 +174,8 @@
readBlobSessionsLocked(allPackages);
readBlobsInfoLocked(allPackages);
}
+ } else if (phase == PHASE_BOOT_COMPLETED) {
+ BlobStoreIdleJobService.schedule(mContext);
}
}
@@ -215,6 +227,40 @@
}
}
+ @VisibleForTesting
+ void addKnownIdsForTest(long... knownIds) {
+ synchronized (mBlobsLock) {
+ for (long id : knownIds) {
+ mKnownBlobIds.add(id);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ Set<Long> getKnownIdsForTest() {
+ synchronized (mBlobsLock) {
+ return mKnownBlobIds;
+ }
+ }
+
+ @GuardedBy("mBlobsLock")
+ private void addSessionForUserLocked(BlobStoreSession session, int userId) {
+ getUserSessionsLocked(userId).put(session.getSessionId(), session);
+ mKnownBlobIds.add(session.getSessionId());
+ }
+
+ @GuardedBy("mBlobsLock")
+ private void addBlobForUserLocked(BlobMetadata blobMetadata, int userId) {
+ addBlobForUserLocked(blobMetadata, getUserBlobsLocked(userId));
+ }
+
+ @GuardedBy("mBlobsLock")
+ private void addBlobForUserLocked(BlobMetadata blobMetadata,
+ ArrayMap<BlobHandle, BlobMetadata> userBlobs) {
+ userBlobs.put(blobMetadata.getBlobHandle(), blobMetadata);
+ mKnownBlobIds.add(blobMetadata.getBlobId());
+ }
+
private long createSessionInternal(BlobHandle blobHandle,
int callingUid, String callingPackage) {
synchronized (mBlobsLock) {
@@ -223,7 +269,11 @@
final BlobStoreSession session = new BlobStoreSession(mContext,
sessionId, blobHandle, callingUid, callingPackage,
mSessionStateChangeListener);
- getUserSessionsLocked(UserHandle.getUserId(callingUid)).put(sessionId, session);
+ addSessionForUserLocked(session, UserHandle.getUserId(callingUid));
+ if (LOGV) {
+ Slog.v(TAG, "Created session for " + blobHandle
+ + "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
+ }
writeBlobSessionsAsync();
return sessionId;
}
@@ -251,7 +301,10 @@
callingUid, callingPackage);
session.open();
session.abandon();
-
+ if (LOGV) {
+ Slog.v(TAG, "Deleted session with id " + sessionId
+ + "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
+ }
writeBlobSessionsAsync();
}
}
@@ -286,6 +339,10 @@
}
blobMetadata.addLeasee(callingPackage, callingUid,
descriptionResId, leaseExpiryTimeMillis);
+ if (LOGV) {
+ Slog.v(TAG, "Acquired lease on " + blobHandle
+ + "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
+ }
writeBlobsInfoAsync();
}
}
@@ -301,6 +358,10 @@
+ "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
}
blobMetadata.removeLeasee(callingPackage, callingUid);
+ if (LOGV) {
+ Slog.v(TAG, "Released lease on " + blobHandle
+ + "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
+ }
writeBlobsInfoAsync();
}
}
@@ -329,6 +390,10 @@
session.getSessionFile().delete();
getUserSessionsLocked(UserHandle.getUserId(session.getOwnerUid()))
.remove(session.getSessionId());
+ mKnownBlobIds.remove(session.getSessionId());
+ if (LOGV) {
+ Slog.v(TAG, "Session is invalid; deleted " + session);
+ }
break;
case STATE_COMMITTED:
session.verifyBlobData();
@@ -340,7 +405,7 @@
if (blob == null) {
blob = new BlobMetadata(mContext,
session.getSessionId(), session.getBlobHandle(), userId);
- userBlobs.put(session.getBlobHandle(), blob);
+ addBlobForUserLocked(blob, userBlobs);
}
final Committer newCommitter = new Committer(session.getOwnerPackageName(),
session.getOwnerUid(), session.getBlobAccessMode());
@@ -355,6 +420,9 @@
}
getUserSessionsLocked(UserHandle.getUserId(session.getOwnerUid()))
.remove(session.getSessionId());
+ if (LOGV) {
+ Slog.v(TAG, "Successfully committed session " + session);
+ }
break;
default:
Slog.wtf(TAG, "Invalid session state: "
@@ -397,6 +465,9 @@
out.endTag(null, TAG_SESSIONS);
out.endDocument();
sessionsIndexFile.finishWrite(fos);
+ if (LOGV) {
+ Slog.v(TAG, "Finished persisting sessions data");
+ }
} catch (Exception e) {
sessionsIndexFile.failWrite(fos);
Slog.wtf(TAG, "Error writing sessions data", e);
@@ -437,8 +508,8 @@
if (userPackages != null
&& session.getOwnerPackageName().equals(
userPackages.get(session.getOwnerUid()))) {
- getUserSessionsLocked(UserHandle.getUserId(session.getOwnerUid())).put(
- session.getSessionId(), session);
+ addSessionForUserLocked(session,
+ UserHandle.getUserId(session.getOwnerUid()));
} else {
// Unknown package or the session data does not belong to this package.
session.getSessionFile().delete();
@@ -446,6 +517,9 @@
mCurrentMaxSessionId = Math.max(mCurrentMaxSessionId, session.getSessionId());
}
}
+ if (LOGV) {
+ Slog.v(TAG, "Finished reading sessions data");
+ }
} catch (Exception e) {
Slog.wtf(TAG, "Error reading sessions data", e);
}
@@ -479,6 +553,9 @@
out.endTag(null, TAG_BLOBS);
out.endDocument();
blobsIndexFile.finishWrite(fos);
+ if (LOGV) {
+ Slog.v(TAG, "Finished persisting blobs data");
+ }
} catch (Exception e) {
blobsIndexFile.failWrite(fos);
Slog.wtf(TAG, "Error writing blobs data", e);
@@ -510,18 +587,21 @@
if (TAG_BLOB.equals(in.getName())) {
final BlobMetadata blobMetadata = BlobMetadata.createFromXml(mContext, in);
- final SparseArray<String> userPackages = allPackages.get(blobMetadata.userId);
+ final SparseArray<String> userPackages = allPackages.get(
+ blobMetadata.getUserId());
if (userPackages == null) {
blobMetadata.getBlobFile().delete();
} else {
- getUserBlobsLocked(blobMetadata.userId).put(
- blobMetadata.blobHandle, blobMetadata);
+ addBlobForUserLocked(blobMetadata, blobMetadata.getUserId());
blobMetadata.removeInvalidCommitters(userPackages);
blobMetadata.removeInvalidLeasees(userPackages);
}
- mCurrentMaxSessionId = Math.max(mCurrentMaxSessionId, blobMetadata.blobId);
+ mCurrentMaxSessionId = Math.max(mCurrentMaxSessionId, blobMetadata.getBlobId());
}
}
+ if (LOGV) {
+ Slog.v(TAG, "Finished reading blobs data");
+ }
} catch (Exception e) {
Slog.wtf(TAG, "Error reading blobs data", e);
}
@@ -614,6 +694,7 @@
if (session.getOwnerUid() == uid
&& session.getOwnerPackageName().equals(packageName)) {
session.getSessionFile().delete();
+ mKnownBlobIds.remove(session.getSessionId());
indicesToRemove.add(i);
}
}
@@ -633,6 +714,7 @@
// Delete the blob if it doesn't have any active leases.
if (!blobMetadata.hasLeases()) {
blobMetadata.getBlobFile().delete();
+ mKnownBlobIds.remove(blobMetadata.getBlobId());
indicesToRemove.add(i);
}
}
@@ -640,6 +722,10 @@
userBlobs.removeAt(indicesToRemove.get(i));
}
writeBlobsInfoAsync();
+ if (LOGV) {
+ Slog.v(TAG, "Removed blobs data associated with pkg="
+ + packageName + ", uid=" + uid);
+ }
}
}
@@ -651,6 +737,7 @@
for (int i = 0, count = userSessions.size(); i < count; ++i) {
final BlobStoreSession session = userSessions.valueAt(i);
session.getSessionFile().delete();
+ mKnownBlobIds.remove(session.getSessionId());
}
}
@@ -660,11 +747,107 @@
for (int i = 0, count = userBlobs.size(); i < count; ++i) {
final BlobMetadata blobMetadata = userBlobs.valueAt(i);
blobMetadata.getBlobFile().delete();
+ mKnownBlobIds.remove(blobMetadata.getBlobId());
}
}
+ if (LOGV) {
+ Slog.v(TAG, "Removed blobs data in user " + userId);
+ }
}
}
+ @GuardedBy("mBlobsLock")
+ @VisibleForTesting
+ void handleIdleMaintenanceLocked() {
+ // Cleanup any left over data on disk that is not part of index.
+ final ArrayList<Long> deletedBlobIds = new ArrayList<>();
+ final ArrayList<File> filesToDelete = new ArrayList<>();
+ final File blobsDir = BlobStoreConfig.getBlobsDir();
+ if (blobsDir.exists()) {
+ for (File file : blobsDir.listFiles()) {
+ try {
+ final long id = Long.parseLong(file.getName());
+ if (mKnownBlobIds.indexOf(id) < 0) {
+ filesToDelete.add(file);
+ deletedBlobIds.add(id);
+ }
+ } catch (NumberFormatException e) {
+ Slog.wtf(TAG, "Error parsing the file name: " + file, e);
+ filesToDelete.add(file);
+ }
+ }
+ for (int i = 0, count = filesToDelete.size(); i < count; ++i) {
+ filesToDelete.get(i).delete();
+ }
+ }
+
+ // Cleanup any stale blobs.
+ for (int i = 0, userCount = mBlobsMap.size(); i < userCount; ++i) {
+ final ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.valueAt(i);
+ userBlobs.entrySet().removeIf(entry -> {
+ final BlobHandle blobHandle = entry.getKey();
+ final BlobMetadata blobMetadata = entry.getValue();
+ boolean shouldRemove = false;
+
+ // Cleanup expired data blobs.
+ if (blobHandle.isExpired()) {
+ shouldRemove = true;
+ }
+
+ // Cleanup blobs with no active leases.
+ // TODO: Exclude blobs which were just committed.
+ if (!blobMetadata.hasLeases()) {
+ shouldRemove = true;
+ }
+
+ if (shouldRemove) {
+ blobMetadata.getBlobFile().delete();
+ mKnownBlobIds.remove(blobMetadata.getBlobId());
+ deletedBlobIds.add(blobMetadata.getBlobId());
+ }
+ return shouldRemove;
+ });
+ }
+ writeBlobsInfoAsync();
+
+ // Cleanup any stale sessions.
+ final ArrayList<Integer> indicesToRemove = new ArrayList<>();
+ for (int i = 0, userCount = mSessions.size(); i < userCount; ++i) {
+ final LongSparseArray<BlobStoreSession> userSessions = mSessions.valueAt(i);
+ indicesToRemove.clear();
+ for (int j = 0, sessionsCount = userSessions.size(); j < sessionsCount; ++j) {
+ final BlobStoreSession blobStoreSession = userSessions.valueAt(j);
+ boolean shouldRemove = false;
+
+ // Cleanup sessions which haven't been modified in a while.
+ if (blobStoreSession.getSessionFile().lastModified()
+ < System.currentTimeMillis() - SESSION_EXPIRY_TIMEOUT_MILLIS) {
+ shouldRemove = true;
+ }
+
+ // Cleanup sessions with already expired data.
+ if (blobStoreSession.getBlobHandle().isExpired()) {
+ shouldRemove = true;
+ }
+
+ if (shouldRemove) {
+ blobStoreSession.getSessionFile().delete();
+ mKnownBlobIds.remove(blobStoreSession.getSessionId());
+ indicesToRemove.add(j);
+ deletedBlobIds.add(blobStoreSession.getSessionId());
+ }
+ }
+ for (int j = 0; j < indicesToRemove.size(); ++j) {
+ userSessions.removeAt(indicesToRemove.get(j));
+ }
+ }
+ if (LOGV) {
+ Slog.v(TAG, "Completed idle maintenance; deleted "
+ + Arrays.toString(deletedBlobIds.toArray()));
+ }
+ writeBlobSessionsAsync();
+ }
+
void runClearAllSessions(@UserIdInt int userId) {
synchronized (mBlobsLock) {
if (userId == UserHandle.USER_ALL) {
@@ -727,10 +910,10 @@
fout.increaseIndent();
for (int j = 0, blobsCount = userBlobs.size(); j < blobsCount; ++j) {
final BlobMetadata blobMetadata = userBlobs.valueAt(j);
- if (!dumpArgs.shouldDumpBlob(blobMetadata.blobId)) {
+ if (!dumpArgs.shouldDumpBlob(blobMetadata.getBlobId())) {
continue;
}
- fout.println("Blob #" + blobMetadata.blobId);
+ fout.println("Blob #" + blobMetadata.getBlobId());
fout.increaseIndent();
blobMetadata.dump(fout, dumpArgs);
fout.decreaseIndent();
@@ -742,6 +925,9 @@
private class PackageChangedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
+ if (LOGV) {
+ Slog.v(TAG, "Received " + intent);
+ }
switch (intent.getAction()) {
case Intent.ACTION_PACKAGE_FULLY_REMOVED:
case Intent.ACTION_PACKAGE_DATA_CLEARED:
@@ -893,6 +1079,14 @@
final DumpArgs dumpArgs = DumpArgs.parse(args);
final IndentingPrintWriter fout = new IndentingPrintWriter(writer, " ");
+ if (dumpArgs.shouldDumpHelp()) {
+ writer.println("dumpsys blob_store [options]:");
+ fout.increaseIndent();
+ dumpArgs.dumpArgsUsage(fout);
+ fout.decreaseIndent();
+ return;
+ }
+
synchronized (mBlobsLock) {
fout.println("mCurrentMaxSessionId: " + mCurrentMaxSessionId);
fout.println();
@@ -926,6 +1120,7 @@
private boolean mDumpOnlySelectedSections;
private boolean mDumpSessions;
private boolean mDumpBlobs;
+ private boolean mDumpHelp;
public boolean shouldDumpSession(String packageName, int uid, long blobId) {
if (!CollectionUtils.isEmpty(mDumpPackages)
@@ -971,6 +1166,10 @@
|| mDumpUserIds.indexOf(userId) >= 0;
}
+ public boolean shouldDumpHelp() {
+ return mDumpHelp;
+ }
+
private DumpArgs() {}
public static DumpArgs parse(String[] args) {
@@ -1000,6 +1199,8 @@
dumpArgs.mDumpUserIds.add(getIntArgRequired(args, ++i, "userId"));
} else if ("--blob".equals(opt) || "-b".equals(opt)) {
dumpArgs.mDumpBlobIds.add(getLongArgRequired(args, ++i, "blobId"));
+ } else if ("--help".equals(opt) || "-h".equals(opt)) {
+ dumpArgs.mDumpHelp = true;
} else {
// Everything else is assumed to be blob ids.
dumpArgs.mDumpBlobIds.add(getLongArgRequired(args, i, "blobId"));
@@ -1040,6 +1241,40 @@
}
return value;
}
+
+ private void dumpArgsUsage(IndentingPrintWriter pw) {
+ pw.println("--help | -h");
+ printWithIndent(pw, "Dump this help text");
+ pw.println("--sessions");
+ printWithIndent(pw, "Dump only the sessions info");
+ pw.println("--blobs");
+ printWithIndent(pw, "Dump only the committed blobs info");
+ pw.println("--package | -p [package-name]");
+ printWithIndent(pw, "Dump blobs info associated with the given package");
+ pw.println("--uid | -u [uid]");
+ printWithIndent(pw, "Dump blobs info associated with the given uid");
+ pw.println("--user [user-id]");
+ printWithIndent(pw, "Dump blobs info in the given user");
+ pw.println("--blob | -b [session-id | blob-id]");
+ printWithIndent(pw, "Dump blob info corresponding to the given ID");
+ pw.println("--full | -f");
+ printWithIndent(pw, "Dump full unredacted blobs data");
+ }
+
+ private void printWithIndent(IndentingPrintWriter pw, String str) {
+ pw.increaseIndent();
+ pw.println(str);
+ pw.decreaseIndent();
+ }
+ }
+
+ private class LocalService extends BlobStoreManagerInternal {
+ @Override
+ public void onIdleMaintenance() {
+ synchronized (mBlobsLock) {
+ handleIdleMaintenanceLocked();
+ }
+ }
}
@VisibleForTesting
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
index 54a2997..bd35b86 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
@@ -21,11 +21,13 @@
import static android.app.blob.XmlTags.ATTR_UID;
import static android.app.blob.XmlTags.TAG_ACCESS_MODE;
import static android.app.blob.XmlTags.TAG_BLOB_HANDLE;
+import static android.os.Trace.TRACE_TAG_SYSTEM_SERVER;
import static android.system.OsConstants.O_CREAT;
import static android.system.OsConstants.O_RDONLY;
import static android.system.OsConstants.O_RDWR;
import static android.system.OsConstants.SEEK_SET;
+import static com.android.server.blob.BlobStoreConfig.LOGV;
import static com.android.server.blob.BlobStoreConfig.TAG;
import android.annotation.BytesLong;
@@ -40,6 +42,7 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.RevocableFileDescriptor;
+import android.os.Trace;
import android.os.storage.StorageManager;
import android.system.ErrnoException;
import android.system.Os;
@@ -381,15 +384,22 @@
void verifyBlobData() {
byte[] actualDigest = null;
try {
+ Trace.traceBegin(TRACE_TAG_SYSTEM_SERVER,
+ "computeBlobDigest-i" + mSessionId + "-l" + getSessionFile().length());
actualDigest = FileUtils.digest(getSessionFile(), mBlobHandle.algorithm);
} catch (IOException | NoSuchAlgorithmException e) {
Slog.e(TAG, "Error computing the digest", e);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_SYSTEM_SERVER);
}
synchronized (mSessionLock) {
if (actualDigest != null && Arrays.equals(actualDigest, mBlobHandle.digest)) {
mState = STATE_VERIFIED_VALID;
// Commit callback will be sent once the data is persisted.
} else {
+ if (LOGV) {
+ Slog.v(TAG, "Digest of the data didn't match the given BlobHandle.digest");
+ }
mState = STATE_VERIFIED_INVALID;
sendCommitCallbackResult(COMMIT_RESULT_ERROR);
}
@@ -447,6 +457,16 @@
}
}
+ @Override
+ public String toString() {
+ return "BlobStoreSession {"
+ + "id:" + mSessionId
+ + ",handle:" + mBlobHandle
+ + ",uid:" + mOwnerUid
+ + ",pkg:" + mOwnerPackageName
+ + "}";
+ }
+
private void assertCallerIsOwner() {
final int callingUid = Binder.getCallingUid();
if (callingUid != mOwnerUid) {
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index 0bb07ca..088cadb 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -1287,7 +1287,7 @@
* {@link #setPeriodic(long)} or {@link #setPersisted(boolean)}. To continually monitor
* for content changes, you need to schedule a new JobInfo observing the same URIs
* before you finish execution of the JobService handling the most recent changes.
- * Following this pattern will ensure you do not lost any content changes: while your
+ * Following this pattern will ensure you do not lose any content changes: while your
* job is running, the system will continue monitoring for content changes, and propagate
* any it sees over to the next job you schedule.</p>
*
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index 91df098..23ae8af 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -38,6 +38,12 @@
"android.media",
],
+ optimize: {
+ enabled: true,
+ shrink: true,
+ proguard_flags_files: ["updatable-media-proguard.flags"],
+ },
+
installable: true,
// TODO: build against stable API surface. Use core_platform for now to avoid
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index d59270c..96110e1 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -15,6 +15,7 @@
*/
package android.media;
+import android.annotation.CheckResult;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.Uri;
@@ -32,6 +33,7 @@
import com.google.android.exoplayer2.extractor.SeekMap.SeekPoints;
import com.google.android.exoplayer2.extractor.TrackOutput;
import com.google.android.exoplayer2.extractor.amr.AmrExtractor;
+import com.google.android.exoplayer2.extractor.flac.FlacExtractor;
import com.google.android.exoplayer2.extractor.flv.FlvExtractor;
import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor;
import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor;
@@ -382,6 +384,7 @@
* parse the input.
*/
@NonNull
+ @CheckResult
private static UnrecognizedInputFormatException createForExtractors(
@NonNull String... extractorNames) {
StringBuilder builder = new StringBuilder();
@@ -536,7 +539,7 @@
}
}
if (mExtractor == null) {
- UnrecognizedInputFormatException.createForExtractors(mExtractorNamesPool);
+ throw UnrecognizedInputFormatException.createForExtractors(mExtractorNamesPool);
}
return true;
}
@@ -912,6 +915,7 @@
extractorFactoriesByName.put("exo.Ac4Extractor", Ac4Extractor::new);
extractorFactoriesByName.put("exo.AdtsExtractor", AdtsExtractor::new);
extractorFactoriesByName.put("exo.AmrExtractor", AmrExtractor::new);
+ extractorFactoriesByName.put("exo.FlacExtractor", FlacExtractor::new);
extractorFactoriesByName.put("exo.FlvExtractor", FlvExtractor::new);
extractorFactoriesByName.put("exo.FragmentedMp4Extractor", FragmentedMp4Extractor::new);
extractorFactoriesByName.put("exo.MatroskaExtractor", MatroskaExtractor::new);
diff --git a/apex/media/framework/updatable-media-proguard.flags b/apex/media/framework/updatable-media-proguard.flags
new file mode 100644
index 0000000..4e7d842
--- /dev/null
+++ b/apex/media/framework/updatable-media-proguard.flags
@@ -0,0 +1,2 @@
+# Keep all symbols in android.media.
+-keep class android.media.* {*;}
diff --git a/apex/sdkextensions/testing/Android.bp b/apex/sdkextensions/testing/Android.bp
index e6451cc..f2f5b32 100644
--- a/apex/sdkextensions/testing/Android.bp
+++ b/apex/sdkextensions/testing/Android.bp
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-apex {
+apex_test {
name: "test_com.android.sdkext",
visibility: [ "//system/apex/tests" ],
defaults: ["com.android.sdkext-defaults"],
diff --git a/apex/statsd/framework/java/android/app/StatsManager.java b/apex/statsd/framework/java/android/app/StatsManager.java
index a1de330..411482b 100644
--- a/apex/statsd/framework/java/android/app/StatsManager.java
+++ b/apex/statsd/framework/java/android/app/StatsManager.java
@@ -476,7 +476,7 @@
/**
* Registers a callback for an atom when that atom is to be pulled. The stats service will
* invoke pullData in the callback when the stats service determines that this atom needs to be
- * pulled.
+ * pulled. This method should not be called by third-party apps.
*
* @param atomTag The tag of the atom for this puller callback.
* @param metadata Optional metadata specifying the timeout, cool down time, and
@@ -485,6 +485,7 @@
* @param executor The executor in which to run the callback.
*
*/
+ @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM)
public void registerPullAtomCallback(int atomTag, @Nullable PullAtomMetadata metadata,
@NonNull @CallbackExecutor Executor executor,
@NonNull StatsPullAtomCallback callback) {
@@ -510,11 +511,12 @@
/**
* Unregisters a callback for an atom when that atom is to be pulled. Note that any ongoing
- * pulls will still occur.
+ * pulls will still occur. This method should not be called by third-party apps.
*
* @param atomTag The tag of the atom of which to unregister
*
*/
+ @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM)
public void unregisterPullAtomCallback(int atomTag) {
synchronized (sLock) {
try {
diff --git a/core/java/android/util/StatsLog.java b/apex/statsd/framework/java/android/util/StatsLog.java
similarity index 100%
rename from core/java/android/util/StatsLog.java
rename to apex/statsd/framework/java/android/util/StatsLog.java
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java
index 4383b50..4495dc9 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java
@@ -38,11 +38,15 @@
private static final String TAG = "StatsCompanion";
private static final boolean DEBUG = false;
- static void enforceStatsCompanionPermission(Context context) {
+ private static final int AID_STATSD = 1066;
+
+ static void enforceStatsdCallingUid() {
if (Binder.getCallingPid() == Process.myPid()) {
return;
}
- context.enforceCallingPermission(android.Manifest.permission.STATSCOMPANION, null);
+ if (Binder.getCallingUid() != AID_STATSD) {
+ throw new SecurityException("Not allowed to access StatsCompanion");
+ }
}
/**
@@ -114,7 +118,7 @@
@Override
public void sendDataBroadcast(long lastReportTimeNs) {
- enforceStatsCompanionPermission(mContext);
+ enforceStatsdCallingUid();
Intent intent = new Intent();
intent.putExtra(EXTRA_LAST_REPORT_TIME, lastReportTimeNs);
try {
@@ -126,7 +130,7 @@
@Override
public void sendActiveConfigsChangedBroadcast(long[] configIds) {
- enforceStatsCompanionPermission(mContext);
+ enforceStatsdCallingUid();
Intent intent = new Intent();
intent.putExtra(StatsManager.EXTRA_STATS_ACTIVE_CONFIG_KEYS, configIds);
try {
@@ -142,7 +146,7 @@
@Override
public void sendSubscriberBroadcast(long configUid, long configId, long subscriptionId,
long subscriptionRuleId, String[] cookies, StatsDimensionsValue dimensionsValue) {
- enforceStatsCompanionPermission(mContext);
+ enforceStatsdCallingUid();
Intent intent =
new Intent()
.putExtra(StatsManager.EXTRA_STATS_CONFIG_UID, configUid)
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index 3e9a488..a735cb8 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -398,7 +398,7 @@
@Override // Binder call
public void setAnomalyAlarm(long timestampMs) {
- StatsCompanion.enforceStatsCompanionPermission(mContext);
+ StatsCompanion.enforceStatsdCallingUid();
if (DEBUG) Slog.d(TAG, "Setting anomaly alarm for " + timestampMs);
final long callingToken = Binder.clearCallingIdentity();
try {
@@ -414,7 +414,7 @@
@Override // Binder call
public void cancelAnomalyAlarm() {
- StatsCompanion.enforceStatsCompanionPermission(mContext);
+ StatsCompanion.enforceStatsdCallingUid();
if (DEBUG) Slog.d(TAG, "Cancelling anomaly alarm");
final long callingToken = Binder.clearCallingIdentity();
try {
@@ -426,7 +426,7 @@
@Override // Binder call
public void setAlarmForSubscriberTriggering(long timestampMs) {
- StatsCompanion.enforceStatsCompanionPermission(mContext);
+ StatsCompanion.enforceStatsdCallingUid();
if (DEBUG) {
Slog.d(TAG,
"Setting periodic alarm in about " + (timestampMs
@@ -445,7 +445,7 @@
@Override // Binder call
public void cancelAlarmForSubscriberTriggering() {
- StatsCompanion.enforceStatsCompanionPermission(mContext);
+ StatsCompanion.enforceStatsdCallingUid();
if (DEBUG) {
Slog.d(TAG, "Cancelling periodic alarm");
}
@@ -459,7 +459,7 @@
@Override // Binder call
public void setPullingAlarm(long nextPullTimeMs) {
- StatsCompanion.enforceStatsCompanionPermission(mContext);
+ StatsCompanion.enforceStatsdCallingUid();
if (DEBUG) {
Slog.d(TAG, "Setting pulling alarm in about "
+ (nextPullTimeMs - SystemClock.elapsedRealtime()));
@@ -477,7 +477,7 @@
@Override // Binder call
public void cancelPullingAlarm() {
- StatsCompanion.enforceStatsCompanionPermission(mContext);
+ StatsCompanion.enforceStatsdCallingUid();
if (DEBUG) {
Slog.d(TAG, "Cancelling pulling alarm");
}
@@ -491,7 +491,7 @@
@Override // Binder call
public void statsdReady() {
- StatsCompanion.enforceStatsCompanionPermission(mContext);
+ StatsCompanion.enforceStatsdCallingUid();
if (DEBUG) {
Slog.d(TAG, "learned that statsdReady");
}
@@ -503,7 +503,7 @@
@Override
public void triggerUidSnapshot() {
- StatsCompanion.enforceStatsCompanionPermission(mContext);
+ StatsCompanion.enforceStatsdCallingUid();
synchronized (sStatsdLock) {
final long token = Binder.clearCallingIdentity();
try {
@@ -518,7 +518,7 @@
@Override // Binder call
public boolean checkPermission(String permission, int pid, int uid) {
- StatsCompanion.enforceStatsCompanionPermission(mContext);
+ StatsCompanion.enforceStatsdCallingUid();
return mContext.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_GRANTED;
}
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
index 04d8b00..c1dc584 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
@@ -171,8 +171,8 @@
@Override
public void registerPullAtomCallback(int atomTag, long coolDownNs, long timeoutNs,
int[] additiveFields, IPullAtomCallback pullerCallback) {
+ enforceRegisterStatsPullAtomPermission();
int callingUid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
PullerKey key = new PullerKey(callingUid, atomTag);
PullerValue val = new PullerValue(coolDownNs, timeoutNs, additiveFields, pullerCallback);
@@ -187,6 +187,7 @@
return;
}
+ final long token = Binder.clearCallingIdentity();
try {
statsd.registerPullAtomCallback(
callingUid, atomTag, coolDownNs, timeoutNs, additiveFields, pullerCallback);
@@ -199,8 +200,8 @@
@Override
public void unregisterPullAtomCallback(int atomTag) {
+ enforceRegisterStatsPullAtomPermission();
int callingUid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
PullerKey key = new PullerKey(callingUid, atomTag);
// Always remove the puller from StatsManagerService even if statsd is down. When statsd
@@ -214,6 +215,7 @@
return;
}
+ final long token = Binder.clearCallingIdentity();
try {
statsd.unregisterPullAtomCallback(callingUid, atomTag);
} catch (RemoteException e) {
@@ -502,6 +504,13 @@
}
}
+ private void enforceRegisterStatsPullAtomPermission() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.REGISTER_STATS_PULL_ATOM,
+ "Need REGISTER_STATS_PULL_ATOM permission.");
+ }
+
+
/**
* Clients should call this if blocking until statsd to be ready is desired
*
diff --git a/api/current.txt b/api/current.txt
index 006ac0b..a5a51d6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2873,7 +2873,7 @@
method public void onSystemActionsChanged();
method public final boolean performGlobalAction(int);
method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
- method public boolean takeScreenshot(int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.graphics.Bitmap>);
+ method public boolean takeScreenshot(int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.accessibilityservice.AccessibilityService.ScreenshotResult>);
field public static final int GESTURE_2_FINGER_DOUBLE_TAP = 20; // 0x14
field public static final int GESTURE_2_FINGER_SINGLE_TAP = 19; // 0x13
field public static final int GESTURE_2_FINGER_SWIPE_DOWN = 26; // 0x1a
@@ -2888,6 +2888,13 @@
field public static final int GESTURE_3_FINGER_SWIPE_RIGHT = 32; // 0x20
field public static final int GESTURE_3_FINGER_SWIPE_UP = 29; // 0x1d
field public static final int GESTURE_3_FINGER_TRIPLE_TAP = 24; // 0x18
+ field public static final int GESTURE_4_FINGER_DOUBLE_TAP = 38; // 0x26
+ field public static final int GESTURE_4_FINGER_SINGLE_TAP = 37; // 0x25
+ field public static final int GESTURE_4_FINGER_SWIPE_DOWN = 34; // 0x22
+ field public static final int GESTURE_4_FINGER_SWIPE_LEFT = 35; // 0x23
+ field public static final int GESTURE_4_FINGER_SWIPE_RIGHT = 36; // 0x24
+ field public static final int GESTURE_4_FINGER_SWIPE_UP = 33; // 0x21
+ field public static final int GESTURE_4_FINGER_TRIPLE_TAP = 39; // 0x27
field public static final int GESTURE_DOUBLE_TAP = 17; // 0x11
field public static final int GESTURE_DOUBLE_TAP_AND_HOLD = 18; // 0x12
field public static final int GESTURE_SWIPE_DOWN = 2; // 0x2
@@ -2945,6 +2952,12 @@
method public void onMagnificationChanged(@NonNull android.accessibilityservice.AccessibilityService.MagnificationController, @NonNull android.graphics.Region, float, float, float);
}
+ public static final class AccessibilityService.ScreenshotResult {
+ method @Nullable public android.graphics.ColorSpace getColorSpace();
+ method @NonNull public android.hardware.HardwareBuffer getHardwareBuffer();
+ method public long getTimestamp();
+ }
+
public static final class AccessibilityService.SoftKeyboardController {
method public void addOnShowModeChangedListener(@NonNull android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
method public void addOnShowModeChangedListener(@NonNull android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener, @Nullable android.os.Handler);
@@ -3850,7 +3863,7 @@
method public void onPerformDirectAction(@NonNull String, @NonNull android.os.Bundle, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<android.os.Bundle>);
method public void onPictureInPictureModeChanged(boolean, android.content.res.Configuration);
method @Deprecated public void onPictureInPictureModeChanged(boolean);
- method public void onPictureInPictureRequested();
+ method public boolean onPictureInPictureRequested();
method @CallSuper protected void onPostCreate(@Nullable android.os.Bundle);
method public void onPostCreate(@Nullable android.os.Bundle, @Nullable android.os.PersistableBundle);
method @CallSuper protected void onPostResume();
@@ -6803,7 +6816,7 @@
ctor public DevicePolicyKeyguardService();
method @Nullable public void dismiss();
method @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
- method @Nullable public android.view.SurfaceControl onSurfaceReady(@Nullable android.os.IBinder);
+ method @Nullable public android.view.SurfaceControlViewHost.SurfacePackage onSurfaceReady(@Nullable android.os.IBinder);
}
public class DevicePolicyManager {
@@ -26799,7 +26812,6 @@
method public abstract void onSelectRoute(@NonNull String, @NonNull String);
method public abstract void onSetVolume(@NonNull String, int);
method public abstract void onTransferToRoute(@NonNull String, @NonNull String);
- method public abstract void onUpdateVolume(@NonNull String, int);
field public static final long REQUEST_ID_UNKNOWN = 0L; // 0x0L
field public static final String SERVICE_INTERFACE = "android.media.MediaRoute2ProviderService";
}
@@ -30127,7 +30139,7 @@
method @NonNull public android.net.NetworkCapabilities setLinkDownstreamBandwidthKbps(int);
method @NonNull public android.net.NetworkCapabilities setLinkUpstreamBandwidthKbps(int);
method @NonNull public android.net.NetworkCapabilities setNetworkSpecifier(@NonNull android.net.NetworkSpecifier);
- method public void setOwnerUid(int);
+ method @NonNull public android.net.NetworkCapabilities setOwnerUid(int);
method @NonNull public android.net.NetworkCapabilities setSignalStrength(int);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkCapabilities> CREATOR;
@@ -35688,6 +35700,7 @@
field public static final String INCREMENTAL;
field public static final int PREVIEW_SDK_INT;
field public static final String RELEASE;
+ field @NonNull public static final String RELEASE_OR_CODENAME;
field @Deprecated public static final String SDK;
field public static final int SDK_INT;
field public static final String SECURITY_PATCH;
@@ -44062,8 +44075,8 @@
}
public static final class AlwaysOnHotwordDetector.ModelParamRange {
- method public int end();
- method public int start();
+ method public int getEnd();
+ method public int getStart();
}
public class VoiceInteractionService extends android.app.Service {
diff --git a/api/system-current.txt b/api/system-current.txt
index 253d6b6..7c5977f 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -188,6 +188,7 @@
field public static final String REGISTER_CALL_PROVIDER = "android.permission.REGISTER_CALL_PROVIDER";
field public static final String REGISTER_CONNECTION_MANAGER = "android.permission.REGISTER_CONNECTION_MANAGER";
field public static final String REGISTER_SIM_SUBSCRIPTION = "android.permission.REGISTER_SIM_SUBSCRIPTION";
+ field public static final String REGISTER_STATS_PULL_ATOM = "android.permission.REGISTER_STATS_PULL_ATOM";
field public static final String REMOTE_DISPLAY_PROVIDER = "android.permission.REMOTE_DISPLAY_PROVIDER";
field public static final String REMOVE_DRM_CERTIFICATES = "android.permission.REMOVE_DRM_CERTIFICATES";
field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
@@ -692,7 +693,7 @@
method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public long[] getRegisteredExperimentIds() throws android.app.StatsManager.StatsUnavailableException;
method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getReports(long) throws android.app.StatsManager.StatsUnavailableException;
method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getStatsMetadata() throws android.app.StatsManager.StatsUnavailableException;
- method public void registerPullAtomCallback(int, @Nullable android.app.StatsManager.PullAtomMetadata, @NonNull java.util.concurrent.Executor, @NonNull android.app.StatsManager.StatsPullAtomCallback);
+ method @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM) public void registerPullAtomCallback(int, @Nullable android.app.StatsManager.PullAtomMetadata, @NonNull java.util.concurrent.Executor, @NonNull android.app.StatsManager.StatsPullAtomCallback);
method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void removeConfig(long) throws android.app.StatsManager.StatsUnavailableException;
method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean removeConfiguration(long);
method @NonNull @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public long[] setActiveConfigsChangedOperation(@Nullable android.app.PendingIntent) throws android.app.StatsManager.StatsUnavailableException;
@@ -700,7 +701,7 @@
method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean setDataFetchOperation(long, android.app.PendingIntent);
method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void setFetchReportsOperation(android.app.PendingIntent, long) throws android.app.StatsManager.StatsUnavailableException;
- method public void unregisterPullAtomCallback(int);
+ method @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM) public void unregisterPullAtomCallback(int);
field public static final String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED";
field public static final String EXTRA_STATS_ACTIVE_CONFIG_KEYS = "android.app.extra.STATS_ACTIVE_CONFIG_KEYS";
field public static final String EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES = "android.app.extra.STATS_BROADCAST_SUBSCRIBER_COOKIES";
@@ -1151,6 +1152,16 @@
}
+package android.app.compat {
+
+ public final class CompatChanges {
+ method public static boolean isChangeEnabled(long);
+ method public static boolean isChangeEnabled(long, @NonNull String, @NonNull android.os.UserHandle);
+ method public static boolean isChangeEnabled(long, int);
+ }
+
+}
+
package android.app.contentsuggestions {
public final class ClassificationsRequest implements android.os.Parcelable {
@@ -1472,9 +1483,9 @@
public final class BluetoothAdapter {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean addOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean connectAllEnabledProfiles(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean connectAllEnabledProfiles(@NonNull android.bluetooth.BluetoothDevice);
method public boolean disableBLE();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean disconnectAllEnabledProfiles(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean disconnectAllEnabledProfiles(@NonNull android.bluetooth.BluetoothDevice);
method public boolean enableBLE();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean enableNoAutoConnect();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean factoryReset();
@@ -2098,6 +2109,10 @@
field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.LauncherApps.AppUsageLimit> CREATOR;
}
+ public static class LauncherApps.ShortcutQuery {
+ method @NonNull public android.content.pm.LauncherApps.ShortcutQuery setLocusIds(@Nullable java.util.List<android.content.LocusId>);
+ }
+
public class PackageInstaller {
method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setPermissionsResult(int, boolean);
field public static final int DATA_LOADER_TYPE_INCREMENTAL = 2; // 0x2
@@ -2197,6 +2212,7 @@
field public static final String EXTRA_REQUEST_PERMISSIONS_NAMES = "android.content.pm.extra.REQUEST_PERMISSIONS_NAMES";
field public static final String EXTRA_REQUEST_PERMISSIONS_RESULTS = "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio";
+ field public static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery";
field public static final String FEATURE_REBOOT_ESCROW = "android.hardware.reboot_escrow";
field public static final String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock";
field public static final int FLAGS_PERMISSION_RESERVED_PERMISSIONCONTROLLER = -268435456; // 0xf0000000
@@ -3680,17 +3696,17 @@
}
public static final class SoundTrigger.ModelParamRange implements android.os.Parcelable {
+ method public int getEnd();
+ method public int getStart();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.ModelParamRange> CREATOR;
- field public final int end;
- field public final int start;
}
public static final class SoundTrigger.ModuleProperties implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
- field public static final int CAPABILITY_ECHO_CANCELLATION = 1; // 0x1
- field public static final int CAPABILITY_NOISE_SUPPRESSION = 2; // 0x2
+ field public static final int AUDIO_CAPABILITY_ECHO_CANCELLATION = 1; // 0x1
+ field public static final int AUDIO_CAPABILITY_NOISE_SUPPRESSION = 2; // 0x2
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.ModuleProperties> CREATOR;
field public final int audioCapabilities;
field @NonNull public final String description;
@@ -6292,7 +6308,9 @@
method @Nullable public String getSSID();
method @NonNull public int[] getTransportTypes();
method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
- method public void setAdministratorUids(@NonNull java.util.List<java.lang.Integer>);
+ method @NonNull public android.net.NetworkCapabilities setAdministratorUids(@NonNull java.util.List<java.lang.Integer>);
+ method @NonNull public android.net.NetworkCapabilities setRequestorPackageName(@NonNull String);
+ method @NonNull public android.net.NetworkCapabilities setRequestorUid(int);
method @NonNull public android.net.NetworkCapabilities setSSID(@Nullable String);
method @NonNull public android.net.NetworkCapabilities setTransportInfo(@NonNull android.net.TransportInfo);
field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16
@@ -6344,6 +6362,8 @@
}
public class NetworkRequest implements android.os.Parcelable {
+ method @Nullable public String getRequestorPackageName();
+ method public int getRequestorUid();
method public boolean satisfiedBy(@Nullable android.net.NetworkCapabilities);
}
@@ -6428,7 +6448,6 @@
}
public abstract class NetworkSpecifier {
- method public void assertValidFromUid(int);
method @Nullable public android.net.NetworkSpecifier redact();
method public abstract boolean satisfiedBy(@Nullable android.net.NetworkSpecifier);
}
@@ -7556,13 +7575,12 @@
@Deprecated public static class WifiConfiguration.NetworkSelectionStatus {
method @Deprecated public int getDisableReasonCounter(int);
method @Deprecated public long getDisableTime();
+ method @Deprecated public static int getMaxNetworkSelectionDisableReason();
method @Deprecated @Nullable public static String getNetworkDisableReasonString(int);
method @Deprecated public int getNetworkSelectionDisableReason();
method @Deprecated public int getNetworkSelectionStatus();
method @Deprecated @NonNull public String getNetworkStatusString();
method @Deprecated public boolean hasEverConnected();
- method @Deprecated public boolean isNetworkEnabled();
- method @Deprecated public boolean isNetworkPermanentlyDisabled();
field @Deprecated public static final int DISABLED_ASSOCIATION_REJECTION = 1; // 0x1
field @Deprecated public static final int DISABLED_AUTHENTICATION_FAILURE = 2; // 0x2
field @Deprecated public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 5; // 0x5
@@ -7573,7 +7591,6 @@
field @Deprecated public static final int DISABLED_NONE = 0; // 0x0
field @Deprecated public static final int DISABLED_NO_INTERNET_PERMANENT = 6; // 0x6
field @Deprecated public static final int DISABLED_NO_INTERNET_TEMPORARY = 4; // 0x4
- field @Deprecated public static final int NETWORK_SELECTION_DISABLED_MAX = 10; // 0xa
field @Deprecated public static final int NETWORK_SELECTION_ENABLED = 0; // 0x0
field @Deprecated public static final int NETWORK_SELECTION_PERMANENTLY_DISABLED = 2; // 0x2
field @Deprecated public static final int NETWORK_SELECTION_TEMPORARY_DISABLED = 1; // 0x1
@@ -8197,7 +8214,7 @@
ctor public NativeScanResult();
method public int describeContents();
method @NonNull public byte[] getBssid();
- method @NonNull public java.util.BitSet getCapabilities();
+ method @NonNull public int getCapabilities();
method public int getFrequencyMhz();
method @NonNull public byte[] getInformationElements();
method @NonNull public java.util.List<android.net.wifi.wificond.RadioChainInfo> getRadioChainInfos();
@@ -8233,12 +8250,12 @@
public final class PnoSettings implements android.os.Parcelable {
ctor public PnoSettings();
method public int describeContents();
- method public int getIntervalMillis();
+ method public long getIntervalMillis();
method public int getMin2gRssiDbm();
method public int getMin5gRssiDbm();
method public int getMin6gRssiDbm();
method @NonNull public java.util.List<android.net.wifi.wificond.PnoNetwork> getPnoNetworks();
- method public void setIntervalMillis(int);
+ method public void setIntervalMillis(long);
method public void setMin2gRssiDbm(int);
method public void setMin5gRssiDbm(int);
method public void setMin6gRssiDbm(int);
@@ -8263,10 +8280,10 @@
method @Nullable public android.net.wifi.wificond.DeviceWiphyCapabilities getDeviceWiphyCapabilities(@NonNull String);
method @NonNull public java.util.List<android.net.wifi.wificond.NativeScanResult> getScanResults(@NonNull String, int);
method @Nullable public android.net.wifi.wificond.WifiCondManager.TxPacketCounters getTxPacketCounters(@NonNull String);
- method public boolean initialize(@NonNull Runnable);
method @Nullable public static android.net.wifi.wificond.WifiCondManager.OemSecurityType parseOemSecurityTypeElement(int, int, @NonNull byte[]);
method public boolean registerApCallback(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiCondManager.SoftApCallback);
method public void sendMgmtFrame(@NonNull String, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiCondManager.SendMgmtFrameCallback);
+ method public void setOnServiceDeadCallback(@NonNull Runnable);
method public boolean setupInterfaceForClientMode(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiCondManager.ScanEventCallback, @NonNull android.net.wifi.wificond.WifiCondManager.ScanEventCallback);
method public boolean setupInterfaceForSoftApMode(@NonNull String);
method @Nullable public android.net.wifi.wificond.WifiCondManager.SignalPollResult signalPoll(@NonNull String);
@@ -12407,7 +12424,6 @@
field public static final int CDMA_SUBSCRIPTION_RUIM_SIM = 0; // 0x0
field public static final int CDMA_SUBSCRIPTION_UNKNOWN = -1; // 0xffffffff
field public static final int CHANGE_ICC_LOCK_SUCCESS = 2147483647; // 0x7fffffff
- field public static final int DEFAULT_PREFERRED_NETWORK_MODE = 0; // 0x0
field public static final String EXTRA_ANOMALY_DESCRIPTION = "android.telephony.extra.ANOMALY_DESCRIPTION";
field public static final String EXTRA_ANOMALY_ID = "android.telephony.extra.ANOMALY_ID";
field @Deprecated public static final String EXTRA_APN_PROTOCOL = "apnProto";
diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt
index a57e178..0caee6b 100644
--- a/api/system-lint-baseline.txt
+++ b/api/system-lint-baseline.txt
@@ -64,10 +64,6 @@
-HeavyBitSet: android.net.wifi.wificond.NativeScanResult#getCapabilities():
-
-
-
IntentBuilderName: android.content.Context#registerReceiverForAllUsers(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler):
Methods creating an Intent should be named `create<Foo>Intent()`, was `registerReceiverForAllUsers`
diff --git a/api/test-current.txt b/api/test-current.txt
index d3e7ea1..e1f8382 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -183,6 +183,9 @@
field public static final int HISTORICAL_MODE_DISABLED = 0; // 0x0
field public static final int HISTORICAL_MODE_ENABLED_ACTIVE = 1; // 0x1
field public static final int HISTORICAL_MODE_ENABLED_PASSIVE = 2; // 0x2
+ field public static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time";
+ field public static final String KEY_FG_SERVICE_STATE_SETTLE_TIME = "fg_service_state_settle_time";
+ field public static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
field public static final String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
field public static final String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
field public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h
index de1dbc9..c643b0e 100644
--- a/cmds/idmap2/include/idmap2/ResourceUtils.h
+++ b/cmds/idmap2/include/idmap2/ResourceUtils.h
@@ -37,6 +37,10 @@
namespace utils {
+// Returns whether the Res_value::data_type represents a dynamic or regular resource reference.
+bool IsReference(uint8_t data_type);
+
+// Converts the Res_value::data_type to a human-readable string representation.
StringPiece DataTypeToString(uint8_t data_type);
struct OverlayManifestInfo {
diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp
index 4074789..43cfec3 100644
--- a/cmds/idmap2/libidmap2/ResourceMapping.cpp
+++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp
@@ -27,6 +27,7 @@
#include "idmap2/ResourceUtils.h"
using android::base::StringPrintf;
+using android::idmap2::utils::IsReference;
using android::idmap2::utils::ResToTypeEntryName;
namespace android::idmap2 {
@@ -200,8 +201,7 @@
// Only rewrite resources defined within the overlay package to their corresponding target
// resource ids at runtime.
bool rewrite_overlay_reference =
- (overlay_resource->dataType == Res_value::TYPE_REFERENCE ||
- overlay_resource->dataType == Res_value::TYPE_DYNAMIC_REFERENCE)
+ IsReference(overlay_resource->dataType)
? overlay_package_id == EXTRACT_PACKAGE(overlay_resource->data)
: false;
@@ -331,8 +331,13 @@
std::unique_ptr<uint8_t[]> string_pool_data;
Result<ResourceMapping> resource_mapping = {{}};
if (overlay_info.resource_mapping != 0U) {
+ // Use the dynamic reference table to find the assigned resource id of the map xml.
+ const auto& ref_table = overlay_asset_manager.GetDynamicRefTableForCookie(0);
+ uint32_t resource_mapping_id = overlay_info.resource_mapping;
+ ref_table->lookupResourceId(&resource_mapping_id);
+
// Load the overlay resource mappings from the file specified using android:resourcesMap.
- auto asset = OpenNonAssetFromResource(overlay_info.resource_mapping, overlay_asset_manager);
+ auto asset = OpenNonAssetFromResource(resource_mapping_id, overlay_asset_manager);
if (!asset) {
return Error("failed opening xml for android:resourcesMap: %s",
asset.GetErrorMessage().c_str());
@@ -404,8 +409,7 @@
target_map_.insert(std::make_pair(target_resource, TargetValue{data_type, data_value}));
- if (rewrite_overlay_reference &&
- (data_type == Res_value::TYPE_REFERENCE || data_type == Res_value::TYPE_DYNAMIC_REFERENCE)) {
+ if (rewrite_overlay_reference && IsReference(data_type)) {
overlay_map_.insert(std::make_pair(data_value, target_resource));
}
@@ -421,8 +425,7 @@
const TargetValue value = target_iter->second;
target_map_.erase(target_iter);
- if (value.data_type != Res_value::TYPE_REFERENCE &&
- value.data_type != Res_value::TYPE_DYNAMIC_REFERENCE) {
+ if (!IsReference(value.data_type)) {
return;
}
diff --git a/cmds/idmap2/libidmap2/ResourceUtils.cpp b/cmds/idmap2/libidmap2/ResourceUtils.cpp
index a5df746..98d026b 100644
--- a/cmds/idmap2/libidmap2/ResourceUtils.cpp
+++ b/cmds/idmap2/libidmap2/ResourceUtils.cpp
@@ -33,6 +33,10 @@
namespace android::idmap2::utils {
+bool IsReference(uint8_t data_type) {
+ return data_type == Res_value::TYPE_REFERENCE || data_type == Res_value::TYPE_DYNAMIC_REFERENCE;
+}
+
StringPiece DataTypeToString(uint8_t data_type) {
switch (data_type) {
case Res_value::TYPE_NULL:
@@ -133,7 +137,7 @@
}
if (auto result_value = overlay_it->GetAttributeValue("resourcesMap")) {
- if ((*result_value).dataType == Res_value::TYPE_REFERENCE) {
+ if (IsReference((*result_value).dataType)) {
info.resource_mapping = (*result_value).data;
} else {
return Error("android:resourcesMap is not a reference in AndroidManifest.xml of %s",
diff --git a/cmds/idmap2/tests/FileUtilsTests.cpp b/cmds/idmap2/tests/FileUtilsTests.cpp
index f55acee..8af4037 100644
--- a/cmds/idmap2/tests/FileUtilsTests.cpp
+++ b/cmds/idmap2/tests/FileUtilsTests.cpp
@@ -56,12 +56,12 @@
return type == DT_REG && path.size() > 4 && path.compare(path.size() - 4, 4, ".apk") == 0;
});
ASSERT_THAT(v, NotNull());
- ASSERT_EQ(v->size(), 10U);
+ ASSERT_EQ(v->size(), 11U);
ASSERT_EQ(std::set<std::string>(v->begin(), v->end()),
std::set<std::string>(
{root + "/target/target.apk", root + "/target/target-no-overlayable.apk",
root + "/overlay/overlay.apk", root + "/overlay/overlay-no-name.apk",
- root + "/overlay/overlay-no-name-static.apk",
+ root + "/overlay/overlay-no-name-static.apk", root + "/overlay/overlay-shared.apk",
root + "/overlay/overlay-static-1.apk", root + "/overlay/overlay-static-2.apk",
root + "/signature-overlay/signature-overlay.apk",
root + "/system-overlay/system-overlay.apk",
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 4bc6255..a2c1560 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -247,6 +247,43 @@
ASSERT_OVERLAY_ENTRY(overlay_entries[3], 0x7f020002, 0x7f02000f);
}
+TEST(IdmapTests, CreateIdmapDataFromApkAssetsSharedLibOverlay) {
+ std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
+ std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay-shared.apk";
+
+ std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
+ ASSERT_THAT(target_apk, NotNull());
+
+ std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
+ ASSERT_THAT(overlay_apk, NotNull());
+
+ auto idmap_result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ true);
+ ASSERT_TRUE(idmap_result) << idmap_result.GetErrorMessage();
+ auto& idmap = *idmap_result;
+ ASSERT_THAT(idmap, NotNull());
+
+ const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
+ ASSERT_EQ(dataBlocks.size(), 1U);
+
+ const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
+ ASSERT_THAT(data, NotNull());
+
+ const auto& target_entries = data->GetTargetEntries();
+ ASSERT_EQ(target_entries.size(), 4U);
+ ASSERT_TARGET_ENTRY(target_entries[0], 0x7f010000, Res_value::TYPE_DYNAMIC_REFERENCE, 0x00010000);
+ ASSERT_TARGET_ENTRY(target_entries[1], 0x7f02000c, Res_value::TYPE_DYNAMIC_REFERENCE, 0x00020000);
+ ASSERT_TARGET_ENTRY(target_entries[2], 0x7f02000e, Res_value::TYPE_DYNAMIC_REFERENCE, 0x00020001);
+ ASSERT_TARGET_ENTRY(target_entries[3], 0x7f02000f, Res_value::TYPE_DYNAMIC_REFERENCE, 0x00020002);
+
+ const auto& overlay_entries = data->GetOverlayEntries();
+ ASSERT_EQ(target_entries.size(), 4U);
+ ASSERT_OVERLAY_ENTRY(overlay_entries[0], 0x00010000, 0x7f010000);
+ ASSERT_OVERLAY_ENTRY(overlay_entries[1], 0x00020000, 0x7f02000c);
+ ASSERT_OVERLAY_ENTRY(overlay_entries[2], 0x00020001, 0x7f02000e);
+ ASSERT_OVERLAY_ENTRY(overlay_entries[3], 0x00020002, 0x7f02000f);
+}
+
TEST(IdmapTests, CreateIdmapDataDoNotRewriteNonOverlayResourceId) {
OverlayManifestInfo info{};
info.target_package = "test.target";
diff --git a/cmds/idmap2/tests/data/overlay/build b/cmds/idmap2/tests/data/overlay/build
index b921b0d..114b099 100755
--- a/cmds/idmap2/tests/data/overlay/build
+++ b/cmds/idmap2/tests/data/overlay/build
@@ -51,4 +51,12 @@
-o overlay-static-2.apk \
compiled.flata
+aapt2 link \
+ --no-resource-removal \
+ --shared-lib \
+ -I "$FRAMEWORK_RES_APK" \
+ --manifest AndroidManifest.xml \
+ -o overlay-shared.apk \
+ compiled.flata
+
rm compiled.flata
diff --git a/cmds/idmap2/tests/data/overlay/overlay-shared.apk b/cmds/idmap2/tests/data/overlay/overlay-shared.apk
new file mode 100644
index 0000000..93dcc82
--- /dev/null
+++ b/cmds/idmap2/tests/data/overlay/overlay-shared.apk
Binary files differ
diff --git a/cmds/incident/Android.bp b/cmds/incident/Android.bp
index 9e9dac1..94855aa 100644
--- a/cmds/incident/Android.bp
+++ b/cmds/incident/Android.bp
@@ -26,7 +26,7 @@
"libcutils",
"liblog",
"libutils",
- "libincident",
+ "libincidentpriv",
],
static_libs: [
diff --git a/cmds/incident_helper/Android.bp b/cmds/incident_helper/Android.bp
index 64f4c66..f07743e 100644
--- a/cmds/incident_helper/Android.bp
+++ b/cmds/incident_helper/Android.bp
@@ -44,7 +44,7 @@
"src/ih_util.cpp",
],
- generated_headers: ["gen-platform-proto-constants"],
+ generated_headers: ["framework-cppstream-protos"],
shared_libs: [
"libbase",
diff --git a/cmds/incidentd/Android.bp b/cmds/incidentd/Android.bp
index 25e0328..c47526a 100644
--- a/cmds/incidentd/Android.bp
+++ b/cmds/incidentd/Android.bp
@@ -43,7 +43,7 @@
],
local_include_dirs: ["src"],
- generated_headers: ["gen-platform-proto-constants"],
+ generated_headers: ["framework-cppstream-protos"],
proto: {
type: "lite",
@@ -54,7 +54,7 @@
"libbinder",
"libdebuggerd_client",
"libdumputils",
- "libincident",
+ "libincidentpriv",
"liblog",
"libprotoutil",
"libservices",
@@ -98,7 +98,7 @@
],
local_include_dirs: ["src"],
- generated_headers: ["gen-platform-proto-constants"],
+ generated_headers: ["framework-cppstream-protos"],
srcs: [
"tests/**/*.cpp",
@@ -128,7 +128,7 @@
"libbinder",
"libdebuggerd_client",
"libdumputils",
- "libincident",
+ "libincidentpriv",
"liblog",
"libprotobuf-cpp-full",
"libprotoutil",
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index e6cc1da..7e069a6 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -65,7 +65,6 @@
"src/config/ConfigListener.cpp",
"src/config/ConfigManager.cpp",
"src/experiment_ids.proto",
- "src/external/GpuStatsPuller.cpp",
"src/external/Perfetto.cpp",
"src/external/PullResultReceiver.cpp",
"src/external/puller_util.cpp",
@@ -111,7 +110,7 @@
],
cflags: [
- // "-DNEW_ENCODING_SCHEME",
+ "-DNEW_ENCODING_SCHEME",
],
local_include_dirs: [
@@ -119,22 +118,19 @@
],
static_libs: [
- "android.frameworks.stats@1.0",
"libbase",
"libcutils",
- "liblog",
"libprotoutil",
"libstatslog",
- "libstatssocket",
+ "libstatsmetadata",
"libsysutils",
],
shared_libs: [
"libbinder",
- "libgraphicsenv",
- "libhidlbase",
"libincident",
+ "liblog",
"libservices",
- "libstatsmetadata",
+ "libstatssocket",
"libutils",
],
}
@@ -161,7 +157,7 @@
],
}
-cc_library_shared {
+cc_library_static {
name: "libstatsmetadata",
host_supported: true,
generated_sources: [
@@ -224,8 +220,6 @@
shared_libs: ["libgtest_prod"],
- vintf_fragments: ["android.frameworks.stats@1.0-service.xml"],
-
init_rc: ["statsd.rc"],
}
@@ -278,8 +272,6 @@
"tests/e2e/PartialBucket_e2e_test.cpp",
"tests/e2e/ValueMetric_pull_e2e_test.cpp",
"tests/e2e/WakelockDuration_e2e_test.cpp",
- "tests/external/GpuStatsPuller_test.cpp",
- "tests/external/IncidentReportArgs_test.cpp",
"tests/external/puller_util_test.cpp",
"tests/external/StatsCallbackPuller_test.cpp",
"tests/external/StatsPuller_test.cpp",
diff --git a/cmds/statsd/android.frameworks.stats@1.0-service.xml b/cmds/statsd/android.frameworks.stats@1.0-service.xml
deleted file mode 100644
index bb02f66..0000000
--- a/cmds/statsd/android.frameworks.stats@1.0-service.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<manifest version="1.0" type="framework">
- <hal>
- <name>android.frameworks.stats</name>
- <transport>hwbinder</transport>
- <version>1.0</version>
- <interface>
- <name>IStats</name>
- <instance>default</instance>
- </interface>
- </hal>
-</manifest>
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 0256e36..a06e59c 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1354,7 +1354,6 @@
return Status::ok();
}
-
Status StatsService::getRegisteredExperimentIds(std::vector<int64_t>* experimentIdsOut) {
ENFORCE_UID(AID_SYSTEM);
// TODO: add verifier permission
@@ -1372,103 +1371,6 @@
return Status::ok();
}
-hardware::Return<void> StatsService::reportSpeakerImpedance(
- const SpeakerImpedance& speakerImpedance) {
- android::util::stats_write(android::util::SPEAKER_IMPEDANCE_REPORTED,
- speakerImpedance.speakerLocation, speakerImpedance.milliOhms);
-
- return hardware::Void();
-}
-
-hardware::Return<void> StatsService::reportHardwareFailed(const HardwareFailed& hardwareFailed) {
- android::util::stats_write(android::util::HARDWARE_FAILED, int32_t(hardwareFailed.hardwareType),
- hardwareFailed.hardwareLocation, int32_t(hardwareFailed.errorCode));
-
- return hardware::Void();
-}
-
-hardware::Return<void> StatsService::reportPhysicalDropDetected(
- const PhysicalDropDetected& physicalDropDetected) {
- android::util::stats_write(android::util::PHYSICAL_DROP_DETECTED,
- int32_t(physicalDropDetected.confidencePctg), physicalDropDetected.accelPeak,
- physicalDropDetected.freefallDuration);
-
- return hardware::Void();
-}
-
-hardware::Return<void> StatsService::reportChargeCycles(const ChargeCycles& chargeCycles) {
- std::vector<int32_t> buckets = chargeCycles.cycleBucket;
- int initialSize = buckets.size();
- for (int i = 0; i < 10 - initialSize; i++) {
- buckets.push_back(-1); // Push -1 for buckets that do not exist.
- }
- android::util::stats_write(android::util::CHARGE_CYCLES_REPORTED, buckets[0], buckets[1],
- buckets[2], buckets[3], buckets[4], buckets[5], buckets[6], buckets[7], buckets[8],
- buckets[9]);
-
- return hardware::Void();
-}
-
-hardware::Return<void> StatsService::reportBatteryHealthSnapshot(
- const BatteryHealthSnapshotArgs& batteryHealthSnapshotArgs) {
- android::util::stats_write(android::util::BATTERY_HEALTH_SNAPSHOT,
- int32_t(batteryHealthSnapshotArgs.type), batteryHealthSnapshotArgs.temperatureDeciC,
- batteryHealthSnapshotArgs.voltageMicroV, batteryHealthSnapshotArgs.currentMicroA,
- batteryHealthSnapshotArgs.openCircuitVoltageMicroV,
- batteryHealthSnapshotArgs.resistanceMicroOhm, batteryHealthSnapshotArgs.levelPercent);
-
- return hardware::Void();
-}
-
-hardware::Return<void> StatsService::reportSlowIo(const SlowIo& slowIo) {
- android::util::stats_write(android::util::SLOW_IO, int32_t(slowIo.operation), slowIo.count);
-
- return hardware::Void();
-}
-
-hardware::Return<void> StatsService::reportBatteryCausedShutdown(
- const BatteryCausedShutdown& batteryCausedShutdown) {
- android::util::stats_write(android::util::BATTERY_CAUSED_SHUTDOWN,
- batteryCausedShutdown.voltageMicroV);
-
- return hardware::Void();
-}
-
-hardware::Return<void> StatsService::reportUsbPortOverheatEvent(
- const UsbPortOverheatEvent& usbPortOverheatEvent) {
- android::util::stats_write(android::util::USB_PORT_OVERHEAT_EVENT_REPORTED,
- usbPortOverheatEvent.plugTemperatureDeciC, usbPortOverheatEvent.maxTemperatureDeciC,
- usbPortOverheatEvent.timeToOverheat, usbPortOverheatEvent.timeToHysteresis,
- usbPortOverheatEvent.timeToInactive);
-
- return hardware::Void();
-}
-
-hardware::Return<void> StatsService::reportSpeechDspStat(
- const SpeechDspStat& speechDspStat) {
- android::util::stats_write(android::util::SPEECH_DSP_STAT_REPORTED,
- speechDspStat.totalUptimeMillis, speechDspStat.totalDowntimeMillis,
- speechDspStat.totalCrashCount, speechDspStat.totalRecoverCount);
-
- return hardware::Void();
-}
-
-hardware::Return<void> StatsService::reportVendorAtom(const VendorAtom& vendorAtom) {
- std::string reverseDomainName = (std::string) vendorAtom.reverseDomainName;
- if (vendorAtom.atomId < 100000 || vendorAtom.atomId >= 200000) {
- ALOGE("Atom ID %ld is not a valid vendor atom ID", (long) vendorAtom.atomId);
- return hardware::Void();
- }
- if (reverseDomainName.length() > 50) {
- ALOGE("Vendor atom reverse domain name %s is too long.", reverseDomainName.c_str());
- return hardware::Void();
- }
- LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), vendorAtom);
- mProcessor->OnLogEvent(&event);
-
- return hardware::Void();
-}
-
void StatsService::binderDied(const wp <IBinder>& who) {
ALOGW("statscompanion service died");
StatsdStats::getInstance().noteSystemServerRestart(getWallClockSec());
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index af3016f..82a5a53 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -27,8 +27,6 @@
#include "shell/ShellSubscriber.h"
#include "statscompanion_util.h"
-#include <android/frameworks/stats/1.0/IStats.h>
-#include <android/frameworks/stats/1.0/types.h>
#include <android/os/BnStatsd.h>
#include <android/os/IPendingIntentRef.h>
#include <android/os/IStatsCompanionService.h>
@@ -41,7 +39,6 @@
using namespace android;
using namespace android::binder;
-using namespace android::frameworks::stats::V1_0;
using namespace android::os;
using namespace std;
@@ -49,10 +46,7 @@
namespace os {
namespace statsd {
-using android::hardware::Return;
-
class StatsService : public BnStatsd,
- public IStats,
public IBinder::DeathRecipient {
public:
StatsService(const sp<Looper>& handlerLooper, std::shared_ptr<LogEventQueue> queue);
@@ -207,61 +201,6 @@
*/
virtual Status getRegisteredExperimentIds(std::vector<int64_t>* expIdsOut);
- /**
- * Binder call to get SpeakerImpedance atom.
- */
- virtual Return<void> reportSpeakerImpedance(const SpeakerImpedance& speakerImpedance) override;
-
- /**
- * Binder call to get HardwareFailed atom.
- */
- virtual Return<void> reportHardwareFailed(const HardwareFailed& hardwareFailed) override;
-
- /**
- * Binder call to get PhysicalDropDetected atom.
- */
- virtual Return<void> reportPhysicalDropDetected(
- const PhysicalDropDetected& physicalDropDetected) override;
-
- /**
- * Binder call to get ChargeCyclesReported atom.
- */
- virtual Return<void> reportChargeCycles(const ChargeCycles& chargeCycles) override;
-
- /**
- * Binder call to get BatteryHealthSnapshot atom.
- */
- virtual Return<void> reportBatteryHealthSnapshot(
- const BatteryHealthSnapshotArgs& batteryHealthSnapshotArgs) override;
-
- /**
- * Binder call to get SlowIo atom.
- */
- virtual Return<void> reportSlowIo(const SlowIo& slowIo) override;
-
- /**
- * Binder call to get BatteryCausedShutdown atom.
- */
- virtual Return<void> reportBatteryCausedShutdown(
- const BatteryCausedShutdown& batteryCausedShutdown) override;
-
- /**
- * Binder call to get UsbPortOverheatEvent atom.
- */
- virtual Return<void> reportUsbPortOverheatEvent(
- const UsbPortOverheatEvent& usbPortOverheatEvent) override;
-
- /**
- * Binder call to get Speech DSP state atom.
- */
- virtual Return<void> reportSpeechDspStat(
- const SpeechDspStat& speechDspStat) override;
-
- /**
- * Binder call to get vendor atom.
- */
- virtual Return<void> reportVendorAtom(const VendorAtom& vendorAtom) override;
-
/** IBinder::DeathRecipient */
virtual void binderDied(const wp<IBinder>& who) override;
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 183d741..71afc32 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -391,6 +391,7 @@
WifiHealthStatReported wifi_health_stat_reported = 251 [(module) = "wifi"];
WifiFailureStatReported wifi_failure_stat_reported = 252 [(module) = "wifi"];
WifiConnectionResultReported wifi_connection_result_reported = 253 [(module) = "wifi"];
+ SdkExtensionStatus sdk_extension_status = 354;
}
// Pulled events will start at field 10000.
@@ -8337,3 +8338,27 @@
// Exception message (or log message) associated with the error (max 1000 chars)
optional string exception_message = 2;
}
+
+/**
+ * Logs when the SDK Extensions test app has polled the current version.
+ * This is atom ID 354.
+ *
+ * Logged from:
+ * vendor/google_testing/integration/packages/apps/SdkExtensionsTestApp/
+ */
+message SdkExtensionStatus {
+ enum ApiCallStatus {
+ CALL_NOT_ATTEMPTED = 0;
+ CALL_SUCCESSFUL = 1;
+ CALL_FAILED = 2;
+ }
+
+ optional ApiCallStatus result = 1;
+
+ // The R extension version, i.e. android.os.ext.SdkExtension.getExtensionVersion(R).
+ optional int32 r_extension_version = 2;
+
+ // A number identifying which particular symbol's call failed, if any. 0 means no missing symbol.
+ // "Failed" here can mean a symbol that wasn't meant to be visible was, or the other way around.
+ optional int32 failed_call_symbol = 3;
+}
diff --git a/cmds/statsd/src/external/GpuStatsPuller.cpp b/cmds/statsd/src/external/GpuStatsPuller.cpp
deleted file mode 100644
index 3229ba8..0000000
--- a/cmds/statsd/src/external/GpuStatsPuller.cpp
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "GpuStatsPuller.h"
-
-#include <binder/IServiceManager.h>
-#include <graphicsenv/GpuStatsInfo.h>
-#include <graphicsenv/IGpuService.h>
-
-#include "logd/LogEvent.h"
-
-#include "stats_log_util.h"
-#include "statslog.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using android::util::ProtoReader;
-
-GpuStatsPuller::GpuStatsPuller(const int tagId) : StatsPuller(tagId) {
-}
-
-static sp<IGpuService> getGpuService() {
- const sp<IBinder> binder = defaultServiceManager()->checkService(String16("gpu"));
- if (!binder) {
- ALOGE("Failed to get gpu service");
- return nullptr;
- }
-
- return interface_cast<IGpuService>(binder);
-}
-
-static bool pullGpuStatsGlobalInfo(const sp<IGpuService>& gpuService,
- std::vector<std::shared_ptr<LogEvent>>* data) {
- std::vector<GpuStatsGlobalInfo> stats;
- status_t status = gpuService->getGpuStatsGlobalInfo(&stats);
- if (status != OK) {
- return false;
- }
-
- data->clear();
- data->reserve(stats.size());
- for (const auto& info : stats) {
- std::shared_ptr<LogEvent> event = make_shared<LogEvent>(
- android::util::GPU_STATS_GLOBAL_INFO, getWallClockNs(), getElapsedRealtimeNs());
- if (!event->write(info.driverPackageName)) return false;
- if (!event->write(info.driverVersionName)) return false;
- if (!event->write((int64_t)info.driverVersionCode)) return false;
- if (!event->write(info.driverBuildTime)) return false;
- if (!event->write((int64_t)info.glLoadingCount)) return false;
- if (!event->write((int64_t)info.glLoadingFailureCount)) return false;
- if (!event->write((int64_t)info.vkLoadingCount)) return false;
- if (!event->write((int64_t)info.vkLoadingFailureCount)) return false;
- if (!event->write(info.vulkanVersion)) return false;
- if (!event->write(info.cpuVulkanVersion)) return false;
- if (!event->write(info.glesVersion)) return false;
- if (!event->write((int64_t)info.angleLoadingCount)) return false;
- if (!event->write((int64_t)info.angleLoadingFailureCount)) return false;
- event->init();
- data->emplace_back(event);
- }
-
- return true;
-}
-
-static bool pullGpuStatsAppInfo(const sp<IGpuService>& gpuService,
- std::vector<std::shared_ptr<LogEvent>>* data) {
- std::vector<GpuStatsAppInfo> stats;
- status_t status = gpuService->getGpuStatsAppInfo(&stats);
- if (status != OK) {
- return false;
- }
-
- data->clear();
- data->reserve(stats.size());
- for (const auto& info : stats) {
- std::shared_ptr<LogEvent> event = make_shared<LogEvent>(
- android::util::GPU_STATS_APP_INFO, getWallClockNs(), getElapsedRealtimeNs());
- if (!event->write(info.appPackageName)) return false;
- if (!event->write((int64_t)info.driverVersionCode)) return false;
- if (!event->writeBytes(int64VectorToProtoByteString(info.glDriverLoadingTime))) {
- return false;
- }
- if (!event->writeBytes(int64VectorToProtoByteString(info.vkDriverLoadingTime))) {
- return false;
- }
- if (!event->writeBytes(int64VectorToProtoByteString(info.angleDriverLoadingTime))) {
- return false;
- }
- if (!event->write(info.cpuVulkanInUse)) return false;
- if (!event->write(info.falsePrerotation)) return false;
- if (!event->write(info.gles1InUse)) return false;
- event->init();
- data->emplace_back(event);
- }
-
- return true;
-}
-
-bool GpuStatsPuller::PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) {
- const sp<IGpuService> gpuService = getGpuService();
- if (!gpuService) {
- return false;
- }
-
- switch (mTagId) {
- case android::util::GPU_STATS_GLOBAL_INFO:
- return pullGpuStatsGlobalInfo(gpuService, data);
- case android::util::GPU_STATS_APP_INFO:
- return pullGpuStatsAppInfo(gpuService, data);
- default:
- break;
- }
-
- return false;
-}
-
-static std::string protoOutputStreamToByteString(ProtoOutputStream& proto) {
- if (!proto.size()) return "";
-
- std::string byteString;
- sp<ProtoReader> reader = proto.data();
- while (reader->readBuffer() != nullptr) {
- const size_t toRead = reader->currentToRead();
- byteString.append((char*)reader->readBuffer(), toRead);
- reader->move(toRead);
- }
-
- if (byteString.size() != proto.size()) return "";
-
- return byteString;
-}
-
-std::string int64VectorToProtoByteString(const std::vector<int64_t>& value) {
- if (value.empty()) return "";
-
- ProtoOutputStream proto;
- for (const auto& ele : value) {
- proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED |
- 1 /* field id */,
- (long long)ele);
- }
-
- return protoOutputStreamToByteString(proto);
-}
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/external/GpuStatsPuller.h b/cmds/statsd/src/external/GpuStatsPuller.h
deleted file mode 100644
index 2da199c..0000000
--- a/cmds/statsd/src/external/GpuStatsPuller.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "StatsPuller.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * Pull GpuStats from GpuService.
- */
-class GpuStatsPuller : public StatsPuller {
-public:
- explicit GpuStatsPuller(const int tagId);
- bool PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) override;
-};
-
-// convert a int64_t vector into a byte string for proto message like:
-// message RepeatedInt64Wrapper {
-// repeated int64 value = 1;
-// }
-std::string int64VectorToProtoByteString(const std::vector<int64_t>& value);
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 15d7e33..3ceff75 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -32,7 +32,6 @@
#include "../logd/LogEvent.h"
#include "../stats_log_util.h"
#include "../statscompanion_util.h"
-#include "GpuStatsPuller.h"
#include "StatsCallbackPuller.h"
#include "TrainInfoPuller.h"
#include "statslog.h"
@@ -51,15 +50,6 @@
: kAllPullAtomInfo({
// TrainInfo.
{{.atomTag = android::util::TRAIN_INFO}, new TrainInfoPuller()},
-
- // GpuStatsGlobalInfo
- {{.atomTag = android::util::GPU_STATS_GLOBAL_INFO},
- new GpuStatsPuller(android::util::GPU_STATS_GLOBAL_INFO)},
-
- // GpuStatsAppInfo
- {{.atomTag = android::util::GPU_STATS_APP_INFO},
- new GpuStatsPuller(android::util::GPU_STATS_APP_INFO)},
-
}),
mNextPullTimeNs(NO_ALARM_UPDATE) {
}
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index e8fc603..103eb0c 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -195,37 +195,6 @@
}
LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
- const VendorAtom& vendorAtom) {
- mLogdTimestampNs = wallClockTimestampNs;
- mElapsedTimestampNs = elapsedTimestampNs;
- mTagId = vendorAtom.atomId;
- mLogUid = AID_STATSD;
-
- mValues.push_back(
- FieldValue(Field(mTagId, getSimpleField(1)), Value(vendorAtom.reverseDomainName)));
- for (int i = 0; i < (int)vendorAtom.values.size(); i++) {
- switch (vendorAtom.values[i].getDiscriminator()) {
- case VendorAtom::Value::hidl_discriminator::intValue:
- mValues.push_back(FieldValue(Field(mTagId, getSimpleField(i + 2)),
- Value(vendorAtom.values[i].intValue())));
- break;
- case VendorAtom::Value::hidl_discriminator::longValue:
- mValues.push_back(FieldValue(Field(mTagId, getSimpleField(i + 2)),
- Value(vendorAtom.values[i].longValue())));
- break;
- case VendorAtom::Value::hidl_discriminator::floatValue:
- mValues.push_back(FieldValue(Field(mTagId, getSimpleField(i + 2)),
- Value(vendorAtom.values[i].floatValue())));
- break;
- case VendorAtom::Value::hidl_discriminator::stringValue:
- mValues.push_back(FieldValue(Field(mTagId, getSimpleField(i + 2)),
- Value(vendorAtom.values[i].stringValue())));
- break;
- }
- }
-}
-
-LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
const InstallTrainInfo& trainInfo) {
mLogdTimestampNs = wallClockTimestampNs;
mElapsedTimestampNs = elapsedTimestampNs;
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index e4b784e..5509c09 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -18,7 +18,6 @@
#include "FieldValue.h"
-#include <android/frameworks/stats/1.0/types.h>
#include <android/util/ProtoOutputStream.h>
#include <private/android_logger.h>
#include <stats_event_list.h>
@@ -27,8 +26,6 @@
#include <string>
#include <vector>
-using namespace android::frameworks::stats::V1_0;
-
namespace android {
namespace os {
namespace statsd {
@@ -103,9 +100,6 @@
const std::vector<uint8_t>& experimentIds, int32_t userId);
explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
- const VendorAtom& vendorAtom);
-
- explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
const InstallTrainInfo& installTrainInfo);
~LogEvent();
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index 58bfeb3..140ef4e 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -23,7 +23,6 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
-#include <hidl/HidlTransportSupport.h>
#include <utils/Looper.h>
#include <stdio.h>
@@ -75,8 +74,6 @@
ps->giveThreadPoolName();
IPCThreadState::self()->disableBackgroundScheduling(true);
- ::android::hardware::configureRpcThreadpool(4 /*threads*/, false /*willJoin*/);
-
std::shared_ptr<LogEventQueue> eventQueue =
std::make_shared<LogEventQueue>(2000 /*buffer limit. Buffer is NOT pre-allocated*/);
@@ -89,12 +86,6 @@
return -1;
}
- auto ret = gStatsService->registerAsService();
- if (ret != ::android::OK) {
- ALOGE("Failed to add service as HIDL service");
- return 1; // or handle error
- }
-
registerSigHandler();
gStatsService->sayHiToStatsCompanion();
diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.cpp b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
index d86e291..30c90b1 100644
--- a/cmds/statsd/src/subscriber/IncidentdReporter.cpp
+++ b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
@@ -21,10 +21,8 @@
#include "packages/UidMap.h"
#include "stats_log_util.h"
-#include <android/os/IIncidentManager.h>
-#include <android/os/IncidentReportArgs.h>
#include <android/util/ProtoOutputStream.h>
-#include <binder/IServiceManager.h>
+#include <incident/incident_report.h>
#include <vector>
@@ -132,7 +130,7 @@
return false;
}
- IncidentReportArgs incidentReport;
+ android::os::IncidentReportRequest incidentReport;
vector<uint8_t> protoData;
getProtoData(rule_id, metricId, dimensionKey, metricValue, configKey,
@@ -146,30 +144,21 @@
uint8_t dest;
switch (config.dest()) {
case IncidentdDetails_Destination_AUTOMATIC:
- dest = android::os::PRIVACY_POLICY_AUTOMATIC;
+ dest = INCIDENT_REPORT_PRIVACY_POLICY_AUTOMATIC;
break;
case IncidentdDetails_Destination_EXPLICIT:
- dest = android::os::PRIVACY_POLICY_EXPLICIT;
+ dest = INCIDENT_REPORT_PRIVACY_POLICY_EXPLICIT;
break;
default:
- dest = android::os::PRIVACY_POLICY_AUTOMATIC;
+ dest = INCIDENT_REPORT_PRIVACY_POLICY_AUTOMATIC;
}
incidentReport.setPrivacyPolicy(dest);
- incidentReport.setReceiverPkg(config.receiver_pkg());
+ incidentReport.setReceiverPackage(config.receiver_pkg());
- incidentReport.setReceiverCls(config.receiver_cls());
+ incidentReport.setReceiverClass(config.receiver_cls());
- sp<IIncidentManager> service = interface_cast<IIncidentManager>(
- defaultServiceManager()->getService(android::String16("incident")));
- if (service == nullptr) {
- ALOGW("Failed to fetch incident service.");
- return false;
- }
- VLOG("Calling incidentd %p", service.get());
- binder::Status s = service->reportIncident(incidentReport);
- VLOG("Report incident status: %s", s.toString8().string());
- return s.isOk();
+ return incidentReport.takeReport() == NO_ERROR;
}
} // namespace statsd
diff --git a/cmds/statsd/tests/external/GpuStatsPuller_test.cpp b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
deleted file mode 100644
index ae92705..0000000
--- a/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#undef LOG_TAG
-#define LOG_TAG "GpuStatsPuller_test"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <graphicsenv/GpuStatsInfo.h>
-#include <log/log.h>
-
-#include "src/external/GpuStatsPuller.h"
-#include "statslog.h"
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// clang-format off
-static const std::string DRIVER_PACKAGE_NAME = "TEST_DRIVER";
-static const std::string DRIVER_VERSION_NAME = "TEST_DRIVER_VERSION";
-static const std::string APP_PACKAGE_NAME = "TEST_APP";
-static const int64_t TIMESTAMP_WALLCLOCK = 111;
-static const int64_t TIMESTAMP_ELAPSED = 222;
-static const int64_t DRIVER_VERSION_CODE = 333;
-static const int64_t DRIVER_BUILD_TIME = 444;
-static const int64_t GL_LOADING_COUNT = 3;
-static const int64_t GL_LOADING_FAILURE_COUNT = 1;
-static const int64_t VK_LOADING_COUNT = 4;
-static const int64_t VK_LOADING_FAILURE_COUNT = 0;
-static const int64_t ANGLE_LOADING_COUNT = 2;
-static const int64_t ANGLE_LOADING_FAILURE_COUNT = 1;
-static const int64_t GL_DRIVER_LOADING_TIME_0 = 555;
-static const int64_t GL_DRIVER_LOADING_TIME_1 = 666;
-static const int64_t VK_DRIVER_LOADING_TIME_0 = 777;
-static const int64_t VK_DRIVER_LOADING_TIME_1 = 888;
-static const int64_t VK_DRIVER_LOADING_TIME_2 = 999;
-static const int64_t ANGLE_DRIVER_LOADING_TIME_0 = 1010;
-static const int64_t ANGLE_DRIVER_LOADING_TIME_1 = 1111;
-static const int32_t VULKAN_VERSION = 1;
-static const int32_t CPU_VULKAN_VERSION = 2;
-static const int32_t GLES_VERSION = 3;
-static const bool CPU_VULKAN_IN_USE = true;
-static const bool FALSE_PREROTATION = true;
-static const bool GLES_1_IN_USE = true;
-static const size_t NUMBER_OF_VALUES_GLOBAL = 13;
-static const size_t NUMBER_OF_VALUES_APP = 8;
-// clang-format on
-
-class MockGpuStatsPuller : public GpuStatsPuller {
-public:
- MockGpuStatsPuller(const int tagId, vector<std::shared_ptr<LogEvent>>* data)
- : GpuStatsPuller(tagId), mData(data){};
-
-private:
- bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override {
- *data = *mData;
- return true;
- }
-
- vector<std::shared_ptr<LogEvent>>* mData;
-};
-
-class GpuStatsPuller_test : public ::testing::Test {
-public:
- GpuStatsPuller_test() {
- const ::testing::TestInfo* const test_info =
- ::testing::UnitTest::GetInstance()->current_test_info();
- ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
- }
-
- ~GpuStatsPuller_test() {
- const ::testing::TestInfo* const test_info =
- ::testing::UnitTest::GetInstance()->current_test_info();
- ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
- }
-};
-
-TEST_F(GpuStatsPuller_test, PullGpuStatsGlobalInfo) {
- vector<std::shared_ptr<LogEvent>> inData, outData;
- std::shared_ptr<LogEvent> event = make_shared<LogEvent>(android::util::GPU_STATS_GLOBAL_INFO,
- TIMESTAMP_WALLCLOCK, TIMESTAMP_ELAPSED);
- EXPECT_TRUE(event->write(DRIVER_PACKAGE_NAME));
- EXPECT_TRUE(event->write(DRIVER_VERSION_NAME));
- EXPECT_TRUE(event->write(DRIVER_VERSION_CODE));
- EXPECT_TRUE(event->write(DRIVER_BUILD_TIME));
- EXPECT_TRUE(event->write(GL_LOADING_COUNT));
- EXPECT_TRUE(event->write(GL_LOADING_FAILURE_COUNT));
- EXPECT_TRUE(event->write(VK_LOADING_COUNT));
- EXPECT_TRUE(event->write(VK_LOADING_FAILURE_COUNT));
- EXPECT_TRUE(event->write(VULKAN_VERSION));
- EXPECT_TRUE(event->write(CPU_VULKAN_VERSION));
- EXPECT_TRUE(event->write(GLES_VERSION));
- EXPECT_TRUE(event->write(ANGLE_LOADING_COUNT));
- EXPECT_TRUE(event->write(ANGLE_LOADING_FAILURE_COUNT));
- event->init();
- inData.emplace_back(event);
- MockGpuStatsPuller mockPuller(android::util::GPU_STATS_GLOBAL_INFO, &inData);
- mockPuller.ForceClearCache();
- mockPuller.Pull(&outData);
-
- ASSERT_EQ(1, outData.size());
- EXPECT_EQ(android::util::GPU_STATS_GLOBAL_INFO, outData[0]->GetTagId());
- ASSERT_EQ(NUMBER_OF_VALUES_GLOBAL, outData[0]->size());
- EXPECT_EQ(DRIVER_PACKAGE_NAME, outData[0]->getValues()[0].mValue.str_value);
- EXPECT_EQ(DRIVER_VERSION_NAME, outData[0]->getValues()[1].mValue.str_value);
- EXPECT_EQ(DRIVER_VERSION_CODE, outData[0]->getValues()[2].mValue.long_value);
- EXPECT_EQ(DRIVER_BUILD_TIME, outData[0]->getValues()[3].mValue.long_value);
- EXPECT_EQ(GL_LOADING_COUNT, outData[0]->getValues()[4].mValue.long_value);
- EXPECT_EQ(GL_LOADING_FAILURE_COUNT, outData[0]->getValues()[5].mValue.long_value);
- EXPECT_EQ(VK_LOADING_COUNT, outData[0]->getValues()[6].mValue.long_value);
- EXPECT_EQ(VK_LOADING_FAILURE_COUNT, outData[0]->getValues()[7].mValue.long_value);
- EXPECT_EQ(VULKAN_VERSION, outData[0]->getValues()[8].mValue.int_value);
- EXPECT_EQ(CPU_VULKAN_VERSION, outData[0]->getValues()[9].mValue.int_value);
- EXPECT_EQ(GLES_VERSION, outData[0]->getValues()[10].mValue.int_value);
- EXPECT_EQ(ANGLE_LOADING_COUNT, outData[0]->getValues()[11].mValue.long_value);
- EXPECT_EQ(ANGLE_LOADING_FAILURE_COUNT, outData[0]->getValues()[12].mValue.long_value);
-}
-
-TEST_F(GpuStatsPuller_test, PullGpuStatsAppInfo) {
- vector<std::shared_ptr<LogEvent>> inData, outData;
- std::shared_ptr<LogEvent> event = make_shared<LogEvent>(android::util::GPU_STATS_APP_INFO,
- TIMESTAMP_WALLCLOCK, TIMESTAMP_ELAPSED);
- EXPECT_TRUE(event->write(APP_PACKAGE_NAME));
- EXPECT_TRUE(event->write(DRIVER_VERSION_CODE));
- std::vector<int64_t> glDriverLoadingTime;
- glDriverLoadingTime.emplace_back(GL_DRIVER_LOADING_TIME_0);
- glDriverLoadingTime.emplace_back(GL_DRIVER_LOADING_TIME_1);
- std::vector<int64_t> vkDriverLoadingTime;
- vkDriverLoadingTime.emplace_back(VK_DRIVER_LOADING_TIME_0);
- vkDriverLoadingTime.emplace_back(VK_DRIVER_LOADING_TIME_1);
- vkDriverLoadingTime.emplace_back(VK_DRIVER_LOADING_TIME_2);
- std::vector<int64_t> angleDriverLoadingTime;
- angleDriverLoadingTime.emplace_back(ANGLE_DRIVER_LOADING_TIME_0);
- angleDriverLoadingTime.emplace_back(ANGLE_DRIVER_LOADING_TIME_1);
- EXPECT_TRUE(event->write(int64VectorToProtoByteString(glDriverLoadingTime)));
- EXPECT_TRUE(event->write(int64VectorToProtoByteString(vkDriverLoadingTime)));
- EXPECT_TRUE(event->write(int64VectorToProtoByteString(angleDriverLoadingTime)));
- EXPECT_TRUE(event->write(CPU_VULKAN_IN_USE));
- EXPECT_TRUE(event->write(FALSE_PREROTATION));
- EXPECT_TRUE(event->write(GLES_1_IN_USE));
- event->init();
- inData.emplace_back(event);
- MockGpuStatsPuller mockPuller(android::util::GPU_STATS_APP_INFO, &inData);
- mockPuller.ForceClearCache();
- mockPuller.Pull(&outData);
-
- ASSERT_EQ(1, outData.size());
- EXPECT_EQ(android::util::GPU_STATS_APP_INFO, outData[0]->GetTagId());
- ASSERT_EQ(NUMBER_OF_VALUES_APP, outData[0]->size());
- EXPECT_EQ(APP_PACKAGE_NAME, outData[0]->getValues()[0].mValue.str_value);
- EXPECT_EQ(DRIVER_VERSION_CODE, outData[0]->getValues()[1].mValue.long_value);
- EXPECT_EQ(int64VectorToProtoByteString(glDriverLoadingTime),
- outData[0]->getValues()[2].mValue.str_value);
- EXPECT_EQ(int64VectorToProtoByteString(vkDriverLoadingTime),
- outData[0]->getValues()[3].mValue.str_value);
- EXPECT_EQ(int64VectorToProtoByteString(angleDriverLoadingTime),
- outData[0]->getValues()[4].mValue.str_value);
- EXPECT_EQ(CPU_VULKAN_IN_USE, outData[0]->getValues()[5].mValue.int_value);
- EXPECT_EQ(FALSE_PREROTATION, outData[0]->getValues()[6].mValue.int_value);
- EXPECT_EQ(GLES_1_IN_USE, outData[0]->getValues()[7].mValue.int_value);
-}
-
-} // namespace statsd
-} // namespace os
-} // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
index 9cf1de9..ace13513 100644
--- a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
+++ b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
@@ -31,6 +31,13 @@
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_RIGHT;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_UP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_TRIPLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_DOUBLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SINGLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_DOWN;
+import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_LEFT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_RIGHT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_UP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_TRIPLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_DOUBLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_DOUBLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN;
@@ -105,7 +112,14 @@
GESTURE_3_FINGER_SWIPE_DOWN,
GESTURE_3_FINGER_SWIPE_LEFT,
GESTURE_3_FINGER_SWIPE_RIGHT,
- GESTURE_3_FINGER_SWIPE_UP
+ GESTURE_3_FINGER_SWIPE_UP,
+ GESTURE_4_FINGER_DOUBLE_TAP,
+ GESTURE_4_FINGER_SINGLE_TAP,
+ GESTURE_4_FINGER_SWIPE_DOWN,
+ GESTURE_4_FINGER_SWIPE_LEFT,
+ GESTURE_4_FINGER_SWIPE_RIGHT,
+ GESTURE_4_FINGER_SWIPE_UP,
+ GESTURE_4_FINGER_TRIPLE_TAP
})
@Retention(RetentionPolicy.SOURCE)
public @interface GestureId {}
@@ -165,6 +179,9 @@
case GESTURE_3_FINGER_SINGLE_TAP: return "GESTURE_3_FINGER_SINGLE_TAP";
case GESTURE_3_FINGER_DOUBLE_TAP: return "GESTURE_3_FINGER_DOUBLE_TAP";
case GESTURE_3_FINGER_TRIPLE_TAP: return "GESTURE_3_FINGER_TRIPLE_TAP";
+ case GESTURE_4_FINGER_SINGLE_TAP: return "GESTURE_4_FINGER_SINGLE_TAP";
+ case GESTURE_4_FINGER_DOUBLE_TAP: return "GESTURE_4_FINGER_DOUBLE_TAP";
+ case GESTURE_4_FINGER_TRIPLE_TAP: return "GESTURE_4_FINGER_TRIPLE_TAP";
case GESTURE_DOUBLE_TAP: return "GESTURE_DOUBLE_TAP";
case GESTURE_DOUBLE_TAP_AND_HOLD: return "GESTURE_DOUBLE_TAP_AND_HOLD";
case GESTURE_SWIPE_DOWN: return "GESTURE_SWIPE_DOWN";
@@ -191,6 +208,10 @@
case GESTURE_3_FINGER_SWIPE_LEFT: return "GESTURE_3_FINGER_SWIPE_LEFT";
case GESTURE_3_FINGER_SWIPE_RIGHT: return "GESTURE_3_FINGER_SWIPE_RIGHT";
case GESTURE_3_FINGER_SWIPE_UP: return "GESTURE_3_FINGER_SWIPE_UP";
+ case GESTURE_4_FINGER_SWIPE_DOWN: return "GESTURE_4_FINGER_SWIPE_DOWN";
+ case GESTURE_4_FINGER_SWIPE_LEFT: return "GESTURE_4_FINGER_SWIPE_LEFT";
+ case GESTURE_4_FINGER_SWIPE_RIGHT: return "GESTURE_4_FINGER_SWIPE_RIGHT";
+ case GESTURE_4_FINGER_SWIPE_UP: return "GESTURE_4_FINGER_SWIPE_UP";
default: return Integer.toHexString(eventType);
}
}
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 2165fb3..b65f68e 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -28,7 +28,9 @@
import android.content.Intent;
import android.content.pm.ParceledListSlice;
import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
import android.graphics.Region;
+import android.hardware.HardwareBuffer;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -388,6 +390,27 @@
*/
public static final int GESTURE_3_FINGER_SWIPE_RIGHT = 32;
+ /** The user has performed a four-finger swipe up gesture on the touch screen. */
+ public static final int GESTURE_4_FINGER_SWIPE_UP = 33;
+
+ /** The user has performed a four-finger swipe down gesture on the touch screen. */
+ public static final int GESTURE_4_FINGER_SWIPE_DOWN = 34;
+
+ /** The user has performed a four-finger swipe left gesture on the touch screen. */
+ public static final int GESTURE_4_FINGER_SWIPE_LEFT = 35;
+
+ /** The user has performed a four-finger swipe right gesture on the touch screen. */
+ public static final int GESTURE_4_FINGER_SWIPE_RIGHT = 36;
+
+ /** The user has performed a four-finger single tap gesture on the touch screen. */
+ public static final int GESTURE_4_FINGER_SINGLE_TAP = 37;
+
+ /** The user has performed a four-finger double tap gesture on the touch screen. */
+ public static final int GESTURE_4_FINGER_DOUBLE_TAP = 38;
+
+ /** The user has performed a four-finger triple tap gesture on the touch screen. */
+ public static final int GESTURE_4_FINGER_TRIPLE_TAP = 39;
+
/**
* The {@link Intent} that must be declared as handled by the service.
*/
@@ -564,7 +587,12 @@
private FingerprintGestureController mFingerprintGestureController;
/** @hide */
- public static final String KEY_ACCESSIBILITY_SCREENSHOT = "screenshot";
+ public static final String KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER =
+ "screenshot_hardwareBuffer";
+
+ /** @hide */
+ public static final String KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE_ID =
+ "screenshot_colorSpaceId";
/**
* Callback for {@link android.view.accessibility.AccessibilityEvent}s.
@@ -1867,8 +1895,9 @@
}
/**
- * Takes a screenshot of the specified display and returns it by {@link Bitmap.Config#HARDWARE}
- * format.
+ * Takes a screenshot of the specified display and returns it via an
+ * {@link AccessibilityService.ScreenshotResult}. You can use {@link Bitmap#wrapHardwareBuffer}
+ * to construct the bitmap from the ScreenshotResult's payload.
* <p>
* <strong>Note:</strong> In order to take screenshot your service has
* to declare the capability to take screenshot by setting the
@@ -1886,7 +1915,7 @@
* @return {@code true} if the taking screenshot accepted, {@code false} if not.
*/
public boolean takeScreenshot(int displayId, @NonNull @CallbackExecutor Executor executor,
- @NonNull Consumer<Bitmap> callback) {
+ @NonNull Consumer<ScreenshotResult> callback) {
Preconditions.checkNotNull(executor, "executor cannot be null");
Preconditions.checkNotNull(callback, "callback cannot be null");
final IAccessibilityServiceConnection connection =
@@ -1896,14 +1925,22 @@
return false;
}
try {
- connection.takeScreenshotWithCallback(displayId, new RemoteCallback((result) -> {
- final Bitmap screenshot = result.getParcelable(KEY_ACCESSIBILITY_SCREENSHOT);
- final long identity = Binder.clearCallingIdentity();
- try {
- executor.execute(() -> callback.accept(screenshot));
- } finally {
- Binder.restoreCallingIdentity(identity);
+ connection.takeScreenshot(displayId, new RemoteCallback((result) -> {
+ if (result == null) {
+ sendScreenshotResult(executor, callback, null);
+ return;
}
+ final HardwareBuffer hardwareBuffer =
+ result.getParcelable(KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER);
+ final int colorSpaceId =
+ result.getInt(KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE_ID);
+ ColorSpace colorSpace = null;
+ if (colorSpaceId >= 0 && colorSpaceId < ColorSpace.Named.values().length) {
+ colorSpace = ColorSpace.get(ColorSpace.Named.values()[colorSpaceId]);
+ }
+ ScreenshotResult screenshot = new ScreenshotResult(hardwareBuffer,
+ colorSpace, System.currentTimeMillis());
+ sendScreenshotResult(executor, callback, screenshot);
}));
} catch (RemoteException re) {
throw new RuntimeException(re);
@@ -2302,4 +2339,67 @@
this.handler = handler;
}
}
+
+ private void sendScreenshotResult(Executor executor, Consumer<ScreenshotResult> callback,
+ ScreenshotResult screenshot) {
+ final ScreenshotResult result = screenshot;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.accept(result));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Class including hardwareBuffer, colorSpace, and timestamp to be the result for
+ * {@link AccessibilityService#takeScreenshot} API.
+ * <p>
+ * <strong>Note:</strong> colorSpace would be null if the name of this colorSpace isn't at
+ * {@link ColorSpace.Named}.
+ * </p>
+ */
+ public static final class ScreenshotResult {
+ private final @NonNull HardwareBuffer mHardwareBuffer;
+ private final @Nullable ColorSpace mColorSpace;
+ private final long mTimestamp;
+
+ private ScreenshotResult(@NonNull HardwareBuffer hardwareBuffer,
+ @Nullable ColorSpace colorSpace, long timestamp) {
+ Preconditions.checkNotNull(hardwareBuffer, "hardwareBuffer cannot be null");
+ mHardwareBuffer = hardwareBuffer;
+ mColorSpace = colorSpace;
+ mTimestamp = timestamp;
+ }
+
+ /**
+ * Gets the colorSpace identifying a specific organization of colors of the screenshot.
+ *
+ * @return the colorSpace or {@code null} if the name of colorSpace isn't at
+ * {@link ColorSpace.Named}
+ */
+ @Nullable
+ public ColorSpace getColorSpace() {
+ return mColorSpace;
+ }
+
+ /**
+ * Gets the hardwareBuffer representing a memory buffer of the screenshot.
+ *
+ * @return the hardwareBuffer
+ */
+ @NonNull
+ public HardwareBuffer getHardwareBuffer() {
+ return mHardwareBuffer;
+ }
+
+ /**
+ * Gets the timestamp of taking the screenshot.
+ *
+ * @return the timestamp from {@link System#currentTimeMillis()}
+ */
+ public long getTimestamp() {
+ return mTimestamp;
+ };
+ }
}
diff --git a/core/java/android/accessibilityservice/GestureDescription.java b/core/java/android/accessibilityservice/GestureDescription.java
index 3b79d21..a821dad 100644
--- a/core/java/android/accessibilityservice/GestureDescription.java
+++ b/core/java/android/accessibilityservice/GestureDescription.java
@@ -40,7 +40,7 @@
*/
public final class GestureDescription {
/** Gestures may contain no more than this many strokes */
- private static final int MAX_STROKE_COUNT = 10;
+ private static final int MAX_STROKE_COUNT = 20;
/**
* Upper bound on total gesture duration. Nearly all gestures will be much shorter.
@@ -194,7 +194,10 @@
public Builder addStroke(@NonNull StrokeDescription strokeDescription) {
if (mStrokes.size() >= MAX_STROKE_COUNT) {
throw new IllegalStateException(
- "Attempting to add too many strokes to a gesture");
+ "Attempting to add too many strokes to a gesture. Maximum is "
+ + MAX_STROKE_COUNT
+ + ", got "
+ + mStrokes.size());
}
mStrokes.add(strokeDescription);
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 5db4dd7..9177d4d 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -110,7 +110,5 @@
int getWindowIdForLeashToken(IBinder token);
- Bitmap takeScreenshot(int displayId);
-
- void takeScreenshotWithCallback(int displayId, in RemoteCallback callback);
+ void takeScreenshot(int displayId, in RemoteCallback callback);
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index f31c614..642f51b 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2880,13 +2880,14 @@
* {@link #enterPictureInPictureMode(PictureInPictureParams)} at this time. For example, the
* system will call this method when the activity is being put into the background, so the app
* developer might want to switch an activity into PIP mode instead.</p>
+ *
+ * @return {@code true} if the activity received this callback regardless of if it acts on it
+ * or not. If {@code false}, the framework will assume the app hasn't been updated to leverage
+ * this callback and will in turn send a legacy callback of {@link #onUserLeaveHint()} for the
+ * app to enter picture-in-picture mode.
*/
- public void onPictureInPictureRequested() {
- // Previous recommendation was for apps to enter picture-in-picture in onUserLeaveHint()
- // which is sent after onPause(). This new method allows the system to request the app to
- // go into picture-in-picture decoupling it from life cycle events. For backwards
- // compatibility we schedule the life cycle events if the app didn't override this method.
- mMainThread.schedulePauseAndReturnToCurrentState(mToken);
+ public boolean onPictureInPictureRequested() {
+ return false;
}
void dispatchMovedToDisplay(int displayId, Configuration config) {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 206c771..db9aa18 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1472,7 +1472,7 @@
dest.writeInt(1);
dest.writeString(mLabel);
}
- if (mIcon == null) {
+ if (mIcon == null || mIcon.isRecycled()) {
dest.writeInt(0);
} else {
dest.writeInt(1);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index c901d2a..1921567 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3772,7 +3772,15 @@
return;
}
- r.activity.onPictureInPictureRequested();
+ final boolean receivedByApp = r.activity.onPictureInPictureRequested();
+ if (!receivedByApp) {
+ // Previous recommendation was for apps to enter picture-in-picture in
+ // onUserLeavingHint() for cases such as the app being put into the background. For
+ // backwards compatibility with apps that are not using the newer
+ // onPictureInPictureRequested() callback, we schedule the life cycle events needed to
+ // trigger onUserLeavingHint(), then we return the activity to its previous state.
+ schedulePauseWithUserLeaveHintAndReturnToCurrentState(r);
+ }
}
/**
@@ -3780,18 +3788,7 @@
* return to its previous state. This allows activities that rely on onUserLeaveHint instead of
* onPictureInPictureRequested to enter picture-in-picture.
*/
- public void schedulePauseAndReturnToCurrentState(IBinder token) {
- final ActivityClientRecord r = mActivities.get(token);
- if (r == null) {
- Log.w(TAG, "Activity to request pause with user leaving hint to no longer exists");
- return;
- }
-
- if (r.mIsUserLeaving) {
- // The activity is about to perform user leaving, so there's no need to cycle ourselves.
- return;
- }
-
+ private void schedulePauseWithUserLeaveHintAndReturnToCurrentState(ActivityClientRecord r) {
final int prevState = r.getLifecycleState();
if (prevState != ON_RESUME && prevState != ON_PAUSE) {
return;
@@ -4544,7 +4541,6 @@
if (r != null) {
if (userLeaving) {
performUserLeavingActivity(r);
- r.mIsUserLeaving = false;
}
r.activity.mConfigChangeFlags |= configChanges;
@@ -4559,7 +4555,6 @@
}
final void performUserLeavingActivity(ActivityClientRecord r) {
- r.mIsUserLeaving = true;
mInstrumentation.callActivityOnPictureInPictureRequested(r.activity);
mInstrumentation.callActivityOnUserLeaving(r.activity);
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 861d41d..6ef99a3 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -27,6 +27,8 @@
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.app.usage.UsageStatsManager;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
import android.content.Context;
@@ -101,6 +103,18 @@
@SystemService(Context.APP_OPS_SERVICE)
public class AppOpsManager {
/**
+ * This is a subtle behavior change to {@link #startWatchingMode}.
+ *
+ * Before this change the system called back for the switched op. After the change the system
+ * will call back for the actually requested op or all switched ops if no op is specified.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
+ public static final long CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE = 148180766L;
+
+ /**
* <p>App ops allows callers to:</p>
*
* <ul>
@@ -147,6 +161,38 @@
static IBinder sClientId;
+ /**
+ * How many seconds we want for a drop in uid state from top to settle before applying it.
+ *
+ * <>Set a parameter to {@link android.provider.Settings.Global#APP_OPS_CONSTANTS}
+ *
+ * @hide
+ */
+ @TestApi
+ public static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
+
+ /**
+ * How many second we want for a drop in uid state from foreground to settle before applying it.
+ *
+ * <>Set a parameter to {@link android.provider.Settings.Global#APP_OPS_CONSTANTS}
+ *
+ * @hide
+ */
+ @TestApi
+ public static final String KEY_FG_SERVICE_STATE_SETTLE_TIME =
+ "fg_service_state_settle_time";
+
+ /**
+ * How many seconds we want for a drop in uid state from background to settle before applying
+ * it.
+ *
+ * <>Set a parameter to {@link android.provider.Settings.Global#APP_OPS_CONSTANTS}
+ *
+ * @hide
+ */
+ @TestApi
+ public static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time";
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = { "HISTORICAL_MODE_" }, value = {
@@ -2808,7 +2854,7 @@
* @param flags The op flags
*
* @return the last access time (in milliseconds since epoch start (January 1, 1970
- * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+ * 00:00:00.000 GMT - Gregorian)) or {@code -1} if there was no access
*
* @see #getLastAccessForegroundTime(int)
* @see #getLastAccessBackgroundTime(int)
@@ -2825,7 +2871,7 @@
* @param flags The op flags
*
* @return the last access time (in milliseconds since epoch start (January 1, 1970
- * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+ * 00:00:00.000 GMT - Gregorian)) or {@code -1} if there was no foreground access
*
* @see #getLastAccessTime(int)
* @see #getLastAccessBackgroundTime(int)
@@ -2843,7 +2889,7 @@
* @param flags The op flags
*
* @return the last access time (in milliseconds since epoch start (January 1, 1970
- * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+ * 00:00:00.000 GMT - Gregorian)) or {@code -1} if there was no background access
*
* @see #getLastAccessTime(int)
* @see #getLastAccessForegroundTime(int)
@@ -2860,7 +2906,7 @@
*
* @param flags The op flags
*
- * @return the last access event of {@code null}
+ * @return the last access event of {@code null} if there was no access
*/
private @Nullable NoteOpEvent getLastAccessEvent(@UidState int fromUidState,
@UidState int toUidState, @OpFlags int flags) {
@@ -2875,7 +2921,7 @@
* @param flags The op flags
*
* @return the last access time (in milliseconds since epoch start (January 1, 1970
- * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+ * 00:00:00.000 GMT - Gregorian)) or {@code -1} if there was no access
*
* @see #getLastAccessTime(int)
* @see #getLastAccessForegroundTime(int)
@@ -2898,7 +2944,7 @@
* @param flags The op flags
*
* @return the last rejection time (in milliseconds since epoch start (January 1, 1970
- * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+ * 00:00:00.000 GMT - Gregorian)) or {@code -1} if there was no rejection
*
* @see #getLastRejectForegroundTime(int)
* @see #getLastRejectBackgroundTime(int)
@@ -2915,7 +2961,7 @@
* @param flags The op flags
*
* @return the last rejection time (in milliseconds since epoch start (January 1, 1970
- * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+ * 00:00:00.000 GMT - Gregorian)) or {@code -1} if there was no foreground rejection
*
* @see #getLastRejectTime(int)
* @see #getLastRejectBackgroundTime(int)
@@ -2933,7 +2979,7 @@
* @param flags The op flags
*
* @return the last rejection time (in milliseconds since epoch start (January 1, 1970
- * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+ * 00:00:00.000 GMT - Gregorian)) or {@code -1} if there was no background rejection
*
* @see #getLastRejectTime(int)
* @see #getLastRejectForegroundTime(int)
@@ -2950,8 +2996,7 @@
*
* @param flags The op flags
*
- * @return the last rejection time (in milliseconds since epoch start (January 1, 1970
- * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+ * @return the last rejection event of {@code null} if there was no rejection
*
* @see #getLastRejectTime(int)
* @see #getLastRejectForegroundTime(int)
@@ -2970,7 +3015,8 @@
* @param toUidState The highest UID state for which to query (inclusive)
* @param flags The op flags
*
- * @return the last access time (in milliseconds since epoch) or {@code -1}
+ * @return the last access time (in milliseconds since epoch) or {@code -1} if there was no
+ * rejection
*
* @see #getLastRejectTime(int)
* @see #getLastRejectForegroundTime(int)
@@ -2993,7 +3039,7 @@
*
* @param flags The op flags
*
- * @return the duration in milliseconds or {@code -1}
+ * @return the duration in milliseconds or {@code -1} if there was no rejection
*
* @see #getLastForegroundDuration(int)
* @see #getLastBackgroundDuration(int)
@@ -3009,7 +3055,7 @@
*
* @param flags The op flags
*
- * @return the duration in milliseconds or {@code -1}
+ * @return the duration in milliseconds or {@code -1} if there was no foreground rejection
*
* @see #getLastDuration(int)
* @see #getLastBackgroundDuration(int)
@@ -3026,7 +3072,7 @@
*
* @param flags The op flags
*
- * @return the duration in milliseconds or {@code -1}
+ * @return the duration in milliseconds or {@code -1} if there was no background rejection
*
* @see #getLastDuration(int)
* @see #getLastForegroundDuration(int)
@@ -3045,7 +3091,7 @@
* @param toUidState The highest UID state for which to query (inclusive)
* @param flags The op flags
*
- * @return the duration in milliseconds or {@code -1}
+ * @return the duration in milliseconds or {@code -1} if there was no rejection
*
* @see #getLastDuration(int)
* @see #getLastForegroundDuration(int)
@@ -3069,7 +3115,7 @@
*
* @param flags The op flags
*
- * @return The proxy name or {@code null}
+ * @return The proxy info or {@code null} if there was no proxy access
*
* @see #getLastForegroundProxyInfo(int)
* @see #getLastBackgroundProxyInfo(int)
@@ -3086,7 +3132,7 @@
*
* @param flags The op flags
*
- * @return The proxy name or {@code null}
+ * @return The proxy info or {@code null} if there was no proxy access
*
* @see #getLastProxyInfo(int)
* @see #getLastBackgroundProxyInfo(int)
@@ -3104,7 +3150,7 @@
*
* @param flags The op flags
*
- * @return The proxy name or {@code null}
+ * @return The proxy info or {@code null} if there was no proxy background access
*
* @see #getLastProxyInfo(int)
* @see #getLastForegroundProxyInfo(int)
@@ -3124,7 +3170,7 @@
* @param toUidState The highest UID state for which to query (inclusive)
* @param flags The op flags
*
- * @return The proxy name or {@code null}
+ * @return The proxy info or {@code null} if there was no proxy foreground access
*
* @see #getLastProxyInfo(int)
* @see #getLastForegroundProxyInfo(int)
@@ -3380,7 +3426,7 @@
* @param flags The op flags
*
* @return the last access time (in milliseconds since epoch start (January 1, 1970
- * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+ * 00:00:00.000 GMT - Gregorian)) or {@code -1} if there was no access
*
* @see #getLastAccessForegroundTime(int)
* @see #getLastAccessBackgroundTime(int)
@@ -3397,7 +3443,7 @@
* @param flags The op flags
*
* @return the last access time (in milliseconds since epoch start (January 1, 1970
- * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+ * 00:00:00.000 GMT - Gregorian)) or {@code -1} if there was no foreground access
*
* @see #getLastAccessTime(int)
* @see #getLastAccessBackgroundTime(int)
@@ -3415,7 +3461,7 @@
* @param flags The op flags
*
* @return the last access time (in milliseconds since epoch start (January 1, 1970
- * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+ * 00:00:00.000 GMT - Gregorian)) or {@code -1} if there was no background access
*
* @see #getLastAccessTime(int)
* @see #getLastAccessForegroundTime(int)
@@ -3432,7 +3478,7 @@
*
* @param flags The op flags
*
- * @return the last access event of {@code null}
+ * @return the last access event of {@code null} if there was no access
*/
private @Nullable NoteOpEvent getLastAccessEvent(@UidState int fromUidState,
@UidState int toUidState, @OpFlags int flags) {
@@ -3458,7 +3504,7 @@
* @param flags The op flags
*
* @return the last access time (in milliseconds since epoch start (January 1, 1970
- * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+ * 00:00:00.000 GMT - Gregorian)) or {@code -1} if there was no access
*
* @see #getLastAccessTime(int)
* @see #getLastAccessForegroundTime(int)
@@ -3494,7 +3540,7 @@
* @param flags The op flags
*
* @return the last rejection time (in milliseconds since epoch start (January 1, 1970
- * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+ * 00:00:00.000 GMT - Gregorian)) or {@code -1} if there was no rejection
*
* @see #getLastRejectForegroundTime(int)
* @see #getLastRejectBackgroundTime(int)
@@ -3511,7 +3557,7 @@
* @param flags The op flags
*
* @return the last rejection time (in milliseconds since epoch start (January 1, 1970
- * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+ * 00:00:00.000 GMT - Gregorian)) or {@code -1} if there was no foreground rejection
*
* @see #getLastRejectTime(int)
* @see #getLastRejectBackgroundTime(int)
@@ -3529,7 +3575,7 @@
* @param flags The op flags
*
* @return the last rejection time (in milliseconds since epoch start (January 1, 1970
- * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+ * 00:00:00.000 GMT - Gregorian)) or {@code -1} if there was no background rejection
*
* @see #getLastRejectTime(int)
* @see #getLastRejectForegroundTime(int)
@@ -3546,7 +3592,7 @@
*
* @param flags The op flags
*
- * @return the last reject event of {@code null}
+ * @return the last reject event of {@code null} if there was no rejection
*/
private @Nullable NoteOpEvent getLastRejectEvent(@UidState int fromUidState,
@UidState int toUidState, @OpFlags int flags) {
@@ -3572,7 +3618,7 @@
* @param flags The op flags
*
* @return the last rejection time (in milliseconds since epoch start (January 1, 1970
- * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+ * 00:00:00.000 GMT - Gregorian)) or {@code -1} if there was no rejection
*
* @see #getLastRejectTime(int)
* @see #getLastRejectForegroundTime(int)
@@ -3616,7 +3662,7 @@
*
* @param flags The op flags
*
- * @return the duration in milliseconds or {@code -1}
+ * @return the duration in milliseconds or {@code -1} if there was no access
*
* @see #getLastForegroundDuration(int)
* @see #getLastBackgroundDuration(int)
@@ -3632,7 +3678,7 @@
*
* @param flags The op flags
*
- * @return the duration in milliseconds or {@code -1}
+ * @return the duration in milliseconds or {@code -1} if there was no foreground access
*
* @see #getLastDuration(int)
* @see #getLastBackgroundDuration(int)
@@ -3649,7 +3695,7 @@
*
* @param flags The op flags
*
- * @return the duration in milliseconds or {@code -1}
+ * @return the duration in milliseconds or {@code -1} if there was no background access
*
* @see #getLastDuration(int)
* @see #getLastForegroundDuration(int)
@@ -3668,7 +3714,7 @@
* @param toUidState The highest UID state for which to query (inclusive)
* @param flags The op flags
*
- * @return the duration in milliseconds or {@code -1}
+ * @return the duration in milliseconds or {@code -1} if there was no access
*
* @see #getLastDuration(int)
* @see #getLastForegroundDuration(int)
@@ -3743,7 +3789,7 @@
*
* @param flags The op flags
*
- * @return The proxy name or {@code null}
+ * @return The proxy info or {@code null} if there was no proxy access
*
* @see #getLastForegroundProxyInfo(int)
* @see #getLastBackgroundProxyInfo(int)
@@ -3760,7 +3806,7 @@
*
* @param flags The op flags
*
- * @return The proxy name or {@code null}
+ * @return The proxy info or {@code null} if there was no foreground proxy access
*
* @see #getLastProxyInfo(int)
* @see #getLastBackgroundProxyInfo(int)
@@ -3778,7 +3824,7 @@
*
* @param flags The op flags
*
- * @return The proxy name or {@code null}
+ * @return The proxy info or {@code null} if there was no background proxy access
*
* @see #getLastProxyInfo(int)
* @see #getLastForegroundProxyInfo(int)
@@ -3798,7 +3844,7 @@
* @param toUidState The highest UID state for which to query (inclusive)
* @param flags The op flags
*
- * @return The proxy name or {@code null}
+ * @return The proxy info or {@code null} if there was no proxy access
*
* @see #getLastProxyInfo(int)
* @see #getLastForegroundProxyInfo(int)
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 4b1ba02..16c0910 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -48,6 +48,8 @@
void clearData(String pkg, int uid, boolean fromApp);
void enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration, int displayId, @nullable ITransientNotificationCallback callback);
void enqueueToast(String pkg, IBinder token, ITransientNotification callback, int duration, int displayId);
+ // TODO(b/144152069): Remove this after assessing impact on dogfood.
+ void enqueueTextOrCustomToast(String pkg, IBinder token, ITransientNotification callback, int duration, int displayId, boolean isCustom);
void cancelToast(String pkg, IBinder token);
void finishToken(String pkg, IBinder token);
diff --git a/core/java/android/app/ITaskOrganizerController.aidl b/core/java/android/app/ITaskOrganizerController.aidl
index 168f782..bfc42ef 100644
--- a/core/java/android/app/ITaskOrganizerController.aidl
+++ b/core/java/android/app/ITaskOrganizerController.aidl
@@ -31,8 +31,19 @@
*/
void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode);
- /** Apply multiple WindowContainer operations at once. */
- void applyContainerTransaction(in WindowContainerTransaction t);
+ /**
+ * Apply multiple WindowContainer operations at once.
+ * @param organizer If non-null this transaction will use the synchronization
+ * scheme described in BLASTSyncEngine.java. The SurfaceControl transaction
+ * containing the effects of this WindowContainer transaction will be passed
+ * to the organizers Transaction ready callback. If null the transaction
+ * will apply with non particular synchronization constraints (other than
+ * it will all apply at once).
+ * @return If organizer was non-null returns an ID for the sync operation which will
+ * later be passed to transactionReady. This lets TaskOrganizer implementations
+ * differentiate overlapping sync operations.
+ */
+ int applyContainerTransaction(in WindowContainerTransaction t, ITaskOrganizer organizer);
/** Creates a persistent root task in WM for a particular windowing-mode. */
ActivityManager.RunningTaskInfo createRootTask(int displayId, int windowingMode);
diff --git a/core/java/android/app/admin/DevicePolicyKeyguardService.java b/core/java/android/app/admin/DevicePolicyKeyguardService.java
index c2a76c5..2ac5ebf 100644
--- a/core/java/android/app/admin/DevicePolicyKeyguardService.java
+++ b/core/java/android/app/admin/DevicePolicyKeyguardService.java
@@ -22,7 +22,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
-import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
/**
* Client interface for providing the SystemUI with secondary lockscreen information.
@@ -43,14 +43,14 @@
@Override
public void onSurfaceReady(@Nullable IBinder hostInputToken, IKeyguardCallback callback) {
mCallback = callback;
- SurfaceControl surfaceControl =
+ SurfaceControlViewHost.SurfacePackage surfacePackage =
DevicePolicyKeyguardService.this.onSurfaceReady(hostInputToken);
if (mCallback != null) {
try {
- mCallback.onSurfaceControlCreated(surfaceControl);
+ mCallback.onRemoteContentReady(surfacePackage);
} catch (RemoteException e) {
- Log.e(TAG, "Failed to return created SurfaceControl", e);
+ Log.e(TAG, "Failed to return created SurfacePackage", e);
}
}
}
@@ -65,11 +65,11 @@
/**
* Called by keyguard once the host surface for the secondary lockscreen is ready to display
* remote content.
- * @return the {@link SurfaceControl} for the Surface the secondary lockscreen content is
- * attached to.
+ * @return the {@link SurfaceControlViewHost.SurfacePackage} for the Surface the
+ * secondary lockscreen content is attached to.
*/
@Nullable
- public SurfaceControl onSurfaceReady(@Nullable IBinder hostInputToken) {
+ public SurfaceControlViewHost.SurfacePackage onSurfaceReady(@Nullable IBinder hostInputToken) {
return null;
}
diff --git a/core/java/android/app/admin/IKeyguardCallback.aidl b/core/java/android/app/admin/IKeyguardCallback.aidl
index 81e7d4d..856033d 100644
--- a/core/java/android/app/admin/IKeyguardCallback.aidl
+++ b/core/java/android/app/admin/IKeyguardCallback.aidl
@@ -15,13 +15,13 @@
*/
package android.app.admin;
-import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
/**
* Internal IPC interface for informing the keyguard of events on the secondary lockscreen.
* @hide
*/
interface IKeyguardCallback {
- oneway void onSurfaceControlCreated(in SurfaceControl remoteSurfaceControl);
+ oneway void onRemoteContentReady(in SurfaceControlViewHost.SurfacePackage surfacePackage);
oneway void onDismiss();
}
diff --git a/core/java/android/app/compat/CompatChanges.java b/core/java/android/app/compat/CompatChanges.java
new file mode 100644
index 0000000..5b36789
--- /dev/null
+++ b/core/java/android/app/compat/CompatChanges.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.compat;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.compat.Compatibility;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+
+import com.android.internal.compat.IPlatformCompat;
+
+/**
+ * CompatChanges APIs - to be used by platform code only (including mainline
+ * modules).
+ *
+ * @hide
+ */
+@SystemApi
+public final class CompatChanges {
+ private CompatChanges() {}
+
+ /**
+ * Query if a given compatibility change is enabled for the current process. This method is
+ * intended to be called by code running inside a process of the affected app only.
+ *
+ * <p>If this method returns {@code true}, the calling code should implement the compatibility
+ * change, resulting in differing behaviour compared to earlier releases. If this method returns
+ * {@code false}, the calling code should behave as it did in earlier releases.
+ *
+ * @param changeId The ID of the compatibility change in question.
+ * @return {@code true} if the change is enabled for the current app.
+ */
+ public static boolean isChangeEnabled(long changeId) {
+ return Compatibility.isChangeEnabled(changeId);
+ }
+
+ /**
+ * Same as {@code #isChangeEnabled(long)}, except this version should be called on behalf of an
+ * app from a different process that's performing work for the app.
+ *
+ * <p> Note that this involves a binder call to the system server (unless running in the system
+ * server). If the binder call fails, a {@code RuntimeException} will be thrown.
+ *
+ * <p> Caller must have android.permission.READ_COMPAT_CHANGE_CONFIG permission. If it
+ * doesn't, a {@code RuntimeException} will be thrown.
+ *
+ * @param changeId The ID of the compatibility change in question.
+ * @param packageName The package name of the app in question.
+ * @param user The user that the operation is done for.
+ * @return {@code true} if the change is enabled for the current app.
+ */
+ public static boolean isChangeEnabled(long changeId, @NonNull String packageName,
+ @NonNull UserHandle user) {
+ IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
+ ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+ try {
+ return platformCompat.isChangeEnabledByPackageName(changeId, packageName,
+ user.getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Same as {@code #isChangeEnabled(long)}, except this version should be called on behalf of an
+ * app from a different process that's performing work for the app.
+ *
+ * <p> Note that this involves a binder call to the system server (unless running in the system
+ * server). If the binder call fails, {@code RuntimeException} will be thrown.
+ *
+ * <p> Caller must have android.permission.READ_COMPAT_CHANGE_CONFIG permission. If it
+ * doesn't, a {@code RuntimeException} will be thrown.
+ *
+ * <p> Returns {@code true} if there are no installed packages for the required UID, or if the
+ * change is enabled for ALL of the installed packages associated with the provided UID. Please
+ * use a more specific API if you want a different behaviour for multi-package UIDs.
+ *
+ * @param changeId The ID of the compatibility change in question.
+ * @param uid The UID of the app in question.
+ * @return {@code true} if the change is enabled for the current app.
+ */
+ public static boolean isChangeEnabled(long changeId, int uid) {
+ IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
+ ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+ try {
+ return platformCompat.isChangeEnabledByUid(changeId, uid);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/core/java/android/app/timedetector/ITimeDetectorService.aidl b/core/java/android/app/timedetector/ITimeDetectorService.aidl
index de8f470..5ead0c9 100644
--- a/core/java/android/app/timedetector/ITimeDetectorService.aidl
+++ b/core/java/android/app/timedetector/ITimeDetectorService.aidl
@@ -18,7 +18,7 @@
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
-import android.app.timedetector.PhoneTimeSuggestion;
+import android.app.timedetector.TelephonyTimeSuggestion;
/**
* System private API to communicate with time detector service.
@@ -34,7 +34,7 @@
* {@hide}
*/
interface ITimeDetectorService {
- void suggestPhoneTime(in PhoneTimeSuggestion timeSuggestion);
void suggestManualTime(in ManualTimeSuggestion timeSuggestion);
void suggestNetworkTime(in NetworkTimeSuggestion timeSuggestion);
+ void suggestTelephonyTime(in TelephonyTimeSuggestion timeSuggestion);
}
diff --git a/core/java/android/app/timedetector/PhoneTimeSuggestion.aidl b/core/java/android/app/timedetector/TelephonyTimeSuggestion.aidl
similarity index 94%
rename from core/java/android/app/timedetector/PhoneTimeSuggestion.aidl
rename to core/java/android/app/timedetector/TelephonyTimeSuggestion.aidl
index f5e2405..d9b0386 100644
--- a/core/java/android/app/timedetector/PhoneTimeSuggestion.aidl
+++ b/core/java/android/app/timedetector/TelephonyTimeSuggestion.aidl
@@ -16,4 +16,4 @@
package android.app.timedetector;
-parcelable PhoneTimeSuggestion;
+parcelable TelephonyTimeSuggestion;
diff --git a/core/java/android/app/timedetector/PhoneTimeSuggestion.java b/core/java/android/app/timedetector/TelephonyTimeSuggestion.java
similarity index 79%
rename from core/java/android/app/timedetector/PhoneTimeSuggestion.java
rename to core/java/android/app/timedetector/TelephonyTimeSuggestion.java
index 0133a44..c0e8957 100644
--- a/core/java/android/app/timedetector/PhoneTimeSuggestion.java
+++ b/core/java/android/app/timedetector/TelephonyTimeSuggestion.java
@@ -50,17 +50,17 @@
*
* @hide
*/
-public final class PhoneTimeSuggestion implements Parcelable {
+public final class TelephonyTimeSuggestion implements Parcelable {
/** @hide */
- public static final @NonNull Parcelable.Creator<PhoneTimeSuggestion> CREATOR =
- new Parcelable.Creator<PhoneTimeSuggestion>() {
- public PhoneTimeSuggestion createFromParcel(Parcel in) {
- return PhoneTimeSuggestion.createFromParcel(in);
+ public static final @NonNull Parcelable.Creator<TelephonyTimeSuggestion> CREATOR =
+ new Parcelable.Creator<TelephonyTimeSuggestion>() {
+ public TelephonyTimeSuggestion createFromParcel(Parcel in) {
+ return TelephonyTimeSuggestion.createFromParcel(in);
}
- public PhoneTimeSuggestion[] newArray(int size) {
- return new PhoneTimeSuggestion[size];
+ public TelephonyTimeSuggestion[] newArray(int size) {
+ return new TelephonyTimeSuggestion[size];
}
};
@@ -68,15 +68,15 @@
@Nullable private final TimestampedValue<Long> mUtcTime;
@Nullable private ArrayList<String> mDebugInfo;
- private PhoneTimeSuggestion(Builder builder) {
+ private TelephonyTimeSuggestion(Builder builder) {
mSlotIndex = builder.mSlotIndex;
mUtcTime = builder.mUtcTime;
mDebugInfo = builder.mDebugInfo != null ? new ArrayList<>(builder.mDebugInfo) : null;
}
- private static PhoneTimeSuggestion createFromParcel(Parcel in) {
+ private static TelephonyTimeSuggestion createFromParcel(Parcel in) {
int slotIndex = in.readInt();
- PhoneTimeSuggestion suggestion = new PhoneTimeSuggestion.Builder(slotIndex)
+ TelephonyTimeSuggestion suggestion = new TelephonyTimeSuggestion.Builder(slotIndex)
.setUtcTime(in.readParcelable(null /* classLoader */))
.build();
@SuppressWarnings("unchecked")
@@ -102,7 +102,7 @@
/**
* Returns an identifier for the source of this suggestion.
*
- * <p>See {@link PhoneTimeSuggestion} for more information about {@code slotIndex}.
+ * <p>See {@link TelephonyTimeSuggestion} for more information about {@code slotIndex}.
*/
public int getSlotIndex() {
return mSlotIndex;
@@ -111,7 +111,7 @@
/**
* Returns the suggested time or {@code null} if there isn't one.
*
- * <p>See {@link PhoneTimeSuggestion} for more information about {@code utcTime}.
+ * <p>See {@link TelephonyTimeSuggestion} for more information about {@code utcTime}.
*/
@Nullable
public TimestampedValue<Long> getUtcTime() {
@@ -121,7 +121,7 @@
/**
* Returns debug metadata for the suggestion.
*
- * <p>See {@link PhoneTimeSuggestion} for more information about {@code debugInfo}.
+ * <p>See {@link TelephonyTimeSuggestion} for more information about {@code debugInfo}.
*/
@NonNull
public List<String> getDebugInfo() {
@@ -132,7 +132,7 @@
/**
* Associates information with the instance that can be useful for debugging / logging.
*
- * <p>See {@link PhoneTimeSuggestion} for more information about {@code debugInfo}.
+ * <p>See {@link TelephonyTimeSuggestion} for more information about {@code debugInfo}.
*/
public void addDebugInfo(@NonNull String debugInfo) {
if (mDebugInfo == null) {
@@ -144,7 +144,7 @@
/**
* Associates information with the instance that can be useful for debugging / logging.
*
- * <p>See {@link PhoneTimeSuggestion} for more information about {@code debugInfo}.
+ * <p>See {@link TelephonyTimeSuggestion} for more information about {@code debugInfo}.
*/
public void addDebugInfo(@NonNull List<String> debugInfo) {
if (mDebugInfo == null) {
@@ -161,7 +161,7 @@
if (o == null || getClass() != o.getClass()) {
return false;
}
- PhoneTimeSuggestion that = (PhoneTimeSuggestion) o;
+ TelephonyTimeSuggestion that = (TelephonyTimeSuggestion) o;
return mSlotIndex == that.mSlotIndex
&& Objects.equals(mUtcTime, that.mUtcTime);
}
@@ -173,7 +173,7 @@
@Override
public String toString() {
- return "PhoneTimeSuggestion{"
+ return "TelephonyTimeSuggestion{"
+ "mSlotIndex='" + mSlotIndex + '\''
+ ", mUtcTime=" + mUtcTime
+ ", mDebugInfo=" + mDebugInfo
@@ -181,7 +181,7 @@
}
/**
- * Builds {@link PhoneTimeSuggestion} instances.
+ * Builds {@link TelephonyTimeSuggestion} instances.
*
* @hide
*/
@@ -193,7 +193,7 @@
/**
* Creates a builder with the specified {@code slotIndex}.
*
- * <p>See {@link PhoneTimeSuggestion} for more information about {@code slotIndex}.
+ * <p>See {@link TelephonyTimeSuggestion} for more information about {@code slotIndex}.
*/
public Builder(int slotIndex) {
mSlotIndex = slotIndex;
@@ -202,7 +202,7 @@
/**
* Returns the builder for call chaining.
*
- * <p>See {@link PhoneTimeSuggestion} for more information about {@code utcTime}.
+ * <p>See {@link TelephonyTimeSuggestion} for more information about {@code utcTime}.
*/
@NonNull
public Builder setUtcTime(@Nullable TimestampedValue<Long> utcTime) {
@@ -218,7 +218,7 @@
/**
* Returns the builder for call chaining.
*
- * <p>See {@link PhoneTimeSuggestion} for more information about {@code debugInfo}.
+ * <p>See {@link TelephonyTimeSuggestion} for more information about {@code debugInfo}.
*/
@NonNull
public Builder addDebugInfo(@NonNull String debugInfo) {
@@ -229,10 +229,10 @@
return this;
}
- /** Returns the {@link PhoneTimeSuggestion}. */
+ /** Returns the {@link TelephonyTimeSuggestion}. */
@NonNull
- public PhoneTimeSuggestion build() {
- return new PhoneTimeSuggestion(this);
+ public TelephonyTimeSuggestion build() {
+ return new TelephonyTimeSuggestion(this);
}
}
}
diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java
index df4f513..84ad495 100644
--- a/core/java/android/app/timedetector/TimeDetector.java
+++ b/core/java/android/app/timedetector/TimeDetector.java
@@ -45,12 +45,12 @@
}
/**
- * Suggests the current phone-signal derived time to the detector. The detector may ignore the
- * signal if better signals are available such as those that come from more reliable sources or
- * were determined more recently.
+ * Suggests a telephony-signal derived time to the detector. The detector may ignore the signal
+ * if better signals are available such as those that come from more reliable sources or were
+ * determined more recently.
*/
- @RequiresPermission(android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE)
- void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion);
+ @RequiresPermission(android.Manifest.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE)
+ void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion timeSuggestion);
/**
* Suggests the user's manually entered current time to the detector.
diff --git a/core/java/android/app/timedetector/TimeDetectorImpl.java b/core/java/android/app/timedetector/TimeDetectorImpl.java
index 1683817..c1d6667 100644
--- a/core/java/android/app/timedetector/TimeDetectorImpl.java
+++ b/core/java/android/app/timedetector/TimeDetectorImpl.java
@@ -40,12 +40,12 @@
}
@Override
- public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
+ public void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion timeSuggestion) {
if (DEBUG) {
- Log.d(TAG, "suggestPhoneTime called: " + timeSuggestion);
+ Log.d(TAG, "suggestTelephonyTime called: " + timeSuggestion);
}
try {
- mITimeDetectorService.suggestPhoneTime(timeSuggestion);
+ mITimeDetectorService.suggestTelephonyTime(timeSuggestion);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
index df643831..b06f4b8 100644
--- a/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
+++ b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
@@ -17,7 +17,7 @@
package android.app.timezonedetector;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
-import android.app.timezonedetector.PhoneTimeZoneSuggestion;
+import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
/**
* System private API to communicate with time zone detector service.
@@ -34,5 +34,5 @@
*/
interface ITimeZoneDetectorService {
void suggestManualTimeZone(in ManualTimeZoneSuggestion timeZoneSuggestion);
- void suggestPhoneTimeZone(in PhoneTimeZoneSuggestion timeZoneSuggestion);
+ void suggestTelephonyTimeZone(in TelephonyTimeZoneSuggestion timeZoneSuggestion);
}
diff --git a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.aidl b/core/java/android/app/timezonedetector/TelephonyTimeZoneSuggestion.aidl
similarity index 94%
rename from core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.aidl
rename to core/java/android/app/timezonedetector/TelephonyTimeZoneSuggestion.aidl
index 3ad903b..b57ad20 100644
--- a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.aidl
+++ b/core/java/android/app/timezonedetector/TelephonyTimeZoneSuggestion.aidl
@@ -16,4 +16,4 @@
package android.app.timezonedetector;
-parcelable PhoneTimeZoneSuggestion;
+parcelable TelephonyTimeZoneSuggestion;
diff --git a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java b/core/java/android/app/timezonedetector/TelephonyTimeZoneSuggestion.java
similarity index 84%
rename from core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java
rename to core/java/android/app/timezonedetector/TelephonyTimeZoneSuggestion.java
index 9147b44..150c01d 100644
--- a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java
+++ b/core/java/android/app/timezonedetector/TelephonyTimeZoneSuggestion.java
@@ -56,18 +56,18 @@
*
* @hide
*/
-public final class PhoneTimeZoneSuggestion implements Parcelable {
+public final class TelephonyTimeZoneSuggestion implements Parcelable {
/** @hide */
@NonNull
- public static final Creator<PhoneTimeZoneSuggestion> CREATOR =
- new Creator<PhoneTimeZoneSuggestion>() {
- public PhoneTimeZoneSuggestion createFromParcel(Parcel in) {
- return PhoneTimeZoneSuggestion.createFromParcel(in);
+ public static final Creator<TelephonyTimeZoneSuggestion> CREATOR =
+ new Creator<TelephonyTimeZoneSuggestion>() {
+ public TelephonyTimeZoneSuggestion createFromParcel(Parcel in) {
+ return TelephonyTimeZoneSuggestion.createFromParcel(in);
}
- public PhoneTimeZoneSuggestion[] newArray(int size) {
- return new PhoneTimeZoneSuggestion[size];
+ public TelephonyTimeZoneSuggestion[] newArray(int size) {
+ return new TelephonyTimeZoneSuggestion[size];
}
};
@@ -76,7 +76,7 @@
* the same {@code slotIndex}.
*/
@NonNull
- public static PhoneTimeZoneSuggestion createEmptySuggestion(
+ public static TelephonyTimeZoneSuggestion createEmptySuggestion(
int slotIndex, @NonNull String debugInfo) {
return new Builder(slotIndex).addDebugInfo(debugInfo).build();
}
@@ -144,7 +144,7 @@
@Quality private final int mQuality;
@Nullable private List<String> mDebugInfo;
- private PhoneTimeZoneSuggestion(Builder builder) {
+ private TelephonyTimeZoneSuggestion(Builder builder) {
mSlotIndex = builder.mSlotIndex;
mZoneId = builder.mZoneId;
mMatchType = builder.mMatchType;
@@ -153,15 +153,16 @@
}
@SuppressWarnings("unchecked")
- private static PhoneTimeZoneSuggestion createFromParcel(Parcel in) {
+ private static TelephonyTimeZoneSuggestion createFromParcel(Parcel in) {
// Use the Builder so we get validation during build().
int slotIndex = in.readInt();
- PhoneTimeZoneSuggestion suggestion = new Builder(slotIndex)
+ TelephonyTimeZoneSuggestion suggestion = new Builder(slotIndex)
.setZoneId(in.readString())
.setMatchType(in.readInt())
.setQuality(in.readInt())
.build();
- List<String> debugInfo = in.readArrayList(PhoneTimeZoneSuggestion.class.getClassLoader());
+ List<String> debugInfo =
+ in.readArrayList(TelephonyTimeZoneSuggestion.class.getClassLoader());
if (debugInfo != null) {
suggestion.addDebugInfo(debugInfo);
}
@@ -185,7 +186,7 @@
/**
* Returns an identifier for the source of this suggestion.
*
- * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code slotIndex}.
+ * <p>See {@link TelephonyTimeZoneSuggestion} for more information about {@code slotIndex}.
*/
public int getSlotIndex() {
return mSlotIndex;
@@ -195,7 +196,7 @@
* Returns the suggested time zone Olson ID, e.g. "America/Los_Angeles". {@code null} means that
* the caller is no longer sure what the current time zone is.
*
- * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code zoneId}.
+ * <p>See {@link TelephonyTimeZoneSuggestion} for more information about {@code zoneId}.
*/
@Nullable
public String getZoneId() {
@@ -206,7 +207,7 @@
* Returns information about how the suggestion was determined which could be used to rank
* suggestions when several are available from different sources.
*
- * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code matchType}.
+ * <p>See {@link TelephonyTimeZoneSuggestion} for more information about {@code matchType}.
*/
@MatchType
public int getMatchType() {
@@ -216,7 +217,7 @@
/**
* Returns information about the likelihood of the suggested zone being correct.
*
- * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code quality}.
+ * <p>See {@link TelephonyTimeZoneSuggestion} for more information about {@code quality}.
*/
@Quality
public int getQuality() {
@@ -226,7 +227,7 @@
/**
* Returns debug metadata for the suggestion.
*
- * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code debugInfo}.
+ * <p>See {@link TelephonyTimeZoneSuggestion} for more information about {@code debugInfo}.
*/
@NonNull
public List<String> getDebugInfo() {
@@ -237,7 +238,7 @@
/**
* Associates information with the instance that can be useful for debugging / logging.
*
- * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code debugInfo}.
+ * <p>See {@link TelephonyTimeZoneSuggestion} for more information about {@code debugInfo}.
*/
public void addDebugInfo(@NonNull String debugInfo) {
if (mDebugInfo == null) {
@@ -249,7 +250,7 @@
/**
* Associates information with the instance that can be useful for debugging / logging.
*
- * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code debugInfo}.
+ * <p>See {@link TelephonyTimeZoneSuggestion} for more information about {@code debugInfo}.
*/
public void addDebugInfo(@NonNull List<String> debugInfo) {
if (mDebugInfo == null) {
@@ -266,7 +267,7 @@
if (o == null || getClass() != o.getClass()) {
return false;
}
- PhoneTimeZoneSuggestion that = (PhoneTimeZoneSuggestion) o;
+ TelephonyTimeZoneSuggestion that = (TelephonyTimeZoneSuggestion) o;
return mSlotIndex == that.mSlotIndex
&& mMatchType == that.mMatchType
&& mQuality == that.mQuality
@@ -280,7 +281,7 @@
@Override
public String toString() {
- return "PhoneTimeZoneSuggestion{"
+ return "TelephonyTimeZoneSuggestion{"
+ "mSlotIndex=" + mSlotIndex
+ ", mZoneId='" + mZoneId + '\''
+ ", mMatchType=" + mMatchType
@@ -290,7 +291,7 @@
}
/**
- * Builds {@link PhoneTimeZoneSuggestion} instances.
+ * Builds {@link TelephonyTimeZoneSuggestion} instances.
*
* @hide
*/
@@ -304,7 +305,7 @@
/**
* Creates a builder with the specified {@code slotIndex}.
*
- * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code slotIndex}.
+ * <p>See {@link TelephonyTimeZoneSuggestion} for more information about {@code slotIndex}.
*/
public Builder(int slotIndex) {
mSlotIndex = slotIndex;
@@ -313,7 +314,7 @@
/**
* Returns the builder for call chaining.
*
- * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code zoneId}.
+ * <p>See {@link TelephonyTimeZoneSuggestion} for more information about {@code zoneId}.
*/
@NonNull
public Builder setZoneId(@Nullable String zoneId) {
@@ -324,7 +325,7 @@
/**
* Returns the builder for call chaining.
*
- * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code matchType}.
+ * <p>See {@link TelephonyTimeZoneSuggestion} for more information about {@code matchType}.
*/
@NonNull
public Builder setMatchType(@MatchType int matchType) {
@@ -335,7 +336,7 @@
/**
* Returns the builder for call chaining.
*
- * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code quality}.
+ * <p>See {@link TelephonyTimeZoneSuggestion} for more information about {@code quality}.
*/
@NonNull
public Builder setQuality(@Quality int quality) {
@@ -346,7 +347,7 @@
/**
* Returns the builder for call chaining.
*
- * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code debugInfo}.
+ * <p>See {@link TelephonyTimeZoneSuggestion} for more information about {@code debugInfo}.
*/
@NonNull
public Builder addDebugInfo(@NonNull String debugInfo) {
@@ -384,11 +385,11 @@
}
}
- /** Returns the {@link PhoneTimeZoneSuggestion}. */
+ /** Returns the {@link TelephonyTimeZoneSuggestion}. */
@NonNull
- public PhoneTimeZoneSuggestion build() {
+ public TelephonyTimeZoneSuggestion build() {
validate();
- return new PhoneTimeZoneSuggestion(this);
+ return new TelephonyTimeZoneSuggestion(this);
}
}
}
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java
index 6a3953e..20761ad 100644
--- a/core/java/android/app/timezonedetector/TimeZoneDetector.java
+++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java
@@ -47,8 +47,8 @@
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE)
- void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion timeZoneSuggestion);
+ @RequiresPermission(android.Manifest.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE)
+ void suggestTelephonyTimeZone(@NonNull TelephonyTimeZoneSuggestion timeZoneSuggestion);
/**
* Suggests the current time zone, determined for the user's manually information, to the
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
index 27b8374..0ada885 100644
--- a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
+++ b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
@@ -40,12 +40,12 @@
}
@Override
- public void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion timeZoneSuggestion) {
+ public void suggestTelephonyTimeZone(@NonNull TelephonyTimeZoneSuggestion timeZoneSuggestion) {
if (DEBUG) {
- Log.d(TAG, "suggestPhoneTimeZone called: " + timeZoneSuggestion);
+ Log.d(TAG, "suggestTelephonyTimeZone called: " + timeZoneSuggestion);
}
try {
- mITimeZoneDetectorService.suggestPhoneTimeZone(timeZoneSuggestion);
+ mITimeZoneDetectorService.suggestTelephonyTimeZone(timeZoneSuggestion);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 2e93d43..01ccb86 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1861,15 +1861,19 @@
}
/**
- * Connects all enabled and supported bluetooth profiles between the local and remote device
+ * Connects all enabled and supported bluetooth profiles between the local and remote device.
+ * Connection is asynchronous and you should listen to each profile's broadcast intent
+ * ACTION_CONNECTION_STATE_CHANGED to verify whether connection was successful. For example,
+ * to verify a2dp is connected, you would listen for
+ * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED}
*
* @param device is the remote device with which to connect these profiles
- * @return true if all profiles successfully connected, false if an error occurred
+ * @return true if message sent to try to connect all profiles, false if an error occurred
*
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean connectAllEnabledProfiles(@NonNull BluetoothDevice device) {
try {
mServiceLock.readLock().lock();
@@ -1886,15 +1890,19 @@
}
/**
- * Disconnects all enabled and supported bluetooth profiles between the local and remote device
+ * Disconnects all enabled and supported bluetooth profiles between the local and remote device.
+ * Disconnection is asynchronous and you should listen to each profile's broadcast intent
+ * ACTION_CONNECTION_STATE_CHANGED to verify whether disconnection was successful. For example,
+ * to verify a2dp is disconnected, you would listen for
+ * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED}
*
* @param device is the remote device with which to disconnect these profiles
- * @return true if all profiles successfully disconnected, false if an error occurred
+ * @return true if message sent to try to disconnect all profiles, false if an error occurred
*
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean disconnectAllEnabledProfiles(@NonNull BluetoothDevice device) {
try {
mServiceLock.readLock().lock();
diff --git a/core/java/android/content/integrity/AtomicFormula.java b/core/java/android/content/integrity/AtomicFormula.java
index 439d536..d25f413 100644
--- a/core/java/android/content/integrity/AtomicFormula.java
+++ b/core/java/android/content/integrity/AtomicFormula.java
@@ -332,9 +332,12 @@
* Constructs a new {@link StringAtomicFormula} together with handling the necessary
* hashing for the given key.
*
- * <p> The value will be hashed with SHA256 and the hex digest will be computed; for
- * all cases except when the key is PACKAGE_NAME or INSTALLER_NAME and the value
- * is less than 33 characters.
+ * <p> The value will be automatically hashed with SHA256 and the hex digest will be
+ * computed when the key is PACKAGE_NAME or INSTALLER_NAME and the value is more than 32
+ * characters.
+ *
+ * <p> The APP_CERTIFICATES and INSTALLER_CERTIFICATES are always delivered in hashed
+ * form. So the isHashedValue is set to true by default.
*
* @throws IllegalArgumentException if {@code key} cannot be used with string value.
*/
@@ -348,7 +351,10 @@
String.format(
"Key %s cannot be used with StringAtomicFormula", keyToString(key)));
mValue = hashValue(key, value);
- mIsHashedValue = !mValue.equals(value);
+ mIsHashedValue =
+ key == APP_CERTIFICATE || key == INSTALLER_CERTIFICATE
+ ? true
+ : !mValue.equals(value);
}
StringAtomicFormula(Parcel in) {
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index de153d0..edc20d9 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -323,6 +323,7 @@
*/
@RequiresPermission(
allOf={android.Manifest.permission.MANAGE_APP_OPS_MODES,
+ android.Manifest.permission.UPDATE_APP_OPS_STATS,
android.Manifest.permission.INTERACT_ACROSS_USERS})
public void setInteractAcrossProfilesAppOp(@NonNull String packageName, @Mode int newMode) {
try {
@@ -363,6 +364,7 @@
*/
@RequiresPermission(
allOf={android.Manifest.permission.MANAGE_APP_OPS_MODES,
+ android.Manifest.permission.UPDATE_APP_OPS_STATS,
android.Manifest.permission.INTERACT_ACROSS_USERS})
public void resetInteractAcrossProfilesAppOps(
@NonNull Collection<String> previousCrossProfilePackages,
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index 50bb3c7..0492359 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -20,11 +20,13 @@
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentSender;
+import android.content.LocusId;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IOnAppsChangedListener;
import android.content.pm.LauncherApps;
import android.content.pm.IPackageInstallerCallback;
+import android.content.pm.IShortcutChangeCallback;
import android.content.pm.PackageInstaller;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
@@ -66,7 +68,8 @@
in UserHandle user);
ParceledListSlice getShortcuts(String callingPackage, long changedSince, String packageName,
- in List shortcutIds, in ComponentName componentName, int flags, in UserHandle user);
+ in List shortcutIds, in List<LocusId> locusIds, in ComponentName componentName,
+ int flags, in UserHandle user);
void pinShortcuts(String callingPackage, String packageName, in List<String> shortcutIds,
in UserHandle user);
boolean startShortcut(String callingPackage, String packageName, String id,
@@ -89,4 +92,10 @@
void registerPackageInstallerCallback(String callingPackage,
in IPackageInstallerCallback callback);
ParceledListSlice getAllSessions(String callingPackage);
+
+ void registerShortcutChangeCallback(String callingPackage, long changedSince,
+ String packageName, in List shortcutIds, in List<LocusId> locusIds,
+ in ComponentName componentName, int flags, in IShortcutChangeCallback callback,
+ int callbackId);
+ void unregisterShortcutChangeCallback(String callingPackage, int callbackId);
}
diff --git a/core/java/android/content/pm/IShortcutChangeCallback.aidl b/core/java/android/content/pm/IShortcutChangeCallback.aidl
new file mode 100644
index 0000000..fed4e4a
--- /dev/null
+++ b/core/java/android/content/pm/IShortcutChangeCallback.aidl
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.content.pm.ParceledListSlice;
+import android.content.pm.ShortcutInfo;
+import android.os.UserHandle;
+
+import java.util.List;
+
+/**
+ * Interface for LauncherApps#ShortcutChangeCallbackProxy.
+ *
+ * @hide
+ */
+oneway interface IShortcutChangeCallback
+{
+ void onShortcutsAddedOrUpdated(String packageName, in List<ShortcutInfo> shortcuts,
+ in UserHandle user);
+
+ void onShortcutsRemoved(String packageName, in List<ShortcutInfo> shortcuts,
+ in UserHandle user);
+}
\ No newline at end of file
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index cea0b6b..73c9e4d 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -34,6 +34,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
+import android.content.LocusId;
import android.content.pm.PackageInstaller.SessionCallback;
import android.content.pm.PackageInstaller.SessionCallbackDelegate;
import android.content.pm.PackageInstaller.SessionInfo;
@@ -61,15 +62,21 @@
import android.os.UserManager;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.Pair;
+
+import com.android.internal.util.function.pooled.PooledLambda;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -152,6 +159,9 @@
private final List<CallbackMessageHandler> mCallbacks = new ArrayList<>();
private final List<SessionCallbackDelegate> mDelegates = new ArrayList<>();
+ private final Map<Integer, Pair<Executor, ShortcutChangeCallback>>
+ mShortcutChangeCallbacks = new HashMap<>();
+
/**
* Callbacks for package changes to this and related managed profiles.
*/
@@ -406,6 +416,9 @@
List<String> mShortcutIds;
@Nullable
+ List<LocusId> mLocusIds;
+
+ @Nullable
ComponentName mActivity;
@QueryFlags
@@ -442,6 +455,19 @@
}
/**
+ * If non-null, return only the specified shortcuts by locus ID. When setting this field,
+ * a package name must also be set with {@link #setPackage}.
+ *
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ public ShortcutQuery setLocusIds(@Nullable List<LocusId> locusIds) {
+ mLocusIds = locusIds;
+ return this;
+ }
+
+ /**
* If non-null, returns only shortcuts associated with the activity; i.e.
* {@link ShortcutInfo}s whose {@link ShortcutInfo#getActivity()} are equal
* to {@code activity}.
@@ -469,6 +495,95 @@
}
}
+ /**
+ * Callbacks for shortcut changes to this and related managed profiles.
+ *
+ * @hide
+ */
+ public interface ShortcutChangeCallback {
+ /**
+ * Indicates that one or more shortcuts, that match the {@link ShortcutQuery} used to
+ * register this callback, have been added or updated.
+ * @see LauncherApps#registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery)
+ *
+ * <p>Only the applications that are allowed to access the shortcut information,
+ * as defined in {@link #hasShortcutHostPermission()}, will receive it.
+ *
+ * @param packageName The name of the package that has the shortcuts.
+ * @param shortcuts Shortcuts from the package that have updated or added. Only "key"
+ * information will be provided, as defined in {@link ShortcutInfo#hasKeyFieldsOnly()}.
+ * @param user The UserHandle of the profile that generated the change.
+ *
+ * @see ShortcutManager
+ */
+ default void onShortcutsAddedOrUpdated(@NonNull String packageName,
+ @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {}
+
+ /**
+ * Indicates that one or more shortcuts, that match the {@link ShortcutQuery} used to
+ * register this callback, have been removed.
+ * @see LauncherApps#registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery)
+ *
+ * <p>Only the applications that are allowed to access the shortcut information,
+ * as defined in {@link #hasShortcutHostPermission()}, will receive it.
+ *
+ * @param packageName The name of the package that has the shortcuts.
+ * @param shortcuts Shortcuts from the package that have been removed. Only "key"
+ * information will be provided, as defined in {@link ShortcutInfo#hasKeyFieldsOnly()}.
+ * @param user The UserHandle of the profile that generated the change.
+ *
+ * @see ShortcutManager
+ */
+ default void onShortcutsRemoved(@NonNull String packageName,
+ @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {}
+ }
+
+ /**
+ * Callback proxy class for {@link ShortcutChangeCallback}
+ *
+ * @hide
+ */
+ private static class ShortcutChangeCallbackProxy extends
+ android.content.pm.IShortcutChangeCallback.Stub {
+ private final WeakReference<Pair<Executor, ShortcutChangeCallback>> mRemoteReferences;
+
+ ShortcutChangeCallbackProxy(Pair<Executor, ShortcutChangeCallback> remoteReferences) {
+ mRemoteReferences = new WeakReference<>(remoteReferences);
+ }
+
+ @Override
+ public void onShortcutsAddedOrUpdated(@NonNull String packageName,
+ @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
+ Pair<Executor, ShortcutChangeCallback> remoteReferences = mRemoteReferences.get();
+ if (remoteReferences == null) {
+ // Binder is dead.
+ return;
+ }
+
+ final Executor executor = remoteReferences.first;
+ final ShortcutChangeCallback callback = remoteReferences.second;
+ executor.execute(
+ PooledLambda.obtainRunnable(ShortcutChangeCallback::onShortcutsAddedOrUpdated,
+ callback, packageName, shortcuts, user).recycleOnUse());
+ }
+
+ @Override
+ public void onShortcutsRemoved(@NonNull String packageName,
+ @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
+ Pair<Executor, ShortcutChangeCallback> remoteReferences = mRemoteReferences.get();
+ if (remoteReferences == null) {
+ // Binder is dead.
+ return;
+ }
+
+ final Executor executor = remoteReferences.first;
+ final ShortcutChangeCallback callback = remoteReferences.second;
+ executor.execute(
+ PooledLambda.obtainRunnable(ShortcutChangeCallback::onShortcutsRemoved,
+ callback, packageName, shortcuts, user).recycleOnUse());
+ }
+ }
+
/** @hide */
public LauncherApps(Context context, ILauncherApps service) {
mContext = context;
@@ -924,8 +1039,8 @@
// changed callback, but that only returns shortcuts with the "key" information, so
// that won't return disabled message.
return maybeUpdateDisabledMessage(mService.getShortcuts(mContext.getPackageName(),
- query.mChangedSince, query.mPackage, query.mShortcutIds, query.mActivity,
- query.mQueryFlags, user)
+ query.mChangedSince, query.mPackage, query.mShortcutIds, query.mLocusIds,
+ query.mActivity, query.mQueryFlags, user)
.getList());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1560,6 +1675,63 @@
}
/**
+ * Register a callback to watch for shortcut change events in this user and managed profiles.
+ *
+ * @param callback The callback to register.
+ * @param query {@link ShortcutQuery} to match and filter the shortcut events. Only matching
+ * shortcuts will be returned by the callback.
+ * @param executor {@link Executor} to handle the callbacks. To dispatch callbacks to the main
+ * thread of your application, you can use {@link android.content.Context#getMainExecutor()}.
+ *
+ * @hide
+ */
+ public void registerShortcutChangeCallback(@NonNull ShortcutChangeCallback callback,
+ @NonNull ShortcutQuery query, @NonNull @CallbackExecutor Executor executor) {
+ Objects.requireNonNull(callback, "Callback cannot be null");
+ Objects.requireNonNull(query, "Query cannot be null");
+ Objects.requireNonNull(executor, "Executor cannot be null");
+
+ synchronized (mShortcutChangeCallbacks) {
+ final int callbackId = callback.hashCode();
+ final Pair<Executor, ShortcutChangeCallback> state = new Pair<>(executor, callback);
+ mShortcutChangeCallbacks.put(callbackId, state);
+ try {
+ mService.registerShortcutChangeCallback(mContext.getPackageName(),
+ query.mChangedSince, query.mPackage, query.mShortcutIds, query.mLocusIds,
+ query.mActivity, query.mQueryFlags, new ShortcutChangeCallbackProxy(state),
+ callbackId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Unregisters a callback that was previously registered.
+ * @see #registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery, Executor)
+ *
+ * @param callback Callback to be unregistered.
+ *
+ * @hide
+ */
+ public void unregisterShortcutChangeCallback(@NonNull ShortcutChangeCallback callback) {
+ Objects.requireNonNull(callback, "Callback cannot be null");
+
+ synchronized (mShortcutChangeCallbacks) {
+ final int callbackId = callback.hashCode();
+ if (mShortcutChangeCallbacks.containsKey(callbackId)) {
+ mShortcutChangeCallbacks.remove(callbackId);
+ try {
+ mService.unregisterShortcutChangeCallback(mContext.getPackageName(),
+ callbackId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+ }
+
+ /**
* A helper method to extract a {@link PinItemRequest} set to
* the {@link #EXTRA_PIN_ITEM_REQUEST} extra.
*/
diff --git a/core/java/android/content/pm/PackageInfoLite.java b/core/java/android/content/pm/PackageInfoLite.java
index 6743a3f..9735f81 100644
--- a/core/java/android/content/pm/PackageInfoLite.java
+++ b/core/java/android/content/pm/PackageInfoLite.java
@@ -74,6 +74,11 @@
public boolean multiArch;
/**
+ * The android:debuggable flag from the package manifest.
+ */
+ public boolean debuggable;
+
+ /**
* Specifies the recommended install location. Can be one of
* {@link PackageHelper#RECOMMEND_INSTALL_INTERNAL} to install on internal storage,
* {@link PackageHelper#RECOMMEND_INSTALL_EXTERNAL} to install on external media,
@@ -108,6 +113,7 @@
dest.writeInt(recommendedInstallLocation);
dest.writeInt(installLocation);
dest.writeInt(multiArch ? 1 : 0);
+ dest.writeInt(debuggable ? 1 : 0);
if (verifiers == null || verifiers.length == 0) {
dest.writeInt(0);
@@ -139,6 +145,7 @@
recommendedInstallLocation = source.readInt();
installLocation = source.readInt();
multiArch = (source.readInt() != 0);
+ debuggable = (source.readInt() != 0);
final int verifiersLength = source.readInt();
if (verifiersLength == 0) {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 5a0bcf0..9f7f482 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -60,6 +60,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.incremental.IncrementalManager;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.util.AndroidException;
@@ -2997,6 +2998,18 @@
public static final String FEATURE_REBOOT_ESCROW = "android.hardware.reboot_escrow";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has
+ * the requisite kernel support to support incremental delivery aka Incremental FileSystem.
+ *
+ * @see IncrementalManager#isEnabled
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_INCREMENTAL_DELIVERY =
+ "android.software.incremental_delivery";
+
+ /**
* Extra field name for the URI to a verification file. Passed to a package
* verifier.
*
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index e6f682d..a11a1dd 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -23,6 +23,7 @@
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentSender;
+import android.content.LocusId;
import android.content.pm.LauncherApps.ShortcutQuery;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
@@ -45,8 +46,8 @@
getShortcuts(int launcherUserId,
@NonNull String callingPackage, long changedSince,
@Nullable String packageName, @Nullable List<String> shortcutIds,
- @Nullable ComponentName componentName, @ShortcutQuery.QueryFlags int flags,
- int userId, int callingPid, int callingUid);
+ @Nullable List<LocusId> locusIds, @Nullable ComponentName componentName,
+ @ShortcutQuery.QueryFlags int flags, int userId, int callingPid, int callingUid);
public abstract boolean
isPinnedByCaller(int launcherUserId, @NonNull String callingPackage,
diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING
index 0549c34..6f30ecd 100644
--- a/core/java/android/content/pm/TEST_MAPPING
+++ b/core/java/android/content/pm/TEST_MAPPING
@@ -15,5 +15,15 @@
"name": "FrameworksInstantAppResolverTests",
"file_patterns": ["(/|^)InstantApp[^/]*"]
}
+ ],
+ "postsubmit": [
+ {
+ "name": "CtsAppSecurityHostTestCases",
+ "options": [
+ {
+ "include-filter": "android.appsecurity.cts.AppSecurityTests#testPermissionDiffCert"
+ }
+ ]
+ }
]
}
diff --git a/core/java/android/hardware/biometrics/BiometricNativeHandleUtils.java b/core/java/android/hardware/biometrics/BiometricNativeHandleUtils.java
new file mode 100644
index 0000000..5544eae
--- /dev/null
+++ b/core/java/android/hardware/biometrics/BiometricNativeHandleUtils.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics;
+
+import android.os.NativeHandle;
+import android.os.ParcelFileDescriptor;
+
+import java.io.IOException;
+
+/**
+ * A class that contains utilities for IBiometricNativeHandle.
+ *
+ * @hide
+ */
+public final class BiometricNativeHandleUtils {
+
+ private BiometricNativeHandleUtils() {
+ }
+
+ /**
+ * Converts a {@link NativeHandle} into an {@link IBiometricNativeHandle} by duplicating the
+ * underlying file descriptors.
+ *
+ * Both the original and new handle must be closed after use.
+ *
+ * @param h {@link NativeHandle}. Usually used to identify a WindowManager window. Can be null.
+ * @return A {@link IBiometricNativeHandle} representation of {@code h}. Will be null if
+ * {@code h} or its raw file descriptors are null.
+ */
+ public static IBiometricNativeHandle dup(NativeHandle h) {
+ IBiometricNativeHandle handle = null;
+ if (h != null && h.getFileDescriptors() != null && h.getInts() != null) {
+ handle = new IBiometricNativeHandle();
+ handle.ints = h.getInts().clone();
+ handle.fds = new ParcelFileDescriptor[h.getFileDescriptors().length];
+ for (int i = 0; i < h.getFileDescriptors().length; ++i) {
+ try {
+ handle.fds[i] = ParcelFileDescriptor.dup(h.getFileDescriptors()[i]);
+ } catch (IOException e) {
+ return null;
+ }
+ }
+ }
+ return handle;
+ }
+
+ /**
+ * Closes the handle's file descriptors.
+ *
+ * @param h {@link IBiometricNativeHandle} handle.
+ */
+ public static void close(IBiometricNativeHandle h) {
+ if (h != null) {
+ for (ParcelFileDescriptor fd : h.fds) {
+ if (fd != null) {
+ try {
+ fd.close();
+ } catch (IOException e) {
+ // do nothing.
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.aidl b/core/java/android/hardware/biometrics/IBiometricNativeHandle.aidl
similarity index 64%
copy from core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.aidl
copy to core/java/android/hardware/biometrics/IBiometricNativeHandle.aidl
index 3ad903b..6dcdc1b 100644
--- a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricNativeHandle.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package android.hardware.biometrics;
-package android.app.timezonedetector;
-
-parcelable PhoneTimeZoneSuggestion;
+/**
+ * Representation of a native handle.
+ * Copied from /common/aidl/android/hardware/common/NativeHandle.aidl
+ * @hide
+ */
+parcelable IBiometricNativeHandle {
+ ParcelFileDescriptor[] fds;
+ int[] ints;
+}
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 55ebe28..6bda46b 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -29,7 +29,9 @@
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricFaceConstants;
+import android.hardware.biometrics.BiometricNativeHandleUtils;
import android.hardware.biometrics.CryptoObject;
+import android.hardware.biometrics.IBiometricNativeHandle;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.os.Binder;
import android.os.CancellationSignal;
@@ -38,6 +40,7 @@
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.Looper;
+import android.os.NativeHandle;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.Trace;
@@ -245,6 +248,19 @@
}
/**
+ * Defaults to {@link FaceManager#enroll(int, byte[], CancellationSignal, EnrollmentCallback,
+ * int[], NativeHandle)} with {@code windowId} set to null.
+ *
+ * @see FaceManager#enroll(int, byte[], CancellationSignal, EnrollmentCallback, int[],
+ * NativeHandle)
+ */
+ @RequiresPermission(MANAGE_BIOMETRIC)
+ public void enroll(int userId, byte[] token, CancellationSignal cancel,
+ EnrollmentCallback callback, int[] disabledFeatures) {
+ enroll(userId, token, cancel, callback, disabledFeatures, null /* windowId */);
+ }
+
+ /**
* Request face authentication enrollment. This call operates the face authentication hardware
* and starts capturing images. Progress will be indicated by callbacks to the
* {@link EnrollmentCallback} object. It terminates when
@@ -259,11 +275,13 @@
* @param flags optional flags
* @param userId the user to whom this face will belong to
* @param callback an object to receive enrollment events
+ * @param windowId optional ID of a camera preview window for a single-camera device. Must be
+ * null if not used.
* @hide
*/
@RequiresPermission(MANAGE_BIOMETRIC)
public void enroll(int userId, byte[] token, CancellationSignal cancel,
- EnrollmentCallback callback, int[] disabledFeatures) {
+ EnrollmentCallback callback, int[] disabledFeatures, @Nullable NativeHandle windowId) {
if (callback == null) {
throw new IllegalArgumentException("Must supply an enrollment callback");
}
@@ -278,20 +296,72 @@
}
if (mService != null) {
+ IBiometricNativeHandle handle = BiometricNativeHandleUtils.dup(windowId);
try {
mEnrollmentCallback = callback;
Trace.beginSection("FaceManager#enroll");
mService.enroll(userId, mToken, token, mServiceReceiver,
- mContext.getOpPackageName(), disabledFeatures);
+ mContext.getOpPackageName(), disabledFeatures, handle);
} catch (RemoteException e) {
Log.w(TAG, "Remote exception in enroll: ", e);
- if (callback != null) {
- // Though this may not be a hardware issue, it will cause apps to give up or
- // try again later.
- callback.onEnrollmentError(FACE_ERROR_HW_UNAVAILABLE,
- getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
+ // Though this may not be a hardware issue, it will cause apps to give up or
+ // try again later.
+ callback.onEnrollmentError(FACE_ERROR_HW_UNAVAILABLE,
+ getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */));
- }
+ } finally {
+ Trace.endSection();
+ BiometricNativeHandleUtils.close(handle);
+ }
+ }
+ }
+
+ /**
+ * Request face authentication enrollment for a remote client, for example Android Auto.
+ * This call operates the face authentication hardware and starts capturing images.
+ * Progress will be indicated by callbacks to the
+ * {@link EnrollmentCallback} object. It terminates when
+ * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} or
+ * {@link EnrollmentCallback#onEnrollmentProgress(int) is called with remaining == 0, at
+ * which point the object is no longer valid. The operation can be canceled by using the
+ * provided cancel object.
+ *
+ * @param token a unique token provided by a recent creation or verification of device
+ * credentials (e.g. pin, pattern or password).
+ * @param cancel an object that can be used to cancel enrollment
+ * @param userId the user to whom this face will belong to
+ * @param callback an object to receive enrollment events
+ * @hide
+ */
+ @RequiresPermission(MANAGE_BIOMETRIC)
+ public void enrollRemotely(int userId, byte[] token, CancellationSignal cancel,
+ EnrollmentCallback callback, int[] disabledFeatures) {
+ if (callback == null) {
+ throw new IllegalArgumentException("Must supply an enrollment callback");
+ }
+
+ if (cancel != null) {
+ if (cancel.isCanceled()) {
+ Log.w(TAG, "enrollRemotely is already canceled.");
+ return;
+ } else {
+ cancel.setOnCancelListener(new OnEnrollCancelListener());
+ }
+ }
+
+ if (mService != null) {
+ try {
+ mEnrollmentCallback = callback;
+ Trace.beginSection("FaceManager#enrollRemotely");
+ mService.enrollRemotely(userId, mToken, token, mServiceReceiver,
+ mContext.getOpPackageName(), disabledFeatures);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Remote exception in enrollRemotely: ", e);
+ // Though this may not be a hardware issue, it will cause apps to give up or
+ // try again later.
+ callback.onEnrollmentError(FACE_ERROR_HW_UNAVAILABLE,
+ getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */));
} finally {
Trace.endSection();
}
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 68a4aef..8ba2473 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -15,6 +15,7 @@
*/
package android.hardware.face;
+import android.hardware.biometrics.IBiometricNativeHandle;
import android.hardware.biometrics.IBiometricServiceReceiverInternal;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.face.IFaceServiceReceiver;
@@ -51,6 +52,10 @@
// Start face enrollment
void enroll(int userId, IBinder token, in byte [] cryptoToken, IFaceServiceReceiver receiver,
+ String opPackageName, in int [] disabledFeatures, in IBiometricNativeHandle windowId);
+
+ // Start remote face enrollment
+ void enrollRemotely(int userId, IBinder token, in byte [] cryptoToken, IFaceServiceReceiver receiver,
String opPackageName, in int [] disabledFeatures);
// Cancel enrollment in progress
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index ff9d145..f6717c7 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -32,7 +32,9 @@
import android.content.pm.PackageManager;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricFingerprintConstants;
+import android.hardware.biometrics.BiometricNativeHandleUtils;
import android.hardware.biometrics.BiometricPrompt;
+import android.hardware.biometrics.IBiometricNativeHandle;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.os.Binder;
import android.os.CancellationSignal;
@@ -41,6 +43,7 @@
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.Looper;
+import android.os.NativeHandle;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -403,15 +406,33 @@
}
/**
- * Per-user version, see {@link FingerprintManager#authenticate(CryptoObject,
- * CancellationSignal, int, AuthenticationCallback, Handler)}. This version does not
- * display the BiometricPrompt.
- * @param userId the user ID that the fingerprint hardware will authenticate for.
+ * Defaults to {@link FingerprintManager#authenticate(CryptoObject, CancellationSignal, int,
+ * AuthenticationCallback, Handler, int, NativeHandle)} with {@code windowId} set to null.
+ *
+ * @see FingerprintManager#authenticate(CryptoObject, CancellationSignal, int,
+ * AuthenticationCallback, Handler, int, NativeHandle)
+ *
* @hide
*/
@RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) {
+ authenticate(crypto, cancel, flags, callback, handler, userId, null /* windowId */);
+ }
+
+ /**
+ * Per-user version, see {@link FingerprintManager#authenticate(CryptoObject,
+ * CancellationSignal, int, AuthenticationCallback, Handler)}. This version does not
+ * display the BiometricPrompt.
+ * @param userId the user ID that the fingerprint hardware will authenticate for.
+ * @param windowId for optical fingerprint sensors that require active illumination by the OLED
+ * display. Should be null for devices that don't require illumination.
+ * @hide
+ */
+ @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
+ public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
+ int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId,
+ @Nullable NativeHandle windowId) {
if (callback == null) {
throw new IllegalArgumentException("Must supply an authentication callback");
}
@@ -425,26 +446,44 @@
}
}
- if (mService != null) try {
- useHandler(handler);
- mAuthenticationCallback = callback;
- mCryptoObject = crypto;
- long sessionId = crypto != null ? crypto.getOpId() : 0;
- mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags,
- mContext.getOpPackageName());
- } catch (RemoteException e) {
- Slog.w(TAG, "Remote exception while authenticating: ", e);
- if (callback != null) {
+ if (mService != null) {
+ IBiometricNativeHandle handle = BiometricNativeHandleUtils.dup(windowId);
+ try {
+ useHandler(handler);
+ mAuthenticationCallback = callback;
+ mCryptoObject = crypto;
+ long sessionId = crypto != null ? crypto.getOpId() : 0;
+ mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags,
+ mContext.getOpPackageName(), handle);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Remote exception while authenticating: ", e);
// Though this may not be a hardware issue, it will cause apps to give up or try
// again later.
callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE,
- 0 /* vendorCode */));
+ 0 /* vendorCode */));
+ } finally {
+ BiometricNativeHandleUtils.close(handle);
}
}
}
/**
+ * Defaults to {@link FingerprintManager#enroll(byte[], CancellationSignal, int, int,
+ * EnrollmentCallback, NativeHandle)} with {@code windowId} set to null.
+ *
+ * @see FingerprintManager#enroll(byte[], CancellationSignal, int, int, EnrollmentCallback,
+ * NativeHandle)
+ *
+ * @hide
+ */
+ @RequiresPermission(MANAGE_FINGERPRINT)
+ public void enroll(byte [] token, CancellationSignal cancel, int flags,
+ int userId, EnrollmentCallback callback) {
+ enroll(token, cancel, flags, userId, callback, null /* windowId */);
+ }
+
+ /**
* Request fingerprint enrollment. This call warms up the fingerprint hardware
* and starts scanning for fingerprints. Progress will be indicated by callbacks to the
* {@link EnrollmentCallback} object. It terminates when
@@ -462,7 +501,7 @@
*/
@RequiresPermission(MANAGE_FINGERPRINT)
public void enroll(byte [] token, CancellationSignal cancel, int flags,
- int userId, EnrollmentCallback callback) {
+ int userId, EnrollmentCallback callback, @Nullable NativeHandle windowId) {
if (userId == UserHandle.USER_CURRENT) {
userId = getCurrentUserId();
}
@@ -479,18 +518,21 @@
}
}
- if (mService != null) try {
- mEnrollmentCallback = callback;
- mService.enroll(mToken, token, userId, mServiceReceiver, flags,
- mContext.getOpPackageName());
- } catch (RemoteException e) {
- Slog.w(TAG, "Remote exception in enroll: ", e);
- if (callback != null) {
+ if (mService != null) {
+ IBiometricNativeHandle handle = BiometricNativeHandleUtils.dup(windowId);
+ try {
+ mEnrollmentCallback = callback;
+ mService.enroll(mToken, token, userId, mServiceReceiver, flags,
+ mContext.getOpPackageName(), handle);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Remote exception in enroll: ", e);
// Though this may not be a hardware issue, it will cause apps to give up or try
// again later.
callback.onEnrollmentError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE,
- 0 /* vendorCode */));
+ 0 /* vendorCode */));
+ } finally {
+ BiometricNativeHandleUtils.close(handle);
}
}
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 1a7e128..f2ffd08d 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -15,6 +15,7 @@
*/
package android.hardware.fingerprint;
+import android.hardware.biometrics.IBiometricNativeHandle;
import android.hardware.biometrics.IBiometricServiceReceiverInternal;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.fingerprint.IFingerprintClientActiveCallback;
@@ -31,7 +32,8 @@
// USE_FINGERPRINT/USE_BIOMETRIC permission. This is effectively deprecated, since it only comes
// through FingerprintManager now.
void authenticate(IBinder token, long sessionId, int userId,
- IFingerprintServiceReceiver receiver, int flags, String opPackageName);
+ IFingerprintServiceReceiver receiver, int flags, String opPackageName,
+ in IBiometricNativeHandle windowId);
// This method prepares the service to start authenticating, but doesn't start authentication.
// This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be
@@ -40,7 +42,7 @@
// startPreparedClient().
void prepareForAuthentication(IBinder token, long sessionId, int userId,
IBiometricServiceReceiverInternal wrapperReceiver, String opPackageName, int cookie,
- int callingUid, int callingPid, int callingUserId);
+ int callingUid, int callingPid, int callingUserId, in IBiometricNativeHandle windowId);
// Starts authentication with the previously prepared client.
void startPreparedClient(int cookie);
@@ -55,7 +57,7 @@
// Start fingerprint enrollment
void enroll(IBinder token, in byte [] cryptoToken, int groupId, IFingerprintServiceReceiver receiver,
- int flags, String opPackageName);
+ int flags, String opPackageName, in IBiometricNativeHandle windowId);
// Cancel enrollment in progress
void cancelEnrollment(IBinder token);
diff --git a/core/java/android/hardware/soundtrigger/ConversionUtil.java b/core/java/android/hardware/soundtrigger/ConversionUtil.java
index a30fd6b..dbf33ca 100644
--- a/core/java/android/hardware/soundtrigger/ConversionUtil.java
+++ b/core/java/android/hardware/soundtrigger/ConversionUtil.java
@@ -17,7 +17,6 @@
package android.hardware.soundtrigger;
import android.annotation.Nullable;
-import android.hardware.soundtrigger.ModelParams;
import android.media.AudioFormat;
import android.media.audio.common.AudioConfig;
import android.media.soundtrigger_middleware.AudioCapabilities;
@@ -333,20 +332,22 @@
public static int aidl2apiAudioCapabilities(int aidlCapabilities) {
int result = 0;
if ((aidlCapabilities & AudioCapabilities.ECHO_CANCELLATION) != 0) {
- result |= SoundTrigger.ModuleProperties.CAPABILITY_ECHO_CANCELLATION;
+ result |= SoundTrigger.ModuleProperties.AUDIO_CAPABILITY_ECHO_CANCELLATION;
}
if ((aidlCapabilities & AudioCapabilities.NOISE_SUPPRESSION) != 0) {
- result |= SoundTrigger.ModuleProperties.CAPABILITY_NOISE_SUPPRESSION;
+ result |= SoundTrigger.ModuleProperties.AUDIO_CAPABILITY_NOISE_SUPPRESSION;
}
return result;
}
public static int api2aidlAudioCapabilities(int apiCapabilities) {
int result = 0;
- if ((apiCapabilities & SoundTrigger.ModuleProperties.CAPABILITY_ECHO_CANCELLATION) != 0) {
+ if ((apiCapabilities & SoundTrigger.ModuleProperties.AUDIO_CAPABILITY_ECHO_CANCELLATION)
+ != 0) {
result |= AudioCapabilities.ECHO_CANCELLATION;
}
- if ((apiCapabilities & SoundTrigger.ModuleProperties.CAPABILITY_NOISE_SUPPRESSION) != 0) {
+ if ((apiCapabilities & SoundTrigger.ModuleProperties.AUDIO_CAPABILITY_NOISE_SUPPRESSION)
+ != 0) {
result |= AudioCapabilities.NOISE_SUPPRESSION;
}
return result;
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index d505ae5..a74871d2 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -97,8 +97,8 @@
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = { "AUDIO_CAPABILITY_" }, value = {
- CAPABILITY_ECHO_CANCELLATION,
- CAPABILITY_NOISE_SUPPRESSION
+ AUDIO_CAPABILITY_ECHO_CANCELLATION,
+ AUDIO_CAPABILITY_NOISE_SUPPRESSION
})
public @interface AudioCapabilities {}
@@ -106,12 +106,12 @@
* If set the underlying module supports AEC.
* Describes bit field {@link ModuleProperties#audioCapabilities}
*/
- public static final int CAPABILITY_ECHO_CANCELLATION = 0x1;
+ public static final int AUDIO_CAPABILITY_ECHO_CANCELLATION = 0x1;
/**
* If set, the underlying module supports noise suppression.
* Describes bit field {@link ModuleProperties#audioCapabilities}
*/
- public static final int CAPABILITY_NOISE_SUPPRESSION = 0x2;
+ public static final int AUDIO_CAPABILITY_NOISE_SUPPRESSION = 0x2;
/** Unique module ID provided by the native service */
public final int id;
@@ -735,22 +735,40 @@
/**
* The inclusive start of supported range.
*/
- public final int start;
+ private final int mStart;
/**
* The inclusive end of supported range.
*/
- public final int end;
+ private final int mEnd;
ModelParamRange(int start, int end) {
- this.start = start;
- this.end = end;
+ this.mStart = start;
+ this.mEnd = end;
}
/** @hide */
private ModelParamRange(@NonNull Parcel in) {
- this.start = in.readInt();
- this.end = in.readInt();
+ this.mStart = in.readInt();
+ this.mEnd = in.readInt();
+ }
+
+ /**
+ * Get the beginning of the param range
+ *
+ * @return The inclusive start of the supported range.
+ */
+ public int getStart() {
+ return mStart;
+ }
+
+ /**
+ * Get the end of the param range
+ *
+ * @return The inclusive end of the supported range.
+ */
+ public int getEnd() {
+ return mEnd;
}
@NonNull
@@ -780,8 +798,8 @@
public int hashCode() {
final int prime = 31;
int result = 1;
- result = prime * result + (start);
- result = prime * result + (end);
+ result = prime * result + (mStart);
+ result = prime * result + (mEnd);
return result;
}
@@ -797,10 +815,10 @@
return false;
}
ModelParamRange other = (ModelParamRange) obj;
- if (start != other.start) {
+ if (mStart != other.mStart) {
return false;
}
- if (end != other.end) {
+ if (mEnd != other.mEnd) {
return false;
}
return true;
@@ -808,14 +826,14 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(start);
- dest.writeInt(end);
+ dest.writeInt(mStart);
+ dest.writeInt(mEnd);
}
@Override
@NonNull
public String toString() {
- return "ModelParamRange [start=" + start + ", end=" + end + "]";
+ return "ModelParamRange [start=" + mStart + ", end=" + mEnd + "]";
}
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index fa12c08..f644f14 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -3750,6 +3750,7 @@
checkCallbackNotNull(callback);
Preconditions.checkArgument(action == REQUEST || need != null, "null NetworkCapabilities");
final NetworkRequest request;
+ final String callingPackageName = mContext.getOpPackageName();
try {
synchronized(sCallbacks) {
if (callback.networkRequest != null
@@ -3761,10 +3762,11 @@
Messenger messenger = new Messenger(handler);
Binder binder = new Binder();
if (action == LISTEN) {
- request = mService.listenForNetwork(need, messenger, binder);
+ request = mService.listenForNetwork(
+ need, messenger, binder, callingPackageName);
} else {
request = mService.requestNetwork(
- need, messenger, timeoutMs, binder, legacyType);
+ need, messenger, timeoutMs, binder, legacyType, callingPackageName);
}
if (request != null) {
sCallbacks.put(request, callback);
@@ -4037,8 +4039,10 @@
@NonNull PendingIntent operation) {
printStackTrace();
checkPendingIntentNotNull(operation);
+ final String callingPackageName = mContext.getOpPackageName();
try {
- mService.pendingRequestForNetwork(request.networkCapabilities, operation);
+ mService.pendingRequestForNetwork(
+ request.networkCapabilities, operation, callingPackageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
@@ -4150,8 +4154,10 @@
@NonNull PendingIntent operation) {
printStackTrace();
checkPendingIntentNotNull(operation);
+ final String callingPackageName = mContext.getOpPackageName();
try {
- mService.pendingListenForNetwork(request.networkCapabilities, operation);
+ mService.pendingListenForNetwork(
+ request.networkCapabilities, operation, callingPackageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 0fae607..1c7628f 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -167,18 +167,19 @@
in int factorySerialNumber);
NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities,
- in Messenger messenger, int timeoutSec, in IBinder binder, int legacy);
+ in Messenger messenger, int timeoutSec, in IBinder binder, int legacy,
+ String callingPackageName);
NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities,
- in PendingIntent operation);
+ in PendingIntent operation, String callingPackageName);
void releasePendingNetworkRequest(in PendingIntent operation);
NetworkRequest listenForNetwork(in NetworkCapabilities networkCapabilities,
- in Messenger messenger, in IBinder binder);
+ in Messenger messenger, in IBinder binder, String callingPackageName);
void pendingListenForNetwork(in NetworkCapabilities networkCapabilities,
- in PendingIntent operation);
+ in PendingIntent operation, String callingPackageName);
void releaseNetworkRequest(in NetworkRequest networkRequest);
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index cf5f225..f8b51dd 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -27,6 +27,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.proto.ProtoOutputStream;
@@ -63,6 +64,16 @@
// Set to true when private DNS is broken.
private boolean mPrivateDnsBroken;
+ /**
+ * Uid of the app making the request.
+ */
+ private int mRequestorUid;
+
+ /**
+ * Package name of the app making the request.
+ */
+ private String mRequestorPackageName;
+
public NetworkCapabilities() {
clearAll();
mNetworkCapabilities = DEFAULT_CAPABILITIES;
@@ -89,6 +100,8 @@
mOwnerUid = Process.INVALID_UID;
mSSID = null;
mPrivateDnsBroken = false;
+ mRequestorUid = Process.INVALID_UID;
+ mRequestorPackageName = null;
}
/**
@@ -109,6 +122,8 @@
mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities;
mSSID = nc.mSSID;
mPrivateDnsBroken = nc.mPrivateDnsBroken;
+ mRequestorUid = nc.mRequestorUid;
+ mRequestorPackageName = nc.mRequestorPackageName;
}
/**
@@ -810,7 +825,7 @@
}
/**
- * UID of the app that owns this network, or INVALID_UID if none/unknown.
+ * UID of the app that owns this network, or Process#INVALID_UID if none/unknown.
*
* <p>This field keeps track of the UID of the app that created this network and is in charge of
* its lifecycle. This could be the UID of apps such as the Wifi network suggestor, the running
@@ -821,8 +836,9 @@
/**
* Set the UID of the owner app.
*/
- public void setOwnerUid(final int uid) {
+ public @NonNull NetworkCapabilities setOwnerUid(final int uid) {
mOwnerUid = uid;
+ return this;
}
/**
@@ -865,9 +881,11 @@
* @hide
*/
@SystemApi
- public void setAdministratorUids(@NonNull final List<Integer> administratorUids) {
+ public @NonNull NetworkCapabilities setAdministratorUids(
+ @NonNull final List<Integer> administratorUids) {
mAdministratorUids.clear();
mAdministratorUids.addAll(administratorUids);
+ return this;
}
/**
@@ -1385,6 +1403,7 @@
combineSignalStrength(nc);
combineUids(nc);
combineSSIDs(nc);
+ combineRequestor(nc);
}
/**
@@ -1404,7 +1423,8 @@
&& satisfiedBySpecifier(nc)
&& (onlyImmutable || satisfiedBySignalStrength(nc))
&& (onlyImmutable || satisfiedByUids(nc))
- && (onlyImmutable || satisfiedBySSID(nc)));
+ && (onlyImmutable || satisfiedBySSID(nc)))
+ && (onlyImmutable || satisfiedByRequestor(nc));
}
/**
@@ -1488,7 +1508,7 @@
public boolean equals(@Nullable Object obj) {
if (obj == null || (obj instanceof NetworkCapabilities == false)) return false;
NetworkCapabilities that = (NetworkCapabilities) obj;
- return (equalsNetCapabilities(that)
+ return equalsNetCapabilities(that)
&& equalsTransportTypes(that)
&& equalsLinkBandwidths(that)
&& equalsSignalStrength(that)
@@ -1496,7 +1516,8 @@
&& equalsTransportInfo(that)
&& equalsUids(that)
&& equalsSSID(that)
- && equalsPrivateDnsBroken(that));
+ && equalsPrivateDnsBroken(that)
+ && equalsRequestor(that);
}
@Override
@@ -1514,7 +1535,9 @@
+ Objects.hashCode(mUids) * 31
+ Objects.hashCode(mSSID) * 37
+ Objects.hashCode(mTransportInfo) * 41
- + Objects.hashCode(mPrivateDnsBroken) * 43;
+ + Objects.hashCode(mPrivateDnsBroken) * 43
+ + Objects.hashCode(mRequestorUid) * 47
+ + Objects.hashCode(mRequestorPackageName) * 53;
}
@Override
@@ -1537,6 +1560,8 @@
dest.writeBoolean(mPrivateDnsBroken);
dest.writeList(mAdministratorUids);
dest.writeInt(mOwnerUid);
+ dest.writeInt(mRequestorUid);
+ dest.writeString(mRequestorPackageName);
}
public static final @android.annotation.NonNull Creator<NetworkCapabilities> CREATOR =
@@ -1559,6 +1584,8 @@
netCap.mPrivateDnsBroken = in.readBoolean();
netCap.setAdministratorUids(in.readArrayList(null));
netCap.mOwnerUid = in.readInt();
+ netCap.mRequestorUid = in.readInt();
+ netCap.mRequestorPackageName = in.readString();
return netCap;
}
@Override
@@ -1624,6 +1651,9 @@
sb.append(" Private DNS is broken");
}
+ sb.append(" RequestorUid: ").append(mRequestorUid);
+ sb.append(" RequestorPackageName: ").append(mRequestorPackageName);
+
sb.append("]");
return sb.toString();
}
@@ -1632,6 +1662,7 @@
private interface NameOf {
String nameOf(int value);
}
+
/**
* @hide
*/
@@ -1799,4 +1830,120 @@
private boolean equalsPrivateDnsBroken(NetworkCapabilities nc) {
return mPrivateDnsBroken == nc.mPrivateDnsBroken;
}
+
+ /**
+ * Set the uid of the app making the request.
+ *
+ * Note: This works only for {@link NetworkAgent} instances. Any capabilities passed in
+ * via the public {@link ConnectivityManager} API's will have this field overwritten.
+ *
+ * @param uid UID of the app.
+ * @hide
+ */
+ @SystemApi
+ public @NonNull NetworkCapabilities setRequestorUid(int uid) {
+ mRequestorUid = uid;
+ return this;
+ }
+
+ /**
+ * @return the uid of the app making the request.
+ *
+ * Note: This could return {@link Process#INVALID_UID} if the {@link NetworkRequest}
+ * object was not obtained from {@link ConnectivityManager}.
+ * @hide
+ */
+ public int getRequestorUid() {
+ return mRequestorUid;
+ }
+
+ /**
+ * Set the package name of the app making the request.
+ *
+ * Note: This works only for {@link NetworkAgent} instances. Any capabilities passed in
+ * via the public {@link ConnectivityManager} API's will have this field overwritten.
+ *
+ * @param packageName package name of the app.
+ * @hide
+ */
+ @SystemApi
+ public @NonNull NetworkCapabilities setRequestorPackageName(@NonNull String packageName) {
+ mRequestorPackageName = packageName;
+ return this;
+ }
+
+ /**
+ * @return the package name of the app making the request.
+ *
+ * Note: This could return {@code null} if the {@link NetworkRequest} object was not obtained
+ * from {@link ConnectivityManager}.
+ * @hide
+ */
+ @Nullable
+ public String getRequestorPackageName() {
+ return mRequestorPackageName;
+ }
+
+ /**
+ * Set the uid and package name of the app making the request.
+ *
+ * Note: This is intended to be only invoked from within connectivitiy service.
+ *
+ * @param uid UID of the app.
+ * @param packageName package name of the app.
+ * @hide
+ */
+ public @NonNull NetworkCapabilities setRequestorUidAndPackageName(
+ int uid, @NonNull String packageName) {
+ return setRequestorUid(uid).setRequestorPackageName(packageName);
+ }
+
+ /**
+ * Test whether the passed NetworkCapabilities satisfies the requestor restrictions of this
+ * capabilities.
+ *
+ * This method is called on the NetworkCapabilities embedded in a request with the
+ * capabilities of an available network. If the available network, sets a specific
+ * requestor (by uid and optionally package name), then this will only match a request from the
+ * same app. If either of the capabilities have an unset uid or package name, then it matches
+ * everything.
+ * <p>
+ * nc is assumed nonnull. Else, NPE.
+ */
+ private boolean satisfiedByRequestor(NetworkCapabilities nc) {
+ // No uid set, matches everything.
+ if (mRequestorUid == Process.INVALID_UID || nc.mRequestorUid == Process.INVALID_UID) {
+ return true;
+ }
+ // uids don't match.
+ if (mRequestorUid != nc.mRequestorUid) return false;
+ // No package names set, matches everything
+ if (null == nc.mRequestorPackageName || null == mRequestorPackageName) return true;
+ // check for package name match.
+ return TextUtils.equals(mRequestorPackageName, nc.mRequestorPackageName);
+ }
+
+ /**
+ * Combine requestor info of the capabilities.
+ * <p>
+ * This is only legal if either the requestor info of this object is reset, or both info are
+ * equal.
+ * nc is assumed nonnull.
+ */
+ private void combineRequestor(@NonNull NetworkCapabilities nc) {
+ if (mRequestorUid != Process.INVALID_UID && mRequestorUid != nc.mOwnerUid) {
+ throw new IllegalStateException("Can't combine two uids");
+ }
+ if (mRequestorPackageName != null
+ && !mRequestorPackageName.equals(nc.mRequestorPackageName)) {
+ throw new IllegalStateException("Can't combine two package names");
+ }
+ setRequestorUid(nc.mRequestorUid);
+ setRequestorPackageName(nc.mRequestorPackageName);
+ }
+
+ private boolean equalsRequestor(NetworkCapabilities nc) {
+ return mRequestorUid == nc.mRequestorUid
+ && TextUtils.equals(mRequestorPackageName, nc.mRequestorPackageName);
+ }
}
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 301d203..964f13f 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -380,6 +380,7 @@
dest.writeInt(requestId);
dest.writeString(type.name());
}
+
public static final @android.annotation.NonNull Creator<NetworkRequest> CREATOR =
new Creator<NetworkRequest>() {
public NetworkRequest createFromParcel(Parcel in) {
@@ -494,6 +495,31 @@
return networkCapabilities.getNetworkSpecifier();
}
+ /**
+ * @return the uid of the app making the request.
+ *
+ * Note: This could return {@link Process#INVALID_UID} if the {@link NetworkRequest} object was
+ * not obtained from {@link ConnectivityManager}.
+ * @hide
+ */
+ @SystemApi
+ public int getRequestorUid() {
+ return networkCapabilities.getRequestorUid();
+ }
+
+ /**
+ * @return the package name of the app making the request.
+ *
+ * Note: This could return {@code null} if the {@link NetworkRequest} object was not obtained
+ * from {@link ConnectivityManager}.
+ * @hide
+ */
+ @SystemApi
+ @Nullable
+ public String getRequestorPackageName() {
+ return networkCapabilities.getRequestorPackageName();
+ }
+
public String toString() {
return "NetworkRequest [ " + type + " id=" + requestId +
(legacyType != ConnectivityManager.TYPE_NONE ? ", legacyType=" + legacyType : "") +
diff --git a/core/java/android/net/NetworkSpecifier.java b/core/java/android/net/NetworkSpecifier.java
index cf31d21..2dd0c4e 100644
--- a/core/java/android/net/NetworkSpecifier.java
+++ b/core/java/android/net/NetworkSpecifier.java
@@ -39,23 +39,6 @@
/**
* Optional method which can be overridden by concrete implementations of NetworkSpecifier to
- * check a self-reported UID. A concrete implementation may contain a UID which would be self-
- * reported by the caller (since NetworkSpecifier implementations should be non-mutable). This
- * function is called by ConnectivityService and is passed the actual UID of the caller -
- * allowing the verification of the self-reported UID. In cases of mismatch the implementation
- * should throw a SecurityException.
- *
- * @param requestorUid The UID of the requestor as obtained from its binder.
- *
- * @hide
- */
- @SystemApi
- public void assertValidFromUid(int requestorUid) {
- // empty
- }
-
- /**
- * Optional method which can be overridden by concrete implementations of NetworkSpecifier to
* perform any redaction of information from the NetworkSpecifier, e.g. if it contains
* sensitive information. The default implementation simply returns the object itself - i.e.
* no information is redacted. A concrete implementation may return a modified (copy) of the
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index a291734..70b2db7 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -240,6 +240,13 @@
public static final String RELEASE = getString("ro.build.version.release");
/**
+ * The version string we show to the user; may be {@link #RELEASE} or
+ * {@link #CODENAME} if not a final release build.
+ */
+ @NonNull public static final String RELEASE_OR_CODENAME = getString(
+ "ro.build.version.release_or_codename");
+
+ /**
* The base OS build the product is based on.
*/
public static final String BASE_OS = SystemProperties.get("ro.build.version.base_os", "");
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 44f12a6..21a1e0f 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -34,9 +34,11 @@
import android.util.Log;
import java.io.File;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
+import java.util.List;
/**
* Provides access to environment variables.
@@ -539,12 +541,21 @@
@SystemApi
public static @NonNull Collection<File> getInternalMediaDirectories() {
final ArrayList<File> res = new ArrayList<>();
- res.add(new File(Environment.getRootDirectory(), "media"));
- res.add(new File(Environment.getOemDirectory(), "media"));
- res.add(new File(Environment.getProductDirectory(), "media"));
+ addCanonicalFile(res, new File(Environment.getRootDirectory(), "media"));
+ addCanonicalFile(res, new File(Environment.getOemDirectory(), "media"));
+ addCanonicalFile(res, new File(Environment.getProductDirectory(), "media"));
return res;
}
+ private static void addCanonicalFile(List<File> list, File file) {
+ try {
+ list.add(file.getCanonicalFile());
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to resolve " + file + ": " + e);
+ list.add(file);
+ }
+ }
+
/**
* Return the primary shared/external storage directory. This directory may
* not currently be accessible if it has been mounted by the user on their
diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
index 8990bdf..0024ac7 100644
--- a/core/java/android/os/incremental/IncrementalManager.java
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -23,8 +23,6 @@
import android.content.Context;
import android.content.pm.DataLoaderParams;
import android.os.RemoteException;
-import android.system.ErrnoException;
-import android.system.Os;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
@@ -193,116 +191,54 @@
}
/**
- * Renames an Incremental path to a new path. If source path is a file, make a link from the old
- * Incremental file to the new one. If source path is a dir, unbind old dir from Incremental
- * Storage and bind the new one.
- * <ol>
- * <li> For renaming a dir, dest dir will be created if not exists, and does not need to
- * be on the same Incremental storage as the source. </li>
- * <li> For renaming a file, dest file must be on the same Incremental storage as source.
- * </li>
- * </ol>
+ * Set up an app's code path. The expected outcome of this method is:
+ * 1) The actual apk directory under /data/incremental is bind-mounted to the parent directory
+ * of {@code afterCodeFile}.
+ * 2) All the files under {@code beforeCodeFile} will show up under {@code afterCodeFile}.
*
- * @param sourcePath Absolute path to the source. Should be the same type as the destPath (file
- * or dir). Expected to already exist and is an Incremental path.
- * @param destPath Absolute path to the destination.
- * @throws IllegalArgumentException when 1) source does not exist, or 2) source and dest type
- * mismatch (one is file and the other is dir), or 3) source
- * path is not on Incremental File System,
- * @throws IOException when 1) cannot find the root path of the Incremental storage
- * of source, or 2) cannot retrieve the Incremental storage
- * instance of the source, or 3) renaming a file, but dest is
- * not on the same Incremental Storage, or 4) renaming a dir,
- * dest dir does not exist but fails to be created.
- * <p>
- * TODO(b/136132412): add unit tests
+ * @param beforeCodeFile Path that is currently bind-mounted and have APKs under it.
+ * Should no longer have any APKs after this method is called.
+ * Example: /data/app/vmdl*tmp
+ * @param afterCodeFile Path that should will have APKs after this method is called. Its parent
+ * directory should be bind-mounted to a directory under /data/incremental.
+ * Example: /data/app/~~[randomStringA]/[packageName]-[randomStringB]
+ * @throws IllegalArgumentException
+ * @throws IOException
+ * TODO(b/147371381): add unit tests
*/
- public void rename(@NonNull String sourcePath, @NonNull String destPath) throws IOException {
- final File source = new File(sourcePath);
- final File dest = new File(destPath);
- if (!source.exists()) {
- throw new IllegalArgumentException("Path not exist: " + sourcePath);
+ public void renameCodePath(File beforeCodeFile, File afterCodeFile)
+ throws IllegalArgumentException, IOException {
+ final String beforeCodePath = beforeCodeFile.getAbsolutePath();
+ final String afterCodePathParent = afterCodeFile.getParentFile().getAbsolutePath();
+ if (!isIncrementalPath(beforeCodePath)) {
+ throw new IllegalArgumentException("Not an Incremental path: " + beforeCodePath);
}
- if (dest.exists()) {
- throw new IllegalArgumentException("Target path already exists: " + destPath);
+ final String afterCodePathName = afterCodeFile.getName();
+ final Path apkStoragePath = Paths.get(beforeCodePath);
+ if (apkStoragePath == null || apkStoragePath.toAbsolutePath() == null) {
+ throw new IOException("Invalid source storage path for: " + beforeCodePath);
}
- if (source.isDirectory() && dest.exists() && dest.isFile()) {
- throw new IllegalArgumentException(
- "Trying to rename a dir but destination is a file: " + destPath);
- }
- if (source.isFile() && dest.exists() && dest.isDirectory()) {
- throw new IllegalArgumentException(
- "Trying to rename a file but destination is a dir: " + destPath);
- }
- if (!isIncrementalPath(sourcePath)) {
- throw new IllegalArgumentException("Not an Incremental path: " + sourcePath);
- }
-
- Path storagePath = Paths.get(sourcePath);
- if (source.isFile()) {
- storagePath = getStoragePathForFile(source);
- }
- if (storagePath == null || storagePath.toAbsolutePath() == null) {
- throw new IOException("Invalid source storage path for: " + sourcePath);
- }
- final IncrementalStorage storage = openStorage(storagePath.toAbsolutePath().toString());
- if (storage == null) {
+ final IncrementalStorage apkStorage =
+ openStorage(apkStoragePath.toAbsolutePath().toString());
+ if (apkStorage == null) {
throw new IOException("Failed to retrieve storage from Incremental Service.");
}
-
- if (source.isFile()) {
- renameFile(storage, storagePath, source, dest);
- } else {
- renameDir(storage, storagePath, source, dest);
+ final IncrementalStorage linkedApkStorage = createStorage(afterCodePathParent, apkStorage,
+ IncrementalManager.CREATE_MODE_CREATE
+ | IncrementalManager.CREATE_MODE_PERMANENT_BIND);
+ if (linkedApkStorage == null) {
+ throw new IOException("Failed to create linked storage at dir: " + afterCodePathParent);
}
- }
-
- private void renameFile(IncrementalStorage storage, Path storagePath,
- File source, File dest) throws IOException {
- Path sourcePath = source.toPath();
- Path destPath = dest.toPath();
- if (!sourcePath.startsWith(storagePath)) {
- throw new IOException("Path: " + source.getAbsolutePath() + " is not on storage at: "
- + storagePath.toString());
- }
- if (!destPath.startsWith(storagePath)) {
- throw new IOException("Path: " + dest.getAbsolutePath() + " is not on storage at: "
- + storagePath.toString());
- }
- final Path sourceRelativePath = storagePath.relativize(sourcePath);
- final Path destRelativePath = storagePath.relativize(destPath);
- storage.moveFile(sourceRelativePath.toString(), destRelativePath.toString());
-
- }
-
- private void renameDir(IncrementalStorage storage, Path storagePath,
- File source, File dest) throws IOException {
- Path destPath = dest.toPath();
- boolean usedMkdir = false;
- try {
- Os.mkdir(dest.getAbsolutePath(), 0755);
- usedMkdir = true;
- } catch (ErrnoException e) {
- // Traditional mkdir fails but maybe we can create it on Incremental File System if
- // the dest path is on the same Incremental storage as the source.
- if (destPath.startsWith(storagePath)) {
- storage.makeDirectories(storagePath.relativize(destPath).toString());
- } else {
- throw new IOException("Failed to create directory: " + dest.getAbsolutePath(), e);
+ linkedApkStorage.makeDirectory(afterCodePathName);
+ File[] files = beforeCodeFile.listFiles();
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].isFile()) {
+ String fileName = files[i].getName();
+ apkStorage.makeLink(
+ fileName, linkedApkStorage, afterCodePathName + "/" + fileName);
}
}
- try {
- storage.moveDir(source.getAbsolutePath(), dest.getAbsolutePath());
- } catch (Exception ex) {
- if (usedMkdir) {
- try {
- Os.remove(dest.getAbsolutePath());
- } catch (ErrnoException ignored) {
- }
- }
- throw new IOException(
- "Failed to move " + source.getAbsolutePath() + " to " + dest.getAbsolutePath());
- }
+ apkStorage.unBind(beforeCodePath);
}
/**
@@ -325,6 +261,13 @@
}
/**
+ * Checks if Incremental is enabled
+ */
+ public static boolean isEnabled() {
+ return nativeIsEnabled();
+ }
+
+ /**
* Checks if path is mounted on Incremental File System.
*/
public static boolean isIncrementalPath(@NonNull String path) {
@@ -332,5 +275,6 @@
}
/* Native methods */
+ private static native boolean nativeIsEnabled();
private static native boolean nativeIsIncrementalPath(@NonNull String path);
}
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index b6f5138..adfa885 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -5205,6 +5205,7 @@
/**
* TelephonyProvider column name for allowed network types. Indicate which network types
* are allowed. Default is -1.
+ * <P>Type: BIGINT (long) </P>
*/
public static final String ALLOWED_NETWORK_TYPES = "allowed_network_types";
}
diff --git a/core/java/android/service/textclassifier/TextClassifierService.java b/core/java/android/service/textclassifier/TextClassifierService.java
index 848868a..3ff6f54 100644
--- a/core/java/android/service/textclassifier/TextClassifierService.java
+++ b/core/java/android/service/textclassifier/TextClassifierService.java
@@ -41,6 +41,7 @@
import android.view.textclassifier.ConversationActions;
import android.view.textclassifier.SelectionEvent;
import android.view.textclassifier.TextClassification;
+import android.view.textclassifier.TextClassificationConstants;
import android.view.textclassifier.TextClassificationContext;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassificationSessionId;
@@ -404,22 +405,27 @@
*/
@NonNull
public static TextClassifier getDefaultTextClassifierImplementation(@NonNull Context context) {
- final String defaultTextClassifierPackageName =
- context.getPackageManager().getDefaultTextClassifierPackageName();
- if (TextUtils.isEmpty(defaultTextClassifierPackageName)) {
- return TextClassifier.NO_OP;
- }
- if (defaultTextClassifierPackageName.equals(context.getPackageName())) {
- throw new RuntimeException(
- "The default text classifier itself should not call the"
- + "getDefaultTextClassifierImplementation() method.");
- }
final TextClassificationManager tcm =
context.getSystemService(TextClassificationManager.class);
- if (tcm != null) {
- return tcm.getTextClassifier(TextClassifier.DEFAULT_SERVICE);
+ if (tcm == null) {
+ return TextClassifier.NO_OP;
}
- return TextClassifier.NO_OP;
+ TextClassificationConstants settings = new TextClassificationConstants();
+ if (settings.getUseDefaultTextClassifierAsDefaultImplementation()) {
+ final String defaultTextClassifierPackageName =
+ context.getPackageManager().getDefaultTextClassifierPackageName();
+ if (TextUtils.isEmpty(defaultTextClassifierPackageName)) {
+ return TextClassifier.NO_OP;
+ }
+ if (defaultTextClassifierPackageName.equals(context.getPackageName())) {
+ throw new RuntimeException(
+ "The default text classifier itself should not call the"
+ + "getDefaultTextClassifierImplementation() method.");
+ }
+ return tcm.getTextClassifier(TextClassifier.DEFAULT_SERVICE);
+ } else {
+ return tcm.getTextClassifier(TextClassifier.LOCAL);
+ }
}
/** @hide **/
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 1966f17..a88d389 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -181,14 +181,14 @@
* Returned by {@link #getSupportedAudioCapabilities()}
*/
public static final int AUDIO_CAPABILITY_ECHO_CANCELLATION =
- SoundTrigger.ModuleProperties.CAPABILITY_ECHO_CANCELLATION;
+ SoundTrigger.ModuleProperties.AUDIO_CAPABILITY_ECHO_CANCELLATION;
/**
* If set, the underlying module supports noise suppression.
* Returned by {@link #getSupportedAudioCapabilities()}
*/
public static final int AUDIO_CAPABILITY_NOISE_SUPPRESSION =
- SoundTrigger.ModuleProperties.CAPABILITY_NOISE_SUPPRESSION;
+ SoundTrigger.ModuleProperties.AUDIO_CAPABILITY_NOISE_SUPPRESSION;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -249,21 +249,21 @@
}
/**
- * The inclusive start of supported range.
+ * Get the beginning of the param range
*
- * @return start of range
+ * @return The inclusive start of the supported range.
*/
- public int start() {
- return mModelParamRange.start;
+ public int getStart() {
+ return mModelParamRange.getStart();
}
/**
- * The inclusive end of supported range.
+ * Get the end of the param range
*
- * @return end of range
+ * @return The inclusive end of the supported range.
*/
- public int end() {
- return mModelParamRange.end;
+ public int getEnd() {
+ return mModelParamRange.getEnd();
}
@Override
diff --git a/core/java/android/timezone/CountryTimeZones.java b/core/java/android/timezone/CountryTimeZones.java
index ab2c4fc..ee3a8a7 100644
--- a/core/java/android/timezone/CountryTimeZones.java
+++ b/core/java/android/timezone/CountryTimeZones.java
@@ -18,7 +18,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SuppressLint;
import android.icu.util.TimeZone;
import java.util.ArrayList;
@@ -206,27 +205,47 @@
}
/**
- * Returns a time zone for the country, if there is one, that matches the desired properties. If
- * there are multiple matches and the {@code bias} is one of them then it is returned, otherwise
- * an arbitrary match is returned based on the {@link #getEffectiveTimeZoneMappingsAt(long)}
- * ordering.
+ * Returns a time zone for the country, if there is one, that matches the supplied properties.
+ * If there are multiple matches and the {@code bias} is one of them then it is returned,
+ * otherwise an arbitrary match is returned based on the {@link
+ * #getEffectiveTimeZoneMappingsAt(long)} ordering.
*
+ * @param whenMillis the UTC time to match against
+ * @param bias the time zone to prefer, can be {@code null} to indicate there is no preference
* @param totalOffsetMillis the offset from UTC at {@code whenMillis}
* @param isDst the Daylight Savings Time state at {@code whenMillis}. {@code true} means DST,
- * {@code false} means not DST, {@code null} means unknown
- * @param dstOffsetMillis the part of {@code totalOffsetMillis} contributed by DST, only used if
- * {@code isDst} is {@code true}. The value can be {@code null} if the DST offset is
- * unknown
- * @param whenMillis the UTC time to match against
- * @param bias the time zone to prefer, can be {@code null}
+ * {@code false} means not DST
+ * @return an {@link OffsetResult} with information about a matching zone, or {@code null} if
+ * there is no match
*/
@Nullable
- public OffsetResult lookupByOffsetWithBias(int totalOffsetMillis, @Nullable Boolean isDst,
- @SuppressLint("AutoBoxing") @Nullable Integer dstOffsetMillis, long whenMillis,
- @Nullable TimeZone bias) {
+ public OffsetResult lookupByOffsetWithBias(long whenMillis, @Nullable TimeZone bias,
+ int totalOffsetMillis, boolean isDst) {
libcore.timezone.CountryTimeZones.OffsetResult delegateOffsetResult =
mDelegate.lookupByOffsetWithBias(
- totalOffsetMillis, isDst, dstOffsetMillis, whenMillis, bias);
+ whenMillis, bias, totalOffsetMillis, isDst);
+ return delegateOffsetResult == null ? null :
+ new OffsetResult(
+ delegateOffsetResult.getTimeZone(), delegateOffsetResult.isOnlyMatch());
+ }
+
+ /**
+ * Returns a time zone for the country, if there is one, that matches the supplied properties.
+ * If there are multiple matches and the {@code bias} is one of them then it is returned,
+ * otherwise an arbitrary match is returned based on the {@link
+ * #getEffectiveTimeZoneMappingsAt(long)} ordering.
+ *
+ * @param whenMillis the UTC time to match against
+ * @param bias the time zone to prefer, can be {@code null} to indicate there is no preference
+ * @param totalOffsetMillis the offset from UTC at {@code whenMillis}
+ * @return an {@link OffsetResult} with information about a matching zone, or {@code null} if
+ * there is no match
+ */
+ @Nullable
+ public OffsetResult lookupByOffsetWithBias(long whenMillis, @Nullable TimeZone bias,
+ int totalOffsetMillis) {
+ libcore.timezone.CountryTimeZones.OffsetResult delegateOffsetResult =
+ mDelegate.lookupByOffsetWithBias(whenMillis, bias, totalOffsetMillis);
return delegateOffsetResult == null ? null :
new OffsetResult(
delegateOffsetResult.getTimeZone(), delegateOffsetResult.isOnlyMatch());
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 36f4e53..4b3afba 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -80,7 +80,7 @@
return null;
}
CountryTimeZones.OffsetResult offsetResult = countryTimeZones.lookupByOffsetWithBias(
- offsetMillis, isDst, null /* dstOffsetMillis */, whenMillis, bias);
+ whenMillis, bias, offsetMillis, isDst);
return offsetResult != null ? offsetResult.getTimeZone() : null;
}
diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java
index 6463509..b933664 100644
--- a/core/java/android/util/apk/ApkSignatureVerifier.java
+++ b/core/java/android/util/apk/ApkSignatureVerifier.java
@@ -66,46 +66,49 @@
public static PackageParser.SigningDetails verify(String apkPath,
@SignatureSchemeVersion int minSignatureSchemeVersion)
throws PackageParserException {
+ return verifySignatures(apkPath, minSignatureSchemeVersion, true);
+ }
+
+ /**
+ * Returns the certificates associated with each signer for the given APK without verification.
+ * This method is dangerous and should not be used, unless the caller is absolutely certain the
+ * APK is trusted.
+ *
+ * @throws PackageParserException if the APK's signature failed to verify.
+ * or greater is not found, except in the case of no JAR signature.
+ */
+ public static PackageParser.SigningDetails unsafeGetCertsWithoutVerification(
+ String apkPath, int minSignatureSchemeVersion)
+ throws PackageParserException {
+ return verifySignatures(apkPath, minSignatureSchemeVersion, false);
+ }
+
+ /**
+ * Verifies the provided APK using all allowed signing schemas.
+ * @return the certificates associated with each signer.
+ * @param verifyFull whether to verify all contents of this APK or just collect certificates.
+ * @throws PackageParserException if there was a problem collecting certificates
+ */
+ private static PackageParser.SigningDetails verifySignatures(String apkPath,
+ @SignatureSchemeVersion int minSignatureSchemeVersion, boolean verifyFull)
+ throws PackageParserException {
if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V3) {
// V3 and before are older than the requested minimum signing version
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No signature found in package of version " + minSignatureSchemeVersion
- + " or newer for package " + apkPath);
+ + " or newer for package " + apkPath);
}
// first try v3
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV3");
try {
- ApkSignatureSchemeV3Verifier.VerifiedSigner vSigner =
- ApkSignatureSchemeV3Verifier.verify(apkPath);
- Certificate[][] signerCerts = new Certificate[][] { vSigner.certs };
- Signature[] signerSigs = convertToSignatures(signerCerts);
- Signature[] pastSignerSigs = null;
- if (vSigner.por != null) {
- // populate proof-of-rotation information
- pastSignerSigs = new Signature[vSigner.por.certs.size()];
- for (int i = 0; i < pastSignerSigs.length; i++) {
- pastSignerSigs[i] = new Signature(vSigner.por.certs.get(i).getEncoded());
- pastSignerSigs[i].setFlags(vSigner.por.flagsList.get(i));
- }
- }
- return new PackageParser.SigningDetails(
- signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V3,
- pastSignerSigs);
+ return verifyV3Signature(apkPath, verifyFull);
} catch (SignatureNotFoundException e) {
// not signed with v3, try older if allowed
if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V3) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No APK Signature Scheme v3 signature in package " + apkPath, e);
}
- } catch (Exception e) {
- // APK Signature Scheme v2 signature found but did not verify
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
- "Failed to collect certificates from " + apkPath
- + " using APK Signature Scheme v3", e);
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
// redundant, protective version check
@@ -117,26 +120,14 @@
}
// try v2
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV2");
try {
- Certificate[][] signerCerts = ApkSignatureSchemeV2Verifier.verify(apkPath);
- Signature[] signerSigs = convertToSignatures(signerCerts);
-
- return new PackageParser.SigningDetails(
- signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V2);
+ return verifyV2Signature(apkPath, verifyFull);
} catch (SignatureNotFoundException e) {
// not signed with v2, try older if allowed
if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V2) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No APK Signature Scheme v2 signature in package " + apkPath, e);
}
- } catch (Exception e) {
- // APK Signature Scheme v2 signature found but did not verify
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
- "Failed to collect certificates from " + apkPath
- + " using APK Signature Scheme v2", e);
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
// redundant, protective version check
@@ -148,14 +139,83 @@
}
// v2 didn't work, try jarsigner
- return verifyV1Signature(apkPath, true);
+ return verifyV1Signature(apkPath, verifyFull);
}
/**
- * Verifies the provided APK and returns the certificates associated with each signer.
+ * Verifies the provided APK using V3 schema.
*
* @param verifyFull whether to verify all contents of this APK or just collect certificates.
+ * @return the certificates associated with each signer.
+ * @throws SignatureNotFoundException is there are no V3 signatures in the APK
+ * @throws PackageParserException if there was a problem collecting certificates
+ */
+ private static PackageParser.SigningDetails verifyV3Signature(String apkPath,
+ boolean verifyFull) throws SignatureNotFoundException, PackageParserException {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, verifyFull ? "verifyV3" : "certsOnlyV3");
+ try {
+ ApkSignatureSchemeV3Verifier.VerifiedSigner vSigner =
+ verifyFull ? ApkSignatureSchemeV3Verifier.verify(apkPath)
+ : ApkSignatureSchemeV3Verifier.unsafeGetCertsWithoutVerification(
+ apkPath);
+ Certificate[][] signerCerts = new Certificate[][]{vSigner.certs};
+ Signature[] signerSigs = convertToSignatures(signerCerts);
+ Signature[] pastSignerSigs = null;
+ if (vSigner.por != null) {
+ // populate proof-of-rotation information
+ pastSignerSigs = new Signature[vSigner.por.certs.size()];
+ for (int i = 0; i < pastSignerSigs.length; i++) {
+ pastSignerSigs[i] = new Signature(vSigner.por.certs.get(i).getEncoded());
+ pastSignerSigs[i].setFlags(vSigner.por.flagsList.get(i));
+ }
+ }
+ return new PackageParser.SigningDetails(signerSigs,
+ SignatureSchemeVersion.SIGNING_BLOCK_V3, pastSignerSigs);
+ } catch (SignatureNotFoundException e) {
+ throw e;
+ } catch (Exception e) {
+ // APK Signature Scheme v3 signature found but did not verify
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "Failed to collect certificates from " + apkPath
+ + " using APK Signature Scheme v3", e);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
+ /**
+ * Verifies the provided APK using V2 schema.
*
+ * @param verifyFull whether to verify all contents of this APK or just collect certificates.
+ * @return the certificates associated with each signer.
+ * @throws SignatureNotFoundException is there are no V2 signatures in the APK
+ * @throws PackageParserException if there was a problem collecting certificates
+ */
+ private static PackageParser.SigningDetails verifyV2Signature(String apkPath,
+ boolean verifyFull) throws SignatureNotFoundException, PackageParserException {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, verifyFull ? "verifyV2" : "certsOnlyV2");
+ try {
+ Certificate[][] signerCerts = verifyFull ? ApkSignatureSchemeV2Verifier.verify(apkPath)
+ : ApkSignatureSchemeV2Verifier.unsafeGetCertsWithoutVerification(apkPath);
+ Signature[] signerSigs = convertToSignatures(signerCerts);
+ return new PackageParser.SigningDetails(signerSigs,
+ SignatureSchemeVersion.SIGNING_BLOCK_V2);
+ } catch (SignatureNotFoundException e) {
+ throw e;
+ } catch (Exception e) {
+ // APK Signature Scheme v2 signature found but did not verify
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "Failed to collect certificates from " + apkPath
+ + " using APK Signature Scheme v2", e);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
+ /**
+ * Verifies the provided APK using JAR schema.
+ * @return the certificates associated with each signer.
+ * @param verifyFull whether to verify all contents of this APK or just collect certificates.
* @throws PackageParserException if there was a problem collecting certificates
*/
private static PackageParser.SigningDetails verifyV1Signature(
@@ -277,7 +337,7 @@
*
* @throws CertificateEncodingException if it is unable to create a Signature object.
*/
- public static Signature[] convertToSignatures(Certificate[][] certs)
+ private static Signature[] convertToSignatures(Certificate[][] certs)
throws CertificateEncodingException {
final Signature[] res = new Signature[certs.length];
for (int i = 0; i < certs.length; i++) {
@@ -296,99 +356,29 @@
}
/**
- * Returns the certificates associated with each signer for the given APK without verification.
- * This method is dangerous and should not be used, unless the caller is absolutely certain the
- * APK is trusted.
- *
- * @throws PackageParserException if the APK's signature failed to verify.
- * or greater is not found, except in the case of no JAR signature.
+ * Returns the minimum signature scheme version required for an app targeting the specified
+ * {@code targetSdk}.
*/
- public static PackageParser.SigningDetails unsafeGetCertsWithoutVerification(
- String apkPath, int minSignatureSchemeVersion)
- throws PackageParserException {
-
- if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V3) {
- // V3 and before are older than the requested minimum signing version
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
- "No signature found in package of version " + minSignatureSchemeVersion
- + " or newer for package " + apkPath);
+ public static int getMinimumSignatureSchemeVersionForTargetSdk(int targetSdk) {
+ if (targetSdk >= Build.VERSION_CODES.R) {
+ return SignatureSchemeVersion.SIGNING_BLOCK_V2;
}
+ return SignatureSchemeVersion.JAR;
+ }
- // first try v3
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "certsOnlyV3");
- try {
- ApkSignatureSchemeV3Verifier.VerifiedSigner vSigner =
- ApkSignatureSchemeV3Verifier.unsafeGetCertsWithoutVerification(apkPath);
- Certificate[][] signerCerts = new Certificate[][] { vSigner.certs };
- Signature[] signerSigs = convertToSignatures(signerCerts);
- Signature[] pastSignerSigs = null;
- if (vSigner.por != null) {
- // populate proof-of-rotation information
- pastSignerSigs = new Signature[vSigner.por.certs.size()];
- for (int i = 0; i < pastSignerSigs.length; i++) {
- pastSignerSigs[i] = new Signature(vSigner.por.certs.get(i).getEncoded());
- pastSignerSigs[i].setFlags(vSigner.por.flagsList.get(i));
- }
- }
- return new PackageParser.SigningDetails(
- signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V3,
- pastSignerSigs);
- } catch (SignatureNotFoundException e) {
- // not signed with v3, try older if allowed
- if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V3) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
- "No APK Signature Scheme v3 signature in package " + apkPath, e);
- }
- } catch (Exception e) {
- // APK Signature Scheme v3 signature found but did not verify
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
- "Failed to collect certificates from " + apkPath
- + " using APK Signature Scheme v3", e);
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ /**
+ * Result of a successful APK verification operation.
+ */
+ public static class Result {
+ public final Certificate[][] certs;
+ public final Signature[] sigs;
+ public final int signatureSchemeVersion;
+
+ public Result(Certificate[][] certs, Signature[] sigs, int signingVersion) {
+ this.certs = certs;
+ this.sigs = sigs;
+ this.signatureSchemeVersion = signingVersion;
}
-
- // redundant, protective version check
- if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V2) {
- // V2 and before are older than the requested minimum signing version
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
- "No signature found in package of version " + minSignatureSchemeVersion
- + " or newer for package " + apkPath);
- }
-
- // first try v2
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "certsOnlyV2");
- try {
- Certificate[][] signerCerts =
- ApkSignatureSchemeV2Verifier.unsafeGetCertsWithoutVerification(apkPath);
- Signature[] signerSigs = convertToSignatures(signerCerts);
- return new PackageParser.SigningDetails(signerSigs,
- SignatureSchemeVersion.SIGNING_BLOCK_V2);
- } catch (SignatureNotFoundException e) {
- // not signed with v2, try older if allowed
- if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V2) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
- "No APK Signature Scheme v2 signature in package " + apkPath, e);
- }
- } catch (Exception e) {
- // APK Signature Scheme v2 signature found but did not verify
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
- "Failed to collect certificates from " + apkPath
- + " using APK Signature Scheme v2", e);
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
-
- // redundant, protective version check
- if (minSignatureSchemeVersion > SignatureSchemeVersion.JAR) {
- // V1 and is older than the requested minimum signing version
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
- "No signature found in package of version " + minSignatureSchemeVersion
- + " or newer for package " + apkPath);
- }
-
- // v2 didn't work, try jarsigner
- return verifyV1Signature(apkPath, false);
}
/**
@@ -416,7 +406,7 @@
*/
public static byte[] generateApkVerity(String apkPath, ByteBufferFactory bufferFactory)
throws IOException, SignatureNotFoundException, SecurityException, DigestException,
- NoSuchAlgorithmException {
+ NoSuchAlgorithmException {
// first try v3
try {
return ApkSignatureSchemeV3Verifier.generateApkVerity(apkPath, bufferFactory);
@@ -446,30 +436,4 @@
return null;
}
}
-
- /**
- * Returns the minimum signature scheme version required for an app targeting the specified
- * {@code targetSdk}.
- */
- public static int getMinimumSignatureSchemeVersionForTargetSdk(int targetSdk) {
- if (targetSdk >= Build.VERSION_CODES.R) {
- return SignatureSchemeVersion.SIGNING_BLOCK_V2;
- }
- return SignatureSchemeVersion.JAR;
- }
-
- /**
- * Result of a successful APK verification operation.
- */
- public static class Result {
- public final Certificate[][] certs;
- public final Signature[] sigs;
- public final int signatureSchemeVersion;
-
- public Result(Certificate[][] certs, Signature[] sigs, int signingVersion) {
- this.certs = certs;
- this.sigs = sigs;
- this.signatureSchemeVersion = signingVersion;
- }
- }
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 22d6f37..54de1bb 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -190,9 +190,7 @@
onAnimationFinish();
}
});
- setStartingAnimation(true);
mAnimator.start();
- setStartingAnimation(false);
}
@Override
@@ -203,9 +201,6 @@
}
}
- protected void setStartingAnimation(boolean startingAnimation) {
- }
-
protected void onAnimationFinish() {
mController.finish(mShow);
}
@@ -239,16 +234,6 @@
final @AnimationType int type;
}
- private class DefaultAnimationControlListener extends InternalAnimationControlListener {
- DefaultAnimationControlListener(boolean show) {
- super(show);
- }
-
- @Override
- protected void setStartingAnimation(boolean startingAnimation) {
- mStartingAnimation = startingAnimation;
- }
- }
/**
* Represents a control request that we had to defer because we are waiting for the IME to
* process our show request.
@@ -822,7 +807,8 @@
return;
}
- final DefaultAnimationControlListener listener = new DefaultAnimationControlListener(show);
+ final InternalAnimationControlListener listener =
+ new InternalAnimationControlListener(show);
// Show/hide animations always need to be relative to the display frame, in order that shown
// and hidden state insets are correct.
controlAnimationUnchecked(
@@ -878,7 +864,9 @@
return true;
}
mViewRoot.mView.dispatchWindowInsetsAnimationStart(animation, bounds);
+ mStartingAnimation = true;
listener.onReady(controller, types);
+ mStartingAnimation = false;
return true;
}
});
diff --git a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.aidl b/core/java/android/view/SurfaceControlViewHost.aidl
similarity index 73%
copy from core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.aidl
copy to core/java/android/view/SurfaceControlViewHost.aidl
index 3ad903b..3b31ab8 100644
--- a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.aidl
+++ b/core/java/android/view/SurfaceControlViewHost.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
+/**
+ * Copyright (c) 2020, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.app.timezonedetector;
+package android.view;
-parcelable PhoneTimeZoneSuggestion;
+parcelable SurfaceControlViewHost.SurfacePackage;
\ No newline at end of file
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 75d5538..b1c354f 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1570,7 +1570,8 @@
private void reparentSurfacePackage(SurfaceControl.Transaction t,
SurfaceControlViewHost.SurfacePackage p) {
// TODO: Link accessibility IDs here.
- t.reparent(p.getSurfaceControl(), mSurfaceControl);
+ final SurfaceControl sc = p.getSurfaceControl();
+ t.reparent(sc, mSurfaceControl).show(sc);
}
/**
diff --git a/core/java/android/view/inputmethod/InlineSuggestionInfo.java b/core/java/android/view/inputmethod/InlineSuggestionInfo.java
index 703b64f..024de4d 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionInfo.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionInfo.java
@@ -80,7 +80,6 @@
@NonNull InlinePresentationSpec presentationSpec,
@NonNull @Source String source,
@Nullable String[] autofillHints) {
- // TODO(b/147394280): Add CTS test for the type field.
return new InlineSuggestionInfo(presentationSpec, source, autofillHints, TYPE_SUGGESTION);
}
diff --git a/core/java/android/view/textclassifier/TextClassificationConstants.java b/core/java/android/view/textclassifier/TextClassificationConstants.java
index ed69513..3d5ac58 100644
--- a/core/java/android/view/textclassifier/TextClassificationConstants.java
+++ b/core/java/android/view/textclassifier/TextClassificationConstants.java
@@ -17,6 +17,7 @@
package android.view.textclassifier;
import android.annotation.Nullable;
+import android.content.Context;
import android.provider.DeviceConfig;
import com.android.internal.annotations.VisibleForTesting;
@@ -167,6 +168,16 @@
static final String TEXT_CLASSIFIER_SERVICE_PACKAGE_OVERRIDE =
"textclassifier_service_package_override";
+ /**
+ * Whether to use the default system text classifier as the default text classifier
+ * implementation. The local text classifier is used if it is {@code false}.
+ *
+ * @see android.service.textclassifier.TextClassifierService#getDefaultTextClassifierImplementation(Context)
+ */
+ // TODO: Once the system health experiment is done, remove this together with local TC.
+ private static final String USE_DEFAULT_SYSTEM_TEXT_CLASSIFIER_AS_DEFAULT_IMPL =
+ "use_default_system_text_classifier_as_default_impl";
+
private static final String DEFAULT_TEXT_CLASSIFIER_SERVICE_PACKAGE_OVERRIDE = null;
private static final boolean LOCAL_TEXT_CLASSIFIER_ENABLED_DEFAULT = true;
private static final boolean SYSTEM_TEXT_CLASSIFIER_ENABLED_DEFAULT = true;
@@ -209,7 +220,8 @@
private static final boolean TEMPLATE_INTENT_FACTORY_ENABLED_DEFAULT = true;
private static final boolean TRANSLATE_IN_CLASSIFICATION_ENABLED_DEFAULT = true;
private static final boolean DETECT_LANGUAGES_FROM_TEXT_ENABLED_DEFAULT = true;
- private static final float[] LANG_ID_CONTEXT_SETTINGS_DEFAULT = new float[] {20f, 1.0f, 0.4f};
+ private static final float[] LANG_ID_CONTEXT_SETTINGS_DEFAULT = new float[]{20f, 1.0f, 0.4f};
+ private static final boolean USE_DEFAULT_SYSTEM_TEXT_CLASSIFIER_AS_DEFAULT_IMPL_DEFAULT = true;
@Nullable
public String getTextClassifierServicePackageOverride() {
@@ -331,6 +343,13 @@
LANG_ID_CONTEXT_SETTINGS, LANG_ID_CONTEXT_SETTINGS_DEFAULT);
}
+ public boolean getUseDefaultTextClassifierAsDefaultImplementation() {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ USE_DEFAULT_SYSTEM_TEXT_CLASSIFIER_AS_DEFAULT_IMPL,
+ USE_DEFAULT_SYSTEM_TEXT_CLASSIFIER_AS_DEFAULT_IMPL_DEFAULT);
+ }
+
void dump(IndentingPrintWriter pw) {
pw.println("TextClassificationConstants:");
pw.increaseIndent();
@@ -378,6 +397,8 @@
.println();
pw.printPair("textclassifier_service_package_override",
getTextClassifierServicePackageOverride()).println();
+ pw.printPair("use_default_system_text_classifier_as_default_impl",
+ getUseDefaultTextClassifierAsDefaultImplementation()).println();
pw.decreaseIndent();
}
diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java
index a6c83a1..dfbec9b 100644
--- a/core/java/android/view/textclassifier/TextClassificationManager.java
+++ b/core/java/android/view/textclassifier/TextClassificationManager.java
@@ -25,7 +25,6 @@
import android.os.ServiceManager;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;
-import android.util.SparseArray;
import android.view.textclassifier.TextClassifier.TextClassifierType;
import com.android.internal.annotations.GuardedBy;
@@ -62,8 +61,6 @@
@Nullable
private TextClassifier mLocalTextClassifier;
@GuardedBy("mLock")
- private SparseArray<TextClassifier> mSystemTextClassifiers = new SparseArray<>();
- @GuardedBy("mLock")
private TextClassificationSessionFactory mSessionFactory;
@GuardedBy("mLock")
private TextClassificationConstants mSettings;
@@ -207,23 +204,17 @@
/** @hide */
private TextClassifier getSystemTextClassifier(@TextClassifierType int type) {
synchronized (mLock) {
- if (mSystemTextClassifiers.get(type) == null
- && getSettings().isSystemTextClassifierEnabled()) {
+ if (getSettings().isSystemTextClassifierEnabled()) {
try {
- mSystemTextClassifiers.put(
- type,
- new SystemTextClassifier(
- mContext,
- getSettings(),
- /* useDefault= */ type == TextClassifier.DEFAULT_SERVICE));
- Log.d(LOG_TAG, "Initialized SystemTextClassifier, type = " + type);
+ Log.d(LOG_TAG, "Initializing SystemTextClassifier, type = " + type);
+ return new SystemTextClassifier(
+ mContext,
+ getSettings(),
+ /* useDefault= */ type == TextClassifier.DEFAULT_SERVICE);
} catch (ServiceManager.ServiceNotFoundException e) {
Log.e(LOG_TAG, "Could not initialize SystemTextClassifier", e);
}
}
- if (mSystemTextClassifiers.get(type) != null) {
- return mSystemTextClassifiers.get(type);
- }
return TextClassifier.NO_OP;
}
}
@@ -263,7 +254,6 @@
private void invalidateTextClassifiers() {
synchronized (mLock) {
mLocalTextClassifier = null;
- mSystemTextClassifiers.clear();
}
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 7fd4150..4e4a983 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -454,15 +454,17 @@
aspectRatio = 5.5f;
}
- final Paint.FontMetrics fontMetrics = mTextView.getPaint().getFontMetrics();
- final float sourceHeight = fontMetrics.descent - fontMetrics.ascent;
+ final Layout layout = mTextView.getLayout();
+ final int line = layout.getLineForOffset(mTextView.getSelectionStart());
+ final int sourceHeight =
+ layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line);
// Slightly increase the height to avoid tooLargeTextForMagnifier() returns true.
int height = (int)(sourceHeight * zoom) + 2;
int width = (int)(aspectRatio * height);
params.setFishEyeStyle()
.setSize(width, height)
- .setSourceSize(width, Math.round(sourceHeight))
+ .setSourceSize(width, sourceHeight)
.setElevation(0)
.setInitialZoom(zoom)
.setClippingEnabled(false);
@@ -5041,7 +5043,7 @@
// Vertically snap to middle of current line.
showPosInView.y = ((mTextView.getLayout().getLineTop(lineNumber)
- + mTextView.getLayout().getLineBottom(lineNumber)) / 2.0f
+ + mTextView.getLayout().getLineBottomWithoutSpacing(lineNumber)) / 2.0f
+ mTextView.getTotalPaddingTop() - mTextView.getScrollY()) * mTextViewScaleY;
return true;
}
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 78d4e61..a2c70b9 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -148,6 +148,9 @@
@Nullable
private CharSequence mText;
+ // TODO(b/144152069): Remove this after assessing impact on dogfood.
+ private boolean mIsCustomToast;
+
/**
* Construct an empty Toast object. You must call {@link #setView} before you
* can call {@link #show}.
@@ -214,7 +217,8 @@
service.enqueueTextToast(pkg, mToken, mText, mDuration, displayId, callback);
}
} else {
- service.enqueueToast(pkg, mToken, tn, mDuration, displayId);
+ service.enqueueTextOrCustomToast(pkg, mToken, tn, mDuration, displayId,
+ mIsCustomToast);
}
} catch (RemoteException e) {
// Empty
@@ -252,12 +256,17 @@
*/
@Deprecated
public void setView(View view) {
+ mIsCustomToast = true;
mNextView = view;
}
/**
* Return the view.
*
+ * <p><strong>Warning:</strong> Starting from Android {@link Build.VERSION_CODES#R}, for apps
+ * targeting API level {@link Build.VERSION_CODES#R} or higher that haven't called {@link
+ * #setView(View)} with a non-{@code null} view, this method will return {@code null}.
+ *
* @see #setView
* @deprecated Custom toast views are deprecated. Apps can create a standard text toast with the
* {@link #makeText(Context, CharSequence, int)} method, or use a
@@ -266,6 +275,7 @@
* targeting API level {@link Build.VERSION_CODES#R} or higher that are in the background
* will not have custom toast views displayed.
*/
+ @Deprecated
public View getView() {
return mNextView;
}
@@ -292,6 +302,10 @@
/**
* Set the margins of the view.
*
+ * <p><strong>Warning:</strong> Starting from Android {@link Build.VERSION_CODES#R}, for apps
+ * targeting API level {@link Build.VERSION_CODES#R} or higher, this method is a no-op when
+ * called on text toasts.
+ *
* @param horizontalMargin The horizontal margin, in percentage of the
* container width, between the container's edges and the
* notification
@@ -300,30 +314,59 @@
* notification
*/
public void setMargin(float horizontalMargin, float verticalMargin) {
+ if (isSystemRenderedTextToast()) {
+ Log.e(TAG, "setMargin() shouldn't be called on text toasts, the values won't be used");
+ }
mTN.mHorizontalMargin = horizontalMargin;
mTN.mVerticalMargin = verticalMargin;
}
/**
* Return the horizontal margin.
+ *
+ * <p><strong>Warning:</strong> Starting from Android {@link Build.VERSION_CODES#R}, for apps
+ * targeting API level {@link Build.VERSION_CODES#R} or higher, this method shouldn't be called
+ * on text toasts as its return value may not reflect actual value since text toasts are not
+ * rendered by the app anymore.
*/
public float getHorizontalMargin() {
+ if (isSystemRenderedTextToast()) {
+ Log.e(TAG, "getHorizontalMargin() shouldn't be called on text toasts, the result may "
+ + "not reflect actual values.");
+ }
return mTN.mHorizontalMargin;
}
/**
* Return the vertical margin.
+ *
+ * <p><strong>Warning:</strong> Starting from Android {@link Build.VERSION_CODES#R}, for apps
+ * targeting API level {@link Build.VERSION_CODES#R} or higher, this method shouldn't be called
+ * on text toasts as its return value may not reflect actual value since text toasts are not
+ * rendered by the app anymore.
*/
public float getVerticalMargin() {
+ if (isSystemRenderedTextToast()) {
+ Log.e(TAG, "getVerticalMargin() shouldn't be called on text toasts, the result may not"
+ + " reflect actual values.");
+ }
return mTN.mVerticalMargin;
}
/**
* Set the location at which the notification should appear on the screen.
+ *
+ * <p><strong>Warning:</strong> Starting from Android {@link Build.VERSION_CODES#R}, for apps
+ * targeting API level {@link Build.VERSION_CODES#R} or higher, this method is a no-op when
+ * called on text toasts.
+ *
* @see android.view.Gravity
* @see #getGravity
*/
public void setGravity(int gravity, int xOffset, int yOffset) {
+ if (isSystemRenderedTextToast()) {
+ Log.e(TAG, "setGravity() shouldn't be called on text toasts, the values won't be used");
+ }
mTN.mGravity = gravity;
mTN.mX = xOffset;
mTN.mY = yOffset;
@@ -331,27 +374,59 @@
/**
* Get the location at which the notification should appear on the screen.
+ *
+ * <p><strong>Warning:</strong> Starting from Android {@link Build.VERSION_CODES#R}, for apps
+ * targeting API level {@link Build.VERSION_CODES#R} or higher, this method shouldn't be called
+ * on text toasts as its return value may not reflect actual value since text toasts are not
+ * rendered by the app anymore.
+ *
* @see android.view.Gravity
* @see #getGravity
*/
public int getGravity() {
+ if (isSystemRenderedTextToast()) {
+ Log.e(TAG, "getGravity() shouldn't be called on text toasts, the result may not reflect"
+ + " actual values.");
+ }
return mTN.mGravity;
}
/**
* Return the X offset in pixels to apply to the gravity's location.
+ *
+ * <p><strong>Warning:</strong> Starting from Android {@link Build.VERSION_CODES#R}, for apps
+ * targeting API level {@link Build.VERSION_CODES#R} or higher, this method shouldn't be called
+ * on text toasts as its return value may not reflect actual value since text toasts are not
+ * rendered by the app anymore.
*/
public int getXOffset() {
+ if (isSystemRenderedTextToast()) {
+ Log.e(TAG, "getXOffset() shouldn't be called on text toasts, the result may not reflect"
+ + " actual values.");
+ }
return mTN.mX;
}
/**
* Return the Y offset in pixels to apply to the gravity's location.
+ *
+ * <p><strong>Warning:</strong> Starting from Android {@link Build.VERSION_CODES#R}, for apps
+ * targeting API level {@link Build.VERSION_CODES#R} or higher, this method shouldn't be called
+ * on text toasts as its return value may not reflect actual value since text toasts are not
+ * rendered by the app anymore.
*/
public int getYOffset() {
+ if (isSystemRenderedTextToast()) {
+ Log.e(TAG, "getYOffset() shouldn't be called on text toasts, the result may not reflect"
+ + " actual values.");
+ }
return mTN.mY;
}
+ private boolean isSystemRenderedTextToast() {
+ return Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM) && mNextView == null;
+ }
+
/**
* Adds a callback to be notified when the toast is shown or hidden.
*
@@ -385,7 +460,7 @@
}
/**
- * Make a standard toast that just contains a text view.
+ * Make a standard toast that just contains text.
*
* @param context The context to use. Usually your {@link android.app.Application}
* or {@link android.app.Activity} object.
@@ -428,7 +503,7 @@
}
/**
- * Make a standard toast that just contains a text view with the text from a resource.
+ * Make a standard toast that just contains text from a resource.
*
* @param context The context to use. Usually your {@link android.app.Application}
* or {@link android.app.Activity} object.
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index a43e4fe..65cad83 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -2424,6 +2424,10 @@
offset += findViewById(R.id.content_preview_container).getHeight();
}
+ if (hasWorkProfile() && ENABLE_TABBED_VIEW) {
+ offset += findViewById(R.id.tabs).getHeight();
+ }
+
int directShareHeight = 0;
rowsToShow = Math.min(4, rowsToShow);
for (int i = 0, childCount = recyclerView.getChildCount();
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index f5a19fe..6d2d735 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -52,6 +52,7 @@
public static final String DIALOGS_PACKAGE = "com.android.vpndialogs";
+ // TODO: Rename this to something that encompasses Settings-based Platform VPNs as well.
public static final String LEGACY_VPN = "[Legacy VPN]";
public static Intent getIntentForConfirmation() {
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index c6ed624..518911e 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -323,7 +323,7 @@
result.append(System.getProperty("java.vm.version")); // such as 1.1.0
result.append(" (Linux; U; Android ");
- String version = Build.VERSION.RELEASE; // "1.0" or "3.4b5"
+ String version = Build.VERSION.RELEASE_OR_CODENAME; // "1.0" or "3.4b5"
result.append(version.length() > 0 ? version : "1.0");
// add the model for the release build
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 74b481c..26d2f19 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -29,6 +29,7 @@
import android.os.Process;
import android.os.SystemProperties;
import android.os.Trace;
+import android.os.incremental.IncrementalManager;
import android.os.storage.StorageManager;
import android.permission.PermissionManager.SplitPermissionInfo;
import android.text.TextUtils;
@@ -1156,6 +1157,10 @@
addFeature(PackageManager.FEATURE_RAM_NORMAL, 0);
}
+ if (IncrementalManager.isEnabled()) {
+ addFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY, 0);
+ }
+
for (String featureName : mUnavailableFeatures) {
removeFeature(featureName);
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 9758673..35eb0fc 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -208,6 +208,7 @@
static_libs: [
"libasync_safe",
+ "libbinderthreadstateutils",
"libdmabufinfo",
"libgif",
"libseccomp_policy",
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index aa209cb..38fb8bd 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -569,8 +569,8 @@
// mRecycledBitmap specifies the width and height of the bitmap that we
// want to reuse. Neither can be changed. We will try to find a way
// to reuse the memory.
- const int maxWidth = SkTMax(bitmap->width(), mRecycledBitmap->info().width());
- const int maxHeight = SkTMax(bitmap->height(), mRecycledBitmap->info().height());
+ const int maxWidth = std::max(bitmap->width(), mRecycledBitmap->info().width());
+ const int maxHeight = std::max(bitmap->height(), mRecycledBitmap->info().height());
const SkImageInfo maxInfo = bitmap->info().makeWH(maxWidth, maxHeight);
const size_t rowBytes = maxInfo.minRowBytes();
const size_t bytesNeeded = maxInfo.computeByteSize(rowBytes);
diff --git a/core/jni/android_os_incremental_IncrementalManager.cpp b/core/jni/android_os_incremental_IncrementalManager.cpp
index 698062a..d41e982 100644
--- a/core/jni/android_os_incremental_IncrementalManager.cpp
+++ b/core/jni/android_os_incremental_IncrementalManager.cpp
@@ -26,6 +26,10 @@
namespace android {
+static jboolean nativeIsEnabled(JNIEnv* env, jobject clazz) {
+ return IncFs_IsEnabled();
+}
+
static jboolean nativeIsIncrementalPath(JNIEnv* env,
jobject clazz,
jstring javaPath) {
@@ -34,8 +38,8 @@
}
static const JNINativeMethod method_table[] = {
- {"nativeIsIncrementalPath", "(Ljava/lang/String;)Z",
- (void*)nativeIsIncrementalPath},
+ {"nativeIsEnabled", "()Z", (void*)nativeIsEnabled},
+ {"nativeIsIncrementalPath", "(Ljava/lang/String;)Z", (void*)nativeIsIncrementalPath},
};
int register_android_os_incremental_IncrementalManager(JNIEnv* env) {
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index c269d1c..14d7487 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -37,6 +37,7 @@
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
#include <binder/Stability.h>
+#include <binderthreadstate/CallerUtils.h>
#include <cutils/atomic.h>
#include <log/log.h>
#include <utils/KeyedVector.h>
@@ -950,7 +951,7 @@
static jboolean android_os_Binder_isHandlingTransaction()
{
- return IPCThreadState::self()->isServingCall();
+ return getCurrentServingCall() == BinderCallType::BINDER;
}
static jlong android_os_Binder_clearCallingIdentity()
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 69ca17c..5a8225c 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -147,10 +147,12 @@
}
static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject clazz,
- jboolean translucent, jlong rootRenderNodePtr) {
+ jboolean translucent, jboolean isWideGamut, jlong rootRenderNodePtr) {
RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootRenderNodePtr);
ContextFactoryImpl factory(rootRenderNode);
- return (jlong) new RenderProxy(translucent, rootRenderNode, &factory);
+ RenderProxy* proxy = new RenderProxy(translucent, rootRenderNode, &factory);
+ proxy->setWideGamut(isWideGamut);
+ return (jlong) proxy;
}
static void android_view_ThreadedRenderer_deleteProxy(JNIEnv* env, jobject clazz,
@@ -627,7 +629,7 @@
{ "nSetProcessStatsBuffer", "(I)V", (void*) android_view_ThreadedRenderer_setProcessStatsBuffer },
{ "nGetRenderThreadTid", "(J)I", (void*) android_view_ThreadedRenderer_getRenderThreadTid },
{ "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
- { "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy },
+ { "nCreateProxy", "(ZZJ)J", (void*) android_view_ThreadedRenderer_createProxy },
{ "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
{ "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties },
{ "nSetName", "(JLjava/lang/String;)V", (void*) android_view_ThreadedRenderer_setName },
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index a6e08d2..fc0a2ef 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2562,7 +2562,7 @@
// CATEGORY: SETTINGS
// OS: R
OPEN_SUPPORTED_LINKS = 1824;
-
+
// OPEN: Settings > Display > Dark theme > Set start time dialog
DIALOG_DARK_THEME_SET_START_TIME = 1825;
@@ -2573,4 +2573,9 @@
// CATEGORY: SETTINGS
// OS: R
VIBRATE_FOR_CALLS = 1827;
+
+ // OPEN: Settings > Connected devices > Connection preferences > NFC
+ // CATEGORY: SETTINGS
+ // OS: R
+ CONNECTION_DEVICE_ADVANCED_NFC = 1828;
}
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 8adcc9e..bf4cdee 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -52,6 +52,7 @@
import "frameworks/base/core/proto/android/service/print.proto";
import "frameworks/base/core/proto/android/service/procstats.proto";
import "frameworks/base/core/proto/android/service/restricted_image.proto";
+import "frameworks/base/core/proto/android/service/sensor_service.proto";
import "frameworks/base/core/proto/android/service/usb.proto";
import "frameworks/base/core/proto/android/util/event_log_tags.proto";
import "frameworks/base/core/proto/android/util/log.proto";
@@ -492,6 +493,11 @@
(section).args = "contexthub --proto"
];
+ optional android.service.SensorServiceProto sensor_service = 3053 [
+ (section).type = SECTION_DUMPSYS,
+ (section).args = "sensorservice --proto"
+ ];
+
// Reserved for OEMs.
extensions 50000 to 100000;
}
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 0a2fd70..2d2ead4 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -27,7 +27,6 @@
import "frameworks/base/core/proto/android/content/configuration.proto";
import "frameworks/base/core/proto/android/content/intent.proto";
import "frameworks/base/core/proto/android/content/package_item_info.proto";
-import "frameworks/base/core/proto/android/graphics/rect.proto";
import "frameworks/base/core/proto/android/internal/processstats.proto";
import "frameworks/base/core/proto/android/os/bundle.proto";
import "frameworks/base/core/proto/android/os/looper.proto";
diff --git a/core/proto/android/server/notificationhistory.proto b/core/proto/android/server/notificationhistory.proto
index 1e6ee3f..6749719 100644
--- a/core/proto/android/server/notificationhistory.proto
+++ b/core/proto/android/server/notificationhistory.proto
@@ -17,8 +17,6 @@
syntax = "proto2";
package com.android.server.notification;
-import "frameworks/base/core/proto/android/server/enums.proto";
-
option java_multiple_files = true;
// On disk data store for historical notifications
diff --git a/core/proto/android/service/sensor_service.proto b/core/proto/android/service/sensor_service.proto
new file mode 100644
index 0000000..8598f86
--- /dev/null
+++ b/core/proto/android/service/sensor_service.proto
@@ -0,0 +1,246 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.service;
+
+import "frameworks/base/core/proto/android/privacy.proto";
+
+option java_multiple_files = true;
+
+/*
+ * Notes:
+ * 1. When using ProtoOutputStream to write this proto message, must call
+ * token = ProtoOutputStream#start(fieldId) before and ProtoOutputStream#end(token) after
+ * writing a nested message.
+ * 2. Never reuse a proto field number. When removing a field, mark it as reserved.
+ */
+
+// Proto dump of android::SensorService. dumpsys sensorservice --proto
+message SensorServiceProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ enum OperatingModeEnum {
+ OP_MODE_UNKNOWN = 0;
+ OP_MODE_NORMAL = 1;
+ OP_MODE_RESTRICTED = 2;
+ OP_MODE_DATA_INJECTION = 3;
+ }
+
+ optional int64 current_time_ms = 1;
+ optional SensorDeviceProto sensor_device = 2;
+ optional SensorListProto sensors = 3;
+ optional SensorFusionProto fusion_state = 4;
+ optional SensorEventsProto sensor_events = 5;
+ repeated ActiveSensorProto active_sensors = 6;
+ optional int32 socket_buffer_size = 7;
+ optional int32 socket_buffer_size_in_events = 8;
+ optional bool wake_lock_acquired = 9;
+ optional OperatingModeEnum operating_mode = 10;
+ // Non-empty only if operating_mode is RESTRICTED or DATA_INJECTION.
+ optional string whitelisted_package = 11;
+ optional bool sensor_privacy = 12;
+ repeated SensorEventConnectionProto active_connections = 13;
+ repeated SensorDirectConnectionProto direct_connections = 14;
+ repeated SensorRegistrationInfoProto previous_registrations = 15;
+}
+
+// Proto dump of android::SensorDevice
+message SensorDeviceProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional bool initialized = 1;
+ optional int32 total_sensors = 2;
+ optional int32 active_sensors = 3;
+
+ message SensorProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int32 handle = 1;
+ optional int32 active_count = 2;
+ repeated float sampling_period_ms = 3;
+ optional float sampling_period_selected = 4;
+ repeated float batching_period_ms = 5;
+ optional float batching_period_selected = 6;
+ }
+ repeated SensorProto sensors = 4;
+}
+
+// Proto dump of android::SensorServiceUtil::SensorList
+message SensorListProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ enum ReportingModeEnum {
+ RM_UNKNOWN = 0;
+ RM_CONTINUOUS = 1;
+ RM_ON_CHANGE = 2;
+ RM_ONE_SHOT = 3;
+ RM_SPECIAL_TRIGGER = 4;
+ }
+
+ message SensorProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int32 handle = 1;
+ optional string name = 2;
+ optional string vendor = 3;
+ optional int32 version = 4;
+ optional string string_type = 5;
+ optional int32 type = 6;
+ optional string required_permission = 7;
+ optional int32 flags = 8;
+ optional ReportingModeEnum reporting_mode = 9;
+ optional int32 max_delay_us = 10;
+ optional int32 min_delay_us = 11;
+ optional int32 fifo_max_event_count = 12;
+ optional int32 fifo_reserved_event_count = 13;
+ optional bool is_wakeup = 14;
+ optional bool data_injection_supported = 15;
+ optional bool is_dynamic = 16;
+ optional bool has_additional_info = 17;
+ optional int32 highest_rate_level = 18;
+ optional bool ashmem = 19;
+ optional bool gralloc = 20;
+ optional float min_value = 21;
+ optional float max_value = 22;
+ optional float resolution = 23;
+ optional float power_usage = 24;
+ }
+ repeated SensorProto sensors = 1;
+}
+
+
+// Proto dump of android::SensorFusion
+message SensorFusionProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ message FusionProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional bool enabled = 1;
+ optional int32 num_clients = 2;
+ optional float estimated_gyro_rate = 3;
+ optional float attitude_x = 4;
+ optional float attitude_y = 5;
+ optional float attitude_z = 6;
+ optional float attitude_w = 7;
+ optional float attitude_length = 8;
+ optional float bias_x = 9;
+ optional float bias_y = 10;
+ optional float bias_z = 11;
+ }
+ optional FusionProto fusion_9axis = 1;
+ optional FusionProto fusion_nomag = 2;
+ optional FusionProto fusion_nogyro = 3;
+}
+
+// Proto dump of android::SensorServiceUtil::RecentEventLogger
+message SensorEventsProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ message Event {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional float timestamp_sec = 1;
+ optional int64 wall_timestamp_ms = 2;
+ optional bool masked = 3;
+ optional int64 int64_data = 4;
+ repeated float float_array = 5;
+ }
+
+ message RecentEventsLog {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional string name = 1;
+ optional int32 recent_events_count = 2;
+ repeated Event events = 3;
+ }
+ repeated RecentEventsLog recent_events_logs = 1;
+}
+
+message ActiveSensorProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional string name = 1;
+ optional int32 handle = 2;
+ optional int32 num_connections = 3;
+}
+
+// Proto dump of android::SensorService::SensorDirectConnection
+message SensorDirectConnectionProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ message SensorProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int32 sensor = 1;
+ optional int32 rate = 2;
+ }
+
+ optional string package_name = 1;
+ optional int32 hal_channel_handle = 2;
+ optional int32 num_sensor_activated = 3;
+ repeated SensorProto sensors = 4;
+}
+
+// Proto dump of android::SensorService::SensorEventConnection
+message SensorEventConnectionProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ message FlushInfoProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional string sensor_name = 1;
+ optional int32 sensor_handle = 2;
+ optional bool first_flush_pending = 3;
+ optional int32 pending_flush_events_to_send = 4;
+ }
+
+ enum OperatingModeEnum {
+ OP_MODE_UNKNOWN = 0;
+ OP_MODE_NORMAL = 1;
+ OP_MODE_RESTRICTED = 2;
+ OP_MODE_DATA_INJECTION = 3;
+ }
+
+ optional OperatingModeEnum operating_mode = 1;
+ optional string package_name = 2;
+ optional int32 wake_lock_ref_count = 3;
+ optional int32 uid = 4;
+ optional int32 cache_size = 5;
+ optional int32 max_cache_size = 6;
+ repeated FlushInfoProto flush_infos = 7;
+ optional int32 events_received = 8;
+ optional int32 events_sent = 9;
+ optional int32 events_cache = 10;
+ optional int32 events_dropped = 11;
+ optional int32 total_acks_needed = 12;
+ optional int32 total_acks_received = 13;
+}
+
+// Proto dump of android::SensorService::SensorRegistrationInfo
+message SensorRegistrationInfoProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int64 timestamp_sec = 1;
+ optional int32 sensor_handle = 2;
+ optional string package_name = 3;
+ optional int32 pid = 4;
+ optional int32 uid = 5;
+ optional int64 sampling_rate_us = 6;
+ optional int64 max_report_latency_us = 7;
+ optional bool activated = 8;
+}
diff --git a/core/proto/android/stats/devicepolicy/device_policy_enums.proto b/core/proto/android/stats/devicepolicy/device_policy_enums.proto
index 0f03e69..d1392a5 100644
--- a/core/proto/android/stats/devicepolicy/device_policy_enums.proto
+++ b/core/proto/android/stats/devicepolicy/device_policy_enums.proto
@@ -157,4 +157,6 @@
SET_FACTORY_RESET_PROTECTION = 130;
SET_COMMON_CRITERIA_MODE = 131;
ALLOW_MODIFICATION_OF_ADMIN_CONFIGURED_NETWORKS = 132;
+ SET_TIME = 133;
+ SET_TIME_ZONE = 134;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7a30256..6d63a53 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1998,17 +1998,17 @@
<permission android:name="android.permission.REMOTE_AUDIO_PLAYBACK"
android:protectionLevel="signature" />
- <!-- @SystemApi Allows TvInputService to access underlying TV input hardware such as
+ <!-- Allows TvInputService to access underlying TV input hardware such as
built-in tuners and HDMI-in's.
- @hide This should only be used by OEM's TvInputService's.
- -->
+ <p>This should only be used by OEM's TvInputService's.
+ @hide @SystemApi -->
<permission android:name="android.permission.TV_INPUT_HARDWARE"
android:protectionLevel="signature|privileged|vendorPrivileged" />
- <!-- @SystemApi Allows to capture a frame of TV input hardware such as
+ <!-- Allows to capture a frame of TV input hardware such as
built-in tuners and HDMI-in's.
- @hide <p>Not for use by third-party applications.
- -->
+ <p>Not for use by third-party applications.
+ @hide @SystemApi -->
<permission android:name="android.permission.CAPTURE_TV_INPUT"
android:protectionLevel="signature|privileged" />
@@ -2605,7 +2605,7 @@
<p>Not for use by third-party applications.
@hide
-->
- <permission android:name="android.permission.SUGGEST_PHONE_TIME_AND_ZONE"
+ <permission android:name="android.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE"
android:protectionLevel="signature|telephony" />
<!-- Allows applications like settings to suggest the user's manually chosen time / time zone.
@@ -3433,10 +3433,10 @@
<permission android:name="android.permission.READ_CONTENT_RATING_SYSTEMS"
android:protectionLevel="signature|privileged" />
- <!-- @SystemApi Allows an application to notify TV inputs by sending broadcasts.
+ <!-- Allows an application to notify TV inputs by sending broadcasts.
<p>Protection level: signature|privileged
<p>Not for use by third-party applications.
- @hide -->
+ @hide @SystemApi -->
<permission android:name="android.permission.NOTIFY_TV_INPUTS"
android:protectionLevel="signature|privileged" />
@@ -3448,6 +3448,14 @@
<permission android:name="android.permission.TUNER_RESOURCE_ACCESS"
android:protectionLevel="signature|privileged" />
+ <!-- This permission is required by Media Resource Manager Service when
+ accessing its overridePid Api.
+ <p>Protection level: signature
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.MEDIA_RESOURCE_OVERRIDE_PID"
+ android:protectionLevel="signature" />
+
<!-- Must be required by a {@link android.media.routing.MediaRouteService}
to ensure that only the system can interact with it.
@hide -->
@@ -4057,6 +4065,11 @@
<permission android:name="android.permission.STATSCOMPANION"
android:protectionLevel="signature" />
+ <!--@SystemApi @hide Allows an application to register stats pull atom callbacks.
+ <p>Not for use by third-party applications.-->
+ <permission android:name="android.permission.REGISTER_STATS_PULL_ATOM"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi Allows an application to control the backup and restore process.
<p>Not for use by third-party applications.
@hide pending API council -->
@@ -4865,6 +4878,19 @@
<permission android:name="android.permission.ACCESS_SHARED_LIBRARIES"
android:protectionLevel="signature|installer" />
+ <!-- Allows an app to log compat change usage.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.LOG_COMPAT_CHANGE"
+ android:protectionLevel="signature|privileged" />
+ <!-- Allows an app to read compat change config.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"
+ android:protectionLevel="signature|privileged" />
+ <!-- Allows an app to override compat change config.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG"
+ android:protectionLevel="signature|privileged" />
+
<!-- Allows input events to be monitored. Very dangerous! @hide -->
<permission android:name="android.permission.MONITOR_INPUT"
android:protectionLevel="signature" />
@@ -5302,6 +5328,10 @@
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
+ <service android:name="com.android.server.blob.BlobStoreIdleJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE">
+ </service>
+
<service android:name="com.android.server.pm.PackageManagerShellCommandDataLoader">
<intent-filter>
<action android:name="android.intent.action.LOAD_DATA" />
diff --git a/core/res/res/layout/accessibility_button_chooser_item.xml b/core/res/res/layout/accessibility_button_chooser_item.xml
index d19e313..d6fd7aa 100644
--- a/core/res/res/layout/accessibility_button_chooser_item.xml
+++ b/core/res/res/layout/accessibility_button_chooser_item.xml
@@ -20,6 +20,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:clickable="true"
android:gravity="center"
android:paddingStart="16dp"
android:paddingEnd="16dp"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b2d08a9..31e68e8 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4343,4 +4343,7 @@
Determines whether the specified key groups can be used to wake up the device. -->
<bool name="config_wakeOnDpadKeyPress">true</bool>
<bool name="config_wakeOnAssistKeyPress">true</bool>
+
+ <!-- Whether to default to an expanded list of users on the lock screen user switcher. -->
+ <bool name="config_expandLockScreenUserSwitcher">false</bool>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c59d25f..2453bb1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3863,4 +3863,7 @@
<!-- Toast message for background started foreground service while-in-use permission restriction feature -->
<java-symbol type="string" name="allow_while_in_use_permission_in_fgs" />
+
+ <!-- Whether to expand the lock screen user switcher by default -->
+ <java-symbol type="bool" name="config_expandLockScreenUserSwitcher" />
</resources>
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 0d7ac08..70917e7 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -34,7 +34,7 @@
http://smscoin.net/software/engine/WordPress/Paid+SMS-registration/ -->
<!-- Arab Emirates -->
- <shortcode country="ae" pattern="\\d{1,5}" free="3214|1017" />
+ <shortcode country="ae" pattern="\\d{1,5}" free="1017|1355|3214" />
<!-- Albania: 5 digits, known short codes listed -->
<shortcode country="al" pattern="\\d{5}" premium="15191|55[56]00" />
@@ -184,7 +184,7 @@
<shortcode country="mk" pattern="\\d{1,6}" free="129005|122" />
<!-- Mexico: 4-5 digits (not confirmed), known premium codes listed -->
- <shortcode country="mx" pattern="\\d{4,5}" premium="53035|7766" free="46645|5050|26259|50025|50052|9963|76551" />
+ <shortcode country="mx" pattern="\\d{4,5}" premium="53035|7766" free="26259|46645|50025|50052|5050|76551|88778|9963" />
<!-- Malaysia: 5 digits: http://www.skmm.gov.my/attachment/Consumer_Regulation/Mobile_Content_Services_FAQs.pdf -->
<shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288" />
@@ -199,7 +199,7 @@
<shortcode country="no" pattern="\\d{4,5}" premium="2201|222[67]" free="2171" />
<!-- New Zealand: 3-4 digits, known premium codes listed -->
- <shortcode country="nz" pattern="\\d{3,4}" premium="3903|8995|4679" free="1737|2141|3067|3068|3110|4006|4053|4061|4062|4202|4300|4334|4412|4575|5626|8006|8681" />
+ <shortcode country="nz" pattern="\\d{3,4}" premium="3903|8995|4679" free="1737|176|2141|3067|3068|3110|4006|4053|4061|4062|4202|4300|4334|4412|4575|5626|8006|8681" />
<!-- Peru: 4-5 digits (not confirmed), known premium codes listed -->
<shortcode country="pe" pattern="\\d{4,5}" free="9963" />
@@ -267,4 +267,7 @@
<!-- Mayotte (French Territory): 1-5 digits (not confirmed) -->
<shortcode country="yt" pattern="\\d{1,5}" free="38600,36300,36303,959" />
+ <!-- South Africa -->
+ <shortcode country="za" pattern="\d{1,5}" free="44136" />
+
</shortcodes>
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 38454ec..9f15faf 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -38,6 +38,7 @@
"mockito-target-minus-junit4",
"ub-uiautomator",
"platform-test-annotations",
+ "platform-compat-test-rules",
"truth-prebuilt",
"print-test-util-lib",
"testng",
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index ee93b39..59335a5 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -111,6 +111,10 @@
<uses-permission android:name="android.permission.MOVE_PACKAGE" />
<uses-permission android:name="android.permission.PACKAGE_VERIFICATION_AGENT" />
+ <!-- gating and logging permissions -->
+ <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
+ <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+
<!-- os storage test permissions -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.ASEC_ACCESS" />
diff --git a/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java b/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java
index 6c5d548..02be557 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java
@@ -24,6 +24,9 @@
import android.content.Context;
import android.content.pm.ConfigurationInfo;
import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.test.AndroidTestCase;
import androidx.test.filters.SmallTest;
@@ -137,21 +140,7 @@
// Must overwrite all the fields
td2.copyFrom(td1);
- assertEquals(td1.getLabel(), td2.getLabel());
- assertEquals(td1.getInMemoryIcon(), td2.getInMemoryIcon());
- assertEquals(td1.getIconFilename(), td2.getIconFilename());
- assertEquals(td1.getIconResource(), td2.getIconResource());
- assertEquals(td1.getPrimaryColor(), td2.getPrimaryColor());
- assertEquals(td1.getBackgroundColor(), td2.getBackgroundColor());
- assertEquals(td1.getStatusBarColor(), td2.getStatusBarColor());
- assertEquals(td1.getNavigationBarColor(), td2.getNavigationBarColor());
- assertEquals(td1.getEnsureStatusBarContrastWhenTransparent(),
- td2.getEnsureStatusBarContrastWhenTransparent());
- assertEquals(td1.getEnsureNavigationBarContrastWhenTransparent(),
- td2.getEnsureNavigationBarContrastWhenTransparent());
- assertEquals(td1.getResizeMode(), td2.getResizeMode());
- assertEquals(td1.getMinWidth(), td2.getMinWidth());
- assertEquals(td1.getMinHeight(), td2.getMinHeight());
+ assertTaskDescriptionEqual(td1, td2, true, true);
}
@SmallTest
@@ -191,44 +180,101 @@
// Must overwrite all public and hidden fields, since other has all fields set.
td2.copyFromPreserveHiddenFields(td1);
- assertEquals(td1.getLabel(), td2.getLabel());
- assertEquals(td1.getInMemoryIcon(), td2.getInMemoryIcon());
- assertEquals(td1.getIconFilename(), td2.getIconFilename());
- assertEquals(td1.getIconResource(), td2.getIconResource());
- assertEquals(td1.getPrimaryColor(), td2.getPrimaryColor());
- assertEquals(td1.getBackgroundColor(), td2.getBackgroundColor());
- assertEquals(td1.getStatusBarColor(), td2.getStatusBarColor());
- assertEquals(td1.getNavigationBarColor(), td2.getNavigationBarColor());
- assertEquals(td1.getEnsureStatusBarContrastWhenTransparent(),
- td2.getEnsureStatusBarContrastWhenTransparent());
- assertEquals(td1.getEnsureNavigationBarContrastWhenTransparent(),
- td2.getEnsureNavigationBarContrastWhenTransparent());
- assertEquals(td1.getResizeMode(), td2.getResizeMode());
- assertEquals(td1.getMinWidth(), td2.getMinWidth());
- assertEquals(td1.getMinHeight(), td2.getMinHeight());
+ assertTaskDescriptionEqual(td1, td2, true, true);
TaskDescription td3 = new TaskDescription();
// Must overwrite only public fields, and preserve hidden fields.
td2.copyFromPreserveHiddenFields(td3);
- // Overwritten fields
- assertEquals(td3.getLabel(), td2.getLabel());
- assertEquals(td3.getInMemoryIcon(), td2.getInMemoryIcon());
- assertEquals(td3.getIconFilename(), td2.getIconFilename());
- assertEquals(td3.getIconResource(), td2.getIconResource());
- assertEquals(td3.getPrimaryColor(), td2.getPrimaryColor());
- assertEquals(td3.getEnsureStatusBarContrastWhenTransparent(),
- td2.getEnsureStatusBarContrastWhenTransparent());
- assertEquals(td3.getEnsureNavigationBarContrastWhenTransparent(),
- td2.getEnsureNavigationBarContrastWhenTransparent());
+ assertTaskDescriptionEqual(td3, td2, true, false);
+ assertTaskDescriptionEqual(td1, td2, false, true);
+ }
- // Preserved fields
- assertEquals(td1.getBackgroundColor(), td2.getBackgroundColor());
- assertEquals(td1.getStatusBarColor(), td2.getStatusBarColor());
- assertEquals(td1.getNavigationBarColor(), td2.getNavigationBarColor());
- assertEquals(td1.getResizeMode(), td2.getResizeMode());
- assertEquals(td1.getMinWidth(), td2.getMinWidth());
- assertEquals(td1.getMinHeight(), td2.getMinHeight());
+ @SmallTest
+ public void testTaskDescriptionParceling() throws Exception {
+ TaskDescription tdBitmapNull = new TaskDescription(
+ "test label", // label
+ null, // bitmap
+ 21, // iconRes
+ "dummy file", // iconFilename
+ 0x111111, // colorPrimary
+ 0x222222, // colorBackground
+ 0x333333, // statusBarColor
+ 0x444444, // navigationBarColor
+ false, // ensureStatusBarContrastWhenTransparent
+ false, // ensureNavigationBarContrastWhenTransparent
+ RESIZE_MODE_UNRESIZEABLE, // resizeMode
+ 10, // minWidth
+ 20 // minHeight
+ );
+
+ // Normal parceling should keep everything the same.
+ TaskDescription tdParcelled = new TaskDescription(parcelingRoundTrip(tdBitmapNull));
+ assertTaskDescriptionEqual(tdBitmapNull, tdParcelled, true, true);
+
+ Bitmap recycledBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
+ recycledBitmap.recycle();
+ assertTrue(recycledBitmap.isRecycled());
+ TaskDescription tdBitmapRecycled = new TaskDescription(
+ "test label", // label
+ recycledBitmap, // bitmap
+ 21, // iconRes
+ "dummy file", // iconFilename
+ 0x111111, // colorPrimary
+ 0x222222, // colorBackground
+ 0x333333, // statusBarColor
+ 0x444444, // navigationBarColor
+ false, // ensureStatusBarContrastWhenTransparent
+ false, // ensureNavigationBarContrastWhenTransparent
+ RESIZE_MODE_UNRESIZEABLE, // resizeMode
+ 10, // minWidth
+ 20 // minHeight
+ );
+ // Recycled bitmap will be ignored while parceling.
+ tdParcelled = new TaskDescription(parcelingRoundTrip(tdBitmapRecycled));
+ assertTaskDescriptionEqual(tdBitmapNull, tdParcelled, true, true);
+
+ }
+
+ private void assertTaskDescriptionEqual(TaskDescription td1, TaskDescription td2,
+ boolean checkOverwrittenFields, boolean checkPreservedFields) {
+ if (checkOverwrittenFields) {
+ assertEquals(td1.getLabel(), td2.getLabel());
+ assertEquals(td1.getInMemoryIcon(), td2.getInMemoryIcon());
+ assertEquals(td1.getIconFilename(), td2.getIconFilename());
+ assertEquals(td1.getIconResource(), td2.getIconResource());
+ assertEquals(td1.getPrimaryColor(), td2.getPrimaryColor());
+ assertEquals(td1.getEnsureStatusBarContrastWhenTransparent(),
+ td2.getEnsureStatusBarContrastWhenTransparent());
+ assertEquals(td1.getEnsureNavigationBarContrastWhenTransparent(),
+ td2.getEnsureNavigationBarContrastWhenTransparent());
+ }
+ if (checkPreservedFields) {
+ assertEquals(td1.getBackgroundColor(), td2.getBackgroundColor());
+ assertEquals(td1.getStatusBarColor(), td2.getStatusBarColor());
+ assertEquals(td1.getNavigationBarColor(), td2.getNavigationBarColor());
+ assertEquals(td1.getResizeMode(), td2.getResizeMode());
+ assertEquals(td1.getMinWidth(), td2.getMinWidth());
+ assertEquals(td1.getMinHeight(), td2.getMinHeight());
+ }
+ }
+
+ private <T extends Parcelable> T parcelingRoundTrip(final T in) throws Exception {
+ final Parcel p = Parcel.obtain();
+ in.writeToParcel(p, /* flags */ 0);
+ p.setDataPosition(0);
+ final byte[] marshalledData = p.marshall();
+ p.recycle();
+
+ final Parcel q = Parcel.obtain();
+ q.unmarshall(marshalledData, 0, marshalledData.length);
+ q.setDataPosition(0);
+
+ final Parcelable.Creator<T> creator = (Parcelable.Creator<T>)
+ in.getClass().getField("CREATOR").get(null); // static object, so null receiver
+ final T unmarshalled = (T) creator.createFromParcel(q);
+ q.recycle();
+ return unmarshalled;
}
// If any entries in appear in the list, sanity check them against all running applications
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index c986db8..c328d72 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -504,15 +504,17 @@
}
@Override
- public void onPictureInPictureRequested() {
+ public boolean onPictureInPictureRequested() {
mPipRequested = true;
if (getIntent().getBooleanExtra(PIP_REQUESTED_OVERRIDE_ENTER, false)) {
enterPictureInPictureMode(new PictureInPictureParams.Builder().build());
mPipEntered = true;
+ return true;
} else if (getIntent().getBooleanExtra(PIP_REQUESTED_OVERRIDE_SKIP, false)) {
mPipEnterSkipped = true;
+ return false;
}
- super.onPictureInPictureRequested();
+ return super.onPictureInPictureRequested();
}
boolean pipRequested() {
diff --git a/core/tests/coretests/src/android/app/compat/CompatChangesTest.java b/core/tests/coretests/src/android/app/compat/CompatChangesTest.java
new file mode 100644
index 0000000..fbd02ed
--- /dev/null
+++ b/core/tests/coretests/src/android/app/compat/CompatChangesTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.compat;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Instrumentation;
+import android.compat.testing.PlatformCompatChangeRule;
+import android.os.Process;
+import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+
+/**
+ * {@link CompatChanges} tests.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class CompatChangesTest {
+ static final long CHANGE_ID = 1L;
+
+ private Instrumentation mInstrumentation;
+
+ @Rule
+ public TestRule compatChangeRule = new PlatformCompatChangeRule();
+
+ @Before
+ public void setup() {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ }
+
+
+ private String getPackageName() {
+ return mInstrumentation.getTargetContext().getPackageName();
+ }
+
+ @Test
+ @EnableCompatChanges(CHANGE_ID)
+ public void testEnabledChange() {
+ assertThat(CompatChanges.isChangeEnabled(CHANGE_ID)).isTrue();
+ assertThat(CompatChanges.isChangeEnabled(CHANGE_ID, Process.myUid())).isTrue();
+ assertThat(CompatChanges.isChangeEnabled(CHANGE_ID, getPackageName(),
+ UserHandle.of(UserHandle.myUserId()))).isTrue();
+ }
+
+ @Test
+ @DisableCompatChanges(CHANGE_ID)
+ public void testDisabledChange() {
+ assertThat(CompatChanges.isChangeEnabled(CHANGE_ID)).isFalse();
+ assertThat(CompatChanges.isChangeEnabled(CHANGE_ID, Process.myUid())).isFalse();
+ assertThat(CompatChanges.isChangeEnabled(CHANGE_ID, getPackageName(),
+ UserHandle.of(UserHandle.myUserId()))).isFalse();
+ }
+}
diff --git a/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java
similarity index 66%
rename from core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
rename to core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java
index d17b635..4b64dfc 100644
--- a/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java
@@ -26,44 +26,45 @@
import org.junit.Test;
-public class PhoneTimeSuggestionTest {
+public class TelephonyTimeSuggestionTest {
private static final int SLOT_INDEX = 99999;
@Test
public void testEquals() {
- PhoneTimeSuggestion.Builder builder1 = new PhoneTimeSuggestion.Builder(SLOT_INDEX);
+ TelephonyTimeSuggestion.Builder builder1 = new TelephonyTimeSuggestion.Builder(SLOT_INDEX);
{
- PhoneTimeSuggestion one = builder1.build();
+ TelephonyTimeSuggestion one = builder1.build();
assertEquals(one, one);
}
- PhoneTimeSuggestion.Builder builder2 = new PhoneTimeSuggestion.Builder(SLOT_INDEX);
+ TelephonyTimeSuggestion.Builder builder2 = new TelephonyTimeSuggestion.Builder(SLOT_INDEX);
{
- PhoneTimeSuggestion one = builder1.build();
- PhoneTimeSuggestion two = builder2.build();
+ TelephonyTimeSuggestion one = builder1.build();
+ TelephonyTimeSuggestion two = builder2.build();
assertEquals(one, two);
assertEquals(two, one);
}
builder1.setUtcTime(new TimestampedValue<>(1111L, 2222L));
{
- PhoneTimeSuggestion one = builder1.build();
+ TelephonyTimeSuggestion one = builder1.build();
assertEquals(one, one);
}
builder2.setUtcTime(new TimestampedValue<>(1111L, 2222L));
{
- PhoneTimeSuggestion one = builder1.build();
- PhoneTimeSuggestion two = builder2.build();
+ TelephonyTimeSuggestion one = builder1.build();
+ TelephonyTimeSuggestion two = builder2.build();
assertEquals(one, two);
assertEquals(two, one);
}
- PhoneTimeSuggestion.Builder builder3 = new PhoneTimeSuggestion.Builder(SLOT_INDEX + 1);
+ TelephonyTimeSuggestion.Builder builder3 =
+ new TelephonyTimeSuggestion.Builder(SLOT_INDEX + 1);
builder3.setUtcTime(new TimestampedValue<>(1111L, 2222L));
{
- PhoneTimeSuggestion one = builder1.build();
- PhoneTimeSuggestion three = builder3.build();
+ TelephonyTimeSuggestion one = builder1.build();
+ TelephonyTimeSuggestion three = builder3.build();
assertNotEquals(one, three);
assertNotEquals(three, one);
}
@@ -72,15 +73,15 @@
builder1.addDebugInfo("Debug info 1");
builder2.addDebugInfo("Debug info 2");
{
- PhoneTimeSuggestion one = builder1.build();
- PhoneTimeSuggestion two = builder2.build();
+ TelephonyTimeSuggestion one = builder1.build();
+ TelephonyTimeSuggestion two = builder2.build();
assertEquals(one, two);
}
}
@Test
public void testParcelable() {
- PhoneTimeSuggestion.Builder builder = new PhoneTimeSuggestion.Builder(SLOT_INDEX);
+ TelephonyTimeSuggestion.Builder builder = new TelephonyTimeSuggestion.Builder(SLOT_INDEX);
assertRoundTripParcelable(builder.build());
builder.setUtcTime(new TimestampedValue<>(1111L, 2222L));
@@ -88,9 +89,9 @@
// DebugInfo should also be stored (but is not checked by equals()
{
- PhoneTimeSuggestion suggestion1 = builder.build();
+ TelephonyTimeSuggestion suggestion1 = builder.build();
builder.addDebugInfo("This is debug info");
- PhoneTimeSuggestion rtSuggestion1 = roundTripParcelable(suggestion1);
+ TelephonyTimeSuggestion rtSuggestion1 = roundTripParcelable(suggestion1);
assertEquals(suggestion1.getDebugInfo(), rtSuggestion1.getDebugInfo());
}
}
diff --git a/core/tests/coretests/src/android/app/timezonedetector/PhoneTimeZoneSuggestionTest.java b/core/tests/coretests/src/android/app/timezonedetector/PhoneTimeZoneSuggestionTest.java
deleted file mode 100644
index 384dbf9..0000000
--- a/core/tests/coretests/src/android/app/timezonedetector/PhoneTimeZoneSuggestionTest.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.timezonedetector;
-
-import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
-import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-public class PhoneTimeZoneSuggestionTest {
- private static final int SLOT_INDEX = 99999;
-
- @Test
- public void testEquals() {
- PhoneTimeZoneSuggestion.Builder builder1 = new PhoneTimeZoneSuggestion.Builder(SLOT_INDEX);
- {
- PhoneTimeZoneSuggestion one = builder1.build();
- assertEquals(one, one);
- }
-
- PhoneTimeZoneSuggestion.Builder builder2 = new PhoneTimeZoneSuggestion.Builder(SLOT_INDEX);
- {
- PhoneTimeZoneSuggestion one = builder1.build();
- PhoneTimeZoneSuggestion two = builder2.build();
- assertEquals(one, two);
- assertEquals(two, one);
- }
-
- PhoneTimeZoneSuggestion.Builder builder3 =
- new PhoneTimeZoneSuggestion.Builder(SLOT_INDEX + 1);
- {
- PhoneTimeZoneSuggestion one = builder1.build();
- PhoneTimeZoneSuggestion three = builder3.build();
- assertNotEquals(one, three);
- assertNotEquals(three, one);
- }
-
- builder1.setZoneId("Europe/London");
- builder1.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);
- builder1.setQuality(PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
- {
- PhoneTimeZoneSuggestion one = builder1.build();
- PhoneTimeZoneSuggestion two = builder2.build();
- assertNotEquals(one, two);
- }
-
- builder2.setZoneId("Europe/Paris");
- builder2.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);
- builder2.setQuality(PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
- {
- PhoneTimeZoneSuggestion one = builder1.build();
- PhoneTimeZoneSuggestion two = builder2.build();
- assertNotEquals(one, two);
- }
-
- builder1.setZoneId("Europe/Paris");
- {
- PhoneTimeZoneSuggestion one = builder1.build();
- PhoneTimeZoneSuggestion two = builder2.build();
- assertEquals(one, two);
- }
-
- builder1.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID);
- builder2.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);
- {
- PhoneTimeZoneSuggestion one = builder1.build();
- PhoneTimeZoneSuggestion two = builder2.build();
- assertNotEquals(one, two);
- }
-
- builder1.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);
- {
- PhoneTimeZoneSuggestion one = builder1.build();
- PhoneTimeZoneSuggestion two = builder2.build();
- assertEquals(one, two);
- }
-
- builder1.setQuality(PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
- builder2.setQuality(PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
- {
- PhoneTimeZoneSuggestion one = builder1.build();
- PhoneTimeZoneSuggestion two = builder2.build();
- assertNotEquals(one, two);
- }
-
- builder1.setQuality(PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
- {
- PhoneTimeZoneSuggestion one = builder1.build();
- PhoneTimeZoneSuggestion two = builder2.build();
- assertEquals(one, two);
- }
-
- // DebugInfo must not be considered in equals().
- {
- PhoneTimeZoneSuggestion one = builder1.build();
- PhoneTimeZoneSuggestion two = builder2.build();
- one.addDebugInfo("Debug info 1");
- two.addDebugInfo("Debug info 2");
- assertEquals(one, two);
- }
- }
-
- @Test(expected = RuntimeException.class)
- public void testBuilderValidates_emptyZone_badMatchType() {
- PhoneTimeZoneSuggestion.Builder builder = new PhoneTimeZoneSuggestion.Builder(SLOT_INDEX);
- // No zone ID, so match type should be left unset.
- builder.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET);
- builder.build();
- }
-
- @Test(expected = RuntimeException.class)
- public void testBuilderValidates_zoneSet_badMatchType() {
- PhoneTimeZoneSuggestion.Builder builder = new PhoneTimeZoneSuggestion.Builder(SLOT_INDEX);
- builder.setZoneId("Europe/London");
- builder.setQuality(PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
- builder.build();
- }
-
- @Test
- public void testParcelable() {
- PhoneTimeZoneSuggestion.Builder builder = new PhoneTimeZoneSuggestion.Builder(SLOT_INDEX);
- assertRoundTripParcelable(builder.build());
-
- builder.setZoneId("Europe/London");
- builder.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID);
- builder.setQuality(PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
- PhoneTimeZoneSuggestion suggestion1 = builder.build();
- assertRoundTripParcelable(suggestion1);
-
- // DebugInfo should also be stored (but is not checked by equals()
- String debugString = "This is debug info";
- suggestion1.addDebugInfo(debugString);
- PhoneTimeZoneSuggestion suggestion1_2 = roundTripParcelable(suggestion1);
- assertEquals(suggestion1, suggestion1_2);
- assertTrue(suggestion1_2.getDebugInfo().contains(debugString));
- }
-}
diff --git a/core/tests/coretests/src/android/app/timezonedetector/TelephonyTimeZoneSuggestionTest.java b/core/tests/coretests/src/android/app/timezonedetector/TelephonyTimeZoneSuggestionTest.java
new file mode 100644
index 0000000..59d55b7
--- /dev/null
+++ b/core/tests/coretests/src/android/app/timezonedetector/TelephonyTimeZoneSuggestionTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.timezonedetector;
+
+import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
+import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class TelephonyTimeZoneSuggestionTest {
+ private static final int SLOT_INDEX = 99999;
+
+ @Test
+ public void testEquals() {
+ TelephonyTimeZoneSuggestion.Builder builder1 =
+ new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX);
+ {
+ TelephonyTimeZoneSuggestion one = builder1.build();
+ assertEquals(one, one);
+ }
+
+ TelephonyTimeZoneSuggestion.Builder builder2 =
+ new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX);
+ {
+ TelephonyTimeZoneSuggestion one = builder1.build();
+ TelephonyTimeZoneSuggestion two = builder2.build();
+ assertEquals(one, two);
+ assertEquals(two, one);
+ }
+
+ TelephonyTimeZoneSuggestion.Builder builder3 =
+ new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX + 1);
+ {
+ TelephonyTimeZoneSuggestion one = builder1.build();
+ TelephonyTimeZoneSuggestion three = builder3.build();
+ assertNotEquals(one, three);
+ assertNotEquals(three, one);
+ }
+
+ builder1.setZoneId("Europe/London");
+ builder1.setMatchType(TelephonyTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);
+ builder1.setQuality(TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
+ {
+ TelephonyTimeZoneSuggestion one = builder1.build();
+ TelephonyTimeZoneSuggestion two = builder2.build();
+ assertNotEquals(one, two);
+ }
+
+ builder2.setZoneId("Europe/Paris");
+ builder2.setMatchType(TelephonyTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);
+ builder2.setQuality(TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
+ {
+ TelephonyTimeZoneSuggestion one = builder1.build();
+ TelephonyTimeZoneSuggestion two = builder2.build();
+ assertNotEquals(one, two);
+ }
+
+ builder1.setZoneId("Europe/Paris");
+ {
+ TelephonyTimeZoneSuggestion one = builder1.build();
+ TelephonyTimeZoneSuggestion two = builder2.build();
+ assertEquals(one, two);
+ }
+
+ builder1.setMatchType(TelephonyTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID);
+ builder2.setMatchType(TelephonyTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);
+ {
+ TelephonyTimeZoneSuggestion one = builder1.build();
+ TelephonyTimeZoneSuggestion two = builder2.build();
+ assertNotEquals(one, two);
+ }
+
+ builder1.setMatchType(TelephonyTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);
+ {
+ TelephonyTimeZoneSuggestion one = builder1.build();
+ TelephonyTimeZoneSuggestion two = builder2.build();
+ assertEquals(one, two);
+ }
+
+ builder1.setQuality(TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
+ builder2.setQuality(
+ TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
+ {
+ TelephonyTimeZoneSuggestion one = builder1.build();
+ TelephonyTimeZoneSuggestion two = builder2.build();
+ assertNotEquals(one, two);
+ }
+
+ builder1.setQuality(
+ TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
+ {
+ TelephonyTimeZoneSuggestion one = builder1.build();
+ TelephonyTimeZoneSuggestion two = builder2.build();
+ assertEquals(one, two);
+ }
+
+ // DebugInfo must not be considered in equals().
+ {
+ TelephonyTimeZoneSuggestion one = builder1.build();
+ TelephonyTimeZoneSuggestion two = builder2.build();
+ one.addDebugInfo("Debug info 1");
+ two.addDebugInfo("Debug info 2");
+ assertEquals(one, two);
+ }
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testBuilderValidates_emptyZone_badMatchType() {
+ TelephonyTimeZoneSuggestion.Builder builder =
+ new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX);
+ // No zone ID, so match type should be left unset.
+ builder.setMatchType(TelephonyTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET);
+ builder.build();
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testBuilderValidates_zoneSet_badMatchType() {
+ TelephonyTimeZoneSuggestion.Builder builder =
+ new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX);
+ builder.setZoneId("Europe/London");
+ builder.setQuality(TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
+ builder.build();
+ }
+
+ @Test
+ public void testParcelable() {
+ TelephonyTimeZoneSuggestion.Builder builder =
+ new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX);
+ assertRoundTripParcelable(builder.build());
+
+ builder.setZoneId("Europe/London");
+ builder.setMatchType(TelephonyTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID);
+ builder.setQuality(TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
+ TelephonyTimeZoneSuggestion suggestion1 = builder.build();
+ assertRoundTripParcelable(suggestion1);
+
+ // DebugInfo should also be stored (but is not checked by equals()
+ String debugString = "This is debug info";
+ suggestion1.addDebugInfo(debugString);
+ TelephonyTimeZoneSuggestion suggestion1_2 = roundTripParcelable(suggestion1);
+ assertEquals(suggestion1, suggestion1_2);
+ assertTrue(suggestion1_2.getDebugInfo().contains(debugString));
+ }
+}
diff --git a/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java b/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java
index bf78203..3273e5d 100644
--- a/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java
+++ b/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java
@@ -90,18 +90,18 @@
}
@Test
- public void testValidAtomicFormula_stringValue_appCertificateAutoHashed() {
+ public void testValidAtomicFormula_stringValue_appCertificateIsNotAutoHashed() {
String appCert = "cert";
StringAtomicFormula stringAtomicFormula =
new StringAtomicFormula(AtomicFormula.APP_CERTIFICATE, appCert);
assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.APP_CERTIFICATE);
- assertThat(stringAtomicFormula.getValue()).doesNotMatch(appCert);
+ assertThat(stringAtomicFormula.getValue()).matches(appCert);
assertThat(stringAtomicFormula.getIsHashedValue()).isTrue();
}
@Test
- public void testValidAtomicFormula_stringValue_installerCertificateAutoHashed() {
+ public void testValidAtomicFormula_stringValue_installerCertificateIsNotAutoHashed() {
String installerCert = "cert";
StringAtomicFormula stringAtomicFormula =
new StringAtomicFormula(AtomicFormula.INSTALLER_CERTIFICATE,
@@ -109,7 +109,7 @@
assertThat(stringAtomicFormula.getKey()).isEqualTo(
AtomicFormula.INSTALLER_CERTIFICATE);
- assertThat(stringAtomicFormula.getValue()).doesNotMatch(installerCert);
+ assertThat(stringAtomicFormula.getValue()).matches(installerCert);
assertThat(stringAtomicFormula.getIsHashedValue()).isTrue();
}
diff --git a/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java b/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java
index c180602..75ef1f2 100644
--- a/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java
+++ b/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java
@@ -40,7 +40,7 @@
assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.PACKAGE_NAME);
assertThat(stringAtomicFormula.getValue()).isEqualTo(packageName);
- assertThat(stringAtomicFormula.getIsHashedValue()).isEqualTo(false);
+ assertThat(stringAtomicFormula.getIsHashedValue()).isFalse();
}
@Test
@@ -53,8 +53,8 @@
(AtomicFormula.StringAtomicFormula) formula;
assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.APP_CERTIFICATE);
- assertThat(stringAtomicFormula.getValue()).doesNotMatch(appCertificate);
- assertThat(stringAtomicFormula.getIsHashedValue()).isEqualTo(true);
+ assertThat(stringAtomicFormula.getValue()).matches(appCertificate);
+ assertThat(stringAtomicFormula.getIsHashedValue()).isTrue();
}
@Test
@@ -68,7 +68,7 @@
assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.INSTALLER_NAME);
assertThat(stringAtomicFormula.getValue()).isEqualTo(installerName);
- assertThat(stringAtomicFormula.getIsHashedValue()).isEqualTo(false);
+ assertThat(stringAtomicFormula.getIsHashedValue()).isFalse();
}
@Test
@@ -81,8 +81,8 @@
(AtomicFormula.StringAtomicFormula) formula;
assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.INSTALLER_CERTIFICATE);
- assertThat(stringAtomicFormula.getValue()).doesNotMatch(installerCertificate);
- assertThat(stringAtomicFormula.getIsHashedValue()).isEqualTo(true);
+ assertThat(stringAtomicFormula.getValue()).matches(installerCertificate);
+ assertThat(stringAtomicFormula.getIsHashedValue()).isTrue();
}
@Test
diff --git a/core/tests/coretests/src/android/os/BuildTest.java b/core/tests/coretests/src/android/os/BuildTest.java
index decc768..2295eb9 100644
--- a/core/tests/coretests/src/android/os/BuildTest.java
+++ b/core/tests/coretests/src/android/os/BuildTest.java
@@ -60,7 +60,7 @@
assertNotEmpty("BRAND", Build.BRAND);
assertNotEmpty("MODEL", Build.MODEL);
assertNotEmpty("VERSION.INCREMENTAL", Build.VERSION.INCREMENTAL);
- assertNotEmpty("VERSION.RELEASE", Build.VERSION.RELEASE);
+ assertNotEmpty("VERSION.RELEASE", Build.VERSION.RELEASE_OR_CODENAME);
assertNotEmpty("TYPE", Build.TYPE);
Assert.assertNotNull("TAGS", Build.TAGS); // TAGS is allowed to be empty.
assertNotEmpty("FINGERPRINT", Build.FINGERPRINT);
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
index 8b8e9ea..b71c580 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
@@ -19,7 +19,6 @@
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.IAccessibilityServiceConnection;
import android.content.pm.ParceledListSlice;
-import android.graphics.Bitmap;
import android.graphics.Region;
import android.os.Bundle;
import android.os.IBinder;
@@ -157,9 +156,5 @@
return -1;
}
- public Bitmap takeScreenshot(int displayId) {
- return null;
- }
-
- public void takeScreenshotWithCallback(int displayId, RemoteCallback callback) {}
+ public void takeScreenshot(int displayId, RemoteCallback callback) {}
}
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index df6b906..ce71beb 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -38,6 +38,7 @@
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@@ -355,6 +356,7 @@
// enable the work tab feature flag
ResolverActivity.ENABLE_TABBED_VIEW = true;
+ markWorkProfileUserAvailable();
Intent sendIntent = createSendTextIntent();
List<ResolvedComponentInfo> resolvedComponentInfos =
createResolvedComponentsForTestWithOtherProfile(2);
@@ -1209,17 +1211,24 @@
// enable the work tab feature flag
ResolverActivity.ENABLE_TABBED_VIEW = true;
int personalProfileTargets = 3;
+ int otherProfileTargets = 1;
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTest(personalProfileTargets);
+ createResolvedComponentsForTestWithOtherProfile(
+ personalProfileTargets + otherProfileTargets, /* userID */ 10);
int workProfileTargets = 4;
List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(
workProfileTargets);
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
- Mockito.isA(List.class))).thenReturn(personalResolvedComponentInfos);
+ Mockito.isA(List.class)))
+ .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
- Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos);
+ Mockito.isA(List.class))).thenReturn(new ArrayList<>(workResolvedComponentInfos));
+ when(sOverrides.workResolverListController.getResolversForIntentAsUser(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class),
+ eq(UserHandle.SYSTEM))).thenReturn(new ArrayList<>(personalResolvedComponentInfos));
Intent sendIntent = createSendTextIntent();
sendIntent.setType("TestType");
markWorkProfileUserAvailable();
@@ -1229,8 +1238,6 @@
waitForIdle();
assertThat(activity.getCurrentUserHandle().getIdentifier(), is(0));
- // The work list adapter must only be filled when we open the work tab
- assertThat(activity.getWorkListAdapter().getCount(), is(0));
onView(withText(R.string.resolver_work_tab)).perform(click());
assertThat(activity.getCurrentUserHandle().getIdentifier(), is(10));
assertThat(activity.getPersonalListAdapter().getCount(), is(personalProfileTargets));
@@ -1243,11 +1250,22 @@
ResolverActivity.ENABLE_TABBED_VIEW = true;
markWorkProfileUserAvailable();
int workProfileTargets = 4;
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
List<ResolvedComponentInfo> workResolvedComponentInfos =
createResolvedComponentsForTest(workProfileTargets);
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class)))
+ .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos);
+ when(sOverrides.workResolverListController.getResolversForIntentAsUser(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class),
+ eq(UserHandle.SYSTEM)))
+ .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
Intent sendIntent = createSendTextIntent();
sendIntent.setType("TestType");
@@ -1357,6 +1375,20 @@
return infoList;
}
+ private List<ResolvedComponentInfo> createResolvedComponentsForTestWithOtherProfile(
+ int numberOfResults, int userId) {
+ List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
+ for (int i = 0; i < numberOfResults; i++) {
+ if (i == 0) {
+ infoList.add(
+ ResolverDataProvider.createResolvedComponentInfoWithOtherId(i, userId));
+ } else {
+ infoList.add(ResolverDataProvider.createResolvedComponentInfo(i));
+ }
+ }
+ return infoList;
+ }
+
private List<ResolvedComponentInfo> createResolvedComponentsForTestWithUserId(
int numberOfResults, int userId) {
List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index eee62bb..a68b5908 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -16,10 +16,15 @@
package com.android.internal.app;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.annotation.Nullable;
+import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppPredictionManager;
+import android.app.prediction.AppPredictor;
import android.app.usage.UsageStatsManager;
import android.content.ContentResolver;
import android.content.Context;
@@ -40,6 +45,8 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import org.mockito.Mockito;
+
import java.util.function.Function;
public class ChooserWrapperActivity extends ChooserActivity {
@@ -173,6 +180,12 @@
return mMultiProfilePagerAdapter.getCurrentUserHandle();
}
+ @Override
+ public Context createContextAsUser(UserHandle user, int flags) {
+ // return the current context as a work profile doesn't really exist in these tests
+ return getApplicationContext();
+ }
+
/**
* We cannot directly mock the activity created since instrumentation creates it.
* <p>
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index 911490f..5f4194a 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -225,6 +225,7 @@
// enable the work tab feature flag
ResolverActivity.ENABLE_TABBED_VIEW = true;
+ markWorkProfileUserAvailable();
Intent sendIntent = createSendImageIntent();
List<ResolvedComponentInfo> resolvedComponentInfos =
createResolvedComponentsForTestWithOtherProfile(2);
@@ -246,7 +247,6 @@
chosen[0] = targetInfo.getResolveInfo();
return true;
};
-
// Make a stable copy of the components as the original list may be modified
List<ResolvedComponentInfo> stableCopy =
createResolvedComponentsForTestWithOtherProfile(2);
@@ -443,7 +443,7 @@
// enable the work tab feature flag
ResolverActivity.ENABLE_TABBED_VIEW = true;
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTest(3);
+ createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
@@ -451,6 +451,11 @@
when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos);
+ when(sOverrides.workResolverListController.getResolversForIntentAsUser(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class),
+ eq(UserHandle.SYSTEM)))
+ .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
Intent sendIntent = createSendImageIntent();
markWorkProfileUserAvailable();
@@ -478,17 +483,20 @@
Mockito.anyBoolean(),
Mockito.anyBoolean(),
Mockito.isA(List.class),
- eq(sOverrides.workProfileUserHandle))).thenReturn(new ArrayList<>(workResolvedComponentInfos));
+ eq(sOverrides.workProfileUserHandle)))
+ .thenReturn(new ArrayList<>(workResolvedComponentInfos));
when(sOverrides.workResolverListController.getResolversForIntentAsUser(Mockito.anyBoolean(),
Mockito.anyBoolean(),
Mockito.isA(List.class),
- eq(sOverrides.workProfileUserHandle))).thenReturn(new ArrayList<>(workResolvedComponentInfos));
+ eq(sOverrides.workProfileUserHandle)))
+ .thenReturn(new ArrayList<>(workResolvedComponentInfos));
when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(new ArrayList<>(workResolvedComponentInfos));
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
- Mockito.isA(List.class))).thenReturn(new ArrayList<>(personalResolvedComponentInfos));
+ Mockito.isA(List.class)))
+ .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
when(sOverrides.workResolverListController.getResolversForIntentAsUser(Mockito.anyBoolean(),
Mockito.anyBoolean(),
Mockito.isA(List.class),
@@ -502,7 +510,7 @@
onView(withText(R.string.resolver_work_tab)).perform(click());
assertThat(activity.getCurrentUserHandle().getIdentifier(), is(10));
- assertThat(activity.getPersonalListAdapter().getCount(), is(3));
+ assertThat(activity.getPersonalListAdapter().getCount(), is(2));
}
@Test
@@ -511,14 +519,20 @@
ResolverActivity.ENABLE_TABBED_VIEW = true;
markWorkProfileUserAvailable();
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTest(3);
+ createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
- Mockito.isA(List.class))).thenReturn(personalResolvedComponentInfos);
+ Mockito.isA(List.class)))
+ .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos);
+ when(sOverrides.workResolverListController.getResolversForIntentAsUser(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class),
+ eq(UserHandle.SYSTEM)))
+ .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
Intent sendIntent = createSendImageIntent();
final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
@@ -536,14 +550,20 @@
ResolverActivity.ENABLE_TABBED_VIEW = true;
markWorkProfileUserAvailable();
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTest(3);
+ createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
- Mockito.isA(List.class))).thenReturn(personalResolvedComponentInfos);
+ Mockito.isA(List.class)))
+ .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos);
+ when(sOverrides.workResolverListController.getResolversForIntentAsUser(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class),
+ eq(UserHandle.SYSTEM)))
+ .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
Intent sendIntent = createSendImageIntent();
ResolveInfo[] chosen = new ResolveInfo[1];
sOverrides.onSafelyStartCallback = targetInfo -> {
@@ -587,17 +607,20 @@
Mockito.anyBoolean(),
Mockito.anyBoolean(),
Mockito.isA(List.class),
- eq(sOverrides.workProfileUserHandle))).thenReturn(new ArrayList<>(workResolvedComponentInfos));
+ eq(sOverrides.workProfileUserHandle)))
+ .thenReturn(new ArrayList<>(workResolvedComponentInfos));
when(sOverrides.workResolverListController.getResolversForIntentAsUser(Mockito.anyBoolean(),
Mockito.anyBoolean(),
Mockito.isA(List.class),
- eq(sOverrides.workProfileUserHandle))).thenReturn(new ArrayList<>(workResolvedComponentInfos));
+ eq(sOverrides.workProfileUserHandle)))
+ .thenReturn(new ArrayList<>(workResolvedComponentInfos));
when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(new ArrayList<>(workResolvedComponentInfos));
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
- Mockito.isA(List.class))).thenReturn(new ArrayList<>(personalResolvedComponentInfos));
+ Mockito.isA(List.class)))
+ .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
when(sOverrides.workResolverListController.getResolversForIntentAsUser(Mockito.anyBoolean(),
Mockito.anyBoolean(),
Mockito.isA(List.class),
@@ -678,6 +701,20 @@
return infoList;
}
+ private List<ResolvedComponentInfo> createResolvedComponentsForTestWithOtherProfile(
+ int numberOfResults, int userId) {
+ List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
+ for (int i = 0; i < numberOfResults; i++) {
+ if (i == 0) {
+ infoList.add(
+ ResolverDataProvider.createResolvedComponentInfoWithOtherId(i, userId));
+ } else {
+ infoList.add(ResolverDataProvider.createResolvedComponentInfo(i));
+ }
+ }
+ return infoList;
+ }
+
private void waitForIdle() {
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
diff --git a/data/etc/com.android.settings.xml b/data/etc/com.android.settings.xml
index a200a51..fe1182e 100644
--- a/data/etc/com.android.settings.xml
+++ b/data/etc/com.android.settings.xml
@@ -26,6 +26,7 @@
<permission name="android.permission.DELETE_PACKAGES"/>
<permission name="android.permission.FORCE_STOP_PACKAGES"/>
<permission name="android.permission.LOCAL_MAC_ADDRESS"/>
+ <permission name="android.permission.LOG_COMPAT_CHANGE" />
<permission name="android.permission.MANAGE_DEBUGGING"/>
<permission name="android.permission.MANAGE_DEVICE_ADMINS"/>
<permission name="android.permission.MANAGE_FINGERPRINT"/>
@@ -37,8 +38,10 @@
<permission name="android.permission.MODIFY_PHONE_STATE"/>
<permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<permission name="android.permission.MOVE_PACKAGE"/>
+ <permission name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG" />
<permission name="android.permission.OVERRIDE_WIFI_CONFIG"/>
<permission name="android.permission.PACKAGE_USAGE_STATS"/>
+ <permission name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<permission name="android.permission.READ_SEARCH_INDEXABLES"/>
<permission name="android.permission.REBOOT"/>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index da50550..6929d0d 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -72,6 +72,11 @@
<group gid="net_admin" />
</permission>
+ <permission name="android.permission.MAINLINE_NETWORK_STACK" >
+ <group gid="net_admin" />
+ <group gid="net_raw" />
+ </permission>
+
<!-- The group that /cache belongs to, linked to the permission
set on the applications that can access /cache -->
<permission name="android.permission.ACCESS_CACHE_FILESYSTEM" >
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index b5eba09..f83fb3f 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -169,7 +169,7 @@
<permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/>
<permission name="android.permission.STATUS_BAR"/>
<permission name="android.permission.STOP_APP_SWITCHES"/>
- <permission name="android.permission.SUGGEST_PHONE_TIME_AND_ZONE"/>
+ <permission name="android.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE"/>
<permission name="android.permission.UPDATE_APP_OPS_STATS"/>
<permission name="android.permission.UPDATE_DEVICE_STATS"/>
<permission name="android.permission.UPDATE_LOCK"/>
@@ -366,6 +366,10 @@
<permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
<!-- Permission required for Tethering CTS tests. -->
<permission name="android.permission.TETHER_PRIVILEGED"/>
+ <!-- Permissions required for ganting and logging -->
+ <permission name="android.permission.LOG_COMPAT_CHANGE" />
+ <permission name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+ <permission name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG" />
<!-- Permissions required to test ambient display. -->
<permission name="android.permission.READ_DREAM_STATE" />
<permission name="android.permission.WRITE_DREAM_STATE" />
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index 3b86413..d08bfcf 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -157,7 +157,7 @@
public HardwareRenderer() {
mRootNode = RenderNode.adopt(nCreateRootRenderNode());
mRootNode.setClipToBounds(false);
- mNativeProxy = nCreateProxy(!mOpaque, mRootNode.mNativeRenderNode);
+ mNativeProxy = nCreateProxy(!mOpaque, mIsWideGamut, mRootNode.mNativeRenderNode);
if (mNativeProxy == 0) {
throw new OutOfMemoryError("Unable to create hardware renderer");
}
@@ -1085,7 +1085,8 @@
private static native long nCreateRootRenderNode();
- private static native long nCreateProxy(boolean translucent, long rootRenderNode);
+ private static native long nCreateProxy(boolean translucent, boolean isWideGamut,
+ long rootRenderNode);
private static native void nDeleteProxy(long nativeProxy);
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index 3681c69..a3d552f 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -187,7 +187,9 @@
EGLSyncKHR fence = mUploadThread->queue().runSync([&]() -> EGLSyncKHR {
AutoSkiaGlTexture glTexture;
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
- GL_CHECKPOINT(MODERATE);
+ if (GLUtils::dumpGLErrors()) {
+ return EGL_NO_SYNC_KHR;
+ }
// glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we
// provide.
@@ -195,19 +197,26 @@
// when we first use it in drawing
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
format.format, format.type, bitmap.getPixels());
- GL_CHECKPOINT(MODERATE);
+ if (GLUtils::dumpGLErrors()) {
+ return EGL_NO_SYNC_KHR;
+ }
EGLSyncKHR uploadFence =
eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
- LOG_ALWAYS_FATAL_IF(uploadFence == EGL_NO_SYNC_KHR,
- "Could not create sync fence %#x", eglGetError());
+ if (uploadFence == EGL_NO_SYNC_KHR) {
+ ALOGW("Could not create sync fence %#x", eglGetError());
+ };
glFlush();
+ GLUtils::dumpGLErrors();
return uploadFence;
});
+ if (fence == EGL_NO_SYNC_KHR) {
+ return false;
+ }
EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT);
- LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
- "Failed to wait for the fence %#x", eglGetError());
+ ALOGE_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
+ "Failed to wait for the fence %#x", eglGetError());
eglDestroySyncKHR(display, fence);
}
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index e7efe2f..8d5acc6 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -171,17 +171,15 @@
}
bool SkiaOpenGLPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior,
- ColorMode colorMode, uint32_t extraBuffers) {
+ uint32_t extraBuffers) {
if (mEglSurface != EGL_NO_SURFACE) {
mEglManager.destroySurface(mEglSurface);
mEglSurface = EGL_NO_SURFACE;
}
- setSurfaceColorProperties(colorMode);
-
if (surface) {
mRenderThread.requireGlContext();
- auto newSurface = mEglManager.createSurface(surface, colorMode, mSurfaceColorSpace);
+ auto newSurface = mEglManager.createSurface(surface, mColorMode, mSurfaceColorSpace);
if (!newSurface) {
return false;
}
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index 3fe0f92..e482cad 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -44,7 +44,7 @@
FrameInfo* currentFrameInfo, bool* requireSwap) override;
DeferredLayerUpdater* createTextureLayer() override;
bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior,
- renderthread::ColorMode colorMode, uint32_t extraBuffers) override;
+ uint32_t extraBuffers) override;
void onStop() override;
bool isSurfaceReady() override;
bool isContextReady() override;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 6f4af3d..29b4dd7 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -44,6 +44,7 @@
namespace skiapipeline {
SkiaPipeline::SkiaPipeline(RenderThread& thread) : mRenderThread(thread) {
+ setSurfaceColorProperties(mColorMode);
}
SkiaPipeline::~SkiaPipeline() {
@@ -584,6 +585,7 @@
}
void SkiaPipeline::setSurfaceColorProperties(ColorMode colorMode) {
+ mColorMode = colorMode;
if (colorMode == ColorMode::SRGB) {
mSurfaceColorType = SkColorType::kN32_SkColorType;
mSurfaceColorSpace = SkColorSpace::MakeSRGB();
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index af8414d..8341164 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -50,6 +50,7 @@
bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
ErrorHandler* errorHandler) override;
+ void setSurfaceColorProperties(renderthread::ColorMode colorMode) override;
SkColorType getSurfaceColorType() const override { return mSurfaceColorType; }
sk_sp<SkColorSpace> getSurfaceColorSpace() override { return mSurfaceColorSpace; }
@@ -72,9 +73,10 @@
protected:
void dumpResourceCacheUsage() const;
- void setSurfaceColorProperties(renderthread::ColorMode colorMode);
renderthread::RenderThread& mRenderThread;
+
+ renderthread::ColorMode mColorMode = renderthread::ColorMode::SRGB;
SkColorType mSurfaceColorType;
sk_sp<SkColorSpace> mSurfaceColorSpace;
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index ad7c706..535a199 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -117,17 +117,16 @@
void SkiaVulkanPipeline::onStop() {}
bool SkiaVulkanPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior,
- ColorMode colorMode, uint32_t extraBuffers) {
+ uint32_t extraBuffers) {
if (mVkSurface) {
mVkManager.destroySurface(mVkSurface);
mVkSurface = nullptr;
}
- setSurfaceColorProperties(colorMode);
if (surface) {
mRenderThread.requireVkContext();
mVkSurface =
- mVkManager.createSurface(surface, colorMode, mSurfaceColorSpace, mSurfaceColorType,
+ mVkManager.createSurface(surface, mColorMode, mSurfaceColorSpace, mSurfaceColorType,
mRenderThread.getGrContext(), extraBuffers);
}
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 3173478..c8bf233 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -43,7 +43,7 @@
FrameInfo* currentFrameInfo, bool* requireSwap) override;
DeferredLayerUpdater* createTextureLayer() override;
bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior,
- renderthread::ColorMode colorMode, uint32_t extraBuffers) override;
+ uint32_t extraBuffers) override;
void onStop() override;
bool isSurfaceReady() override;
bool isContextReady() override;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 0b5e005..91f9447 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -161,9 +161,8 @@
mRenderAheadCapacity = mRenderAheadDepth;
}
- ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::SRGB;
bool hasSurface = mRenderPipeline->setSurface(
- mNativeSurface ? mNativeSurface->getNativeWindow() : nullptr, mSwapBehavior, colorMode,
+ mNativeSurface ? mNativeSurface->getNativeWindow() : nullptr, mSwapBehavior,
mRenderAheadCapacity);
mFrameNumber = -1;
@@ -174,7 +173,7 @@
// Enable frame stats after the surface has been bound to the appropriate graphics API.
// Order is important when new and old surfaces are the same, because old surface has
// its frame stats disabled automatically.
- mNativeSurface->enableFrameTimestamps(true);
+ native_window_enable_frame_timestamps(mNativeSurface->getNativeWindow(), true);
} else {
mRenderThread.removeFrameCallback(this);
mGenerationID++;
@@ -225,7 +224,8 @@
}
void CanvasContext::setWideGamut(bool wideGamut) {
- mWideColorGamut = wideGamut;
+ ColorMode colorMode = wideGamut ? ColorMode::WideColorGamut : ColorMode::SRGB;
+ mRenderPipeline->setSurfaceColorProperties(colorMode);
}
bool CanvasContext::makeCurrent() {
@@ -556,8 +556,9 @@
FrameInfo* forthBehind = mLast4FrameInfos.front().first;
int64_t composedFrameId = mLast4FrameInfos.front().second;
nsecs_t acquireTime = -1;
- mNativeSurface->getFrameTimestamps(composedFrameId, nullptr, &acquireTime, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr);
+ native_window_get_frame_timestamps(mNativeSurface->getNativeWindow(), composedFrameId,
+ nullptr, &acquireTime, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr);
// Ignore default -1, NATIVE_WINDOW_TIMESTAMP_INVALID and NATIVE_WINDOW_TIMESTAMP_PENDING
forthBehind->set(FrameInfoIndex::GpuCompleted) = acquireTime > 0 ? acquireTime : -1;
mJankTracker.finishGpuDraw(*forthBehind);
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 0967b20..629c741 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -251,7 +251,6 @@
nsecs_t mLastDropVsync = 0;
bool mOpaque;
- bool mWideColorGamut = false;
bool mUseForceDark = false;
LightInfo mLightInfo;
LightGeometry mLightGeometry = {{0, 0, 0}, 0};
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index ef0aa98..ba0d64c 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -66,7 +66,7 @@
virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
FrameInfo* currentFrameInfo, bool* requireSwap) = 0;
virtual DeferredLayerUpdater* createTextureLayer() = 0;
- virtual bool setSurface(ANativeWindow* window, SwapBehavior swapBehavior, ColorMode colorMode,
+ virtual bool setSurface(ANativeWindow* window, SwapBehavior swapBehavior,
uint32_t extraBuffers) = 0;
virtual void onStop() = 0;
virtual bool isSurfaceReady() = 0;
@@ -80,6 +80,8 @@
virtual bool pinImages(std::vector<SkImage*>& mutableImages) = 0;
virtual bool pinImages(LsaVector<sk_sp<Bitmap>>& images) = 0;
virtual void unpinImages() = 0;
+
+ virtual void setSurfaceColorProperties(ColorMode colorMode) = 0;
virtual SkColorType getSurfaceColorType() const = 0;
virtual sk_sp<SkColorSpace> getSurfaceColorSpace() = 0;
virtual GrSurfaceOrigin getSurfaceOrigin() = 0;
diff --git a/libs/hwui/renderthread/ReliableSurface.h b/libs/hwui/renderthread/ReliableSurface.h
index da5097c..e3cd8c0 100644
--- a/libs/hwui/renderthread/ReliableSurface.h
+++ b/libs/hwui/renderthread/ReliableSurface.h
@@ -49,21 +49,6 @@
return ret;
}
- status_t getFrameTimestamps(uint64_t frameNumber,
- nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime,
- nsecs_t* outLatchTime, nsecs_t* outFirstRefreshStartTime,
- nsecs_t* outLastRefreshStartTime, nsecs_t* outGlCompositionDoneTime,
- nsecs_t* outDisplayPresentTime, nsecs_t* outDequeueReadyTime,
- nsecs_t* outReleaseTime) {
- return mSurface->getFrameTimestamps(frameNumber, outRequestedPresentTime, outAcquireTime,
- outLatchTime, outFirstRefreshStartTime, outLastRefreshStartTime,
- outGlCompositionDoneTime, outDisplayPresentTime, outDequeueReadyTime, outReleaseTime);
- }
-
- void enableFrameTimestamps(bool enable) {
- return mSurface->enableFrameTimestamps(enable);
- }
-
private:
sp<Surface> mSurface;
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 307d136..90bcd1c 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -398,7 +398,7 @@
auto surface = context.surface();
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
EXPECT_FALSE(pipeline->isSurfaceReady());
- EXPECT_TRUE(pipeline->setSurface(surface.get(), SwapBehavior::kSwap_default, ColorMode::SRGB, 0));
+ EXPECT_TRUE(pipeline->setSurface(surface.get(), SwapBehavior::kSwap_default, 0));
EXPECT_TRUE(pipeline->isSurfaceReady());
renderThread.destroyRenderingContext();
EXPECT_FALSE(pipeline->isSurfaceReady());
diff --git a/libs/incident/Android.bp b/libs/incident/Android.bp
index 150f6dc..512b8c4 100644
--- a/libs/incident/Android.bp
+++ b/libs/incident/Android.bp
@@ -12,8 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-cc_library_shared {
- name: "libincident",
+
+cc_defaults {
+ name: "libincidentpriv_defaults",
cflags: [
"-Wall",
@@ -50,6 +51,70 @@
":libincident_aidl",
"src/IncidentReportArgs.cpp",
],
+}
+
+cc_library_shared {
+ name: "libincidentpriv",
+ defaults: ["libincidentpriv_defaults"],
+ export_include_dirs: ["include_priv"],
+}
+
+cc_library_shared {
+ name: "libincident",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-missing-field-initializers",
+ "-Wno-unused-variable",
+ "-Wunused-parameter",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libutils",
+ "libincidentpriv",
+ ],
+
+ srcs: [
+ "src/incident_report.cpp",
+ ],
export_include_dirs: ["include"],
+
+ stubs: {
+ symbol_file: "libincident.map.txt",
+ versions: [
+ "30",
+ ],
+ },
}
+
+cc_test {
+ name: "libincident_test",
+ defaults: ["libincidentpriv_defaults"],
+ test_suites: ["device-tests"],
+
+ include_dirs: [
+ "frameworks/base/libs/incident/include",
+ "frameworks/base/libs/incident/include_priv",
+ ],
+
+ srcs: [
+ "tests/IncidentReportArgs_test.cpp",
+ "tests/IncidentReportRequest_test.cpp",
+ "tests/c_api_compile_test.c",
+ ],
+
+ shared_libs: [
+ "libincident",
+ ],
+
+ static_libs: [
+ "libgmock",
+ ],
+}
+
+
+
diff --git a/libs/incident/include/incident/incident_report.h b/libs/incident/include/incident/incident_report.h
new file mode 100644
index 0000000..49fe5b9
--- /dev/null
+++ b/libs/incident/include/incident/incident_report.h
@@ -0,0 +1,192 @@
+/**
+ * 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.
+ */
+
+/**
+ * @file incident_report.h
+ */
+
+#ifndef ANDROID_INCIDENT_INCIDENT_REPORT_H
+#define ANDROID_INCIDENT_INCIDENT_REPORT_H
+
+#include <stdbool.h>
+
+#if __cplusplus
+#include <set>
+#include <string>
+#include <vector>
+
+extern "C" {
+#endif // __cplusplus
+
+struct AIncidentReportArgs;
+/**
+ * Opaque class to represent the arguments to an incident report request.
+ * Incident reports contain debugging data about the device at runtime.
+ * For more information see the android.os.IncidentManager java class.
+ */
+typedef struct AIncidentReportArgs AIncidentReportArgs;
+
+// Privacy policy enum value, sync with frameworks/base/core/proto/android/privacy.proto,
+// IncidentReportArgs.h and IncidentReportArgs.java.
+enum {
+ /**
+ * Flag marking fields and incident reports than can be taken
+ * off the device only via adb.
+ */
+ INCIDENT_REPORT_PRIVACY_POLICY_LOCAL = 0,
+
+ /**
+ * Flag marking fields and incident reports than can be taken
+ * off the device with contemporary consent.
+ */
+ INCIDENT_REPORT_PRIVACY_POLICY_EXPLICIT = 100,
+
+ /**
+ * Flag marking fields and incident reports than can be taken
+ * off the device with prior consent.
+ */
+ INCIDENT_REPORT_PRIVACY_POLICY_AUTOMATIC = 200,
+
+ /**
+ * Flag to indicate that a given field has not been marked
+ * with a privacy policy.
+ */
+ INCIDENT_REPORT_PRIVACY_POLICY_UNSET = 255
+};
+
+/**
+ * Allocate and initialize an AIncidentReportArgs object.
+ */
+AIncidentReportArgs* AIncidentReportArgs_init();
+
+/**
+ * Duplicate an existing AIncidentReportArgs object.
+ */
+AIncidentReportArgs* AIncidentReportArgs_clone(AIncidentReportArgs* that);
+
+/**
+ * Clean up and delete an AIncidentReportArgs object.
+ */
+void AIncidentReportArgs_delete(AIncidentReportArgs* args);
+
+/**
+ * Set this incident report to include all sections.
+ */
+void AIncidentReportArgs_setAll(AIncidentReportArgs* args, bool all);
+
+/**
+ * Set this incident report privacy policy spec.
+ */
+void AIncidentReportArgs_setPrivacyPolicy(AIncidentReportArgs* args, int privacyPolicy);
+
+/**
+ * Add this section to the incident report. The section IDs are the field numbers
+ * from the android.os.IncidentProto protobuf message.
+ */
+void AIncidentReportArgs_addSection(AIncidentReportArgs* args, int section);
+
+/**
+ * Set the apk package name that will be sent a broadcast when the incident
+ * report completes. Must be called in conjunction with AIncidentReportArgs_setReceiverClass.
+ */
+void AIncidentReportArgs_setReceiverPackage(AIncidentReportArgs* args, char const* pkg);
+
+/**
+ * Set the fully qualified class name of the java BroadcastReceiver class that will be
+ * sent a broadcast when the report completes. Must be called in conjunction with
+ * AIncidentReportArgs_setReceiverPackage.
+ */
+void AIncidentReportArgs_setReceiverClass(AIncidentReportArgs* args, char const* cls);
+
+/**
+ * Add protobuf data as a header to the incident report. The buffer should be a serialized
+ * android.os.IncidentHeaderProto object.
+ */
+void AIncidentReportArgs_addHeader(AIncidentReportArgs* args, uint8_t const* buf, size_t size);
+
+/**
+ * Initiate taking the report described in the args object. Returns 0 on success,
+ * and non-zero otherwise.
+ */
+int AIncidentReportArgs_takeReport(AIncidentReportArgs* args);
+
+#if __cplusplus
+} // extern "C"
+
+namespace android {
+namespace os {
+
+class IncidentReportRequest {
+public:
+ inline IncidentReportRequest() {
+ mImpl = AIncidentReportArgs_init();
+ }
+
+ inline IncidentReportRequest(const IncidentReportRequest& that) {
+ mImpl = AIncidentReportArgs_clone(that.mImpl);
+ }
+
+ inline ~IncidentReportRequest() {
+ AIncidentReportArgs_delete(mImpl);
+ }
+
+ inline AIncidentReportArgs* getImpl() {
+ return mImpl;
+ }
+
+ inline void setAll(bool all) {
+ AIncidentReportArgs_setAll(mImpl, all);
+ }
+
+ inline void setPrivacyPolicy(int privacyPolicy) {
+ AIncidentReportArgs_setPrivacyPolicy(mImpl, privacyPolicy);
+ }
+
+ inline void addSection(int section) {
+ AIncidentReportArgs_addSection(mImpl, section);
+ }
+
+ inline void setReceiverPackage(const std::string& pkg) {
+ AIncidentReportArgs_setReceiverPackage(mImpl, pkg.c_str());
+ };
+
+ inline void setReceiverClass(const std::string& cls) {
+ AIncidentReportArgs_setReceiverClass(mImpl, cls.c_str());
+ };
+
+ inline void addHeader(const std::vector<uint8_t>& headerProto) {
+ AIncidentReportArgs_addHeader(mImpl, headerProto.data(), headerProto.size());
+ };
+
+ inline void addHeader(const uint8_t* buf, size_t size) {
+ AIncidentReportArgs_addHeader(mImpl, buf, size);
+ };
+
+ // returns a status_t
+ inline int takeReport() {
+ return AIncidentReportArgs_takeReport(mImpl);
+ }
+
+private:
+ AIncidentReportArgs* mImpl;
+};
+
+} // namespace os
+} // namespace android
+
+#endif // __cplusplus
+
+#endif // ANDROID_INCIDENT_INCIDENT_REPORT_H
diff --git a/libs/incident/include/android/os/IncidentReportArgs.h b/libs/incident/include_priv/android/os/IncidentReportArgs.h
similarity index 89%
rename from libs/incident/include/android/os/IncidentReportArgs.h
rename to libs/incident/include_priv/android/os/IncidentReportArgs.h
index 94b4ad6..0e61590 100644
--- a/libs/incident/include/android/os/IncidentReportArgs.h
+++ b/libs/incident/include_priv/android/os/IncidentReportArgs.h
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-#ifndef ANDROID_OS_DUMPSTATE_ARGS_H_
-#define ANDROID_OS_DUMPSTATE_ARGS_H_
+#ifndef ANDROID_OS_INCIDENT_REPORT_ARGS_H
+#define ANDROID_OS_INCIDENT_REPORT_ARGS_H
+#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
#include <utils/String16.h>
@@ -29,7 +30,8 @@
using namespace std;
-// DESTINATION enum value, sync with frameworks/base/core/proto/android/privacy.proto
+// DESTINATION enum value, sync with frameworks/base/core/proto/android/privacy.proto,
+// incident/incident_report.h and IncidentReportArgs.java
const uint8_t PRIVACY_POLICY_LOCAL = 0;
const uint8_t PRIVACY_POLICY_EXPLICIT = 100;
const uint8_t PRIVACY_POLICY_AUTOMATIC = 200;
@@ -74,4 +76,4 @@
}
}
-#endif // ANDROID_OS_DUMPSTATE_ARGS_H_
+#endif // ANDROID_OS_INCIDENT_REPORT_ARGS_H
diff --git a/libs/incident/libincident.map.txt b/libs/incident/libincident.map.txt
new file mode 100644
index 0000000..f157763
--- /dev/null
+++ b/libs/incident/libincident.map.txt
@@ -0,0 +1,15 @@
+LIBINCIDENT {
+ global:
+ AIncidentReportArgs_init; # apex # introduced=30
+ AIncidentReportArgs_clone; # apex # introduced=30
+ AIncidentReportArgs_delete; # apex # introduced=30
+ AIncidentReportArgs_setAll; # apex # introduced=30
+ AIncidentReportArgs_setPrivacyPolicy; # apex # introduced=30
+ AIncidentReportArgs_addSection; # apex # introduced=30
+ AIncidentReportArgs_setReceiverPackage; # apex # introduced=30
+ AIncidentReportArgs_setReceiverClass; # apex # introduced=30
+ AIncidentReportArgs_addHeader; # apex # introduced=30
+ AIncidentReportArgs_takeReport; # apex # introduced=30
+ local:
+ *;
+};
diff --git a/libs/incident/src/incident_report.cpp b/libs/incident/src/incident_report.cpp
new file mode 100644
index 0000000..7897ddf
--- /dev/null
+++ b/libs/incident/src/incident_report.cpp
@@ -0,0 +1,83 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "libincident"
+
+#include <incident/incident_report.h>
+
+#include <android/os/IIncidentManager.h>
+#include <android/os/IncidentReportArgs.h>
+#include <binder/IServiceManager.h>
+#include <binder/Status.h>
+#include <log/log.h>
+
+using android::sp;
+using android::binder::Status;
+using android::os::IncidentReportArgs;
+using android::os::IIncidentManager;
+using std::string;
+using std::vector;
+
+AIncidentReportArgs* AIncidentReportArgs_init() {
+ return reinterpret_cast<AIncidentReportArgs*>(new IncidentReportArgs());
+}
+
+AIncidentReportArgs* AIncidentReportArgs_clone(AIncidentReportArgs* that) {
+ return reinterpret_cast<AIncidentReportArgs*>(
+ new IncidentReportArgs(*reinterpret_cast<IncidentReportArgs*>(that)));
+}
+
+void AIncidentReportArgs_delete(AIncidentReportArgs* args) {
+ delete reinterpret_cast<IncidentReportArgs*>(args);
+}
+
+void AIncidentReportArgs_setAll(AIncidentReportArgs* args, bool all) {
+ reinterpret_cast<IncidentReportArgs*>(args)->setAll(all);
+}
+
+void AIncidentReportArgs_setPrivacyPolicy(AIncidentReportArgs* args, int privacyPolicy) {
+ reinterpret_cast<IncidentReportArgs*>(args)->setPrivacyPolicy(privacyPolicy);
+}
+
+void AIncidentReportArgs_addSection(AIncidentReportArgs* args, int section) {
+ reinterpret_cast<IncidentReportArgs*>(args)->addSection(section);
+}
+
+void AIncidentReportArgs_setReceiverPackage(AIncidentReportArgs* args, char const* pkg) {
+ reinterpret_cast<IncidentReportArgs*>(args)->setReceiverPkg(string(pkg));
+}
+
+void AIncidentReportArgs_setReceiverClass(AIncidentReportArgs* args, char const* cls) {
+ reinterpret_cast<IncidentReportArgs*>(args)->setReceiverCls(string(cls));
+}
+
+void AIncidentReportArgs_addHeader(AIncidentReportArgs* args, uint8_t const* buf, size_t size) {
+ vector<uint8_t> vec(buf, buf+size);
+ reinterpret_cast<IncidentReportArgs*>(args)->addHeader(vec);
+}
+
+int AIncidentReportArgs_takeReport(AIncidentReportArgs* argp) {
+ IncidentReportArgs* args = reinterpret_cast<IncidentReportArgs*>(argp);
+
+ sp<IIncidentManager> service = android::interface_cast<IIncidentManager>(
+ android::defaultServiceManager()->getService(android::String16("incident")));
+ if (service == nullptr) {
+ ALOGW("Failed to fetch incident service.");
+ return false;
+ }
+ Status s = service->reportIncident(*args);
+ return s.transactionError();
+}
diff --git a/cmds/statsd/tests/external/IncidentReportArgs_test.cpp b/libs/incident/tests/IncidentReportArgs_test.cpp
similarity index 93%
rename from cmds/statsd/tests/external/IncidentReportArgs_test.cpp
rename to libs/incident/tests/IncidentReportArgs_test.cpp
index 38bc194..224b343 100644
--- a/cmds/statsd/tests/external/IncidentReportArgs_test.cpp
+++ b/libs/incident/tests/IncidentReportArgs_test.cpp
@@ -20,6 +20,8 @@
namespace os {
namespace statsd {
+// Checks that all of the inline methods on IncidentReportRequest and the real C functions
+// result in a working IncidentReportArgs.
TEST(IncidentReportArgsTest, testSerialization) {
IncidentReportArgs args;
args.setAll(0);
diff --git a/libs/incident/tests/IncidentReportRequest_test.cpp b/libs/incident/tests/IncidentReportRequest_test.cpp
new file mode 100644
index 0000000..6d218b6
--- /dev/null
+++ b/libs/incident/tests/IncidentReportRequest_test.cpp
@@ -0,0 +1,65 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <android/os/IncidentReportArgs.h>
+#include <incident/incident_report.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+TEST(IncidentReportRequestTest, testWrite) {
+ IncidentReportRequest request;
+ request.setAll(0);
+ request.addSection(1000);
+ request.addSection(1001);
+
+ vector<uint8_t> header1;
+ header1.push_back(0x1);
+ header1.push_back(0x2);
+ vector<uint8_t> header2;
+ header1.push_back(0x22);
+ header1.push_back(0x33);
+
+ request.addHeader(header1);
+ request.addHeader(header2);
+
+ request.setPrivacyPolicy(1);
+
+ request.setReceiverPackage("com.android.os");
+ request.setReceiverClass("com.android.os.Receiver");
+
+ IncidentReportArgs* args = reinterpret_cast<IncidentReportArgs*>(request.getImpl());
+
+ EXPECT_EQ(0, args->all());
+ set<int> sections;
+ sections.insert(1000);
+ sections.insert(1001);
+ EXPECT_EQ(sections, args->sections());
+ EXPECT_EQ(1, args->getPrivacyPolicy());
+
+ EXPECT_EQ(string("com.android.os"), args->receiverPkg());
+ EXPECT_EQ(string("com.android.os.Receiver"), args->receiverCls());
+
+ vector<vector<uint8_t>> headers;
+ headers.push_back(header1);
+ headers.push_back(header2);
+ EXPECT_EQ(headers, args->headers());
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/libs/incident/tests/c_api_compile_test.c b/libs/incident/tests/c_api_compile_test.c
new file mode 100644
index 0000000..e1620df
--- /dev/null
+++ b/libs/incident/tests/c_api_compile_test.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+#include <incident/incident_report.h>
+
+/*
+ * This file ensures that incident/incident_report.h actually compiles with C,
+ * since there is no other place in the tree that actually uses it from C.
+ */
+int not_called() {
+ return 0;
+}
+
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 197787e..1c10edb 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -33,6 +33,9 @@
import android.annotation.TestApi;
import android.app.AlarmManager;
import android.app.PendingIntent;
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -50,7 +53,6 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.util.ArrayMap;
-import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.location.ProviderProperties;
@@ -82,6 +84,36 @@
private static final String TAG = "LocationManager";
/**
+ * For apps targeting Android K and above, supplied {@link PendingIntent}s must be targeted to a
+ * specific package.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
+ public static final long TARGETED_PENDING_INTENT = 148963590L;
+
+ /**
+ * For apps targeting Android K and above, incomplete locations may not be passed to
+ * {@link #setTestProviderLocation}.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
+ private static final long INCOMPLETE_LOCATION = 148964793L;
+
+ /**
+ * For apps targeting Android S and above, all {@link GpsStatus} API usage must be replaced with
+ * {@link GnssStatus} APIs.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
+ private static final long GPS_STATUS_USAGE = 144027538L;
+
+ /**
* Name of the network location provider.
*
* <p>This provider determines location based on nearby of cell tower and WiFi access points.
@@ -771,7 +803,6 @@
public void requestSingleUpdate(@NonNull String provider,
@NonNull PendingIntent pendingIntent) {
Preconditions.checkArgument(provider != null, "invalid null provider");
- checkPendingIntent(pendingIntent);
LocationRequest request = LocationRequest.createFromDeprecatedProvider(
provider, 0, 0, true);
@@ -800,7 +831,6 @@
public void requestSingleUpdate(@NonNull Criteria criteria,
@NonNull PendingIntent pendingIntent) {
Preconditions.checkArgument(criteria != null, "invalid null criteria");
- checkPendingIntent(pendingIntent);
LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
criteria, 0, 0, true);
@@ -1021,7 +1051,6 @@
public void requestLocationUpdates(@NonNull String provider, long minTimeMs, float minDistanceM,
@NonNull PendingIntent pendingIntent) {
Preconditions.checkArgument(provider != null, "invalid null provider");
- checkPendingIntent(pendingIntent);
LocationRequest request = LocationRequest.createFromDeprecatedProvider(
provider, minTimeMs, minDistanceM, false);
@@ -1048,7 +1077,6 @@
public void requestLocationUpdates(long minTimeMs, float minDistanceM,
@NonNull Criteria criteria, @NonNull PendingIntent pendingIntent) {
Preconditions.checkArgument(criteria != null, "invalid null criteria");
- checkPendingIntent(pendingIntent);
LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
criteria, minTimeMs, minDistanceM, false);
@@ -1164,9 +1192,9 @@
@NonNull PendingIntent pendingIntent) {
Preconditions.checkArgument(locationRequest != null, "invalid null location request");
Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent");
- if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.JELLY_BEAN) {
+ if (Compatibility.isChangeEnabled(TARGETED_PENDING_INTENT)) {
Preconditions.checkArgument(pendingIntent.isTargetedToPackage(),
- "pending intent must be targeted to package");
+ "pending intent must be targeted to a package");
}
try {
@@ -1198,15 +1226,9 @@
*/
@RequiresPermission(allOf = {LOCATION_HARDWARE, ACCESS_FINE_LOCATION})
public boolean injectLocation(@NonNull Location location) {
- if (location == null) {
- IllegalArgumentException e = new IllegalArgumentException("invalid null location");
- if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R) {
- throw e;
- } else {
- Log.w(TAG, e);
- return false;
- }
- }
+ Preconditions.checkArgument(location != null, "invalid null location");
+ Preconditions.checkArgument(location.isComplete(),
+ "incomplete location object, missing timestamp or accuracy?");
try {
return mService.injectLocation(location);
@@ -1487,15 +1509,11 @@
Preconditions.checkArgument(provider != null, "invalid null provider");
Preconditions.checkArgument(location != null, "invalid null location");
- if (!location.isComplete()) {
- IllegalArgumentException e = new IllegalArgumentException(
- "Incomplete location object, missing timestamp or accuracy? " + location);
- if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN) {
- Log.w(TAG, e);
- location.makeComplete();
- } else {
- throw e;
- }
+ if (Compatibility.isChangeEnabled(INCOMPLETE_LOCATION)) {
+ Preconditions.checkArgument(location.isComplete(),
+ "incomplete location object, missing timestamp or accuracy?");
+ } else {
+ location.makeComplete();
}
try {
@@ -1629,7 +1647,11 @@
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void addProximityAlert(double latitude, double longitude, float radius, long expiration,
@NonNull PendingIntent intent) {
- checkPendingIntent(intent);
+ Preconditions.checkArgument(intent != null, "invalid null pending intent");
+ if (Compatibility.isChangeEnabled(TARGETED_PENDING_INTENT)) {
+ Preconditions.checkArgument(intent.isTargetedToPackage(),
+ "pending intent must be targeted to a package");
+ }
if (expiration < 0) expiration = Long.MAX_VALUE;
Geofence fence = Geofence.createCircle(latitude, longitude, radius);
@@ -1659,7 +1681,11 @@
* permission is not present
*/
public void removeProximityAlert(@NonNull PendingIntent intent) {
- checkPendingIntent(intent);
+ Preconditions.checkArgument(intent != null, "invalid null pending intent");
+ if (Compatibility.isChangeEnabled(TARGETED_PENDING_INTENT)) {
+ Preconditions.checkArgument(intent.isTargetedToPackage(),
+ "pending intent must be targeted to a package");
+ }
try {
mService.removeGeofence(null, intent, mContext.getPackageName());
@@ -1709,8 +1735,13 @@
@NonNull LocationRequest request,
@NonNull Geofence fence,
@NonNull PendingIntent intent) {
- checkPendingIntent(intent);
+ Preconditions.checkArgument(request != null, "invalid null location request");
Preconditions.checkArgument(fence != null, "invalid null geofence");
+ Preconditions.checkArgument(intent != null, "invalid null pending intent");
+ if (Compatibility.isChangeEnabled(TARGETED_PENDING_INTENT)) {
+ Preconditions.checkArgument(intent.isTargetedToPackage(),
+ "pending intent must be targeted to a package");
+ }
try {
mService.requestGeofence(request, fence, intent, mContext.getPackageName(),
@@ -1737,8 +1768,12 @@
* @hide
*/
public void removeGeofence(@NonNull Geofence fence, @NonNull PendingIntent intent) {
- checkPendingIntent(intent);
Preconditions.checkArgument(fence != null, "invalid null geofence");
+ Preconditions.checkArgument(intent != null, "invalid null pending intent");
+ if (Compatibility.isChangeEnabled(TARGETED_PENDING_INTENT)) {
+ Preconditions.checkArgument(intent.isTargetedToPackage(),
+ "pending intent must be targeted to a package");
+ }
try {
mService.removeGeofence(fence, intent, mContext.getPackageName());
@@ -1759,7 +1794,11 @@
* @hide
*/
public void removeAllGeofences(@NonNull PendingIntent intent) {
- checkPendingIntent(intent);
+ Preconditions.checkArgument(intent != null, "invalid null pending intent");
+ if (Compatibility.isChangeEnabled(TARGETED_PENDING_INTENT)) {
+ Preconditions.checkArgument(intent.isTargetedToPackage(),
+ "pending intent must be targeted to a package");
+ }
try {
mService.removeGeofence(null, intent, mContext.getPackageName());
@@ -1833,14 +1872,15 @@
* @param status object containing GPS status details, or null.
* @return status object containing updated GPS status.
*
- * @deprecated GpsStatus APIs are deprecated, use {@link GnssStatus} APIs instead.
+ * @deprecated GpsStatus APIs are deprecated, use {@link GnssStatus} APIs instead. No longer
+ * supported in apps targeting S and above.
*/
@Deprecated
@RequiresPermission(ACCESS_FINE_LOCATION)
public @Nullable GpsStatus getGpsStatus(@Nullable GpsStatus status) {
- if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.R) {
+ if (Compatibility.isChangeEnabled(GPS_STATUS_USAGE)) {
throw new UnsupportedOperationException(
- "GpsStatus APIs not supported in S and above, use GnssStatus APIs instead");
+ "GpsStatus APIs not supported, please use GnssStatus APIs instead");
}
GnssStatus gnssStatus = mGnssStatusListenerManager.getGnssStatus();
@@ -1863,17 +1903,14 @@
* @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
*
* @deprecated use {@link #registerGnssStatusCallback(GnssStatus.Callback)} instead. No longer
- * supported in apps targeting R and above.
+ * supported in apps targeting S and above.
*/
@Deprecated
@RequiresPermission(ACCESS_FINE_LOCATION)
public boolean addGpsStatusListener(GpsStatus.Listener listener) {
- UnsupportedOperationException ex = new UnsupportedOperationException(
- "GpsStatus APIs not supported in S and above, use GnssStatus APIs instead");
- if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.R) {
- throw ex;
- } else {
- Log.w(TAG, ex);
+ if (Compatibility.isChangeEnabled(GPS_STATUS_USAGE)) {
+ throw new UnsupportedOperationException(
+ "GpsStatus APIs not supported, please use GnssStatus APIs instead");
}
try {
@@ -1889,16 +1926,13 @@
* @param listener GPS status listener object to remove
*
* @deprecated use {@link #unregisterGnssStatusCallback(GnssStatus.Callback)} instead. No longer
- * supported in apps targeting R and above.
+ * supported in apps targeting S and above.
*/
@Deprecated
public void removeGpsStatusListener(GpsStatus.Listener listener) {
- UnsupportedOperationException ex = new UnsupportedOperationException(
- "GpsStatus APIs not supported in S and above, use GnssStatus APIs instead");
- if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.R) {
- throw ex;
- } else {
- Log.w(TAG, ex);
+ if (Compatibility.isChangeEnabled(GPS_STATUS_USAGE)) {
+ throw new UnsupportedOperationException(
+ "GpsStatus APIs not supported, please use GnssStatus APIs instead");
}
try {
@@ -2397,19 +2431,6 @@
}
}
- private void checkPendingIntent(PendingIntent pendingIntent) {
- Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent");
- if (!pendingIntent.isTargetedToPackage()) {
- IllegalArgumentException e = new IllegalArgumentException(
- "invalid pending intent - must be targeted to package");
- if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.JELLY_BEAN) {
- throw e;
- } else {
- Log.w(TAG, e);
- }
- }
- }
-
private static class GetCurrentLocationTransport extends ILocationListener.Stub implements
AlarmManager.OnAlarmListener {
diff --git a/media/java/android/media/IMediaRoute2Provider.aidl b/media/java/android/media/IMediaRoute2Provider.aidl
index 194669c..9131f3b 100644
--- a/media/java/android/media/IMediaRoute2Provider.aidl
+++ b/media/java/android/media/IMediaRoute2Provider.aidl
@@ -37,5 +37,4 @@
void notifyControlRequestSent(String id, in Intent request);
void requestSetVolume(String id, int volume);
- void requestUpdateVolume(String id, int delta);
}
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index dac0fba..6fef468 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -52,7 +52,6 @@
void sendControlRequest(IMediaRouter2Client client, in MediaRoute2Info route,
in Intent request);
void requestSetVolume2(IMediaRouter2Client client, in MediaRoute2Info route, int volume);
- void requestUpdateVolume2(IMediaRouter2Client client, in MediaRoute2Info route, int direction);
void requestCreateSession(IMediaRouter2Client client, in MediaRoute2Info route, int requestId,
in @nullable Bundle sessionHints);
@@ -70,8 +69,6 @@
void requestSetVolume2Manager(IMediaRouter2Manager manager,
in MediaRoute2Info route, int volume);
- void requestUpdateVolume2Manager(IMediaRouter2Manager manager,
- in MediaRoute2Info route, int direction);
List<RoutingSessionInfo> getActiveSessions(IMediaRouter2Manager manager);
void selectClientRoute(IMediaRouter2Manager manager,
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index d0b5d48..20a59bba5 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -46,13 +46,20 @@
/**
* Base class for media route provider services.
* <p>
+ * Media route provider services are used to publish {@link MediaRoute2Info media routes} such as
+ * speakers, TVs, etc. The routes are published by calling {@link #notifyRoutes(Collection)}.
+ * Media apps which use {@link MediaRouter2} can request to play their media on the routes.
+ * </p><p>
+ * When {@link MediaRouter2 media router} wants to play media on a route,
+ * {@link #onCreateSession(String, String, long, Bundle)} will be called to handle the request.
+ * A session can be considered as a group of currently selected routes for each connection.
+ * Create and manage the sessions by yourself, and notify the {@link RoutingSessionInfo
+ * session infos} when there are any changes.
+ * </p><p>
* The system media router service will bind to media route provider services when a
* {@link RouteDiscoveryPreference discovery preference} is registered via
- * a {@link MediaRouter2 media router} by an application.
- * </p><p>
- * To implement your own media route provider service, extend this class and
- * override {@link #onDiscoveryPreferenceChanged(RouteDiscoveryPreference)} to publish
- * {@link MediaRoute2Info routes}.
+ * a {@link MediaRouter2 media router} by an application. See
+ * {@link #onDiscoveryPreferenceChanged(RouteDiscoveryPreference)} for the details.
* </p>
*/
public abstract class MediaRoute2ProviderService extends Service {
@@ -118,22 +125,15 @@
public abstract void onControlRequest(@NonNull String routeId, @NonNull Intent request);
/**
- * Called when requestSetVolume is called on a route of the provider
+ * Called when requestSetVolume is called on a route of the provider.
*
* @param routeId the id of the route
* @param volume the target volume
+ * @see MediaRoute2Info#getVolumeMax()
*/
public abstract void onSetVolume(@NonNull String routeId, int volume);
/**
- * Called when requestUpdateVolume is called on a route of the provider
- *
- * @param routeId id of the route
- * @param delta the delta to add to the current volume
- */
- public abstract void onUpdateVolume(@NonNull String routeId, int delta);
-
- /**
* Gets information of the session with the given id.
*
* @param sessionId id of the session
@@ -520,14 +520,5 @@
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSetVolume,
MediaRoute2ProviderService.this, routeId, volume));
}
-
- @Override
- public void requestUpdateVolume(String routeId, int delta) {
- if (!checkCallerisSystem()) {
- return;
- }
- mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onUpdateVolume,
- MediaRoute2ProviderService.this, routeId, delta));
- }
}
}
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 515cabe..d7b74df 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -462,31 +462,6 @@
}
}
- /**
- * Requests an incremental volume update for the route asynchronously.
- * <p>
- * It may have no effect if the route is currently not selected.
- * </p>
- *
- * @param delta The delta to add to the current volume.
- * @hide
- */
- public void requestUpdateVolume(@NonNull MediaRoute2Info route, int delta) {
- Objects.requireNonNull(route, "route must not be null");
-
- Client2 client;
- synchronized (sRouterLock) {
- client = mClient;
- }
- if (client != null) {
- try {
- mMediaRouterService.requestUpdateVolume2(client, route, delta);
- } catch (RemoteException ex) {
- Log.e(TAG, "Unable to send control request.", ex);
- }
- }
- }
-
void addRoutesOnHandler(List<MediaRoute2Info> routes) {
// TODO: When onRoutesAdded is first called,
// 1) clear mRoutes before adding the routes
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 662eeb1..b1f930d 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -294,30 +294,6 @@
}
}
- /**
- * Requests an incremental volume update for the route asynchronously.
- * <p>
- * It may have no effect if the route is currently not selected.
- * </p>
- *
- * @param delta The delta to add to the current volume.
- */
- public void requestUpdateVolume(@NonNull MediaRoute2Info route, int delta) {
- Objects.requireNonNull(route, "route must not be null");
-
- Client client;
- synchronized (sLock) {
- client = mClient;
- }
- if (client != null) {
- try {
- mMediaRouterService.requestUpdateVolume2Manager(client, route, delta);
- } catch (RemoteException ex) {
- Log.e(TAG, "Unable to send control request.", ex);
- }
- }
- }
-
void addRoutesOnHandler(List<MediaRoute2Info> routes) {
synchronized (mRoutesLock) {
for (MediaRoute2Info route : routes) {
diff --git a/media/java/android/media/soundtrigger/SoundTriggerDetector.java b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
index 118f65c..0895339 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerDetector.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
@@ -113,7 +113,7 @@
* This capability may or may not be supported by the system, and support can be queried
* by calling {@link SoundTriggerManager#getModuleProperties()} and checking
* {@link ModuleProperties#audioCapabilities}. The corresponding capabilities field for
- * this flag is {@link SoundTrigger.ModuleProperties#CAPABILITY_ECHO_CANCELLATION}.
+ * this flag is {@link SoundTrigger.ModuleProperties#AUDIO_CAPABILITY_ECHO_CANCELLATION}.
* If this flag is passed without the audio capability supported, there will be no audio effect
* applied.
*/
@@ -125,8 +125,9 @@
* This capability may or may not be supported by the system, and support can be queried
* by calling {@link SoundTriggerManager#getModuleProperties()} and checking
* {@link ModuleProperties#audioCapabilities}. The corresponding capabilities field for
- * this flag is {@link SoundTrigger.ModuleProperties#CAPABILITY_NOISE_SUPPRESSION}. If this flag
- * is passed without the audio capability supported, there will be no audio effect applied.
+ * this flag is {@link SoundTrigger.ModuleProperties#AUDIO_CAPABILITY_NOISE_SUPPRESSION}.
+ * If this flag is passed without the audio capability supported, there will be no audio effect
+ * applied.
*/
public static final int RECOGNITION_FLAG_ENABLE_AUDIO_NOISE_SUPPRESSION = 0x8;
@@ -296,10 +297,10 @@
int audioCapabilities = 0;
if ((recognitionFlags & RECOGNITION_FLAG_ENABLE_AUDIO_ECHO_CANCELLATION) != 0) {
- audioCapabilities |= SoundTrigger.ModuleProperties.CAPABILITY_ECHO_CANCELLATION;
+ audioCapabilities |= SoundTrigger.ModuleProperties.AUDIO_CAPABILITY_ECHO_CANCELLATION;
}
if ((recognitionFlags & RECOGNITION_FLAG_ENABLE_AUDIO_NOISE_SUPPRESSION) != 0) {
- audioCapabilities |= SoundTrigger.ModuleProperties.CAPABILITY_NOISE_SUPPRESSION;
+ audioCapabilities |= SoundTrigger.ModuleProperties.AUDIO_CAPABILITY_NOISE_SUPPRESSION;
}
int status;
diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java
index dd4dac2..6a8483c 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerManager.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java
@@ -173,8 +173,13 @@
}
/**
- * Factory constructor to create a SoundModel instance for use with methods in this
- * class.
+ * Factory constructor to a voice model to be used with {@link SoundTriggerManager}
+ *
+ * @param modelUuid Unique identifier associated with the model.
+ * @param vendorUuid Unique identifier associated the calling vendor.
+ * @param data Model's data.
+ * @param version Version identifier for the model.
+ * @return Voice model
*/
@NonNull
public static Model create(@NonNull UUID modelUuid, @NonNull UUID vendorUuid,
@@ -186,8 +191,12 @@
}
/**
- * Factory constructor to create a SoundModel instance for use with methods in this
- * class.
+ * Factory constructor to a voice model to be used with {@link SoundTriggerManager}
+ *
+ * @param modelUuid Unique identifier associated with the model.
+ * @param vendorUuid Unique identifier associated the calling vendor.
+ * @param data Model's data.
+ * @return Voice model
*/
@NonNull
public static Model create(@NonNull UUID modelUuid, @NonNull UUID vendorUuid,
@@ -195,20 +204,40 @@
return create(modelUuid, vendorUuid, data, -1);
}
+ /**
+ * Get the model's unique identifier
+ *
+ * @return UUID associated with the model
+ */
@NonNull
public UUID getModelUuid() {
return mGenericSoundModel.uuid;
}
+ /**
+ * Get the model's vendor identifier
+ *
+ * @return UUID associated with the vendor of the model
+ */
@NonNull
public UUID getVendorUuid() {
return mGenericSoundModel.vendorUuid;
}
+ /**
+ * Get the model's version
+ *
+ * @return Version associated with the model
+ */
public int getVersion() {
return mGenericSoundModel.version;
}
+ /**
+ * Get the underlying model data
+ *
+ * @return Backing data of the model
+ */
@Nullable
public byte[] getModelData() {
return mGenericSoundModel.data;
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 5e01244..3561f83 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -74,6 +74,8 @@
private List<Integer> mFrontendIds;
private Frontend mFrontend;
private EventHandler mHandler;
+ @Nullable
+ private FrontendInfo mFrontendInfo;
private List<Integer> mLnbIds;
private Lnb mLnb;
@@ -97,6 +99,7 @@
public Tuner(@NonNull Context context, @NonNull String tvInputSessionId,
@TvInputService.PriorityHintUseCaseType int useCase,
@Nullable OnResourceLostListener listener) {
+ nativeSetup();
mContext = context;
}
@@ -185,7 +188,7 @@
/**
* Listener for resource lost.
*
- * <p>Resource is reclaimed and tuner instance is forced to close.
+ * <p>Insufficient resources are reclaimed by higher priority clients.
*/
public interface OnResourceLostListener {
/**
@@ -292,6 +295,7 @@
@Result
public int tune(@NonNull FrontendSettings settings) {
TunerUtils.checkTunerPermission(mContext);
+ mFrontendInfo = null;
return nativeTune(settings.getType(), settings);
}
@@ -333,6 +337,7 @@
}
mScanCallback = scanCallback;
mScanCallbackExecutor = executor;
+ mFrontendInfo = null;
return nativeScan(settings.getType(), settings, scanType);
}
@@ -468,7 +473,10 @@
if (mFrontend == null) {
throw new IllegalStateException("frontend is not initialized");
}
- return nativeGetFrontendInfo(mFrontend.mId);
+ if (mFrontendInfo == null) {
+ mFrontendInfo = nativeGetFrontendInfo(mFrontend.mId);
+ }
+ return mFrontendInfo;
}
/**
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 9b37f95..71ba59c 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -724,18 +724,21 @@
}
if (buffer->size() > 0) {
- // asC2Buffer clears internal reference, so set the reference again.
std::shared_ptr<C2Buffer> c2Buffer = buffer->asC2Buffer();
- buffer->copy(c2Buffer);
if (c2Buffer) {
+ // asC2Buffer clears internal reference, so set the reference again.
+ buffer->copy(c2Buffer);
switch (c2Buffer->data().type()) {
case C2BufferData::LINEAR: {
std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
context->mBuffer = c2Buffer;
ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
- env->SetLongField(
- linearBlock.get(), gLinearBlockInfo.contextId, (jlong)context.release());
+ env->CallVoidMethod(
+ linearBlock.get(),
+ gLinearBlockInfo.setInternalStateId,
+ (jlong)context.release(),
+ true);
env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
break;
}
@@ -744,8 +747,11 @@
context->mBuffer = c2Buffer;
ScopedLocalRef<jobject> graphicBlock{env, env->NewObject(
gGraphicBlockInfo.clazz, gGraphicBlockInfo.ctorId)};
- env->SetLongField(
- graphicBlock.get(), gGraphicBlockInfo.contextId, (jlong)context.release());
+ env->CallVoidMethod(
+ graphicBlock.get(),
+ gGraphicBlockInfo.setInternalStateId,
+ (jlong)context.release(),
+ true);
env->SetObjectField(frame, gFields.outputFrameGraphicBlockID, graphicBlock.get());
break;
}
@@ -761,16 +767,22 @@
context->mLegacyBuffer = buffer;
ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
- env->SetLongField(
- linearBlock.get(), gLinearBlockInfo.contextId, (jlong)context.release());
+ env->CallVoidMethod(
+ linearBlock.get(),
+ gLinearBlockInfo.setInternalStateId,
+ (jlong)context.release(),
+ true);
env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
} else {
std::unique_ptr<JMediaCodecGraphicBlock> context{new JMediaCodecGraphicBlock};
context->mLegacyBuffer = buffer;
ScopedLocalRef<jobject> graphicBlock{env, env->NewObject(
gGraphicBlockInfo.clazz, gGraphicBlockInfo.ctorId)};
- env->SetLongField(
- graphicBlock.get(), gGraphicBlockInfo.contextId, (jlong)context.release());
+ env->CallVoidMethod(
+ graphicBlock.get(),
+ gGraphicBlockInfo.setInternalStateId,
+ (jlong)context.release(),
+ true);
env->SetObjectField(frame, gFields.outputFrameGraphicBlockID, graphicBlock.get());
}
}
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 81a85c9..08c3f98 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -322,6 +322,179 @@
(jint) jId);
}
+jobject JTuner::getAnalogFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AnalogFrontendCapabilities");
+ jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(II)V");
+
+ jint typeCap = caps.analogCaps().typeCap;
+ jint sifStandardCap = caps.analogCaps().sifStandardCap;
+ return env->NewObject(clazz, capsInit, typeCap, sifStandardCap);
+}
+
+jobject JTuner::getAtsc3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/Atsc3FrontendCapabilities");
+ jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IIIIII)V");
+
+ jint bandwidthCap = caps.atsc3Caps().bandwidthCap;
+ jint modulationCap = caps.atsc3Caps().modulationCap;
+ jint timeInterleaveModeCap = caps.atsc3Caps().timeInterleaveModeCap;
+ jint codeRateCap = caps.atsc3Caps().codeRateCap;
+ jint fecCap = caps.atsc3Caps().fecCap;
+ jint demodOutputFormatCap = caps.atsc3Caps().demodOutputFormatCap;
+
+ return env->NewObject(clazz, capsInit, bandwidthCap, modulationCap, timeInterleaveModeCap,
+ codeRateCap, fecCap, demodOutputFormatCap);
+}
+
+jobject JTuner::getAtscFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AtscFrontendCapabilities");
+ jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(I)V");
+
+ jint modulationCap = caps.atscCaps().modulationCap;
+
+ return env->NewObject(clazz, capsInit, modulationCap);
+}
+
+jobject JTuner::getDvbcFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbcFrontendCapabilities");
+ jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(III)V");
+
+ jint modulationCap = caps.dvbcCaps().modulationCap;
+ jint fecCap = caps.dvbcCaps().fecCap;
+ jint annexCap = caps.dvbcCaps().annexCap;
+
+ return env->NewObject(clazz, capsInit, modulationCap, fecCap, annexCap);
+}
+
+jobject JTuner::getDvbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbsFrontendCapabilities");
+ jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IJI)V");
+
+ jint modulationCap = caps.dvbsCaps().modulationCap;
+ jlong innerfecCap = caps.dvbsCaps().innerfecCap;
+ jint standard = caps.dvbsCaps().standard;
+
+ return env->NewObject(clazz, capsInit, modulationCap, innerfecCap, standard);
+}
+
+jobject JTuner::getDvbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbtFrontendCapabilities");
+ jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IIIIIIZZ)V");
+
+ jint transmissionModeCap = caps.dvbtCaps().transmissionModeCap;
+ jint bandwidthCap = caps.dvbtCaps().bandwidthCap;
+ jint constellationCap = caps.dvbtCaps().constellationCap;
+ jint coderateCap = caps.dvbtCaps().coderateCap;
+ jint hierarchyCap = caps.dvbtCaps().hierarchyCap;
+ jint guardIntervalCap = caps.dvbtCaps().guardIntervalCap;
+ jboolean isT2Supported = caps.dvbtCaps().isT2Supported;
+ jboolean isMisoSupported = caps.dvbtCaps().isMisoSupported;
+
+ return env->NewObject(clazz, capsInit, transmissionModeCap, bandwidthCap, constellationCap,
+ coderateCap, hierarchyCap, guardIntervalCap, isT2Supported, isMisoSupported);
+}
+
+jobject JTuner::getIsdbs3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/Isdbs3FrontendCapabilities");
+ jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(II)V");
+
+ jint modulationCap = caps.isdbs3Caps().modulationCap;
+ jint coderateCap = caps.isdbs3Caps().coderateCap;
+
+ return env->NewObject(clazz, capsInit, modulationCap, coderateCap);
+}
+
+jobject JTuner::getIsdbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/IsdbsFrontendCapabilities");
+ jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(II)V");
+
+ jint modulationCap = caps.isdbsCaps().modulationCap;
+ jint coderateCap = caps.isdbsCaps().coderateCap;
+
+ return env->NewObject(clazz, capsInit, modulationCap, coderateCap);
+}
+
+jobject JTuner::getIsdbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/IsdbtFrontendCapabilities");
+ jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IIIII)V");
+
+ jint modeCap = caps.isdbtCaps().modeCap;
+ jint bandwidthCap = caps.isdbtCaps().bandwidthCap;
+ jint modulationCap = caps.isdbtCaps().modulationCap;
+ jint coderateCap = caps.isdbtCaps().coderateCap;
+ jint guardIntervalCap = caps.isdbtCaps().guardIntervalCap;
+
+ return env->NewObject(clazz, capsInit, modeCap, bandwidthCap, modulationCap, coderateCap,
+ guardIntervalCap);
+}
+
+jobject JTuner::getFrontendInfo(int id) {
+ FrontendInfo feInfo;
+ Result res;
+ mTuner->getFrontendInfo(id, [&](Result r, const FrontendInfo& info) {
+ feInfo = info;
+ res = r;
+ });
+ if (res != Result::SUCCESS) {
+ return NULL;
+ }
+
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/FrontendInfo");
+ jmethodID infoInit = env->GetMethodID(clazz, "<init>",
+ "(IIIIIIII[ILandroid/media/tv/tuner/frontend/FrontendCapabilities;)V");
+
+ jint type = (jint) feInfo.type;
+ jint minFrequency = feInfo.minFrequency;
+ jint maxFrequency = feInfo.maxFrequency;
+ jint minSymbolRate = feInfo.minSymbolRate;
+ jint maxSymbolRate = feInfo.maxSymbolRate;
+ jint acquireRange = feInfo.acquireRange;
+ jint exclusiveGroupId = feInfo.exclusiveGroupId;
+ jintArray statusCaps = env->NewIntArray(feInfo.statusCaps.size());
+ env->SetIntArrayRegion(
+ statusCaps, 0, feInfo.statusCaps.size(),
+ reinterpret_cast<jint*>(&feInfo.statusCaps[0]));
+ FrontendInfo::FrontendCapabilities caps = feInfo.frontendCaps;
+
+ jobject jcaps = NULL;
+ switch(feInfo.type) {
+ case FrontendType::ANALOG:
+ jcaps = getAnalogFrontendCaps(env, caps);
+ break;
+ case FrontendType::ATSC3:
+ jcaps = getAtsc3FrontendCaps(env, caps);
+ break;
+ case FrontendType::ATSC:
+ jcaps = getAtscFrontendCaps(env, caps);
+ break;
+ case FrontendType::DVBC:
+ jcaps = getDvbcFrontendCaps(env, caps);
+ break;
+ case FrontendType::DVBS:
+ jcaps = getDvbsFrontendCaps(env, caps);
+ break;
+ case FrontendType::DVBT:
+ jcaps = getDvbtFrontendCaps(env, caps);
+ break;
+ case FrontendType::ISDBS:
+ jcaps = getIsdbsFrontendCaps(env, caps);
+ break;
+ case FrontendType::ISDBS3:
+ jcaps = getIsdbs3FrontendCaps(env, caps);
+ break;
+ case FrontendType::ISDBT:
+ jcaps = getIsdbtFrontendCaps(env, caps);
+ break;
+ default:
+ break;
+ }
+
+ return env->NewObject(
+ clazz, infoInit, (jint) id, type, minFrequency, maxFrequency, minSymbolRate,
+ maxSymbolRate, acquireRange, exclusiveGroupId, statusCaps, jcaps);
+}
+
jobject JTuner::getLnbIds() {
ALOGD("JTuner::getLnbIds()");
mTuner->getLnbIds([&](Result, const hidl_vec<FrontendId>& lnbIds) {
@@ -1162,8 +1335,9 @@
return 0;
}
-static jobject android_media_tv_Tuner_get_frontend_info(JNIEnv*, jobject, jint) {
- return NULL;
+static jobject android_media_tv_Tuner_get_frontend_info(JNIEnv *env, jobject thiz, jint id) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->getFrontendInfo(id);
}
static jobject android_media_tv_Tuner_get_lnb_ids(JNIEnv *env, jobject thiz) {
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 978d9c6..cfe99b3 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -39,6 +39,7 @@
using ::android::hardware::tv::tuner::V1_0::DvrType;
using ::android::hardware::tv::tuner::V1_0::FrontendEventType;
using ::android::hardware::tv::tuner::V1_0::FrontendId;
+using ::android::hardware::tv::tuner::V1_0::FrontendInfo;
using ::android::hardware::tv::tuner::V1_0::FrontendScanMessage;
using ::android::hardware::tv::tuner::V1_0::FrontendScanMessageType;
using ::android::hardware::tv::tuner::V1_0::FrontendScanType;
@@ -132,6 +133,7 @@
sp<ITuner> getTunerService();
jobject getFrontendIds();
jobject openFrontendById(int id);
+ jobject getFrontendInfo(int id);
int tune(const FrontendSettings& settings);
int stopTune();
int scan(const FrontendSettings& settings, FrontendScanType scanType);
@@ -158,6 +160,15 @@
sp<ILnb> mLnb;
sp<IDemux> mDemux;
int mDemuxId;
+ static jobject getAnalogFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps);
+ static jobject getAtsc3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps);
+ static jobject getAtscFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps);
+ static jobject getDvbcFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps);
+ static jobject getDvbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps);
+ static jobject getDvbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps);
+ static jobject getIsdbs3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps);
+ static jobject getIsdbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps);
+ static jobject getIsdbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps);
};
} // namespace android
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
index 4316e42..f10e5eb 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
@@ -289,12 +289,13 @@
MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
int originalVolume = volRoute.getVolume();
- int deltaVolume = (originalVolume == volRoute.getVolumeMax() ? -1 : 1);
+ int targetVolume = originalVolume == volRoute.getVolumeMax()
+ ? originalVolume - 1 : originalVolume + 1;
awaitOnRouteChangedManager(
- () -> mManager.requestUpdateVolume(volRoute, deltaVolume),
+ () -> mManager.requestSetVolume(volRoute, targetVolume),
ROUTE_ID_VARIABLE_VOLUME,
- (route -> route.getVolume() == originalVolume + deltaVolume));
+ (route -> route.getVolume() == targetVolume));
awaitOnRouteChangedManager(
() -> mManager.requestSetVolume(volRoute, originalVolume),
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
index f1a08f2..1a866ca 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
@@ -154,20 +154,6 @@
}
@Override
- public void onUpdateVolume(String routeId, int delta) {
- MediaRoute2Info route = mRoutes.get(routeId);
- if (route == null) {
- return;
- }
- int volume = route.getVolume() + delta;
- volume = Math.min(volume, Math.max(0, route.getVolumeMax()));
- mRoutes.put(routeId, new MediaRoute2Info.Builder(route)
- .setVolume(volume)
- .build());
- publishRoutes();
- }
-
- @Override
public void onCreateSession(String packageName, String routeId, long requestId,
@Nullable Bundle sessionHints) {
MediaRoute2Info route = mRoutes.get(routeId);
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 392c9f6..ba793e8 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -294,7 +294,7 @@
auto& aSurfaceControlStats = aSurfaceTransactionStats.aSurfaceControlStats;
- for (const auto& [surfaceControl, acquireTime, previousReleaseFence, transformHint] : surfaceControlStats) {
+ for (const auto& [surfaceControl, latchTime, acquireTime, presentFence, previousReleaseFence, transformHint, frameEvents] : surfaceControlStats) {
ASurfaceControl* aSurfaceControl = reinterpret_cast<ASurfaceControl*>(surfaceControl.get());
aSurfaceControlStats[aSurfaceControl].acquireTime = acquireTime;
aSurfaceControlStats[aSurfaceControl].previousReleaseFence = previousReleaseFence;
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 9c8345d..6212493 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -10,6 +10,7 @@
"androidx.appcompat_appcompat",
"androidx.lifecycle_lifecycle-runtime",
"androidx.mediarouter_mediarouter-nodeps",
+ "iconloader",
"SettingsLibHelpUtils",
"SettingsLibRestrictedLockUtils",
diff --git a/packages/SettingsLib/res/values/config.xml b/packages/SettingsLib/res/values/config.xml
new file mode 100644
index 0000000..332d6c7
--- /dev/null
+++ b/packages/SettingsLib/res/values/config.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+<!-- These resources are around just to allow their values to be customized -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Threshold in micro watts below which a charger is rated as "slow"; 1A @ 5V -->
+ <integer name="config_chargingSlowlyThreshold">5000000</integer>
+
+ <!-- Threshold in micro watts above which a charger is rated as "fast"; 1.5A @ 5V -->
+ <integer name="config_chargingFastThreshold">7500000</integer>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index dd21e5c..2e7a3c0 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1034,8 +1034,10 @@
<string name="battery_info_status_unknown">Unknown</string>
<!-- [CHAR_LIMIT=20] Battery use screen. Battery status shown in chart label when charging from an unknown source. -->
<string name="battery_info_status_charging">Charging</string>
- <!-- [CHAR_LIMIT=20] Battery use screen with lower case. Battery status shown in chart label when charging from an unknown source. -->
- <string name="battery_info_status_charging_lower">charging</string>
+ <!-- [CHAR_LIMIT=20] Battery use screen. Battery status shown in chart label when charging speed is fast. -->
+ <string name="battery_info_status_charging_fast">Charging rapidly</string>
+ <!-- [CHAR_LIMIT=20] Battery use screen. Battery status shown in chart label when charging speed is slow. -->
+ <string name="battery_info_status_charging_slow">Charging slowly</string>
<!-- Battery Info screen. Value for a status item. Used for diagnostic info screens, precise translation isn't needed -->
<string name="battery_info_status_discharging">Not charging</string>
<!-- Battery Info screen. Value for a status item. Used for diagnostic info screens, precise translation isn't needed -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index de523d9..f485793 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -3,6 +3,7 @@
import android.annotation.ColorInt;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -13,6 +14,7 @@
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.location.LocationManager;
import android.media.AudioManager;
@@ -27,9 +29,13 @@
import android.telephony.NetworkRegistrationInfo;
import android.telephony.ServiceState;
+import androidx.annotation.NonNull;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.UserIcons;
+import com.android.launcher3.icons.IconFactory;
import com.android.settingslib.drawable.UserIconDrawable;
+import com.android.settingslib.fuelgauge.BatteryStatus;
import java.text.NumberFormat;
@@ -117,7 +123,7 @@
public static Drawable getUserIcon(Context context, UserManager um, UserInfo user) {
final int iconSize = UserIconDrawable.getSizeForList(context);
if (user.isManagedProfile()) {
- Drawable drawable = UserIconDrawable.getManagedUserDrawable(context);
+ Drawable drawable = UserIconDrawable.getManagedUserDrawable(context);
drawable.setBounds(0, 0, iconSize, iconSize);
return drawable;
}
@@ -159,20 +165,43 @@
return (level * 100) / scale;
}
- public static String getBatteryStatus(Resources res, Intent batteryChangedIntent) {
- int status = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_STATUS,
+ /**
+ * Get battery status string
+ *
+ * @param context the context
+ * @param batteryChangedIntent battery broadcast intent received from {@link
+ * Intent.ACTION_BATTERY_CHANGED}.
+ * @return battery status string
+ */
+ public static String getBatteryStatus(Context context, Intent batteryChangedIntent) {
+ final int status = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_STATUS,
BatteryManager.BATTERY_STATUS_UNKNOWN);
- String statusString;
- if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
- statusString = res.getString(R.string.battery_info_status_charging);
- } else if (status == BatteryManager.BATTERY_STATUS_DISCHARGING) {
- statusString = res.getString(R.string.battery_info_status_discharging);
- } else if (status == BatteryManager.BATTERY_STATUS_NOT_CHARGING) {
- statusString = res.getString(R.string.battery_info_status_not_charging);
- } else if (status == BatteryManager.BATTERY_STATUS_FULL) {
+ final Resources res = context.getResources();
+
+ String statusString = res.getString(R.string.battery_info_status_unknown);
+ final BatteryStatus batteryStatus = new BatteryStatus(batteryChangedIntent);
+
+ if (batteryStatus.isCharged()) {
statusString = res.getString(R.string.battery_info_status_full);
} else {
- statusString = res.getString(R.string.battery_info_status_unknown);
+ if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
+ switch (batteryStatus.getChargingSpeed(context)) {
+ case BatteryStatus.CHARGING_FAST:
+ statusString = res.getString(R.string.battery_info_status_charging_fast);
+ break;
+ case BatteryStatus.CHARGING_SLOWLY:
+ statusString = res.getString(R.string.battery_info_status_charging_slow);
+ break;
+ default:
+ statusString = res.getString(R.string.battery_info_status_charging);
+ break;
+ }
+
+ } else if (status == BatteryManager.BATTERY_STATUS_DISCHARGING) {
+ statusString = res.getString(R.string.battery_info_status_discharging);
+ } else if (status == BatteryManager.BATTERY_STATUS_NOT_CHARGING) {
+ statusString = res.getString(R.string.battery_info_status_not_charging);
+ }
}
return statusString;
@@ -206,7 +235,7 @@
/**
* This method computes disabled color from normal color
*
- * @param context
+ * @param context the context
* @param inputColor normal color.
* @return disabled color.
*/
@@ -424,6 +453,19 @@
return state;
}
+ /**
+ * Get the {@link Drawable} that represents the app icon
+ */
+ public static @NonNull Drawable getBadgedIcon(
+ @NonNull Context context, @NonNull ApplicationInfo appInfo) {
+ final UserHandle user = UserHandle.getUserHandleForUid(appInfo.uid);
+ try (IconFactory iconFactory = IconFactory.obtain(context)) {
+ final Bitmap iconBmp = iconFactory.createBadgedIconBitmap(
+ appInfo.loadUnbadgedIcon(context.getPackageManager()), user, false).icon;
+ return new BitmapDrawable(context.getResources(), iconBmp);
+ }
+ }
+
private static boolean isNotInIwlan(ServiceState serviceState) {
final NetworkRegistrationInfo networkRegWlan = serviceState.getNetworkRegistrationInfo(
NetworkRegistrationInfo.DOMAIN_PS,
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 19c6664..af72888 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -59,6 +59,7 @@
import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
+import com.android.settingslib.Utils;
import java.io.File;
import java.io.IOException;
@@ -495,7 +496,7 @@
return;
}
synchronized (entry) {
- entry.ensureIconLocked(mContext, mDrawableFactory);
+ entry.ensureIconLocked(mContext);
}
}
@@ -1216,7 +1217,7 @@
AppEntry entry = mAppEntries.get(i);
if (entry.icon == null || !entry.mounted) {
synchronized (entry) {
- if (entry.ensureIconLocked(mContext, mDrawableFactory)) {
+ if (entry.ensureIconLocked(mContext)) {
if (!mRunning) {
mRunning = true;
Message m = mMainHandler.obtainMessage(
@@ -1587,10 +1588,10 @@
}
}
- boolean ensureIconLocked(Context context, IconDrawableFactory drawableFactory) {
+ boolean ensureIconLocked(Context context) {
if (this.icon == null) {
if (this.apkFile.exists()) {
- this.icon = drawableFactory.getBadgedIcon(info);
+ this.icon = Utils.getBadgedIcon(context, info);
return true;
} else {
this.mounted = false;
@@ -1601,7 +1602,7 @@
// its icon.
if (this.apkFile.exists()) {
this.mounted = true;
- this.icon = drawableFactory.getBadgedIcon(info);
+ this.icon = Utils.getBadgedIcon(context, info);
return true;
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index ddb7341..1ebe917 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -153,21 +153,6 @@
return mService.getDevicesMatchingConnectionStates(states);
}
- public boolean connect(BluetoothDevice device) {
- if (mService == null) {
- return false;
- }
- return mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
- }
-
- public boolean disconnect(BluetoothDevice device) {
- if (mService == null) {
- return false;
- }
-
- return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
- }
-
public int getConnectionStatus(BluetoothDevice device) {
if (mService == null) {
return BluetoothProfile.STATE_DISCONNECTED;
@@ -187,31 +172,37 @@
return mService.getActiveDevice();
}
- public boolean isPreferred(BluetoothDevice device) {
+ @Override
+ public boolean isEnabled(BluetoothDevice device) {
if (mService == null) {
return false;
}
return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
}
- public int getPreferred(BluetoothDevice device) {
+ @Override
+ public int getConnectionPolicy(BluetoothDevice device) {
if (mService == null) {
return CONNECTION_POLICY_FORBIDDEN;
}
return mService.getConnectionPolicy(device);
}
- public void setPreferred(BluetoothDevice device, boolean preferred) {
+ @Override
+ public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+ boolean isEnabled = false;
if (mService == null) {
- return;
+ return false;
}
- if (preferred) {
+ if (enabled) {
if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
+
+ return isEnabled;
}
boolean isA2dpPlaying() {
if (mService == null) return false;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
index 8ca5a74..c7a5bd8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
@@ -115,21 +115,6 @@
BluetoothProfile.STATE_DISCONNECTING});
}
- public boolean connect(BluetoothDevice device) {
- if (mService == null) {
- return false;
- }
- return mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
- }
-
- public boolean disconnect(BluetoothDevice device) {
- if (mService == null) {
- return false;
- }
-
- return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
- }
-
public int getConnectionStatus(BluetoothDevice device) {
if (mService == null) {
return BluetoothProfile.STATE_DISCONNECTED;
@@ -137,31 +122,37 @@
return mService.getConnectionState(device);
}
- public boolean isPreferred(BluetoothDevice device) {
+ @Override
+ public boolean isEnabled(BluetoothDevice device) {
if (mService == null) {
return false;
}
return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
}
- public int getPreferred(BluetoothDevice device) {
+ @Override
+ public int getConnectionPolicy(BluetoothDevice device) {
if (mService == null) {
return CONNECTION_POLICY_FORBIDDEN;
}
return mService.getConnectionPolicy(device);
}
- public void setPreferred(BluetoothDevice device, boolean preferred) {
+ @Override
+ public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+ boolean isEnabled = false;
if (mService == null) {
- return;
+ return false;
}
- if (preferred) {
+ if (enabled) {
if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
+
+ return isEnabled;
}
boolean isAudioPlaying() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 50d3a5d..3aa35cb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -195,7 +195,7 @@
if (newProfileState == BluetoothProfile.STATE_CONNECTED) {
if (profile instanceof MapProfile) {
- profile.setPreferred(mDevice, true);
+ profile.setEnabled(mDevice, true);
}
if (!mProfiles.contains(profile)) {
mRemovedProfiles.remove(profile);
@@ -208,7 +208,7 @@
}
} else if (profile instanceof MapProfile
&& newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
- profile.setPreferred(mDevice, false);
+ profile.setEnabled(mDevice, false);
} else if (mLocalNapRoleConnected && profile instanceof PanProfile
&& ((PanProfile) profile).isLocalRoleNap(mDevice)
&& newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
@@ -250,12 +250,12 @@
PbapServerProfile PbapProfile = mProfileManager.getPbapProfile();
if (PbapProfile != null && isConnectedProfile(PbapProfile))
{
- PbapProfile.disconnect(mDevice);
+ PbapProfile.setEnabled(mDevice, false);
}
}
public void disconnect(LocalBluetoothProfile profile) {
- if (profile.disconnect(mDevice)) {
+ if (profile.setEnabled(mDevice, false)) {
if (BluetoothUtils.D) {
Log.d(TAG, "Command sent successfully:DISCONNECT " + describe(profile));
}
@@ -342,7 +342,7 @@
if (!ensurePaired()) {
return;
}
- if (profile.connect(mDevice)) {
+ if (profile.setEnabled(mDevice, true)) {
if (BluetoothUtils.D) {
Log.d(TAG, "Command sent successfully:CONNECT " + describe(profile));
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index 218d0b2..9dfc4d9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -114,21 +114,6 @@
return true;
}
- public boolean connect(BluetoothDevice device) {
- if (mService == null) {
- return false;
- }
- return mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
- }
-
- public boolean disconnect(BluetoothDevice device) {
- if (mService == null) {
- return false;
- }
-
- return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
- }
-
public int getConnectionStatus(BluetoothDevice device) {
if (mService == null) {
return BluetoothProfile.STATE_DISCONNECTED;
@@ -164,31 +149,37 @@
return mService.getAudioState(device);
}
- public boolean isPreferred(BluetoothDevice device) {
+ @Override
+ public boolean isEnabled(BluetoothDevice device) {
if (mService == null) {
return false;
}
return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
}
- public int getPreferred(BluetoothDevice device) {
+ @Override
+ public int getConnectionPolicy(BluetoothDevice device) {
if (mService == null) {
return CONNECTION_POLICY_FORBIDDEN;
}
return mService.getConnectionPolicy(device);
}
- public void setPreferred(BluetoothDevice device, boolean preferred) {
+ @Override
+ public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+ boolean isEnabled = false;
if (mService == null) {
- return;
+ return false;
}
- if (preferred) {
+ if (enabled) {
if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
+
+ return isEnabled;
}
public List<BluetoothDevice> getConnectedDevices() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index b82fb37..a3b68b4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -151,21 +151,6 @@
return mService.getDevicesMatchingConnectionStates(states);
}
- public boolean connect(BluetoothDevice device) {
- if (mService == null) {
- return false;
- }
- return mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
- }
-
- public boolean disconnect(BluetoothDevice device) {
- if (mService == null) {
- return false;
- }
-
- return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
- }
-
public int getConnectionStatus(BluetoothDevice device) {
if (mService == null) {
return BluetoothProfile.STATE_DISCONNECTED;
@@ -185,31 +170,37 @@
return mService.getActiveDevices();
}
- public boolean isPreferred(BluetoothDevice device) {
+ @Override
+ public boolean isEnabled(BluetoothDevice device) {
if (mService == null) {
return false;
}
return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
}
- public int getPreferred(BluetoothDevice device) {
+ @Override
+ public int getConnectionPolicy(BluetoothDevice device) {
if (mService == null) {
return CONNECTION_POLICY_FORBIDDEN;
}
return mService.getConnectionPolicy(device);
}
- public void setPreferred(BluetoothDevice device, boolean preferred) {
+ @Override
+ public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+ boolean isEnabled = false;
if (mService == null) {
- return;
+ return false;
}
- if (preferred) {
+ if (enabled) {
if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
+
+ return isEnabled;
}
public void setVolume(int volume) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
index 678f2e3..66225a2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
@@ -125,23 +125,6 @@
}
@Override
- public boolean connect(BluetoothDevice device) {
- if (mService == null) {
- return false;
- }
- return mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
- }
-
- @Override
- public boolean disconnect(BluetoothDevice device) {
- if (mService == null) {
- return false;
- }
-
- return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
- }
-
- @Override
public int getConnectionStatus(BluetoothDevice device) {
if (mService == null) {
return BluetoothProfile.STATE_DISCONNECTED;
@@ -150,7 +133,7 @@
}
@Override
- public boolean isPreferred(BluetoothDevice device) {
+ public boolean isEnabled(BluetoothDevice device) {
if (mService == null) {
return false;
}
@@ -158,7 +141,7 @@
}
@Override
- public int getPreferred(BluetoothDevice device) {
+ public int getConnectionPolicy(BluetoothDevice device) {
if (mService == null) {
return CONNECTION_POLICY_FORBIDDEN;
}
@@ -166,17 +149,20 @@
}
@Override
- public void setPreferred(BluetoothDevice device, boolean preferred) {
+ public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+ boolean isEnabled = false;
if (mService == null) {
- return;
+ return false;
}
- if (preferred) {
+ if (enabled) {
if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
+
+ return isEnabled;
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
index 35600b5..8a2c4f8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
@@ -16,6 +16,8 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
@@ -102,20 +104,6 @@
}
@Override
- public boolean connect(BluetoothDevice device) {
- // Don't invoke method in service because settings is not allowed to connect this profile.
- return false;
- }
-
- @Override
- public boolean disconnect(BluetoothDevice device) {
- if (mService == null) {
- return false;
- }
- return mService.disconnect(device);
- }
-
- @Override
public int getConnectionStatus(BluetoothDevice device) {
if (mService == null) {
return BluetoothProfile.STATE_DISCONNECTED;
@@ -124,21 +112,24 @@
}
@Override
- public boolean isPreferred(BluetoothDevice device) {
+ public boolean isEnabled(BluetoothDevice device) {
return getConnectionStatus(device) != BluetoothProfile.STATE_DISCONNECTED;
}
@Override
- public int getPreferred(BluetoothDevice device) {
+ public int getConnectionPolicy(BluetoothDevice device) {
return PREFERRED_VALUE;
}
@Override
- public void setPreferred(BluetoothDevice device, boolean preferred) {
+ public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+ boolean isEnabled = false;
// if set preferred to false, then disconnect to the current device
- if (!preferred) {
- mService.disconnect(device);
+ if (!enabled) {
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
+
+ return isEnabled;
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
index 588083e..3c24b4a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
@@ -101,20 +101,6 @@
return true;
}
- public boolean connect(BluetoothDevice device) {
- if (mService == null) {
- return false;
- }
- return mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
- }
-
- public boolean disconnect(BluetoothDevice device) {
- if (mService == null) {
- return false;
- }
- return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
- }
-
public int getConnectionStatus(BluetoothDevice device) {
if (mService == null) {
return BluetoothProfile.STATE_DISCONNECTED;
@@ -122,29 +108,37 @@
return mService.getConnectionState(device);
}
- public boolean isPreferred(BluetoothDevice device) {
+ @Override
+ public boolean isEnabled(BluetoothDevice device) {
if (mService == null) {
return false;
}
return mService.getConnectionPolicy(device) != CONNECTION_POLICY_FORBIDDEN;
}
- public int getPreferred(BluetoothDevice device) {
+ @Override
+ public int getConnectionPolicy(BluetoothDevice device) {
if (mService == null) {
return CONNECTION_POLICY_FORBIDDEN;
}
return mService.getConnectionPolicy(device);
}
- public void setPreferred(BluetoothDevice device, boolean preferred) {
- if (mService == null) return;
- if (preferred) {
+ @Override
+ public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+ boolean isEnabled = false;
+ if (mService == null) {
+ return false;
+ }
+ if (enabled) {
if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
+
+ return isEnabled;
}
public String toString() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
index 4b0ca74..f609e43 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
@@ -35,17 +35,26 @@
*/
boolean isAutoConnectable();
- boolean connect(BluetoothDevice device);
-
- boolean disconnect(BluetoothDevice device);
-
int getConnectionStatus(BluetoothDevice device);
- boolean isPreferred(BluetoothDevice device);
+ /**
+ * Return {@code true} if the profile is enabled, otherwise return {@code false}.
+ * @param device the device to query for enable status
+ */
+ boolean isEnabled(BluetoothDevice device);
- int getPreferred(BluetoothDevice device);
+ /**
+ * Get the connection policy of the profile.
+ * @param device the device to query for enable status
+ */
+ int getConnectionPolicy(BluetoothDevice device);
- void setPreferred(BluetoothDevice device, boolean preferred);
+ /**
+ * Enable the profile if {@code enabled} is {@code true}, otherwise disable profile.
+ * @param device the device to set profile status
+ * @param enabled {@code true} for enable profile, otherwise disable profile.
+ */
+ boolean setEnabled(BluetoothDevice device, boolean enabled);
boolean isProfileReady();
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index ae2acbe..c72efb7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -528,14 +528,14 @@
(mMapProfile.getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED)) {
profiles.add(mMapProfile);
removedProfiles.remove(mMapProfile);
- mMapProfile.setPreferred(device, true);
+ mMapProfile.setEnabled(device, true);
}
if ((mPbapProfile != null) &&
(mPbapProfile.getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED)) {
profiles.add(mPbapProfile);
removedProfiles.remove(mPbapProfile);
- mPbapProfile.setPreferred(device, true);
+ mPbapProfile.setEnabled(device, true);
}
if (mMapClientProfile != null) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
index 7d121aa..19cb2f5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
@@ -114,21 +114,6 @@
return true;
}
- public boolean connect(BluetoothDevice device) {
- if (mService == null) {
- return false;
- }
- return mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
- }
-
- public boolean disconnect(BluetoothDevice device) {
- if (mService == null) {
- return false;
- }
-
- return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
- }
-
public int getConnectionStatus(BluetoothDevice device) {
if (mService == null) {
return BluetoothProfile.STATE_DISCONNECTED;
@@ -136,31 +121,37 @@
return mService.getConnectionState(device);
}
- public boolean isPreferred(BluetoothDevice device) {
+ @Override
+ public boolean isEnabled(BluetoothDevice device) {
if (mService == null) {
return false;
}
return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
}
- public int getPreferred(BluetoothDevice device) {
+ @Override
+ public int getConnectionPolicy(BluetoothDevice device) {
if (mService == null) {
return CONNECTION_POLICY_FORBIDDEN;
}
return mService.getConnectionPolicy(device);
}
- public void setPreferred(BluetoothDevice device, boolean preferred) {
+ @Override
+ public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+ boolean isEnabled = false;
if (mService == null) {
- return;
+ return false;
}
- if (preferred) {
+ if (enabled) {
if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
+
+ return isEnabled;
}
public List<BluetoothDevice> getConnectedDevices() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
index a96a4e7..75c1926 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
@@ -16,6 +16,7 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
import android.bluetooth.BluetoothAdapter;
@@ -112,19 +113,6 @@
return true;
}
- public boolean connect(BluetoothDevice device) {
- Log.d(TAG, "connect() - should not get called");
- return false; // MAP never connects out
- }
-
- public boolean disconnect(BluetoothDevice device) {
- if (mService == null) {
- return false;
- }
-
- return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
- }
-
public int getConnectionStatus(BluetoothDevice device) {
if (mService == null) {
return BluetoothProfile.STATE_DISCONNECTED;
@@ -132,31 +120,37 @@
return mService.getConnectionState(device);
}
- public boolean isPreferred(BluetoothDevice device) {
+ @Override
+ public boolean isEnabled(BluetoothDevice device) {
if (mService == null) {
return false;
}
return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
}
- public int getPreferred(BluetoothDevice device) {
+ @Override
+ public int getConnectionPolicy(BluetoothDevice device) {
if (mService == null) {
return CONNECTION_POLICY_FORBIDDEN;
}
return mService.getConnectionPolicy(device);
}
- public void setPreferred(BluetoothDevice device, boolean preferred) {
+ @Override
+ public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+ boolean isEnabled = false;
if (mService == null) {
- return;
+ return false;
}
- if (preferred) {
- if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+ if (enabled) {
+ if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
+
+ return isEnabled;
}
public List<BluetoothDevice> getConnectedDevices() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
index 8e3f3ed..5a6e6e8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
@@ -40,27 +40,23 @@
return false;
}
- public boolean connect(BluetoothDevice device) {
- return false;
- }
-
- public boolean disconnect(BluetoothDevice device) {
- return false;
- }
-
public int getConnectionStatus(BluetoothDevice device) {
return BluetoothProfile.STATE_DISCONNECTED; // Settings app doesn't handle OPP
}
- public boolean isPreferred(BluetoothDevice device) {
+ @Override
+ public boolean isEnabled(BluetoothDevice device) {
return false;
}
- public int getPreferred(BluetoothDevice device) {
+ @Override
+ public int getConnectionPolicy(BluetoothDevice device) {
return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; // Settings app doesn't handle OPP
}
- public void setPreferred(BluetoothDevice device, boolean preferred) {
+ @Override
+ public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+ return false;
}
public boolean isProfileReady() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
index 6638592..767df35 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
@@ -16,6 +16,9 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
@@ -83,22 +86,6 @@
return false;
}
- public boolean connect(BluetoothDevice device) {
- if (mService == null) return false;
- List<BluetoothDevice> sinks = mService.getConnectedDevices();
- if (sinks != null) {
- for (BluetoothDevice sink : sinks) {
- mService.disconnect(sink);
- }
- }
- return mService.connect(device);
- }
-
- public boolean disconnect(BluetoothDevice device) {
- if (mService == null) return false;
- return mService.disconnect(device);
- }
-
public int getConnectionStatus(BluetoothDevice device) {
if (mService == null) {
return BluetoothProfile.STATE_DISCONNECTED;
@@ -106,16 +93,36 @@
return mService.getConnectionState(device);
}
- public boolean isPreferred(BluetoothDevice device) {
+ @Override
+ public boolean isEnabled(BluetoothDevice device) {
return true;
}
- public int getPreferred(BluetoothDevice device) {
+ @Override
+ public int getConnectionPolicy(BluetoothDevice device) {
return -1;
}
- public void setPreferred(BluetoothDevice device, boolean preferred) {
- // ignore: isPreferred is always true for PAN
+ @Override
+ public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+ boolean isEnabled = false;
+ if (mService == null) {
+ return false;
+ }
+
+ if (enabled) {
+ final List<BluetoothDevice> sinks = mService.getConnectedDevices();
+ if (sinks != null) {
+ for (BluetoothDevice sink : sinks) {
+ mService.setConnectionPolicy(sink, CONNECTION_POLICY_FORBIDDEN);
+ }
+ }
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
+ } else {
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
+ }
+
+ return isEnabled;
}
public String toString() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
index 56267fc..0d11293 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
@@ -126,23 +126,6 @@
BluetoothProfile.STATE_DISCONNECTING});
}
- public boolean connect(BluetoothDevice device) {
- Log.d(TAG,"PBAPClientProfile got connect request");
- if (mService == null) {
- return false;
- }
- Log.d(TAG,"PBAPClientProfile attempting to connect to " + device.getAddress());
- return mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
- }
-
- public boolean disconnect(BluetoothDevice device) {
- Log.d(TAG,"PBAPClientProfile got disconnect request");
- if (mService == null) {
- return false;
- }
- return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
- }
-
public int getConnectionStatus(BluetoothDevice device) {
if (mService == null) {
return BluetoothProfile.STATE_DISCONNECTED;
@@ -150,31 +133,37 @@
return mService.getConnectionState(device);
}
- public boolean isPreferred(BluetoothDevice device) {
+ @Override
+ public boolean isEnabled(BluetoothDevice device) {
if (mService == null) {
return false;
}
return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
}
- public int getPreferred(BluetoothDevice device) {
+ @Override
+ public int getConnectionPolicy(BluetoothDevice device) {
if (mService == null) {
return CONNECTION_POLICY_FORBIDDEN;
}
return mService.getConnectionPolicy(device);
}
- public void setPreferred(BluetoothDevice device, boolean preferred) {
+ @Override
+ public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+ boolean isEnabled = false;
if (mService == null) {
- return;
+ return false;
}
- if (preferred) {
+ if (enabled) {
if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
+
+ return isEnabled;
}
public String toString() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
index f7c0bf5..9e2e4a1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
@@ -91,34 +91,33 @@
return false;
}
- public boolean connect(BluetoothDevice device) {
- /*Can't connect from server */
- return false;
-
- }
-
- public boolean disconnect(BluetoothDevice device) {
- if (mService == null) {
- return false;
- }
- return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
- }
-
public int getConnectionStatus(BluetoothDevice device) {
if (mService == null) return BluetoothProfile.STATE_DISCONNECTED;
return mService.getConnectionState(device);
}
- public boolean isPreferred(BluetoothDevice device) {
+ @Override
+ public boolean isEnabled(BluetoothDevice device) {
return false;
}
- public int getPreferred(BluetoothDevice device) {
+ @Override
+ public int getConnectionPolicy(BluetoothDevice device) {
return -1;
}
- public void setPreferred(BluetoothDevice device, boolean preferred) {
- // ignore: isPreferred is always true for PBAP
+ @Override
+ public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+ boolean isEnabled = false;
+ if (mService == null) {
+ return false;
+ }
+
+ if (!enabled) {
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
+ }
+
+ return isEnabled;
}
public String toString() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
index 3022c5b..104f1d7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
@@ -111,21 +111,6 @@
return true;
}
- public boolean connect(BluetoothDevice device) {
- if (mService == null) {
- return false;
- }
- return mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
- }
-
- public boolean disconnect(BluetoothDevice device) {
- if (mService == null) {
- return false;
- }
-
- return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
- }
-
public int getConnectionStatus(BluetoothDevice device) {
if (mService == null) {
return BluetoothProfile.STATE_DISCONNECTED;
@@ -133,31 +118,37 @@
return mService.getConnectionState(device);
}
- public boolean isPreferred(BluetoothDevice device) {
+ @Override
+ public boolean isEnabled(BluetoothDevice device) {
if (mService == null) {
return false;
}
return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
}
- public int getPreferred(BluetoothDevice device) {
+ @Override
+ public int getConnectionPolicy(BluetoothDevice device) {
if (mService == null) {
return CONNECTION_POLICY_FORBIDDEN;
}
return mService.getConnectionPolicy(device);
}
- public void setPreferred(BluetoothDevice device, boolean preferred) {
+ @Override
+ public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+ boolean isEnabled = false;
if (mService == null) {
- return;
+ return false;
}
- if (preferred) {
+ if (enabled) {
if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
+
+ return isEnabled;
}
public List<BluetoothDevice> getConnectedDevices() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
new file mode 100644
index 0000000..bc40903
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.fuelgauge;
+
+import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
+import static android.os.BatteryManager.BATTERY_STATUS_FULL;
+import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
+import static android.os.BatteryManager.EXTRA_HEALTH;
+import static android.os.BatteryManager.EXTRA_LEVEL;
+import static android.os.BatteryManager.EXTRA_MAX_CHARGING_CURRENT;
+import static android.os.BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE;
+import static android.os.BatteryManager.EXTRA_PLUGGED;
+import static android.os.BatteryManager.EXTRA_STATUS;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.BatteryManager;
+
+import com.android.settingslib.R;
+
+/**
+ * Stores and computes some battery information.
+ */
+public class BatteryStatus {
+ private static final int LOW_BATTERY_THRESHOLD = 20;
+ private static final int DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT = 5000000;
+
+ public static final int CHARGING_UNKNOWN = -1;
+ public static final int CHARGING_SLOWLY = 0;
+ public static final int CHARGING_REGULAR = 1;
+ public static final int CHARGING_FAST = 2;
+
+ public final int status;
+ public final int level;
+ public final int plugged;
+ public final int health;
+ public final int maxChargingWattage;
+
+ public BatteryStatus(int status, int level, int plugged, int health,
+ int maxChargingWattage) {
+ this.status = status;
+ this.level = level;
+ this.plugged = plugged;
+ this.health = health;
+ this.maxChargingWattage = maxChargingWattage;
+ }
+
+ public BatteryStatus(Intent batteryChangedIntent) {
+ status = batteryChangedIntent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN);
+ plugged = batteryChangedIntent.getIntExtra(EXTRA_PLUGGED, 0);
+ level = batteryChangedIntent.getIntExtra(EXTRA_LEVEL, 0);
+ health = batteryChangedIntent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN);
+
+ final int maxChargingMicroAmp = batteryChangedIntent.getIntExtra(EXTRA_MAX_CHARGING_CURRENT,
+ -1);
+ int maxChargingMicroVolt = batteryChangedIntent.getIntExtra(EXTRA_MAX_CHARGING_VOLTAGE, -1);
+
+ if (maxChargingMicroVolt <= 0) {
+ maxChargingMicroVolt = DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT;
+ }
+ if (maxChargingMicroAmp > 0) {
+ // Calculating muW = muA * muV / (10^6 mu^2 / mu); splitting up the divisor
+ // to maintain precision equally on both factors.
+ maxChargingWattage = (maxChargingMicroAmp / 1000)
+ * (maxChargingMicroVolt / 1000);
+ } else {
+ maxChargingWattage = -1;
+ }
+ }
+
+ /**
+ * Determine whether the device is plugged in (USB, power, or wireless).
+ *
+ * @return true if the device is plugged in.
+ */
+ public boolean isPluggedIn() {
+ return plugged == BatteryManager.BATTERY_PLUGGED_AC
+ || plugged == BatteryManager.BATTERY_PLUGGED_USB
+ || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS;
+ }
+
+ /**
+ * Determine whether the device is plugged in (USB, power).
+ *
+ * @return true if the device is plugged in wired (as opposed to wireless)
+ */
+ public boolean isPluggedInWired() {
+ return plugged == BatteryManager.BATTERY_PLUGGED_AC
+ || plugged == BatteryManager.BATTERY_PLUGGED_USB;
+ }
+
+ /**
+ * Whether or not the device is charged. Note that some devices never return 100% for
+ * battery level, so this allows either battery level or status to determine if the
+ * battery is charged.
+ *
+ * @return true if the device is charged
+ */
+ public boolean isCharged() {
+ return status == BATTERY_STATUS_FULL || level >= 100;
+ }
+
+ /**
+ * Whether battery is low and needs to be charged.
+ *
+ * @return true if battery is low
+ */
+ public boolean isBatteryLow() {
+ return level < LOW_BATTERY_THRESHOLD;
+ }
+
+ /**
+ * Return current chargin speed is fast, slow or normal.
+ *
+ * @return the charing speed
+ */
+ public final int getChargingSpeed(Context context) {
+ final int slowThreshold = context.getResources().getInteger(
+ R.integer.config_chargingSlowlyThreshold);
+ final int fastThreshold = context.getResources().getInteger(
+ R.integer.config_chargingFastThreshold);
+ return maxChargingWattage <= 0 ? CHARGING_UNKNOWN :
+ maxChargingWattage < slowThreshold ? CHARGING_SLOWLY :
+ maxChargingWattage > fastThreshold ? CHARGING_FAST :
+ CHARGING_REGULAR;
+ }
+
+ @Override
+ public String toString() {
+ return "BatteryStatus{status=" + status + ",level=" + level + ",plugged=" + plugged
+ + ",health=" + health + ",maxChargingWattage=" + maxChargingWattage + "}";
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java
index 12d054e..3a807c9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java
@@ -108,9 +108,9 @@
Log.d(TAG, "addConnectableA2dpDevices() device : " + cachedDevice.getName()
+ ", is connected : " + cachedDevice.isConnected()
- + ", is preferred : " + a2dpProfile.isPreferred(device));
+ + ", is enabled : " + a2dpProfile.isEnabled(device));
- if (a2dpProfile.isPreferred(device)
+ if (a2dpProfile.isEnabled(device)
&& BluetoothDevice.BOND_BONDED == cachedDevice.getBondState()) {
addMediaDevice(cachedDevice);
}
@@ -143,9 +143,9 @@
Log.d(TAG, "addConnectableHearingAidDevices() device : " + cachedDevice.getName()
+ ", is connected : " + cachedDevice.isConnected()
- + ", is preferred : " + hapProfile.isPreferred(device));
+ + ", is enabled : " + hapProfile.isEnabled(device));
- if (hapProfile.isPreferred(device)
+ if (hapProfile.isEnabled(device)
&& BluetoothDevice.BOND_BONDED == cachedDevice.getBondState()) {
addMediaDevice(cachedDevice);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
index d287f95..ba74139 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
@@ -16,9 +16,12 @@
package com.android.settingslib.media;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
+import android.text.TextUtils;
+import android.util.Log;
import com.android.settingslib.R;
import com.android.settingslib.bluetooth.BluetoothUtils;
@@ -89,6 +92,31 @@
}
@Override
+ public String getClientPackageName() {
+ return mRouteInfo.getClientPackageName();
+ }
+
+ @Override
+ public String getClientAppLabel() {
+ final String packageName = mRouteInfo.getClientPackageName();
+ if (TextUtils.isEmpty(packageName)) {
+ Log.d(TAG, "Client package name is empty");
+ return mContext.getResources().getString(R.string.unknown);
+ }
+ try {
+ final PackageManager packageManager = mContext.getPackageManager();
+ final String appLabel = packageManager.getApplicationLabel(
+ packageManager.getApplicationInfo(packageName, 0)).toString();
+ if (!TextUtils.isEmpty(appLabel)) {
+ return appLabel;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "unable to find " + packageName);
+ }
+ return mContext.getResources().getString(R.string.unknown);
+ }
+
+ @Override
public void disconnect() {
//TODO(b/144535188): disconnected last select device
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 50196d2..96d72e7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -235,6 +235,22 @@
return mCurrentConnectedDevice;
}
+ /**
+ * Find the active MediaDevice.
+ *
+ * @param type the media device type.
+ * @return MediaDevice list
+ */
+ public List<MediaDevice> getActiveMediaDevice(@MediaDevice.MediaDeviceType int type) {
+ final List<MediaDevice> devices = new ArrayList<>();
+ for (MediaDevice device : mMediaDevices) {
+ if (type == device.mType && device.getClientPackageName() != null) {
+ devices.add(device);
+ }
+ }
+ return devices;
+ }
+
private MediaDevice updateCurrentConnectedDevice() {
for (MediaDevice device : mMediaDevices) {
if (device instanceof BluetoothMediaDevice) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 44e70f4..bfb79c0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -16,6 +16,9 @@
package com.android.settingslib.wifi;
+import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED;
+import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_PERMANENTLY_DISABLED;
+
import android.annotation.IntDef;
import android.annotation.MainThread;
import android.annotation.Nullable;
@@ -1144,11 +1147,15 @@
mInfo != null ? mInfo.getRequestingPackageName() : null));
} else { // not active
if (mConfig != null && mConfig.hasNoInternetAccess()) {
- int messageID = mConfig.getNetworkSelectionStatus().isNetworkPermanentlyDisabled()
+ int messageID =
+ mConfig.getNetworkSelectionStatus().getNetworkSelectionStatus()
+ == NETWORK_SELECTION_PERMANENTLY_DISABLED
? R.string.wifi_no_internet_no_reconnect
: R.string.wifi_no_internet;
summary.append(mContext.getString(messageID));
- } else if (mConfig != null && !mConfig.getNetworkSelectionStatus().isNetworkEnabled()) {
+ } else if (mConfig != null
+ && (mConfig.getNetworkSelectionStatus().getNetworkSelectionStatus()
+ != NETWORK_SELECTION_ENABLED)) {
WifiConfiguration.NetworkSelectionStatus networkStatus =
mConfig.getNetworkSelectionStatus();
switch (networkStatus.getNetworkSelectionDisableReason()) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
index d4e0510..d233649 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
@@ -16,9 +16,13 @@
package com.android.settingslib.wifi;
+import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED;
+import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.getMaxNetworkSelectionDisableReason;
+
import android.content.Context;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
import android.net.wifi.WifiInfo;
import android.os.SystemClock;
@@ -41,7 +45,9 @@
summary.append(" f=" + Integer.toString(info.getFrequency()));
}
summary.append(" " + getVisibilityStatus(accessPoint));
- if (config != null && !config.getNetworkSelectionStatus().isNetworkEnabled()) {
+ if (config != null
+ && (config.getNetworkSelectionStatus().getNetworkSelectionStatus()
+ != NETWORK_SELECTION_ENABLED)) {
summary.append(" (" + config.getNetworkSelectionStatus().getNetworkStatusString());
if (config.getNetworkSelectionStatus().getDisableTime() > 0) {
long now = System.currentTimeMillis();
@@ -58,15 +64,13 @@
}
if (config != null) {
- WifiConfiguration.NetworkSelectionStatus networkStatus =
- config.getNetworkSelectionStatus();
- for (int index = WifiConfiguration.NetworkSelectionStatus.DISABLED_NONE;
- index < WifiConfiguration.NetworkSelectionStatus
- .NETWORK_SELECTION_DISABLED_MAX; index++) {
- if (networkStatus.getDisableReasonCounter(index) != 0) {
- summary.append(" " + WifiConfiguration.NetworkSelectionStatus
- .getNetworkDisableReasonString(index) + "="
- + networkStatus.getDisableReasonCounter(index));
+ NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus();
+ for (int reason = 0; reason <= getMaxNetworkSelectionDisableReason(); reason++) {
+ if (networkStatus.getDisableReasonCounter(reason) != 0) {
+ summary.append(" ")
+ .append(NetworkSelectionStatus.getNetworkDisableReasonString(reason))
+ .append("=")
+ .append(networkStatus.getDisableReasonCounter(reason));
}
}
}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 42f3cbb..bcabec8 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -465,6 +465,8 @@
WifiConfiguration.NetworkSelectionStatus status =
mock(WifiConfiguration.NetworkSelectionStatus.class);
when(configuration.getNetworkSelectionStatus()).thenReturn(status);
+ when(status.getNetworkSelectionStatus()).thenReturn(
+ WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_TEMPORARY_DISABLED);
when(status.getNetworkSelectionDisableReason()).thenReturn(
WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD);
AccessPoint ap = new AccessPoint(mContext, configuration);
@@ -1370,13 +1372,13 @@
public void testOsuAccessPointSummary_showsProvisioningUpdates() {
OsuProvider provider = createOsuProvider();
Context spyContext = spy(new ContextWrapper(mContext));
- AccessPoint osuAccessPoint = new AccessPoint(spyContext, provider,
- mScanResults);
+ when(spyContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
Map<OsuProvider, PasspointConfiguration> osuProviderConfigMap = new HashMap<>();
osuProviderConfigMap.put(provider, null);
- when(spyContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
when(mMockWifiManager.getMatchingPasspointConfigsForOsuProviders(
Collections.singleton(provider))).thenReturn(osuProviderConfigMap);
+ AccessPoint osuAccessPoint = new AccessPoint(spyContext, provider,
+ mScanResults);
osuAccessPoint.setListener(mMockAccessPointListener);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
index 1182945..6307caf 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -31,6 +31,7 @@
import android.content.res.Resources;
import android.location.LocationManager;
import android.media.AudioManager;
+import android.os.BatteryManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
@@ -122,12 +123,12 @@
public void testGetDefaultStorageManagerDaysToRetain_storageManagerDaysToRetainUsesResources() {
Resources resources = mock(Resources.class);
when(resources.getInteger(
- eq(
- com.android
- .internal
- .R
- .integer
- .config_storageManagerDaystoRetainDefault)))
+ eq(
+ com.android
+ .internal
+ .R
+ .integer
+ .config_storageManagerDaystoRetainDefault)))
.thenReturn(60);
assertThat(Utils.getDefaultStorageManagerDaysToRetain(resources)).isEqualTo(60);
}
@@ -147,7 +148,8 @@
private static Map<String, Integer> map = new HashMap<>();
@Implementation
- public static boolean putIntForUser(ContentResolver cr, String name, int value, int userHandle) {
+ public static boolean putIntForUser(ContentResolver cr, String name, int value,
+ int userHandle) {
map.put(name, value);
return true;
}
@@ -312,4 +314,33 @@
assertThat(Utils.getCombinedServiceState(mServiceState)).isEqualTo(
ServiceState.STATE_OUT_OF_SERVICE);
}
+
+ @Test
+ public void getBatteryStatus_statusIsFull_returnFullString() {
+ final Intent intent = new Intent().putExtra(BatteryManager.EXTRA_LEVEL, 100);
+ final Resources resources = mContext.getResources();
+
+ assertThat(Utils.getBatteryStatus(mContext, intent)).isEqualTo(
+ resources.getString(R.string.battery_info_status_full));
+ }
+
+ @Test
+ public void getBatteryStatus_batteryLevelIs100_returnFullString() {
+ final Intent intent = new Intent().putExtra(BatteryManager.EXTRA_STATUS,
+ BatteryManager.BATTERY_STATUS_FULL);
+ final Resources resources = mContext.getResources();
+
+ assertThat(Utils.getBatteryStatus(mContext, intent)).isEqualTo(
+ resources.getString(R.string.battery_info_status_full));
+ }
+
+ @Test
+ public void getBatteryStatus_batteryLevel99_returnChargingString() {
+ final Intent intent = new Intent().putExtra(BatteryManager.EXTRA_STATUS,
+ BatteryManager.BATTERY_STATUS_CHARGING);
+ final Resources resources = mContext.getResources();
+
+ assertThat(Utils.getBatteryStatus(mContext, intent)).isEqualTo(
+ resources.getString(R.string.battery_info_status_charging));
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java
index ccb6646..9bb2f22d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java
@@ -16,12 +16,8 @@
package com.android.settingslib.bluetooth;
-import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
-import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
-
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothA2dpSink;
@@ -68,18 +64,6 @@
}
@Test
- public void connect_shouldConnectBluetoothA2dpSink() {
- mProfile.connect(mBluetoothDevice);
- verify(mService).setConnectionPolicy(mBluetoothDevice, CONNECTION_POLICY_ALLOWED);
- }
-
- @Test
- public void disconnect_shouldDisconnectBluetoothA2dpSink() {
- mProfile.disconnect(mBluetoothDevice);
- verify(mService).setConnectionPolicy(mBluetoothDevice, CONNECTION_POLICY_FORBIDDEN);
- }
-
- @Test
public void getConnectionStatus_shouldReturnConnectionState() {
when(mService.getConnectionState(mBluetoothDevice)).
thenReturn(BluetoothProfile.STATE_CONNECTED);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java
index 9180760..d121e0b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java
@@ -16,12 +16,8 @@
package com.android.settingslib.bluetooth;
-import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
-import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
-
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
@@ -68,18 +64,6 @@
}
@Test
- public void connect_shouldConnectBluetoothHeadsetClient() {
- mProfile.connect(mBluetoothDevice);
- verify(mService).setConnectionPolicy(mBluetoothDevice, CONNECTION_POLICY_ALLOWED);
- }
-
- @Test
- public void disconnect_shouldDisconnectBluetoothHeadsetClient() {
- mProfile.disconnect(mBluetoothDevice);
- verify(mService).setConnectionPolicy(mBluetoothDevice, CONNECTION_POLICY_FORBIDDEN);
- }
-
- @Test
public void getConnectionStatus_shouldReturnConnectionState() {
when(mService.getConnectionState(mBluetoothDevice)).
thenReturn(BluetoothProfile.STATE_CONNECTED);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HidDeviceProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HidDeviceProfileTest.java
index f38af70..3665d9c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HidDeviceProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HidDeviceProfileTest.java
@@ -18,7 +18,6 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
@@ -65,17 +64,6 @@
}
@Test
- public void connect_shouldReturnFalse() {
- assertThat(mProfile.connect(mBluetoothDevice)).isFalse();
- }
-
- @Test
- public void disconnect_shouldDisconnectBluetoothHidDevice() {
- mProfile.disconnect(mBluetoothDevice);
- verify(mService).disconnect(mBluetoothDevice);
- }
-
- @Test
public void getConnectionStatus_shouldReturnConnectionState() {
when(mService.getConnectionState(mBluetoothDevice)).
thenReturn(BluetoothProfile.STATE_CONNECTED);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java
index 1425c38..25031a6 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java
@@ -16,12 +16,8 @@
package com.android.settingslib.bluetooth;
-import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
-import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
-
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
@@ -68,18 +64,6 @@
}
@Test
- public void connect_shouldConnectBluetoothMapClient() {
- mProfile.connect(mBluetoothDevice);
- verify(mService).setConnectionPolicy(mBluetoothDevice, CONNECTION_POLICY_ALLOWED);
- }
-
- @Test
- public void disconnect_shouldDisconnectBluetoothMapClient() {
- mProfile.disconnect(mBluetoothDevice);
- verify(mService).setConnectionPolicy(mBluetoothDevice, CONNECTION_POLICY_FORBIDDEN);
- }
-
- @Test
public void getConnectionStatus_shouldReturnConnectionState() {
when(mService.getConnectionState(mBluetoothDevice)).
thenReturn(BluetoothProfile.STATE_CONNECTED);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java
index 15f560b..4305a3b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java
@@ -16,12 +16,8 @@
package com.android.settingslib.bluetooth;
-import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
-import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
-
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
@@ -68,18 +64,6 @@
}
@Test
- public void connect_shouldConnectBluetoothPbapClient() {
- mProfile.connect(mBluetoothDevice);
- verify(mService).setConnectionPolicy(mBluetoothDevice, CONNECTION_POLICY_ALLOWED);
- }
-
- @Test
- public void disconnect_shouldDisconnectBluetoothPbapClient() {
- mProfile.disconnect(mBluetoothDevice);
- verify(mService).setConnectionPolicy(mBluetoothDevice, CONNECTION_POLICY_FORBIDDEN);
- }
-
- @Test
public void getConnectionStatus_shouldReturnConnectionState() {
when(mService.getConnectionState(mBluetoothDevice)).
thenReturn(BluetoothProfile.STATE_CONNECTED);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java
index 4f978a8..e460eaf 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java
@@ -16,12 +16,8 @@
package com.android.settingslib.bluetooth;
-import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
-import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
-
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
@@ -67,18 +63,6 @@
}
@Test
- public void connect_shouldConnectBluetoothSap() {
- mProfile.connect(mBluetoothDevice);
- verify(mService).setConnectionPolicy(mBluetoothDevice, CONNECTION_POLICY_ALLOWED);
- }
-
- @Test
- public void disconnect_shouldDisconnectBluetoothSap() {
- mProfile.disconnect(mBluetoothDevice);
- verify(mService).setConnectionPolicy(mBluetoothDevice, CONNECTION_POLICY_FORBIDDEN);
- }
-
- @Test
public void getConnectionStatus_shouldReturnConnectionState() {
when(mService.getConnectionState(mBluetoothDevice)).
thenReturn(BluetoothProfile.STATE_CONNECTED);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java
index f27cef9..0ee5ea8 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java
@@ -96,7 +96,7 @@
when(mA2dpProfile.getConnectableDevices()).thenReturn(devices);
when(mCachedDeviceManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
- when(mA2dpProfile.isPreferred(bluetoothDevice)).thenReturn(true);
+ when(mA2dpProfile.isEnabled(bluetoothDevice)).thenReturn(true);
assertThat(mMediaManager.mMediaDevices).isEmpty();
mMediaManager.startScan();
@@ -113,7 +113,7 @@
when(mA2dpProfile.getConnectableDevices()).thenReturn(devices);
when(mCachedDeviceManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
- when(mA2dpProfile.isPreferred(bluetoothDevice)).thenReturn(true);
+ when(mA2dpProfile.isEnabled(bluetoothDevice)).thenReturn(true);
assertThat(mMediaManager.mMediaDevices).isEmpty();
mMediaManager.startScan();
@@ -141,7 +141,7 @@
when(mHapProfile.getConnectableDevices()).thenReturn(devices);
when(mCachedDeviceManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
- when(mHapProfile.isPreferred(bluetoothDevice)).thenReturn(true);
+ when(mHapProfile.isEnabled(bluetoothDevice)).thenReturn(true);
assertThat(mMediaManager.mMediaDevices).isEmpty();
mMediaManager.startScan();
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java
index c9db0d1..2e304dc 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java
@@ -22,6 +22,9 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageStats;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
@@ -34,11 +37,14 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Shadows;
+import org.robolectric.shadows.ShadowPackageManager;
@RunWith(RobolectricTestRunner.class)
public class InfoMediaDeviceTest {
private static final String TEST_PACKAGE_NAME = "com.test.packagename";
+ private static final String TEST_PACKAGE_NAME2 = "com.test.packagename2";
private static final String TEST_ID = "test_id";
private static final String TEST_NAME = "test_name";
@@ -50,11 +56,24 @@
private Context mContext;
private InfoMediaDevice mInfoMediaDevice;
+ private ShadowPackageManager mShadowPackageManager;
+ private ApplicationInfo mAppInfo;
+ private PackageInfo mPackageInfo;
+ private PackageStats mPackageStats;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
+ mShadowPackageManager = Shadows.shadowOf(mContext.getPackageManager());
+ mAppInfo = new ApplicationInfo();
+ mAppInfo.flags = ApplicationInfo.FLAG_INSTALLED;
+ mAppInfo.packageName = TEST_PACKAGE_NAME;
+ mAppInfo.name = TEST_NAME;
+ mPackageInfo = new PackageInfo();
+ mPackageInfo.packageName = TEST_PACKAGE_NAME;
+ mPackageInfo.applicationInfo = mAppInfo;
+ mPackageStats = new PackageStats(TEST_PACKAGE_NAME);
mInfoMediaDevice = new InfoMediaDevice(mContext, mRouterManager, mRouteInfo,
TEST_PACKAGE_NAME);
@@ -95,4 +114,32 @@
verify(mRouterManager).selectRoute(TEST_PACKAGE_NAME, mRouteInfo);
}
+
+ @Test
+ public void getClientPackageName_returnPackageName() {
+ when(mRouteInfo.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+
+ assertThat(mInfoMediaDevice.getClientPackageName()).isEqualTo(TEST_PACKAGE_NAME);
+ }
+
+ @Test
+ public void getClientAppLabel_matchedPackageName_returnLabel() {
+ when(mRouteInfo.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+
+ assertThat(mInfoMediaDevice.getClientAppLabel()).isEqualTo(
+ mContext.getResources().getString(R.string.unknown));
+
+ mShadowPackageManager.addPackage(mPackageInfo, mPackageStats);
+
+ assertThat(mInfoMediaDevice.getClientAppLabel()).isEqualTo(TEST_NAME);
+ }
+
+ @Test
+ public void getClientAppLabel_noMatchedPackageName_returnDefault() {
+ mShadowPackageManager.addPackage(mPackageInfo, mPackageStats);
+ when(mRouteInfo.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME2);
+
+ assertThat(mInfoMediaDevice.getClientAppLabel()).isEqualTo(
+ mContext.getResources().getString(R.string.unknown));
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
index c780a64..15aaa82 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
@@ -384,4 +384,38 @@
verify(mCallback).onDeviceAttributesChanged();
}
+
+ @Test
+ public void getActiveMediaDevice_checkList() {
+ final List<MediaDevice> devices = new ArrayList<>();
+ final MediaDevice device1 = mock(MediaDevice.class);
+ final MediaDevice device2 = mock(MediaDevice.class);
+ final MediaDevice device3 = mock(MediaDevice.class);
+ device1.mType = MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE;
+ device2.mType = MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE;
+ device3.mType = MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE;
+ when(device1.getClientPackageName()).thenReturn(TEST_DEVICE_ID_1);
+ when(device2.getClientPackageName()).thenReturn(TEST_DEVICE_ID_2);
+ when(device3.getClientPackageName()).thenReturn(TEST_DEVICE_ID_3);
+ when(device1.getId()).thenReturn(TEST_DEVICE_ID_1);
+ when(device2.getId()).thenReturn(TEST_DEVICE_ID_2);
+ when(device3.getId()).thenReturn(TEST_DEVICE_ID_3);
+ devices.add(device1);
+ devices.add(device2);
+ devices.add(device3);
+ mLocalMediaManager.registerCallback(mCallback);
+ mLocalMediaManager.mMediaDeviceCallback.onDeviceListAdded(devices);
+
+ List<MediaDevice> activeDevices = mLocalMediaManager.getActiveMediaDevice(
+ MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE);
+ assertThat(activeDevices).containsExactly(device1);
+
+ activeDevices = mLocalMediaManager.getActiveMediaDevice(
+ MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE);
+ assertThat(activeDevices).containsExactly(device2);
+
+ activeDevices = mLocalMediaManager.getActiveMediaDevice(
+ MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE);
+ assertThat(activeDevices).containsExactly(device3);
+ }
}
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
index d67a9bc..8ff595b 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
@@ -33,7 +33,6 @@
import android.provider.Settings;
import android.util.Log;
-import org.junit.Ignore;
import org.junit.Test;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -692,125 +691,4 @@
cursor.close();
}
}
-
- @Test
- @Ignore("b/140250974")
- public void testLocationModeChanges_viaFrontEndApi() throws Exception {
- setStringViaFrontEndApiSetting(
- SETTING_TYPE_SECURE,
- Settings.Secure.LOCATION_MODE,
- String.valueOf(Settings.Secure.LOCATION_MODE_OFF),
- UserHandle.USER_SYSTEM);
- assertEquals(
- "Wrong location providers",
- "",
- getStringViaFrontEndApiSetting(
- SETTING_TYPE_SECURE,
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- UserHandle.USER_SYSTEM));
-
- setStringViaFrontEndApiSetting(
- SETTING_TYPE_SECURE,
- Settings.Secure.LOCATION_MODE,
- String.valueOf(Settings.Secure.LOCATION_MODE_BATTERY_SAVING),
- UserHandle.USER_SYSTEM);
- assertEquals(
- "Wrong location providers",
- "network",
- getStringViaFrontEndApiSetting(
- SETTING_TYPE_SECURE,
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- UserHandle.USER_SYSTEM));
-
- setStringViaFrontEndApiSetting(
- SETTING_TYPE_SECURE,
- Settings.Secure.LOCATION_MODE,
- String.valueOf(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY),
- UserHandle.USER_SYSTEM);
- assertEquals(
- "Wrong location providers",
- "gps,network",
- getStringViaFrontEndApiSetting(
- SETTING_TYPE_SECURE,
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- UserHandle.USER_SYSTEM));
- }
-
- @Test
- @Ignore("b/140250974")
- public void testLocationProvidersAllowed_disableProviders() throws Exception {
- setStringViaFrontEndApiSetting(
- SETTING_TYPE_SECURE,
- Settings.Secure.LOCATION_MODE,
- String.valueOf(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY),
- UserHandle.USER_SYSTEM);
-
- // Disable providers that were enabled
- updateStringViaProviderApiSetting(
- SETTING_TYPE_SECURE,
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- "-gps,-network");
- assertEquals(
- "Wrong location providers",
- "",
- queryStringViaProviderApi(
- SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
-
- // Disable a provider that was not enabled
- updateStringViaProviderApiSetting(
- SETTING_TYPE_SECURE,
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- "-test");
- assertEquals(
- "Wrong location providers",
- "",
- queryStringViaProviderApi(
- SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
- }
-
- @Test
- @Ignore("b/140250974")
- public void testLocationProvidersAllowed_enableAndDisable() throws Exception {
- setStringViaFrontEndApiSetting(
- SETTING_TYPE_SECURE,
- Settings.Secure.LOCATION_MODE,
- String.valueOf(Settings.Secure.LOCATION_MODE_OFF),
- UserHandle.USER_SYSTEM);
-
- updateStringViaProviderApiSetting(
- SETTING_TYPE_SECURE,
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- "+gps,+network,+test");
- updateStringViaProviderApiSetting(
- SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "-test");
-
- assertEquals(
- "Wrong location providers",
- "gps,network",
- queryStringViaProviderApi(
- SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
- }
-
- @Test
- @Ignore("b/140250974")
- public void testLocationProvidersAllowedLocked_invalidInput() throws Exception {
- setStringViaFrontEndApiSetting(
- SETTING_TYPE_SECURE,
- Settings.Secure.LOCATION_MODE,
- String.valueOf(Settings.Secure.LOCATION_MODE_OFF),
- UserHandle.USER_SYSTEM);
-
- // update providers with a invalid string
- updateStringViaProviderApiSetting(
- SETTING_TYPE_SECURE,
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- "+gps, invalid-string");
-
- // Verifies providers list does not change
- assertEquals(
- "Wrong location providers",
- "",
- queryStringViaProviderApi(
- SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
- }
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 6a89b71..1d679c7 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -223,6 +223,11 @@
<!-- permissions required for CTS test - PhoneStateListenerTest -->
<uses-permission android:name="android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH" />
+ <!-- Permissions required for ganting and logging -->
+ <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.OVERRIDE_COMPAT_CHANGE_CONFIG"/>
+
<!-- Permission required for CTS test - UiModeManagerTest -->
<uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED"/>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 139a8c3..1fe967b 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -645,7 +645,6 @@
<activity android:name=".controls.management.ControlsProviderSelectorActivity"
android:label="Controls Providers"
android:theme="@style/Theme.ControlsManagement"
- android:exported="true"
android:showForAllUsers="true"
android:excludeFromRecents="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
diff --git a/packages/SystemUI/res-keyguard/values/config.xml b/packages/SystemUI/res-keyguard/values/config.xml
index bde6ed5..8d9d6ee 100644
--- a/packages/SystemUI/res-keyguard/values/config.xml
+++ b/packages/SystemUI/res-keyguard/values/config.xml
@@ -22,10 +22,4 @@
<!-- Allow the menu hard key to be disabled in LockScreen on some devices [DO NOT TRANSLATE] -->
<bool name="config_disableMenuKeyInLockScreen">false</bool>
-
- <!-- Threshold in micro watts below which a charger is rated as "slow"; 1A @ 5V -->
- <integer name="config_chargingSlowlyThreshold">5000000</integer>
-
- <!-- Threshold in micro watts above which a charger is rated as "fast"; 1.5A @ 5V -->
- <integer name="config_chargingFastThreshold">7500000</integer>
</resources>
diff --git a/packages/SystemUI/res/drawable/ic_device_unknown_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_device_unknown_gm2_24px.xml
new file mode 100644
index 0000000..24e0635
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_device_unknown_gm2_24px.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12,2l-5.5,9h11L12,2zM12,5.84L13.93,9h-3.87L12,5.84zM17.5,13c-2.49,0 -4.5,2.01 -4.5,4.5s2.01,4.5 4.5,4.5 4.5,-2.01 4.5,-4.5 -2.01,-4.5 -4.5,-4.5zM17.5,20c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5 2.5,1.12 2.5,2.5 -1.12,2.5 -2.5,2.5zM3,21.5h8v-8L3,13.5v8zM5,15.5h4v4L5,19.5v-4z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_touch.xml b/packages/SystemUI/res/drawable/ic_touch.xml
new file mode 100644
index 0000000..4f6698d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_touch.xml
@@ -0,0 +1,26 @@
+<!--
+Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- maybe need android:fillType="evenOdd" -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M9,7.5V11.24C7.79,10.43 7,9.06 7,7.5C7,5.01 9.01,3 11.5,3C13.99,3 16,5.01 16,7.5C16,9.06 15.21,10.43 14,11.24V7.5C14,6.12 12.88,5 11.5,5C10.12,5 9,6.12 9,7.5ZM14.3,13.61L18.84,15.87C19.37,16.09 19.75,16.63 19.75,17.25C19.75,17.31 19.74,17.38 19.73,17.45L18.98,22.72C18.87,23.45 18.29,24 17.54,24H10.75C10.34,24 9.96,23.83 9.69,23.56L4.75,18.62L5.54,17.82C5.74,17.62 6.02,17.49 6.33,17.49C6.39,17.49 6.4411,17.4989 6.4922,17.5078C6.5178,17.5122 6.5433,17.5167 6.57,17.52L10,18.24V7.5C10,6.67 10.67,6 11.5,6C12.33,6 13,6.67 13,7.5V13.5H13.76C13.95,13.5 14.13,13.54 14.3,13.61Z"
+ />
+</vector>
diff --git a/packages/SystemUI/res/layout/auth_credential_password_view.xml b/packages/SystemUI/res/layout/auth_credential_password_view.xml
index a1c593f..b14bc7d 100644
--- a/packages/SystemUI/res/layout/auth_credential_password_view.xml
+++ b/packages/SystemUI/res/layout/auth_credential_password_view.xml
@@ -73,6 +73,7 @@
android:layout_width="208dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
+ android:minHeight="48dp"
android:gravity="center"
android:inputType="textPassword"
android:maxLength="500"
diff --git a/packages/SystemUI/res/layout/screen_record_dialog.xml b/packages/SystemUI/res/layout/screen_record_dialog.xml
new file mode 100644
index 0000000..df576d8
--- /dev/null
+++ b/packages/SystemUI/res/layout/screen_record_dialog.xml
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:background="@drawable/rounded_bg_full">
+
+ <!-- Header -->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:padding="@dimen/screenrecord_dialog_padding">
+ <ImageView
+ android:layout_width="@dimen/screenrecord_logo_size"
+ android:layout_height="@dimen/screenrecord_logo_size"
+ android:src="@drawable/ic_screenrecord"
+ android:tint="@color/GM2_red_500"
+ android:layout_marginBottom="@dimen/screenrecord_dialog_padding"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:text="@string/screenrecord_start_label"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/screenrecord_description"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:paddingTop="@dimen/screenrecord_dialog_padding"
+ android:paddingBottom="@dimen/screenrecord_dialog_padding"/>
+
+ <!-- Options -->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <ImageView
+ android:layout_width="@dimen/screenrecord_logo_size"
+ android:layout_height="@dimen/screenrecord_logo_size"
+ android:src="@drawable/ic_mic_26dp"
+ android:tint="@color/GM2_grey_700"
+ android:layout_gravity="center"
+ android:layout_weight="0"
+ android:layout_marginRight="@dimen/screenrecord_dialog_padding"/>
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_weight="1">
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
+ android:text="@string/screenrecord_audio_label"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/audio_type"
+ android:text="@string/screenrecord_mic_label"
+ android:textAppearance="?android:attr/textAppearanceSmall"/>
+ </LinearLayout>
+ <Switch
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_weight="0"
+ android:id="@+id/screenrecord_audio_switch"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <ImageView
+ android:layout_width="@dimen/screenrecord_logo_size"
+ android:layout_height="@dimen/screenrecord_logo_size"
+ android:src="@drawable/ic_touch"
+ android:tint="@color/GM2_grey_700"
+ android:layout_gravity="center"
+ android:layout_marginRight="@dimen/screenrecord_dialog_padding"/>
+ <Switch
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:id="@+id/screenrecord_taps_switch"
+ android:text="@string/screenrecord_taps_label"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+ </LinearLayout>
+ </LinearLayout>
+
+ <!-- hr -->
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@color/GM2_grey_300"/>
+
+ <!-- Buttons -->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:padding="@dimen/screenrecord_dialog_padding">
+ <Button
+ android:id="@+id/button_cancel"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:layout_gravity="start"
+ android:text="@string/cancel"
+ style="@android:style/Widget.DeviceDefault.Button.Borderless.Colored"/>
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"/>
+ <Button
+ android:id="@+id/button_start"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:layout_gravity="end"
+ android:text="@string/screenrecord_start"
+ style="@android:style/Widget.DeviceDefault.Button.Colored"/>
+ </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 9c997e8..c4fa4e5 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1090,7 +1090,7 @@
<!-- Blur radius on status bar window and power menu -->
<dimen name="min_window_blur_radius">1px</dimen>
- <dimen name="max_window_blur_radius">100px</dimen>
+ <dimen name="max_window_blur_radius">250px</dimen>
<!-- How much into a DisplayCutout's bounds we can go, on each side -->
<dimen name="display_cutout_margin_consumption">0px</dimen>
@@ -1209,5 +1209,7 @@
<dimen name="controls_card_margin">2dp</dimen>
-
+ <!-- Screen Record -->
+ <dimen name="screenrecord_dialog_padding">18dp</dimen>
+ <dimen name="screenrecord_logo_size">24dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 07a926f..b85b51e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -217,15 +217,31 @@
your organization</string>
<!-- Notification title displayed for screen recording [CHAR LIMIT=50]-->
- <string name="screenrecord_name">Screen Recording</string>
+ <string name="screenrecord_name">Screen Recorder</string>
<!-- Description of the screen recording notification channel [CHAR LIMIT=NONE]-->
<string name="screenrecord_channel_description">Ongoing notification for a screen record session</string>
- <!-- Label for the button to begin screen recording [CHAR LIMIT=NONE]-->
- <string name="screenrecord_start_label">Start Recording</string>
- <!-- Label for the checkbox to enable microphone input during screen recording [CHAR LIMIT=NONE]-->
- <string name="screenrecord_mic_label">Record voiceover</string>
+ <!-- Title for the screen prompting the user to begin recording their screen [CHAR LIMIT=NONE]-->
+ <string name="screenrecord_start_label">Start Recording?</string>
+ <!-- Message reminding the user that sensitive information may be captured during a screen recording [CHAR_LIMIT=NONE]-->
+ <string name="screenrecord_description">While recording, Android System can capture any sensitive information that\u2019s visible on your screen or played on your device. This includes passwords, payment info, photos, messages, and audio.</string>
+ <!-- Label for a switch to enable recording audio [CHAR LIMIT=NONE]-->
+ <string name="screenrecord_audio_label">Record audio</string>
+ <!-- Label for the option to record audio from the device [CHAR LIMIT=NONE]-->
+ <string name="screenrecord_device_audio_label">Device audio</string>
+ <!-- Description of what audio may be captured from the device [CHAR LIMIT=NONE]-->
+ <string name="screenrecord_device_audio_description">Sound from your device, like music, calls, and ringtones</string>
+ <!-- Label for the option to enable microphone input during screen recording [CHAR LIMIT=NONE]-->
+ <string name="screenrecord_mic_label">Microphone</string>
+ <!-- Label for an option to record audio from both device and microphone [CHAR LIMIT=NONE]-->
+ <string name="screenrecord_device_audio_and_mic_label">Device audio and microphone</string>
+ <!-- Button to start a screen recording [CHAR LIMIT=50]-->
+ <string name="screenrecord_start">Start</string>
+ <!-- Notification text displayed when we are recording the screen [CHAR LIMIT=100]-->
+ <string name="screenrecord_ongoing_screen_only">Recording screen</string>
+ <!-- Notification text displayed when we are recording both the screen and audio [CHAR LIMIT=100]-->
+ <string name="screenrecord_ongoing_screen_and_audio">Recording screen and audio</string>
<!-- Label for the checkbox to enable showing location of touches during screen recording [CHAR LIMIT=NONE]-->
- <string name="screenrecord_taps_label">Show taps</string>
+ <string name="screenrecord_taps_label">Show touches on screen</string>
<!-- Label for notification that the user can tap to stop and save the screen recording [CHAR LIMIT=NONE] -->
<string name="screenrecord_stop_text">Tap to stop</string>
<!-- Label for notification action to stop and save the screen recording [CHAR LIMIT=35] -->
@@ -250,6 +266,8 @@
<string name="screenrecord_delete_error">Error deleting screen recording</string>
<!-- A toast message shown when the screen recording cannot be started due to insufficient permissions [CHAR LIMIT=NONE] -->
<string name="screenrecord_permission_error">Failed to get permissions</string>
+ <!-- A toast message shown when the screen recording cannot be started due to a generic error [CHAR LIMIT=NONE] -->
+ <string name="screenrecord_start_error">Error starting screen recording</string>
<!-- Title for the USB function chooser in UsbPreferenceActivity. [CHAR LIMIT=30] -->
<string name="usb_preference_title">USB file transfer options</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
index b2423b9..85724a9 100644
--- a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
+++ b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
@@ -27,7 +27,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
-import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup;
@@ -47,7 +47,6 @@
private Handler mHandler;
private IKeyguardClient mClient;
private KeyguardSecurityCallback mKeyguardCallback;
- private SurfaceControl.Transaction mTransaction;
private final ServiceConnection mConnection = new ServiceConnection() {
@Override
@@ -84,13 +83,13 @@
}
@Override
- public void onSurfaceControlCreated(@Nullable SurfaceControl remoteSurfaceControl) {
+ public void onRemoteContentReady(
+ @Nullable SurfaceControlViewHost.SurfacePackage surfacePackage) {
if (mHandler != null) {
mHandler.removeCallbacksAndMessages(null);
}
- if (remoteSurfaceControl != null) {
- mTransaction.reparent(remoteSurfaceControl, mView.getSurfaceControl())
- .apply();
+ if (surfacePackage != null) {
+ mView.setChildSurfacePackage(surfacePackage);
} else {
dismiss(KeyguardUpdateMonitor.getCurrentUser());
}
@@ -138,11 +137,10 @@
public AdminSecondaryLockScreenController(Context context, ViewGroup parent,
KeyguardUpdateMonitor updateMonitor, KeyguardSecurityCallback callback,
- Handler handler, SurfaceControl.Transaction transaction) {
+ Handler handler) {
mContext = context;
mHandler = handler;
mParent = parent;
- mTransaction = transaction;
mUpdateMonitor = updateMonitor;
mKeyguardCallback = callback;
mView = new AdminSecurityView(mContext, mSurfaceHolderCallback);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 29c67ae..ba8a1a9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -39,7 +39,6 @@
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.MotionEvent;
-import android.view.SurfaceControl;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
@@ -149,8 +148,7 @@
mViewConfiguration = ViewConfiguration.get(context);
mKeyguardStateController = Dependency.get(KeyguardStateController.class);
mSecondaryLockScreenController = new AdminSecondaryLockScreenController(context, this,
- mUpdateMonitor, mCallback, new Handler(Looper.myLooper()),
- new SurfaceControl.Transaction());
+ mUpdateMonitor, mCallback, new Handler(Looper.myLooper()));
}
public void setSecurityCallback(SecurityCallback callback) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 6a04583..e5f6d3c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -21,15 +21,7 @@
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.ACTION_USER_STOPPED;
import static android.content.Intent.ACTION_USER_UNLOCKED;
-import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
-import static android.os.BatteryManager.BATTERY_STATUS_FULL;
import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
-import static android.os.BatteryManager.EXTRA_HEALTH;
-import static android.os.BatteryManager.EXTRA_LEVEL;
-import static android.os.BatteryManager.EXTRA_MAX_CHARGING_CURRENT;
-import static android.os.BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE;
-import static android.os.BatteryManager.EXTRA_PLUGGED;
-import static android.os.BatteryManager.EXTRA_STATUS;
import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
import static android.telephony.TelephonyManager.MODEM_COUNT_DUAL_MODEM;
@@ -67,7 +59,6 @@
import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
import android.media.AudioManager;
-import android.os.BatteryManager;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IRemoteCallback;
@@ -94,6 +85,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.LockPatternUtils;
import com.android.settingslib.WirelessUtils;
+import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.systemui.DejankUtils;
import com.android.systemui.DumpController;
import com.android.systemui.Dumpable;
@@ -1059,29 +1051,9 @@
MSG_TIMEZONE_UPDATE, intent.getStringExtra("time-zone"));
mHandler.sendMessage(msg);
} else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
- final int status = intent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN);
- final int plugged = intent.getIntExtra(EXTRA_PLUGGED, 0);
- final int level = intent.getIntExtra(EXTRA_LEVEL, 0);
- final int health = intent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN);
- final int maxChargingMicroAmp = intent.getIntExtra(EXTRA_MAX_CHARGING_CURRENT, -1);
- int maxChargingMicroVolt = intent.getIntExtra(EXTRA_MAX_CHARGING_VOLTAGE, -1);
- final int maxChargingMicroWatt;
-
- if (maxChargingMicroVolt <= 0) {
- maxChargingMicroVolt = DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT;
- }
- if (maxChargingMicroAmp > 0) {
- // Calculating muW = muA * muV / (10^6 mu^2 / mu); splitting up the divisor
- // to maintain precision equally on both factors.
- maxChargingMicroWatt = (maxChargingMicroAmp / 1000)
- * (maxChargingMicroVolt / 1000);
- } else {
- maxChargingMicroWatt = -1;
- }
final Message msg = mHandler.obtainMessage(
- MSG_BATTERY_UPDATE, new BatteryStatus(status, level, plugged, health,
- maxChargingMicroWatt));
+ MSG_BATTERY_UPDATE, new BatteryStatus(intent));
mHandler.sendMessage(msg);
} else if (Intent.ACTION_SIM_STATE_CHANGED.equals(action)) {
SimData args = SimData.fromIntent(intent);
@@ -1323,82 +1295,6 @@
}
}
- public static class BatteryStatus {
- public static final int CHARGING_UNKNOWN = -1;
- public static final int CHARGING_SLOWLY = 0;
- public static final int CHARGING_REGULAR = 1;
- public static final int CHARGING_FAST = 2;
-
- public final int status;
- public final int level;
- public final int plugged;
- public final int health;
- public final int maxChargingWattage;
-
- public BatteryStatus(int status, int level, int plugged, int health,
- int maxChargingWattage) {
- this.status = status;
- this.level = level;
- this.plugged = plugged;
- this.health = health;
- this.maxChargingWattage = maxChargingWattage;
- }
-
- /**
- * Determine whether the device is plugged in (USB, power, or wireless).
- *
- * @return true if the device is plugged in.
- */
- public boolean isPluggedIn() {
- return plugged == BatteryManager.BATTERY_PLUGGED_AC
- || plugged == BatteryManager.BATTERY_PLUGGED_USB
- || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS;
- }
-
- /**
- * Determine whether the device is plugged in (USB, power).
- *
- * @return true if the device is plugged in wired (as opposed to wireless)
- */
- public boolean isPluggedInWired() {
- return plugged == BatteryManager.BATTERY_PLUGGED_AC
- || plugged == BatteryManager.BATTERY_PLUGGED_USB;
- }
-
- /**
- * Whether or not the device is charged. Note that some devices never return 100% for
- * battery level, so this allows either battery level or status to determine if the
- * battery is charged.
- *
- * @return true if the device is charged
- */
- public boolean isCharged() {
- return status == BATTERY_STATUS_FULL || level >= 100;
- }
-
- /**
- * Whether battery is low and needs to be charged.
- *
- * @return true if battery is low
- */
- public boolean isBatteryLow() {
- return level < LOW_BATTERY_THRESHOLD;
- }
-
- public final int getChargingSpeed(int slowThreshold, int fastThreshold) {
- return maxChargingWattage <= 0 ? CHARGING_UNKNOWN :
- maxChargingWattage < slowThreshold ? CHARGING_SLOWLY :
- maxChargingWattage > fastThreshold ? CHARGING_FAST :
- CHARGING_REGULAR;
- }
-
- @Override
- public String toString() {
- return "BatteryStatus{status=" + status + ",level=" + level + ",plugged=" + plugged
- + ",health=" + health + ",maxChargingWattage=" + maxChargingWattage + "}";
- }
- }
-
public static class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
private final Consumer<Integer> mStrongAuthRequiredChangedCallback;
@@ -2640,9 +2536,9 @@
*/
private boolean refreshSimState(int subId, int slotId) {
final TelephonyManager tele =
- (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
int state = (tele != null) ?
- tele.getSimState(slotId) : TelephonyManager.SIM_STATE_UNKNOWN;
+ tele.getSimState(slotId) : TelephonyManager.SIM_STATE_UNKNOWN;
SimData data = mSimDatas.get(subId);
final boolean changed;
if (data == null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 8e87b7a..49f72a9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -23,6 +23,7 @@
import android.telephony.TelephonyManager;
import android.view.WindowManagerPolicyConstants;
+import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.systemui.statusbar.KeyguardIndicationController;
import java.util.TimeZone;
@@ -42,7 +43,7 @@
*
* @param status current battery status
*/
- public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) { }
+ public void onRefreshBatteryInfo(BatteryStatus status) { }
/**
* Called once per minute or when the time changes.
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 5c65977..8a492a8 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -87,7 +87,7 @@
@VisibleForTesting @Nullable AuthBiometricView mBiometricView;
@VisibleForTesting @Nullable AuthCredentialView mCredentialView;
- private final ImageView mBackgroundView;
+ @VisibleForTesting final ImageView mBackgroundView;
@VisibleForTesting final ScrollView mBiometricScrollView;
private final View mPanelView;
@@ -333,6 +333,12 @@
throw new IllegalStateException("Unknown credential type: " + credentialType);
}
+ // The background is used for detecting taps / cancelling authentication. Since the
+ // credential view is full-screen and should not be canceled from background taps,
+ // disable it.
+ mBackgroundView.setOnClickListener(null);
+ mBackgroundView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
+
mCredentialView.setContainerView(this);
mCredentialView.setEffectiveUserId(mEffectiveUserId);
mCredentialView.setCredentialType(credentialType);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 7c07c9d..792b940 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -44,19 +44,13 @@
import android.annotation.UserIdInt;
import android.app.ActivityManager.RunningTaskInfo;
-import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.app.RemoteInput;
import android.content.Context;
-import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ShortcutManager;
import android.content.res.Configuration;
import android.graphics.Rect;
-import android.net.Uri;
-import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.service.notification.NotificationListenerService.RankingMap;
@@ -75,7 +69,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.util.ScreenshotHelper;
import com.android.systemui.R;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -93,7 +86,6 @@
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.statusbar.policy.ZenModeController;
import java.io.FileDescriptor;
@@ -101,10 +93,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.function.Consumer;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -146,8 +136,6 @@
@Nullable private BubbleStackView.SurfaceSynchronizer mSurfaceSynchronizer;
private final NotificationGroupManager mNotificationGroupManager;
private final ShadeController mShadeController;
- private final RemoteInputUriController mRemoteInputUriController;
- private Handler mHandler = new Handler() {};
private BubbleData mBubbleData;
@Nullable private BubbleStackView mStackView;
@@ -171,7 +159,6 @@
private final NotificationShadeWindowController mNotificationShadeWindowController;
private final ZenModeController mZenModeController;
private StatusBarStateListener mStatusBarStateListener;
- private final ScreenshotHelper mScreenshotHelper;
// Callback that updates BubbleOverflowActivity on data change.
@Nullable private Runnable mOverflowCallback = null;
@@ -217,16 +204,6 @@
}
/**
- * Listener for handling bubble screenshot events.
- */
- public interface BubbleScreenshotListener {
- /**
- * Called to trigger taking a screenshot and sending the result to a bubble.
- */
- void onBubbleScreenshot(Bubble bubble);
- }
-
- /**
* Listener to be notified when a bubbles' notification suppression state changes.
*/
public interface NotificationSuppressionChangedListener {
@@ -300,12 +277,10 @@
ZenModeController zenModeController,
NotificationLockscreenUserManager notifUserManager,
NotificationGroupManager groupManager,
- NotificationEntryManager entryManager,
- RemoteInputUriController remoteInputUriController) {
+ NotificationEntryManager entryManager) {
this(context, notificationShadeWindowController, statusBarStateController, shadeController,
data, null /* synchronizer */, configurationController, interruptionStateProvider,
- zenModeController, notifUserManager, groupManager, entryManager,
- remoteInputUriController);
+ zenModeController, notifUserManager, groupManager, entryManager);
}
public BubbleController(Context context,
@@ -319,14 +294,12 @@
ZenModeController zenModeController,
NotificationLockscreenUserManager notifUserManager,
NotificationGroupManager groupManager,
- NotificationEntryManager entryManager,
- RemoteInputUriController remoteInputUriController) {
+ NotificationEntryManager entryManager) {
mContext = context;
mShadeController = shadeController;
mNotificationInterruptionStateProvider = interruptionStateProvider;
mNotifUserManager = notifUserManager;
mZenModeController = zenModeController;
- mRemoteInputUriController = remoteInputUriController;
mZenModeController.addCallback(new ZenModeController.Callback() {
@Override
public void onZenChanged(int zen) {
@@ -399,7 +372,6 @@
mUserCreatedBubbles = new HashSet<>();
mUserBlockedBubbles = new HashSet<>();
- mScreenshotHelper = new ScreenshotHelper(context);
mBubbleIconFactory = new BubbleIconFactory(context);
}
@@ -536,9 +508,6 @@
if (mExpandListener != null) {
mStackView.setExpandListener(mExpandListener);
}
- if (mBubbleScreenshotListener != null) {
- mStackView.setBubbleScreenshotListener(mBubbleScreenshotListener);
- }
}
}
@@ -970,7 +939,7 @@
* The cancellation of summaries with children associated with bubbles are also handled in this
* method. User-cancelled summaries are tracked by {@link BubbleData#addSummaryToSuppress}.
*
- * @return true if we want to intercept the dismissal of the entry, else false
+ * @return true if we want to intercept the dismissal of the entry, else false.
*/
public boolean shouldInterceptDismissal(NotificationEntry entry, int dismissReason) {
if (entry == null) {
@@ -1010,7 +979,8 @@
// The bubble notification sticks around in the data as long as the bubble is
// not dismissed and the app hasn't cancelled the notification.
Bubble bubble = mBubbleData.getBubbleWithKey(key);
- boolean bubbleExtended = entry != null && entry.isBubble() && userRemovedNotif;
+ boolean bubbleExtended = entry != null && entry.isBubble()
+ && (userRemovedNotif || isUserCreatedBubble(bubble.getKey()));
if (bubbleExtended) {
bubble.setSuppressNotification(true);
bubble.setShowDot(false /* show */, true /* animate */);
@@ -1019,8 +989,7 @@
+ ".shouldInterceptDismissal");
}
return true;
- } else if (!userRemovedNotif && entry != null
- && !isUserCreatedBubble(bubble.getKey())) {
+ } else if (!userRemovedNotif && entry != null) {
// This wasn't a user removal so we should remove the bubble as well
mBubbleData.notificationEntryRemoved(entry, DISMISS_NOTIF_CANCEL);
return false;
@@ -1267,68 +1236,4 @@
}
}
}
-
- // TODO: Copied from RemoteInputView. Consolidate RemoteInput intent logic.
- private Intent prepareRemoteInputFromData(String contentType, Uri data,
- RemoteInput remoteInput, NotificationEntry entry) {
- HashMap<String, Uri> results = new HashMap<>();
- results.put(contentType, data);
- mRemoteInputUriController.grantInlineReplyUriPermission(entry.getSbn(), data);
- Intent fillInIntent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- RemoteInput.addDataResultToIntent(remoteInput, fillInIntent, results);
-
- return fillInIntent;
- }
-
- // TODO: Copied from RemoteInputView. Consolidate RemoteInput intent logic.
- private void sendRemoteInput(Intent intent, NotificationEntry entry,
- PendingIntent pendingIntent) {
- // Tell ShortcutManager that this package has been "activated". ShortcutManager
- // will reset the throttling for this package.
- // Strictly speaking, the intent receiver may be different from the notification publisher,
- // but that's an edge case, and also because we can't always know which package will receive
- // an intent, so we just reset for the publisher.
- mContext.getSystemService(ShortcutManager.class).onApplicationActive(
- entry.getSbn().getPackageName(),
- entry.getSbn().getUser().getIdentifier());
-
- try {
- pendingIntent.send(mContext, 0, intent);
- } catch (PendingIntent.CanceledException e) {
- Log.i(TAG, "Unable to send remote input result", e);
- }
- }
-
- private void sendScreenshotToBubble(Bubble bubble) {
- mScreenshotHelper.takeScreenshot(
- android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN,
- true /* hasStatus */,
- true /* hasNav */,
- mHandler,
- new Consumer<Uri>() {
- @Override
- public void accept(Uri uri) {
- if (uri != null) {
- NotificationEntry entry = bubble.getEntry();
- Pair<RemoteInput, Notification.Action> pair = entry.getSbn()
- .getNotification().findRemoteInputActionPair(false);
- if (pair != null) {
- RemoteInput remoteInput = pair.first;
- Notification.Action action = pair.second;
- Intent dataIntent = prepareRemoteInputFromData("image/png", uri,
- remoteInput, entry);
- sendRemoteInput(dataIntent, entry, action.actionIntent);
- mBubbleData.setSelectedBubble(bubble);
- mBubbleData.setExpanded(true);
- } else {
- Log.w(TAG, "No RemoteInput found for notification: "
- + entry.getSbn().getKey());
- }
- }
- }
- });
- }
-
- private final BubbleScreenshotListener mBubbleScreenshotListener =
- bubble -> sendScreenshotToBubble(bubble);
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
index 006de84..20b3386 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
@@ -73,9 +73,6 @@
private static final String WHITELISTED_AUTO_BUBBLE_APPS = "whitelisted_auto_bubble_apps";
- private static final String ALLOW_BUBBLE_MENU = "allow_bubble_screenshot_menu";
- private static final boolean ALLOW_BUBBLE_MENU_DEFAULT = false;
-
private static final String ALLOW_BUBBLE_OVERFLOW = "allow_bubble_overflow";
private static final boolean ALLOW_BUBBLE_OVERFLOW_DEFAULT = false;
@@ -137,16 +134,6 @@
* When true, show a menu when a bubble is long-pressed, which will allow the user to take
* actions on that bubble.
*/
- static boolean allowBubbleScreenshotMenu(Context context) {
- return Settings.Secure.getInt(context.getContentResolver(),
- ALLOW_BUBBLE_MENU,
- ALLOW_BUBBLE_MENU_DEFAULT ? 1 : 0) != 0;
- }
-
- /**
- * When true, show a menu when a bubble is long-pressed, which will allow the user to take
- * actions on that bubble.
- */
static boolean allowBubbleOverflow(Context context) {
return Settings.Secure.getInt(context.getContentResolver(),
ALLOW_BUBBLE_OVERFLOW,
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleMenuView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleMenuView.java
deleted file mode 100644
index bf83065..0000000
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleMenuView.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.bubbles;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-
-import com.android.systemui.R;
-
-/**
- * Menu which allows users to take actions on bubbles, ex. screenshots.
- */
-public class BubbleMenuView extends FrameLayout {
- private FrameLayout mMenu;
- private boolean mShowing = false;
-
- /** Delay before taking a screenshot once the button is tapped to allow the menu time to hide.*/
- public static final long SCREENSHOT_DELAY = 200;
-
- public BubbleMenuView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public BubbleMenuView(Context context) {
- super(context);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mMenu = findViewById(R.id.bubble_menu_view);
- ImageView icon = findViewById(com.android.internal.R.id.icon);
- icon.setImageDrawable(mContext.getDrawable(com.android.internal.R.drawable.ic_screenshot));
- }
-
- /**
- * Get the bubble menu view.
- */
- public View getMenuView() {
- return mMenu;
- }
-
- /**
- * Checks whether the bubble menu is currently displayed.
- */
- public boolean isShowing() {
- return mShowing;
- }
-
- /**
- * Show the bubble menu at the specified position on the screen.
- */
- public void show(float x, float y) {
- mShowing = true;
- this.setVisibility(VISIBLE);
- mMenu.setTranslationX(x);
- mMenu.setTranslationY(y);
- }
-
- /**
- * Hide the bubble menu.
- */
- public void hide() {
- mShowing = false;
- this.setVisibility(GONE);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 6062a3d..bce172b 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -115,7 +115,6 @@
/** How long to wait, in milliseconds, before hiding the flyout. */
@VisibleForTesting
static final int FLYOUT_HIDE_AFTER = 5000;
- private BubbleController.BubbleScreenshotListener mBubbleScreenshotListener;
/**
* Interface to synchronize {@link View} state and the screen.
@@ -169,7 +168,6 @@
private ExpandedAnimationController mExpandedAnimationController;
private FrameLayout mExpandedViewContainer;
- @Nullable private BubbleMenuView mBubbleMenuView;
private BubbleFlyoutView mFlyout;
/** Runnable that fades out the flyout and then sets it to GONE. */
@@ -516,9 +514,6 @@
mDesaturateAndDarkenPaint.setColorFilter(new ColorMatrixColorFilter(animatedMatrix));
mDesaturateAndDarkenTargetView.setLayerPaint(mDesaturateAndDarkenPaint);
});
-
- mInflater.inflate(R.layout.bubble_menu_view, this);
- mBubbleMenuView = findViewById(R.id.bubble_menu_container);
}
private void setUpOverflow() {
@@ -533,10 +528,6 @@
mBubbleContainer.addView(mOverflowBtn, 0,
new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
- mOverflowBtn.setOnClickListener(v -> {
- setSelectedBubble(null);
- });
-
TypedArray ta = mContext.obtainStyledAttributes(
new int[]{android.R.attr.colorBackgroundFloating});
int bgColor = ta.getColor(0, Color.WHITE /* default */);
@@ -742,13 +733,6 @@
}
/**
- * Sets the screenshot listener.
- */
- public void setBubbleScreenshotListener(BubbleController.BubbleScreenshotListener listener) {
- mBubbleScreenshotListener = listener;
- }
-
- /**
* Whether the stack of bubbles is expanded or not.
*/
public boolean isExpanded() {
@@ -856,6 +840,10 @@
updateBubbleZOrdersAndDotPosition(false /* animate */);
}
+ void showOverflow() {
+ setSelectedBubble(null);
+ }
+
/**
* Changes the currently selected bubble. If the stack is already expanded, the newly selected
* bubble will be shown immediately. This does not change the expanded state or change the
@@ -942,14 +930,12 @@
public View getTargetView(MotionEvent event) {
float x = event.getRawX();
float y = event.getRawY();
- if (mBubbleMenuView.isShowing()) {
- if (isIntersecting(mBubbleMenuView.getMenuView(), x, y)) {
- return mBubbleMenuView;
- }
- return null;
- }
if (mIsExpanded) {
if (isIntersecting(mBubbleContainer, x, y)) {
+ if (BubbleExperimentConfig.allowBubbleOverflow(mContext)
+ && isIntersecting(mOverflowBtn, x, y)) {
+ return mOverflowBtn;
+ }
// Could be tapping or dragging a bubble while expanded
for (int i = 0; i < getBubbleCount(); i++) {
BadgedImageView view = (BadgedImageView) mBubbleContainer.getChildAt(i);
@@ -1164,7 +1150,6 @@
}
return;
}
- hideBubbleMenu();
mStackAnimationController.cancelStackPositionAnimations();
mBubbleContainer.setActiveController(mStackAnimationController);
hideFlyoutImmediate();
@@ -1566,10 +1551,6 @@
@Override
public void getBoundsOnScreen(Rect outRect) {
// If the bubble menu is open, the entire screen should capture touch events.
- if (mBubbleMenuView.isShowing()) {
- outRect.set(0, 0, getWidth(), getHeight());
- return;
- }
if (!mIsExpanded) {
if (getBubbleCount() > 0) {
mBubbleContainer.getChildAt(0).getBoundsOnScreen(outRect);
@@ -1804,50 +1785,4 @@
}
return bubbles;
}
-
- /**
- * Show the bubble menu, positioned relative to the stack.
- */
- public void showBubbleMenu() {
- PointF currentPos = mStackAnimationController.getStackPosition();
- mBubbleMenuView.setVisibility(View.INVISIBLE);
- post(() -> {
- float yPos = currentPos.y;
- float xPos = currentPos.x;
- if (mStackAnimationController.isStackOnLeftSide()) {
- xPos += mBubbleSize;
- } else {
- xPos -= mBubbleMenuView.getMenuView().getWidth();
- }
-
- mBubbleMenuView.show(xPos, yPos);
- });
- }
-
- /**
- * Hide the bubble menu.
- */
- public void hideBubbleMenu() {
- mBubbleMenuView.hide();
- }
-
- /**
- * Determines whether the bubble menu is currently showing.
- */
- public boolean isShowingBubbleMenu() {
- return mBubbleMenuView.isShowing();
- }
-
- /**
- * Take a screenshot and send it to the specified bubble.
- */
- public void sendScreenshotToBubble(Bubble bubble) {
- hideBubbleMenu();
- // delay allows the bubble menu to disappear before the screenshot
- // done here because we already have a Handler to delay with.
- // TODO: Hide bubble + menu UI from screenshots entirely instead of just delaying.
- postDelayed(() -> {
- mBubbleScreenshotListener.onBubbleScreenshot(bubble);
- }, BubbleMenuView.SCREENSHOT_DELAY);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
index fdeaf1f..34d3c24 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
@@ -24,6 +24,7 @@
import android.view.ViewConfiguration;
import com.android.systemui.Dependency;
+import com.android.systemui.R;
/**
* Handles interpreting touches on a {@link BubbleStackView}. This includes expanding, collapsing,
@@ -57,14 +58,12 @@
private final PointF mViewPositionOnTouchDown = new PointF();
private final BubbleStackView mStack;
private final BubbleData mBubbleData;
- private final Context mContext;
private BubbleController mController = Dependency.get(BubbleController.class);
private boolean mMovedEnough;
private int mTouchSlopSquared;
private VelocityTracker mVelocityTracker;
- private Runnable mShowBubbleMenuRunnable;
/** View that was initially touched, when we received the first ACTION_DOWN event. */
private View mTouchedView;
@@ -77,7 +76,6 @@
mTouchSlopSquared = touchSlop * touchSlop;
mBubbleData = bubbleData;
mStack = stackView;
- mContext = context;
}
@Override
@@ -94,24 +92,19 @@
// anything, collapse the stack.
if (action == MotionEvent.ACTION_OUTSIDE || mTouchedView == null) {
mBubbleData.setExpanded(false);
- mStack.hideBubbleMenu();
resetForNextGesture();
return false;
}
- if (mTouchedView instanceof BubbleMenuView) {
- mStack.hideBubbleMenu();
- resetForNextGesture();
- mStack.sendScreenshotToBubble(mBubbleData.getSelectedBubble());
- return false;
- }
-
if (!(mTouchedView instanceof BadgedImageView)
&& !(mTouchedView instanceof BubbleStackView)
&& !(mTouchedView instanceof BubbleFlyoutView)) {
+
+ if (mTouchedView.getId() == R.id.bubble_overflow_button) {
+ mStack.showOverflow();
+ }
// Not touching anything touchable, but we shouldn't collapse (e.g. touching edge
// of expanded view).
- mStack.hideBubbleMenu();
resetForNextGesture();
return false;
}
@@ -134,12 +127,6 @@
if (isStack) {
mViewPositionOnTouchDown.set(mStack.getStackPosition());
mStack.onDragStart();
- if (!mStack.isShowingBubbleMenu() && !mStack.isExpanded()
- && BubbleExperimentConfig.allowBubbleScreenshotMenu(mContext)) {
- mShowBubbleMenuRunnable = mStack::showBubbleMenu;
- mStack.postDelayed(mShowBubbleMenuRunnable,
- ViewConfiguration.getLongPressTimeout());
- }
} else if (isFlyout) {
mStack.onFlyoutDragStart();
} else {
@@ -150,10 +137,6 @@
break;
case MotionEvent.ACTION_MOVE:
- // block all further touch inputs once the menu is open
- if (mStack.isShowingBubbleMenu()) {
- return true;
- }
trackMovement(event);
final float deltaX = rawX - mTouchDown.x;
final float deltaY = rawY - mTouchDown.y;
@@ -163,7 +146,6 @@
}
if (mMovedEnough) {
- mStack.removeCallbacks(mShowBubbleMenuRunnable);
if (isStack) {
mStack.onDragged(viewX, viewY);
} else if (isFlyout) {
@@ -194,12 +176,6 @@
break;
case MotionEvent.ACTION_UP:
- if (mStack.isShowingBubbleMenu()) {
- resetForNextGesture();
- return true;
- } else {
- mStack.removeCallbacks(mShowBubbleMenuRunnable);
- }
trackMovement(event);
mVelocityTracker.computeCurrentVelocity(/* maxVelocity */ 1000);
final float velX = mVelocityTracker.getXVelocity();
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index a6f1d84..7de1557 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -19,9 +19,12 @@
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.ComponentName
+import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.database.ContentObserver
+import android.net.Uri
import android.os.Environment
import android.os.UserHandle
import android.provider.Settings
@@ -30,6 +33,7 @@
import android.util.ArrayMap
import android.util.Log
import com.android.internal.annotations.GuardedBy
+import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.DumpController
import com.android.systemui.Dumpable
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -53,15 +57,16 @@
private val uiController: ControlsUiController,
private val bindingController: ControlsBindingController,
private val listingController: ControlsListingController,
- broadcastDispatcher: BroadcastDispatcher,
+ private val broadcastDispatcher: BroadcastDispatcher,
optionalWrapper: Optional<ControlsFavoritePersistenceWrapper>,
dumpController: DumpController
) : Dumpable, ControlsController {
companion object {
private const val TAG = "ControlsControllerImpl"
- const val CONTROLS_AVAILABLE = "systemui.controls_available"
- const val USER_CHANGE_RETRY_DELAY = 500L // ms
+ internal const val CONTROLS_AVAILABLE = "systemui.controls_available"
+ internal val URI = Settings.Secure.getUriFor(CONTROLS_AVAILABLE)
+ private const val USER_CHANGE_RETRY_DELAY = 500L // ms
}
// Map of map: ComponentName -> (String -> ControlInfo).
@@ -69,9 +74,11 @@
@GuardedBy("currentFavorites")
private val currentFavorites = ArrayMap<ComponentName, MutableMap<String, ControlInfo>>()
- private var userChanging = true
- override var available = Settings.Secure.getInt(
- context.contentResolver, CONTROLS_AVAILABLE, 0) != 0
+ private var userChanging: Boolean = true
+
+ private val contentResolver: ContentResolver
+ get() = context.contentResolver
+ override var available = Settings.Secure.getInt(contentResolver, CONTROLS_AVAILABLE, 0) != 0
private set
private var currentUser = context.user
@@ -95,8 +102,8 @@
val fileName = Environment.buildPath(
userContext.filesDir, ControlsFavoritePersistenceWrapper.FILE_NAME)
persistenceWrapper.changeFile(fileName)
- available = Settings.Secure.getIntForUser(
- context.contentResolver, CONTROLS_AVAILABLE, 0) != 0
+ available = Settings.Secure.getIntForUser(contentResolver, CONTROLS_AVAILABLE,
+ /* default */ 0, newUser.identifier) != 0
synchronized(currentFavorites) {
currentFavorites.clear()
}
@@ -123,6 +130,25 @@
}
}
+ @VisibleForTesting
+ internal val settingObserver = object : ContentObserver(null) {
+ override fun onChange(selfChange: Boolean, uri: Uri, userId: Int) {
+ // Do not listen to changes in the middle of user change, those will be read by the
+ // user-switch receiver.
+ if (userChanging || userId != currentUserId) {
+ return
+ }
+ available = Settings.Secure.getIntForUser(contentResolver, CONTROLS_AVAILABLE,
+ /* default */ 0, currentUserId) != 0
+ synchronized(currentFavorites) {
+ currentFavorites.clear()
+ }
+ if (available) {
+ loadFavorites()
+ }
+ }
+ }
+
init {
dumpController.registerDumpable(this)
if (available) {
@@ -135,6 +161,7 @@
executor,
UserHandle.ALL
)
+ contentResolver.registerContentObserver(URI, false, settingObserver, UserHandle.USER_ALL)
}
private fun confirmAvailability(): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index fad2d94..88b19b5 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -34,14 +34,17 @@
import android.widget.TextView
import com.android.systemui.controls.controller.ControlsController
+import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.R
const val MIN_LEVEL = 0
const val MAX_LEVEL = 10000
+private const val UPDATE_DELAY_IN_MILLIS = 2000L
class ControlViewHolder(
val layout: ViewGroup,
- val controlsController: ControlsController
+ val controlsController: ControlsController,
+ val uiExecutor: DelayableExecutor
) {
val icon: ImageView = layout.requireViewById(R.id.icon)
val status: TextView = layout.requireViewById(R.id.status)
@@ -52,6 +55,7 @@
val clipLayer: ClipDrawable
val gd: GradientDrawable
lateinit var cws: ControlWithState
+ var cancelUpdate: Runnable? = null
init {
val ld = layout.getBackground() as LayerDrawable
@@ -63,6 +67,8 @@
fun bindData(cws: ControlWithState) {
this.cws = cws
+ cancelUpdate?.run()
+
val (status, template) = cws.control?.let {
title.setText(it.getTitle())
subtitle.setText(it.getSubtitle())
@@ -86,6 +92,27 @@
findBehavior(status, template).apply(this, cws)
}
+ fun actionResponse(@ControlAction.ResponseResult response: Int) {
+ val text = when (response) {
+ ControlAction.RESPONSE_OK -> "Success"
+ ControlAction.RESPONSE_FAIL -> "Error"
+ else -> ""
+ }
+
+ if (!text.isEmpty()) {
+ val previousText = status.getText()
+ val previousTextExtra = statusExtra.getText()
+
+ cancelUpdate = uiExecutor.executeDelayed({
+ status.setText(previousText)
+ statusExtra.setText(previousTextExtra)
+ }, UPDATE_DELAY_IN_MILLIS)
+
+ status.setText(text)
+ statusExtra.setText("")
+ }
+ }
+
fun action(action: ControlAction) {
controlsController.action(cws.ci, action)
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
index b07a75d..d70c86f 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
@@ -22,6 +22,8 @@
import android.view.ViewGroup
interface ControlsUiController {
+ val available: Boolean
+
fun show(parent: ViewGroup)
fun hide()
fun onRefreshState(componentName: ComponentName, controls: List<Control>)
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 a777faf..ed521e3 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -38,10 +38,10 @@
import com.android.systemui.controls.management.ControlsProviderSelectorActivity
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.R
+import com.android.systemui.util.concurrency.DelayableExecutor
import dagger.Lazy
-import java.util.concurrent.Executor
import javax.inject.Inject
import javax.inject.Singleton
@@ -104,18 +104,23 @@
}
}
+private data class ControlKey(val componentName: ComponentName, val controlId: String)
+
@Singleton
class ControlsUiControllerImpl @Inject constructor (
val controlsController: Lazy<ControlsController>,
val context: Context,
- @Main val uiExecutor: Executor
+ @Main val uiExecutor: DelayableExecutor
) : ControlsUiController {
private lateinit var controlInfos: List<ControlInfo>
- private val controlsById = mutableMapOf<Pair<ComponentName, String>, ControlWithState>()
- private val controlViewsById = mutableMapOf<String, ControlViewHolder>()
+ private val controlsById = mutableMapOf<ControlKey, ControlWithState>()
+ private val controlViewsById = mutableMapOf<ControlKey, ControlViewHolder>()
private lateinit var parent: ViewGroup
+ override val available: Boolean
+ get() = controlsController.get().available
+
override fun show(parent: ViewGroup) {
Log.d(TAG, "show()")
@@ -125,7 +130,7 @@
controlInfos.map {
ControlWithState(it, null)
- }.associateByTo(controlsById) { Pair(it.ci.component, it.ci.controlId) }
+ }.associateByTo(controlsById) { ControlKey(it.ci.component, it.ci.controlId) }
if (controlInfos.isEmpty()) {
showInitialSetupView()
@@ -178,9 +183,10 @@
val item = inflater.inflate(
R.layout.controls_base_item, lastRow, false) as ViewGroup
lastRow.addView(item)
- val cvh = ControlViewHolder(item, controlsController.get())
- cvh.bindData(controlsById.get(Pair(it.component, it.controlId))!!)
- controlViewsById.put(it.controlId, cvh)
+ val cvh = ControlViewHolder(item, controlsController.get(), uiExecutor)
+ val key = ControlKey(it.component, it.controlId)
+ cvh.bindData(controlsById.getValue(key))
+ controlViewsById.put(key, cvh)
}
if ((controlInfos.size % 2) == 1) {
@@ -205,21 +211,24 @@
override fun onRefreshState(componentName: ComponentName, controls: List<Control>) {
Log.d(TAG, "onRefreshState()")
controls.forEach { c ->
- controlsById.get(Pair(componentName, c.getControlId()))?.let {
+ controlsById.get(ControlKey(componentName, c.getControlId()))?.let {
Log.d(TAG, "onRefreshState() for id: " + c.getControlId())
val cws = ControlWithState(it.ci, c)
- controlsById.put(Pair(componentName, c.getControlId()), cws)
+ val key = ControlKey(componentName, c.getControlId())
+ controlsById.put(key, cws)
uiExecutor.execute {
- controlViewsById.get(c.getControlId())?.bindData(cws)
+ controlViewsById.get(key)?.bindData(cws)
}
}
}
}
override fun onActionResponse(componentName: ComponentName, controlId: String, response: Int) {
- Log.d(TAG, "onActionResponse()")
- TODO("not implemented")
+ val key = ControlKey(componentName, controlId)
+ uiExecutor.execute {
+ controlViewsById.get(key)?.actionResponse(response)
+ }
}
private fun createRow(inflater: LayoutInflater, parent: ViewGroup): ViewGroup {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
index 093c99f..da52c6f 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
@@ -108,10 +108,18 @@
DeviceTypes.TYPE_OUTLET to IconState(
R.drawable.ic_power_off_gm2_24px,
R.drawable.ic_power_gm2_24px
+ ),
+ DeviceTypes.TYPE_VACUUM to IconState(
+ R.drawable.ic_vacuum_gm2_24px,
+ R.drawable.ic_vacuum_gm2_24px
+ ),
+ DeviceTypes.TYPE_MOP to IconState(
+ R.drawable.ic_vacuum_gm2_24px,
+ R.drawable.ic_vacuum_gm2_24px
)
).withDefault {
IconState(
- R.drawable.ic_light_off_gm2_24px,
- R.drawable.ic_lightbulb_outline_gm2_24px
+ R.drawable.ic_device_unknown_gm2_24px,
+ R.drawable.ic_device_unknown_gm2_24px
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 45c07a3..b3fc027 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -1725,7 +1725,8 @@
if (!(mBackgroundDrawable instanceof ScrimDrawable)) {
return;
}
- ((ScrimDrawable) mBackgroundDrawable).setColor(Color.BLACK, animate);
+ ((ScrimDrawable) mBackgroundDrawable).setColor(colors.supportsDarkText() ? Color.WHITE
+ : Color.BLACK, animate);
View decorView = getWindow().getDecorView();
if (colors.supportsDarkText()) {
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR |
@@ -1899,9 +1900,7 @@
}
private boolean shouldShowControls() {
- return isCurrentUserOwner()
- && !mKeyguardManager.isDeviceLocked()
- && Settings.Secure.getInt(mContext.getContentResolver(),
- "systemui.controls_available", 0) == 1;
+ return !mKeyguardManager.isDeviceLocked()
+ && mControlsUiController.getAvailable();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/Event.java b/packages/SystemUI/src/com/android/systemui/log/Event.java
deleted file mode 100644
index 7bc1abf..0000000
--- a/packages/SystemUI/src/com/android/systemui/log/Event.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.log;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Stores information about an event that occurred in SystemUI to be used for debugging and triage.
- * Every event has a time stamp, log level and message.
- * Events are stored in {@link SysuiLog} and can be printed in a dumpsys.
- */
-public class Event {
- public static final int UNINITIALIZED = -1;
-
- @IntDef({ERROR, WARN, INFO, DEBUG, VERBOSE})
- @Retention(RetentionPolicy.SOURCE)
- public @interface Level {}
- public static final int VERBOSE = 2;
- public static final int DEBUG = 3;
- public static final int INFO = 4;
- public static final int WARN = 5;
- public static final int ERROR = 6;
- public static final @Level int DEFAULT_LOG_LEVEL = DEBUG;
-
- private long mTimestamp;
- private @Level int mLogLevel = DEFAULT_LOG_LEVEL;
- private String mMessage = "";
-
- /**
- * initialize an event with a message
- */
- public Event init(String message) {
- init(DEFAULT_LOG_LEVEL, message);
- return this;
- }
-
- /**
- * initialize an event with a logLevel and message
- */
- public Event init(@Level int logLevel, String message) {
- mTimestamp = System.currentTimeMillis();
- mLogLevel = logLevel;
- mMessage = message;
- return this;
- }
-
- public String getMessage() {
- return mMessage;
- }
-
- public long getTimestamp() {
- return mTimestamp;
- }
-
- public @Level int getLogLevel() {
- return mLogLevel;
- }
-
- /**
- * Recycle this event
- */
- void recycle() {
- mTimestamp = -1;
- mLogLevel = DEFAULT_LOG_LEVEL;
- mMessage = "";
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/log/RichEvent.java b/packages/SystemUI/src/com/android/systemui/log/RichEvent.java
deleted file mode 100644
index 470f2b0..0000000
--- a/packages/SystemUI/src/com/android/systemui/log/RichEvent.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.log;
-
-/**
- * Stores information about an event that occurred in SystemUI to be used for debugging and triage.
- * Every rich event has a time stamp, event type, and log level, with the option to provide the
- * reason this event was triggered.
- * Events are stored in {@link SysuiLog} and can be printed in a dumpsys.
- */
-public abstract class RichEvent extends Event {
- private int mType;
-
- /**
- * Initializes a rich event that includes an event type that matches with an index in the array
- * getEventLabels().
- */
- public RichEvent init(@Event.Level int logLevel, int type, String reason) {
- final int numEvents = getEventLabels().length;
- if (type < 0 || type >= numEvents) {
- throw new IllegalArgumentException("Unsupported event type. Events only supported"
- + " from 0 to " + (numEvents - 1) + ", but given type=" + type);
- }
- mType = type;
- super.init(logLevel, getEventLabels()[mType] + " " + reason);
- return this;
- }
-
- /**
- * Returns an array of the event labels. The index represents the event type and the
- * corresponding String stored at that index is the user-readable representation of that event.
- * @return array of user readable events, where the index represents its event type constant
- */
- public abstract String[] getEventLabels();
-
- @Override
- public void recycle() {
- super.recycle();
- mType = -1;
- }
-
- public int getType() {
- return mType;
- }
-
- /**
- * Builder to build a RichEvent.
- * @param <B> Log specific builder that is extending this builder
- * @param <E> Type of event we'll be building
- */
- public abstract static class Builder<B extends Builder<B, E>, E extends RichEvent> {
- public static final int UNINITIALIZED = -1;
-
- public final SysuiLog mLog;
- private B mBuilder = getBuilder();
- protected int mType;
- protected String mReason;
- protected @Level int mLogLevel;
-
- public Builder(SysuiLog sysuiLog) {
- mLog = sysuiLog;
- reset();
- }
-
- /**
- * Reset this builder's parameters so it can be reused to build another RichEvent.
- */
- public void reset() {
- mType = UNINITIALIZED;
- mReason = null;
- mLogLevel = VERBOSE;
- }
-
- /**
- * Get the log-specific builder.
- */
- public abstract B getBuilder();
-
- /**
- * Build the log-specific event given an event to populate.
- */
- public abstract E build(E e);
-
- /**
- * Optional - set the log level. Defaults to DEBUG.
- */
- public B setLogLevel(@Level int logLevel) {
- mLogLevel = logLevel;
- return mBuilder;
- }
-
- /**
- * Required - set the event type. These events must correspond with the events from
- * getEventLabels().
- */
- public B setType(int type) {
- mType = type;
- return mBuilder;
- }
-
- /**
- * Optional - set the reason why this event was triggered.
- */
- public B setReason(String reason) {
- mReason = reason;
- return mBuilder;
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java b/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java
deleted file mode 100644
index 9ee3e67..0000000
--- a/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.log;
-
-import android.os.Build;
-import android.os.SystemProperties;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.DumpController;
-import com.android.systemui.Dumpable;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.text.SimpleDateFormat;
-import java.util.ArrayDeque;
-import java.util.Locale;
-
-/**
- * Thread-safe logger in SystemUI which prints logs to logcat and stores logs to be
- * printed by the DumpController. This is an alternative to printing directly
- * to avoid logs being deleted by chatty. The number of logs retained is varied based on
- * whether the build is {@link Build.IS_DEBUGGABLE}.
- *
- * To manually view the logs via adb:
- * adb shell dumpsys activity service com.android.systemui/.SystemUIService \
- * dependency DumpController <SysuiLogId>
- *
- * Logs can be disabled by setting the following SystemProperty and then restarting the device:
- * adb shell setprop persist.sysui.log.enabled.<id> true/false && adb reboot
- *
- * @param <E> Type of event we'll be logging
- */
-public class SysuiLog<E extends Event> implements Dumpable {
- public static final SimpleDateFormat DATE_FORMAT =
- new SimpleDateFormat("MM-dd HH:mm:ss.S", Locale.US);
-
- protected final Object mDataLock = new Object();
- private final String mId;
- private final int mMaxLogs;
- protected boolean mEnabled;
- protected boolean mLogToLogcatEnabled;
-
- @VisibleForTesting protected ArrayDeque<E> mTimeline;
-
- /**
- * Creates a SysuiLog
- * @param dumpController where to register this logger's dumpsys
- * @param id user-readable tag for this logger
- * @param maxDebugLogs maximum number of logs to retain when {@link sDebuggable} is true
- * @param maxLogs maximum number of logs to retain when {@link sDebuggable} is false
- */
- public SysuiLog(DumpController dumpController, String id, int maxDebugLogs, int maxLogs) {
- this(dumpController, id, sDebuggable ? maxDebugLogs : maxLogs,
- SystemProperties.getBoolean(SYSPROP_ENABLED_PREFIX + id, DEFAULT_ENABLED),
- SystemProperties.getBoolean(SYSPROP_LOGCAT_ENABLED_PREFIX + id,
- DEFAULT_LOGCAT_ENABLED));
- }
-
- @VisibleForTesting
- protected SysuiLog(DumpController dumpController, String id, int maxLogs, boolean enabled,
- boolean logcatEnabled) {
- mId = id;
- mMaxLogs = maxLogs;
- mEnabled = enabled;
- mLogToLogcatEnabled = logcatEnabled;
- mTimeline = mEnabled ? new ArrayDeque<>(mMaxLogs) : null;
- dumpController.registerDumpable(mId, this);
- }
-
- /**
- * Logs an event to the timeline which can be printed by the dumpsys.
- * May also log to logcat if enabled.
- * @return the last event that was discarded from the Timeline (can be recycled)
- */
- public E log(E event) {
- if (!mEnabled) {
- return null;
- }
-
- E recycledEvent = null;
- synchronized (mDataLock) {
- if (mTimeline.size() >= mMaxLogs) {
- recycledEvent = mTimeline.removeFirst();
- }
-
- mTimeline.add(event);
- }
-
- if (mLogToLogcatEnabled) {
- final String strEvent = eventToString(event);
- switch (event.getLogLevel()) {
- case Event.VERBOSE:
- Log.v(mId, strEvent);
- break;
- case Event.DEBUG:
- Log.d(mId, strEvent);
- break;
- case Event.ERROR:
- Log.e(mId, strEvent);
- break;
- case Event.INFO:
- Log.i(mId, strEvent);
- break;
- case Event.WARN:
- Log.w(mId, strEvent);
- break;
- }
- }
-
- if (recycledEvent != null) {
- recycledEvent.recycle();
- }
-
- return recycledEvent;
- }
-
- /**
- * @return user-readable string of the given event with timestamp
- */
- private String eventToTimestampedString(Event event) {
- StringBuilder sb = new StringBuilder();
- sb.append(SysuiLog.DATE_FORMAT.format(event.getTimestamp()));
- sb.append(" ");
- sb.append(event.getMessage());
- return sb.toString();
- }
-
- /**
- * @return user-readable string of the given event without a timestamp
- */
- public String eventToString(Event event) {
- return event.getMessage();
- }
-
- @GuardedBy("mDataLock")
- private void dumpTimelineLocked(PrintWriter pw) {
- pw.println("\tTimeline:");
-
- for (Event event : mTimeline) {
- pw.println("\t" + eventToTimestampedString(event));
- }
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println(mId + ":");
-
- if (mEnabled) {
- synchronized (mDataLock) {
- dumpTimelineLocked(pw);
- }
- } else {
- pw.print(" - Logging disabled.");
- }
- }
-
- private static boolean sDebuggable = Build.IS_DEBUGGABLE;
- private static final String SYSPROP_ENABLED_PREFIX = "persist.sysui.log.enabled.";
- private static final String SYSPROP_LOGCAT_ENABLED_PREFIX = "persist.sysui.log.enabled.logcat.";
- private static final boolean DEFAULT_ENABLED = sDebuggable;
- private static final boolean DEFAULT_LOGCAT_ENABLED = false;
- private static final int DEFAULT_MAX_DEBUG_LOGS = 100;
- private static final int DEFAULT_MAX_LOGS = 50;
-}
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 eba2e78..3ae627d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -19,10 +19,6 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import android.animation.AnimationHandler;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.TimeAnimator;
import android.annotation.Nullable;
import android.app.ActivityManager.StackInfo;
import android.app.IActivityManager;
@@ -36,6 +32,7 @@
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
+import android.view.Choreographer;
import androidx.dynamicanimation.animation.SpringForce;
@@ -88,9 +85,11 @@
/** PIP's current bounds on the screen. */
private final Rect mBounds = new Rect();
+ private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider =
+ new SfVsyncFrameCallbackProvider();
+
/**
- * Bounds that are animated using the physics animator. PIP is moved to these bounds whenever
- * the {@link #mVsyncTimeAnimator} ticks.
+ * Bounds that are animated using the physics animator.
*/
private final Rect mAnimatedBounds = new Rect();
@@ -100,12 +99,16 @@
private PhysicsAnimator<Rect> mAnimatedBoundsPhysicsAnimator = PhysicsAnimator.getInstance(
mAnimatedBounds);
+ /** Callback that re-sizes PIP to the animated bounds. */
+ private final Choreographer.FrameCallback mResizePipVsyncCallback =
+ l -> resizePipUnchecked(mAnimatedBounds);
+
/**
- * Time animator whose frame timing comes from the SurfaceFlinger vsync frame provider. At each
- * frame, PIP is moved to {@link #mAnimatedBounds}, which are animated asynchronously using
- * physics animations.
+ * Update listener that posts a vsync frame callback to resize PIP to {@link #mAnimatedBounds}.
*/
- private TimeAnimator mVsyncTimeAnimator;
+ private final PhysicsAnimator.UpdateListener<Rect> mResizePipVsyncUpdateListener =
+ (target, values) ->
+ mSfVsyncFrameProvider.postFrameCallback(mResizePipVsyncCallback);
/** FlingConfig instances provided to PhysicsAnimator for fling gestures. */
private PhysicsAnimator.FlingConfig mFlingConfigX;
@@ -126,39 +129,7 @@
mMenuController = menuController;
mSnapAlgorithm = snapAlgorithm;
mFlingAnimationUtils = flingAnimationUtils;
- final AnimationHandler vsyncFrameCallbackProvider = new AnimationHandler();
- vsyncFrameCallbackProvider.setProvider(new SfVsyncFrameCallbackProvider());
-
onConfigurationChanged();
-
- // Construct a time animator that uses the vsync frame provider. Physics animations can't
- // use custom frame providers, since they rely on constant time between frames to run the
- // physics simulations. To work around this, we physically-animate a second set of bounds,
- // and apply those animating bounds to the PIP in-sync via this TimeAnimator.
- mVsyncTimeAnimator = new TimeAnimator() {
- @Override
- public AnimationHandler getAnimationHandler() {
- return vsyncFrameCallbackProvider;
- }
- };
-
- // When the time animator ticks, move PIP to the animated bounds.
- mVsyncTimeAnimator.setTimeListener(
- (animation, totalTime, deltaTime) ->
- resizePipUnchecked(mAnimatedBounds));
-
- // Add a listener for cancel/end events that moves PIP to the final animated bounds.
- mVsyncTimeAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationCancel(Animator animation) {
- resizePipUnchecked(mAnimatedBounds);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- resizePipUnchecked(mAnimatedBounds);
- }
- });
}
/**
@@ -429,7 +400,6 @@
*/
private void cancelAnimations() {
mAnimatedBoundsPhysicsAnimator.cancel();
- mVsyncTimeAnimator.cancel();
}
/**
@@ -457,10 +427,8 @@
cancelAnimations();
mAnimatedBoundsPhysicsAnimator
- .withEndActions(
- mVsyncTimeAnimator::cancel)
+ .addUpdateListener(mResizePipVsyncUpdateListener)
.start();
- mVsyncTimeAnimator.start();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index 0134aa3..5de6d1c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -169,7 +169,7 @@
if (DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)) {
v.setText(mContext.getString(
com.android.internal.R.string.bugreport_status,
- Build.VERSION.RELEASE,
+ Build.VERSION.RELEASE_OR_CODENAME,
Build.ID));
v.setVisibility(View.VISIBLE);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
index 9e3e94c..6c69718 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
@@ -36,6 +36,7 @@
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
+import android.os.Handler;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -370,6 +371,13 @@
if (mSeamless == null) {
return;
}
+ Handler handler = mSeamless.getHandler();
+ handler.post(() -> {
+ updateChipInternal(device);
+ });
+ }
+
+ private void updateChipInternal(MediaDevice device) {
ColorStateList fgTintList = ColorStateList.valueOf(mForegroundColor);
// Update the outline color
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index b091ad8..626f298 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -16,7 +16,6 @@
package com.android.systemui.screenrecord;
-import android.app.Activity;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
@@ -26,16 +25,21 @@
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.MediaRecorder;
+import android.media.projection.IMediaProjection;
+import android.media.projection.IMediaProjectionManager;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.provider.MediaStore;
import android.provider.Settings;
import android.util.DisplayMetrics;
@@ -83,7 +87,6 @@
private static final int AUDIO_SAMPLE_RATE = 44100;
private final RecordingController mController;
- private MediaProjectionManager mMediaProjectionManager;
private MediaProjection mMediaProjection;
private Surface mInputSurface;
private VirtualDisplay mVirtualDisplay;
@@ -134,13 +137,30 @@
switch (action) {
case ACTION_START:
- int resultCode = intent.getIntExtra(EXTRA_RESULT_CODE, Activity.RESULT_CANCELED);
mUseAudio = intent.getBooleanExtra(EXTRA_USE_AUDIO, false);
mShowTaps = intent.getBooleanExtra(EXTRA_SHOW_TAPS, false);
- Intent data = intent.getParcelableExtra(EXTRA_DATA);
- if (data != null) {
- mMediaProjection = mMediaProjectionManager.getMediaProjection(resultCode, data);
+ try {
+ IBinder b = ServiceManager.getService(MEDIA_PROJECTION_SERVICE);
+ IMediaProjectionManager mediaService =
+ IMediaProjectionManager.Stub.asInterface(b);
+ IMediaProjection proj = mediaService.createProjection(getUserId(),
+ getPackageName(),
+ MediaProjectionManager.TYPE_SCREEN_CAPTURE, false);
+ IBinder projection = proj.asBinder();
+ if (projection == null) {
+ Log.e(TAG, "Projection was null");
+ Toast.makeText(this, R.string.screenrecord_start_error, Toast.LENGTH_LONG)
+ .show();
+ return Service.START_NOT_STICKY;
+ }
+ mMediaProjection = new MediaProjection(getApplicationContext(),
+ IMediaProjection.Stub.asInterface(projection));
startRecording();
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ Toast.makeText(this, R.string.screenrecord_start_error, Toast.LENGTH_LONG)
+ .show();
+ return Service.START_NOT_STICKY;
}
break;
@@ -195,9 +215,6 @@
@Override
public void onCreate() {
super.onCreate();
-
- mMediaProjectionManager =
- (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
}
/**
@@ -269,6 +286,7 @@
}
private void createRecordingNotification() {
+ Resources res = getResources();
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID,
getString(R.string.screenrecord_name),
@@ -281,11 +299,15 @@
Bundle extras = new Bundle();
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
- getResources().getString(R.string.screenrecord_name));
+ res.getString(R.string.screenrecord_name));
+
+ String notificationTitle = mUseAudio
+ ? res.getString(R.string.screenrecord_ongoing_screen_and_audio)
+ : res.getString(R.string.screenrecord_ongoing_screen_only);
mRecordingNotificationBuilder = new Notification.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_screenrecord)
- .setContentTitle(getResources().getString(R.string.screenrecord_name))
+ .setContentTitle(notificationTitle)
.setContentText(getResources().getString(R.string.screenrecord_stop_text))
.setUsesChronometer(true)
.setColorized(true)
@@ -332,8 +354,7 @@
Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_screenrecord)
- .setContentTitle(getResources().getString(R.string.screenrecord_name))
- .setContentText(getResources().getString(R.string.screenrecord_save_message))
+ .setContentTitle(getResources().getString(R.string.screenrecord_save_message))
.setContentIntent(PendingIntent.getActivity(
this,
REQUEST_CODE,
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
index 8324986..566f12b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
@@ -16,15 +16,14 @@
package com.android.systemui.screenrecord;
-import android.Manifest;
import android.app.Activity;
import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.media.projection.MediaProjectionManager;
import android.os.Bundle;
-import android.widget.Toast;
+import android.view.Gravity;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.Switch;
import com.android.systemui.R;
@@ -34,15 +33,11 @@
* Activity to select screen recording options
*/
public class ScreenRecordDialog extends Activity {
- private static final int REQUEST_CODE_VIDEO_ONLY = 200;
- private static final int REQUEST_CODE_VIDEO_TAPS = 201;
- private static final int REQUEST_CODE_PERMISSIONS = 299;
- private static final int REQUEST_CODE_VIDEO_AUDIO = 300;
- private static final int REQUEST_CODE_VIDEO_AUDIO_TAPS = 301;
- private static final int REQUEST_CODE_PERMISSIONS_AUDIO = 399;
private static final long DELAY_MS = 3000;
private final RecordingController mController;
+ private Switch mAudioSwitch;
+ private Switch mTapsSwitch;
@Inject
public ScreenRecordDialog(RecordingController controller) {
@@ -52,81 +47,42 @@
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- requestScreenCapture();
+
+ Window window = getWindow();
+ // Inflate the decor view, so the attributes below are not overwritten by the theme.
+ window.getDecorView();
+ window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ window.setGravity(Gravity.TOP);
+
+ setContentView(R.layout.screen_record_dialog);
+
+ Button cancelBtn = findViewById(R.id.button_cancel);
+ cancelBtn.setOnClickListener(v -> {
+ finish();
+ });
+
+ Button startBtn = findViewById(R.id.button_start);
+ startBtn.setOnClickListener(v -> {
+ requestScreenCapture();
+ finish();
+ });
+
+ mAudioSwitch = findViewById(R.id.screenrecord_audio_switch);
+ mTapsSwitch = findViewById(R.id.screenrecord_taps_switch);
}
private void requestScreenCapture() {
- MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(
- Context.MEDIA_PROJECTION_SERVICE);
- Intent permissionIntent = mediaProjectionManager.createScreenCaptureIntent();
-
- // TODO get saved settings
- boolean useAudio = false;
- boolean showTaps = false;
- if (useAudio) {
- startActivityForResult(permissionIntent,
- showTaps ? REQUEST_CODE_VIDEO_AUDIO_TAPS : REQUEST_CODE_VIDEO_AUDIO);
- } else {
- startActivityForResult(permissionIntent,
- showTaps ? REQUEST_CODE_VIDEO_TAPS : REQUEST_CODE_VIDEO_ONLY);
- }
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- boolean showTaps = (requestCode == REQUEST_CODE_VIDEO_TAPS
- || requestCode == REQUEST_CODE_VIDEO_AUDIO_TAPS);
- boolean useAudio = (requestCode == REQUEST_CODE_VIDEO_AUDIO
- || requestCode == REQUEST_CODE_VIDEO_AUDIO_TAPS);
- switch (requestCode) {
- case REQUEST_CODE_VIDEO_TAPS:
- case REQUEST_CODE_VIDEO_AUDIO_TAPS:
- case REQUEST_CODE_VIDEO_ONLY:
- case REQUEST_CODE_VIDEO_AUDIO:
- if (resultCode == RESULT_OK) {
- PendingIntent startIntent = PendingIntent.getForegroundService(
- this, RecordingService.REQUEST_CODE, RecordingService.getStartIntent(
- ScreenRecordDialog.this, resultCode, data, useAudio,
- showTaps),
- PendingIntent.FLAG_UPDATE_CURRENT
- );
- PendingIntent stopIntent = PendingIntent.getService(
- this, RecordingService.REQUEST_CODE,
- RecordingService.getStopIntent(this),
- PendingIntent.FLAG_UPDATE_CURRENT);
- mController.startCountdown(DELAY_MS, startIntent, stopIntent);
- } else {
- Toast.makeText(this,
- getResources().getString(R.string.screenrecord_permission_error),
- Toast.LENGTH_SHORT).show();
- }
- finish();
- break;
- case REQUEST_CODE_PERMISSIONS:
- int permission = checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
- if (permission != PackageManager.PERMISSION_GRANTED) {
- Toast.makeText(this,
- getResources().getString(R.string.screenrecord_permission_error),
- Toast.LENGTH_SHORT).show();
- finish();
- } else {
- requestScreenCapture();
- }
- break;
- case REQUEST_CODE_PERMISSIONS_AUDIO:
- int videoPermission = checkSelfPermission(
- Manifest.permission.WRITE_EXTERNAL_STORAGE);
- int audioPermission = checkSelfPermission(Manifest.permission.RECORD_AUDIO);
- if (videoPermission != PackageManager.PERMISSION_GRANTED
- || audioPermission != PackageManager.PERMISSION_GRANTED) {
- Toast.makeText(this,
- getResources().getString(R.string.screenrecord_permission_error),
- Toast.LENGTH_SHORT).show();
- finish();
- } else {
- requestScreenCapture();
- }
- break;
- }
+ boolean useAudio = mAudioSwitch.isChecked();
+ boolean showTaps = mTapsSwitch.isChecked();
+ PendingIntent startIntent = PendingIntent.getForegroundService(this,
+ RecordingService.REQUEST_CODE,
+ RecordingService.getStartIntent(
+ ScreenRecordDialog.this, RESULT_OK, null, useAudio, showTaps),
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ PendingIntent stopIntent = PendingIntent.getService(this,
+ RecordingService.REQUEST_CODE,
+ RecordingService.getStopIntent(this),
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ mController.startCountdown(DELAY_MS, startIntent, stopIntent);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 7ad07c2..7d3d406 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -20,7 +20,6 @@
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.res.ColorStateList;
-import android.content.res.Resources;
import android.graphics.Color;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.face.FaceManager;
@@ -46,6 +45,7 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.settingslib.Utils;
+import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -97,8 +97,6 @@
private final LockPatternUtils mLockPatternUtils;
private final DockManager mDockManager;
- private final int mSlowThreshold;
- private final int mFastThreshold;
private final LockIcon mLockIcon;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
@@ -178,10 +176,6 @@
mWakeLock = new SettableWakeLock(wakeLock, TAG);
mLockPatternUtils = lockPatternUtils;
- Resources res = context.getResources();
- mSlowThreshold = res.getInteger(R.integer.config_chargingSlowlyThreshold);
- mFastThreshold = res.getInteger(R.integer.config_chargingFastThreshold);
-
mUserManager = context.getSystemService(UserManager.class);
mBatteryInfo = iBatteryStats;
@@ -484,12 +478,12 @@
int chargingId;
if (mPowerPluggedInWired) {
switch (mChargingSpeed) {
- case KeyguardUpdateMonitor.BatteryStatus.CHARGING_FAST:
+ case BatteryStatus.CHARGING_FAST:
chargingId = hasChargingTime
? R.string.keyguard_indication_charging_time_fast
: R.string.keyguard_plugged_in_charging_fast;
break;
- case KeyguardUpdateMonitor.BatteryStatus.CHARGING_SLOWLY:
+ case BatteryStatus.CHARGING_SLOWLY:
chargingId = hasChargingTime
? R.string.keyguard_indication_charging_time_slowly
: R.string.keyguard_plugged_in_charging_slowly;
@@ -620,7 +614,7 @@
public static final int HIDE_DELAY_MS = 5000;
@Override
- public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) {
+ public void onRefreshBatteryInfo(BatteryStatus status) {
boolean isChargingOrFull = status.status == BatteryManager.BATTERY_STATUS_CHARGING
|| status.status == BatteryManager.BATTERY_STATUS_FULL;
boolean wasPluggedIn = mPowerPluggedIn;
@@ -628,7 +622,7 @@
mPowerPluggedIn = status.isPluggedIn() && isChargingOrFull;
mPowerCharged = status.isCharged();
mChargingWattage = status.maxChargingWattage;
- mChargingSpeed = status.getChargingSpeed(mSlowThreshold, mFastThreshold);
+ mChargingSpeed = status.getChargingSpeed(mContext);
mBatteryLevel = status.level;
try {
mChargingTimeRemaining = mPowerPluggedIn
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 61915ad..916da6e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -47,8 +47,6 @@
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
-import com.android.systemui.statusbar.notification.logging.NotifEvent;
-import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -129,6 +127,8 @@
private final Map<NotificationEntry, NotificationLifetimeExtender> mRetainedNotifications =
new ArrayMap<>();
+ private final NotificationEntryManagerLogger mLogger;
+
// Lazily retrieved dependencies
private final Lazy<NotificationRowBinder> mNotificationRowBinderLazy;
private final Lazy<NotificationRemoteInputManager> mRemoteInputManagerLazy;
@@ -143,7 +143,6 @@
private NotificationPresenter mPresenter;
private RankingMap mLatestRankingMap;
- private NotifLog mNotifLog;
@VisibleForTesting
final ArrayList<NotificationLifetimeExtender> mNotificationLifetimeExtenders
@@ -184,7 +183,7 @@
@Inject
public NotificationEntryManager(
- NotifLog notifLog,
+ NotificationEntryManagerLogger logger,
NotificationGroupManager groupManager,
NotificationRankingManager rankingManager,
KeyguardEnvironment keyguardEnvironment,
@@ -193,7 +192,7 @@
Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy,
LeakDetector leakDetector,
ForegroundServiceDismissalFeatureController fgsFeatureController) {
- mNotifLog = notifLog;
+ mLogger = logger;
mGroupManager = groupManager;
mRankingManager = rankingManager;
mKeyguardEnvironment = keyguardEnvironment;
@@ -291,13 +290,12 @@
NotificationEntry entry = mPendingNotifications.get(key);
entry.abortTask();
mPendingNotifications.remove(key);
- mNotifLog.log(NotifEvent.INFLATION_ABORTED, entry, "PendingNotification aborted"
- + " reason=" + reason);
+ mLogger.logInflationAborted(key, "pending", reason);
}
NotificationEntry addedEntry = getActiveNotificationUnfiltered(key);
if (addedEntry != null) {
addedEntry.abortTask();
- mNotifLog.log(NotifEvent.INFLATION_ABORTED, addedEntry.getKey() + " " + reason);
+ mLogger.logInflationAborted(key, "active", reason);
}
}
@@ -328,9 +326,9 @@
// the list, otherwise we might get leaks.
if (!entry.isRowRemoved()) {
boolean isNew = getActiveNotificationUnfiltered(entry.getKey()) == null;
+ mLogger.logNotifInflated(entry.getKey(), isNew);
if (isNew) {
for (NotificationEntryListener listener : mNotificationEntryListeners) {
- mNotifLog.log(NotifEvent.INFLATED, entry);
listener.onEntryInflated(entry);
}
addActiveNotification(entry);
@@ -340,7 +338,6 @@
}
} else {
for (NotificationEntryListener listener : mNotificationEntryListeners) {
- mNotifLog.log(NotifEvent.INFLATED, entry);
listener.onEntryReinflated(entry);
}
}
@@ -422,7 +419,7 @@
for (NotificationRemoveInterceptor interceptor : mRemoveInterceptors) {
if (interceptor.onNotificationRemoveRequested(key, entry, reason)) {
// Remove intercepted; log and skip
- mNotifLog.log(NotifEvent.REMOVE_INTERCEPTED);
+ mLogger.logRemovalIntercepted(key);
return;
}
}
@@ -437,10 +434,7 @@
if (extender.shouldExtendLifetimeForPendingNotification(pendingEntry)) {
extendLifetime(pendingEntry, extender);
lifetimeExtended = true;
- mNotifLog.log(
- NotifEvent.LIFETIME_EXTENDED,
- pendingEntry.getSbn(),
- "pendingEntry extendedBy=" + extender.toString());
+ mLogger.logLifetimeExtended(key, extender.getClass().getName(), "pending");
}
}
}
@@ -460,10 +454,7 @@
mLatestRankingMap = ranking;
extendLifetime(entry, extender);
lifetimeExtended = true;
- mNotifLog.log(
- NotifEvent.LIFETIME_EXTENDED,
- entry.getSbn(),
- "entry extendedBy=" + extender.toString());
+ mLogger.logLifetimeExtended(key, extender.getClass().getName(), "active");
break;
}
}
@@ -486,8 +477,7 @@
mLeakDetector.trackGarbage(entry);
removedByUser |= entryDismissed;
- mNotifLog.log(NotifEvent.NOTIF_REMOVED, entry.getSbn(),
- "removedByUser=" + removedByUser);
+ mLogger.logNotifRemoved(entry.getKey(), removedByUser);
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onEntryRemoved(entry, visibility, removedByUser);
}
@@ -576,7 +566,7 @@
abortExistingInflation(key, "addNotification");
mPendingNotifications.put(key, entry);
- mNotifLog.log(NotifEvent.NOTIF_ADDED, entry);
+ mLogger.logNotifAdded(entry.getKey());
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onPendingEntryAdded(entry);
}
@@ -613,7 +603,7 @@
entry.setSbn(notification);
mGroupManager.onEntryUpdated(entry, oldSbn);
- mNotifLog.log(NotifEvent.NOTIF_UPDATED, entry);
+ mLogger.logNotifUpdated(entry.getKey());
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onPreEntryUpdated(entry);
}
@@ -808,7 +798,7 @@
//TODO: Get rid of this in favor of NotificationUpdateHandler#updateNotificationRanking
/**
* @param rankingMap the {@link RankingMap} to apply to the current notification list
- * @param reason the reason for calling this method, for {@link NotifLog}
+ * @param reason the reason for calling this method, which will be logged
*/
public void updateRanking(RankingMap rankingMap, String reason) {
updateRankingAndSort(rankingMap, reason);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManagerLogger.kt
new file mode 100644
index 0000000..4382ab5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManagerLogger.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.log.dagger.NotificationLog
+import javax.inject.Inject
+
+/** Logger for [NotificationEntryManager]. */
+class NotificationEntryManagerLogger @Inject constructor(
+ @NotificationLog private val buffer: LogBuffer
+) {
+ fun logNotifAdded(key: String) {
+ buffer.log(TAG, INFO, {
+ str1 = key
+ }, {
+ "NOTIF ADDED $str1"
+ })
+ }
+
+ fun logNotifUpdated(key: String) {
+ buffer.log(TAG, INFO, {
+ str1 = key
+ }, {
+ "NOTIF UPDATED $str1"
+ })
+ }
+
+ fun logInflationAborted(key: String, status: String, reason: String) {
+ buffer.log(TAG, DEBUG, {
+ str1 = key
+ str2 = status
+ str3 = reason
+ }, {
+ "NOTIF INFLATION ABORTED $str1 notifStatus=$str2 reason=$str3"
+ })
+ }
+
+ fun logNotifInflated(key: String, isNew: Boolean) {
+ buffer.log(TAG, DEBUG, {
+ str1 = key
+ bool1 = isNew
+ }, {
+ "NOTIF INFLATED $str1 isNew=$bool1}"
+ })
+ }
+
+ fun logRemovalIntercepted(key: String) {
+ buffer.log(TAG, INFO, {
+ str1 = key
+ }, {
+ "NOTIF REMOVE INTERCEPTED for $str1"
+ })
+ }
+
+ fun logLifetimeExtended(key: String, extenderName: String, status: String) {
+ buffer.log(TAG, INFO, {
+ str1 = key
+ str2 = extenderName
+ str3 = status
+ }, {
+ "NOTIF LIFETIME EXTENDED $str1 extender=$str2 status=$str3"
+ })
+ }
+
+ fun logNotifRemoved(key: String, removedByUser: Boolean) {
+ buffer.log(TAG, INFO, {
+ str1 = key
+ bool1 = removedByUser
+ }, {
+ "NOTIF REMOVED $str1 removedByUser=$bool1"
+ })
+ }
+
+ fun logFilterAndSort(reason: String) {
+ buffer.log(TAG, INFO, {
+ str1 = reason
+ }, {
+ "FILTER AND SORT reason=$str1"
+ })
+ }
+}
+
+private const val TAG = "NotificationEntryMgr"
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
index 1eeeab3..2981252 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
@@ -22,11 +22,10 @@
import android.service.notification.NotificationListenerService.RankingMap
import android.service.notification.StatusBarNotification
import com.android.systemui.statusbar.NotificationMediaManager
+import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger
import com.android.systemui.statusbar.notification.NotificationFilter
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
-import com.android.systemui.statusbar.notification.logging.NotifEvent
-import com.android.systemui.statusbar.notification.logging.NotifLog
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE
@@ -53,7 +52,7 @@
private val groupManager: NotificationGroupManager,
private val headsUpManager: HeadsUpManager,
private val notifFilter: NotificationFilter,
- private val notifLog: NotifLog,
+ private val logger: NotificationEntryManagerLogger,
sectionsFeatureManager: NotificationSectionsFeatureManager,
private val peopleNotificationIdentifier: PeopleNotificationIdentifier,
private val highPriorityProvider: HighPriorityProvider
@@ -134,7 +133,7 @@
entries: Sequence<NotificationEntry>,
reason: String
): Sequence<NotificationEntry> {
- notifLog.log(NotifEvent.FILTER_AND_SORT, reason)
+ logger.logFilterAndSort(reason)
return entries.filter { !notifFilter.shouldFilterOut(it) }
.sortedWith(rankingComparator)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
index 41314b8..1e5946a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
@@ -22,8 +22,6 @@
import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
-import com.android.systemui.statusbar.notification.logging.NotifEvent;
-import com.android.systemui.statusbar.notification.logging.NotifLog;
import java.util.ArrayList;
import java.util.List;
@@ -42,13 +40,15 @@
public class PreparationCoordinator implements Coordinator {
private static final String TAG = "PreparationCoordinator";
- private final NotifLog mNotifLog;
+ private final PreparationCoordinatorLogger mLogger;
private final NotifInflater mNotifInflater;
private final List<NotificationEntry> mPendingNotifications = new ArrayList<>();
@Inject
- public PreparationCoordinator(NotifLog notifLog, NotifInflaterImpl notifInflater) {
- mNotifLog = notifLog;
+ public PreparationCoordinator(
+ PreparationCoordinatorLogger logger,
+ NotifInflaterImpl notifInflater) {
+ mLogger = logger;
mNotifInflater = notifInflater;
mNotifInflater.setInflationCallback(mInflationCallback);
}
@@ -106,7 +106,7 @@
new NotifInflater.InflationCallback() {
@Override
public void onInflationFinished(NotificationEntry entry) {
- mNotifLog.log(NotifEvent.INFLATED, entry);
+ mLogger.logNotifInflated(entry.getKey());
mPendingNotifications.remove(entry);
mNotifInflatingFilter.invalidateList();
}
@@ -123,7 +123,7 @@
}
private void abortInflation(NotificationEntry entry, String reason) {
- mNotifLog.log(NotifEvent.INFLATION_ABORTED, reason);
+ mLogger.logInflationAborted(entry.getKey(), reason);
entry.abortTask();
mPendingNotifications.remove(entry);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
new file mode 100644
index 0000000..75e7bc9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.dagger.NotificationLog
+import javax.inject.Inject
+
+class PreparationCoordinatorLogger @Inject constructor(
+ @NotificationLog private val buffer: LogBuffer
+) {
+ fun logNotifInflated(key: String) {
+ buffer.log(TAG, LogLevel.DEBUG, {
+ str1 = key
+ }, {
+ "NOTIF INFLATED $str1"
+ })
+ }
+
+ fun logInflationAborted(key: String, reason: String) {
+ buffer.log(TAG, LogLevel.DEBUG, {
+ str1 = key
+ str2 = reason
+ }, {
+ "NOTIF INFLATION ABORTED $str1 reason=$str2"
+ })
+ }
+}
+
+private const val TAG = "PreparationCoordinator"
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 59d82a1..ecf62db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -295,6 +295,7 @@
}
//TODO: Replace this API with RowContentBindParams directly
row.setNeedsRedaction(mNotificationLockscreenUserManager.needsRedaction(entry));
+ params.rebindAllContentViews();
mRowContentBindStage.requestRebind(entry, en -> {
row.setUsesIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
row.setUsesIncreasedHeadsUpHeight(useIncreasedHeadsUp);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
deleted file mode 100644
index 9adceb7..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.logging;
-
-import android.annotation.IntDef;
-import android.service.notification.NotificationListenerService;
-import android.service.notification.StatusBarNotification;
-
-import com.android.systemui.log.RichEvent;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.ShadeListBuilder;
-import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * An event related to notifications. {@link NotifLog} stores and prints these events for debugging
- * and triaging purposes. We do not store a copy of the status bar notification nor ranking
- * here to mitigate memory usage.
- */
-public class NotifEvent extends RichEvent {
- /**
- * Initializes a rich event that includes an event type that matches with an index in the array
- * getEventLabels().
- */
- public NotifEvent init(@EventType int type, StatusBarNotification sbn,
- NotificationListenerService.Ranking ranking, String reason) {
- StringBuilder extraInfo = new StringBuilder(reason);
- if (sbn != null) {
- extraInfo.append(" " + sbn.getKey());
- }
-
- if (ranking != null) {
- extraInfo.append(" Ranking=");
- extraInfo.append(ranking.getRank());
- }
- super.init(INFO, type, extraInfo.toString());
- return this;
- }
-
- /**
- * Event labels for ListBuilderEvents
- * Index corresponds to an # in {@link EventType}
- */
- @Override
- public String[] getEventLabels() {
- assert (TOTAL_EVENT_LABELS
- == (TOTAL_NEM_EVENT_TYPES
- + TOTAL_LIST_BUILDER_EVENT_TYPES
- + TOTAL_COALESCER_EVENT_TYPES));
- return EVENT_LABELS;
- }
-
- /**
- * @return if this event occurred in {@link ShadeListBuilder}
- */
- static boolean isListBuilderEvent(@EventType int type) {
- return isBetweenInclusive(type, 0, TOTAL_LIST_BUILDER_EVENT_TYPES);
- }
-
- /**
- * @return if this event occurred in {@link NotificationEntryManager}
- */
- static boolean isNemEvent(@EventType int type) {
- return isBetweenInclusive(type, TOTAL_LIST_BUILDER_EVENT_TYPES,
- TOTAL_LIST_BUILDER_EVENT_TYPES + TOTAL_NEM_EVENT_TYPES);
- }
-
- private static boolean isBetweenInclusive(int x, int a, int b) {
- return x >= a && x <= b;
- }
-
- @IntDef({
- // NotifListBuilder events:
- WARN,
- ON_BUILD_LIST,
- START_BUILD_LIST,
- DISPATCH_FINAL_LIST,
- LIST_BUILD_COMPLETE,
- PRE_GROUP_FILTER_INVALIDATED,
- PROMOTER_INVALIDATED,
- SECTION_INVALIDATED,
- COMPARATOR_INVALIDATED,
- PARENT_CHANGED,
- FILTER_CHANGED,
- PROMOTER_CHANGED,
- PRE_RENDER_FILTER_INVALIDATED,
-
- // NotificationEntryManager events:
- NOTIF_ADDED,
- NOTIF_REMOVED,
- NOTIF_UPDATED,
- FILTER,
- SORT,
- FILTER_AND_SORT,
- NOTIF_VISIBILITY_CHANGED,
- LIFETIME_EXTENDED,
- REMOVE_INTERCEPTED,
- INFLATION_ABORTED,
- INFLATED,
-
- // GroupCoalescer
- COALESCED_EVENT,
- EARLY_BATCH_EMIT,
- EMIT_EVENT_BATCH
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface EventType {}
-
- private static final String[] EVENT_LABELS =
- new String[]{
- // NotifListBuilder labels:
- "Warning",
- "OnBuildList",
- "StartBuildList",
- "DispatchFinalList",
- "ListBuildComplete",
- "FilterInvalidated",
- "PromoterInvalidated",
- "SectionInvalidated",
- "ComparatorInvalidated",
- "ParentChanged",
- "FilterChanged",
- "PromoterChanged",
- "FinalFilterInvalidated",
- "SectionerChanged",
-
- // NEM event labels:
- "NotifAdded",
- "NotifRemoved",
- "NotifUpdated",
- "Filter",
- "Sort",
- "FilterAndSort",
- "NotifVisibilityChanged",
- "LifetimeExtended",
- "RemoveIntercepted",
- "InflationAborted",
- "Inflated",
-
- // GroupCoalescer labels:
- "CoalescedEvent",
- "EarlyBatchEmit",
- "EmitEventBatch",
- "BatchMaxTimeout"
- };
-
- private static final int TOTAL_EVENT_LABELS = EVENT_LABELS.length;
-
- /**
- * Events related to {@link ShadeListBuilder}
- */
- public static final int WARN = 0;
- public static final int ON_BUILD_LIST = 1;
- public static final int START_BUILD_LIST = 2;
- public static final int DISPATCH_FINAL_LIST = 3;
- public static final int LIST_BUILD_COMPLETE = 4;
- public static final int PRE_GROUP_FILTER_INVALIDATED = 5;
- public static final int PROMOTER_INVALIDATED = 6;
- public static final int SECTION_INVALIDATED = 7;
- public static final int COMPARATOR_INVALIDATED = 8;
- public static final int PARENT_CHANGED = 9;
- public static final int FILTER_CHANGED = 10;
- public static final int PROMOTER_CHANGED = 11;
- public static final int PRE_RENDER_FILTER_INVALIDATED = 12;
- public static final int SECTION_CHANGED = 13;
- private static final int TOTAL_LIST_BUILDER_EVENT_TYPES = 14;
-
- /**
- * Events related to {@link NotificationEntryManager}
- */
- private static final int NEM_EVENT_START_INDEX = TOTAL_LIST_BUILDER_EVENT_TYPES;
- public static final int NOTIF_ADDED = NEM_EVENT_START_INDEX;
- public static final int NOTIF_REMOVED = NEM_EVENT_START_INDEX + 1;
- public static final int NOTIF_UPDATED = NEM_EVENT_START_INDEX + 2;
- public static final int FILTER = NEM_EVENT_START_INDEX + 3;
- public static final int SORT = NEM_EVENT_START_INDEX + 4;
- public static final int FILTER_AND_SORT = NEM_EVENT_START_INDEX + 5;
- public static final int NOTIF_VISIBILITY_CHANGED = NEM_EVENT_START_INDEX + 6;
- public static final int LIFETIME_EXTENDED = NEM_EVENT_START_INDEX + 7;
- // unable to remove notif - removal intercepted by {@link NotificationRemoveInterceptor}
- public static final int REMOVE_INTERCEPTED = NEM_EVENT_START_INDEX + 8;
- public static final int INFLATION_ABORTED = NEM_EVENT_START_INDEX + 9;
- public static final int INFLATED = NEM_EVENT_START_INDEX + 10;
- private static final int TOTAL_NEM_EVENT_TYPES = 11;
-
- /**
- * Events related to {@link GroupCoalescer}
- */
- private static final int COALESCER_EVENT_START_INDEX = NEM_EVENT_START_INDEX
- + TOTAL_NEM_EVENT_TYPES;
- public static final int COALESCED_EVENT = COALESCER_EVENT_START_INDEX;
- public static final int EARLY_BATCH_EMIT = COALESCER_EVENT_START_INDEX + 1;
- public static final int EMIT_EVENT_BATCH = COALESCER_EVENT_START_INDEX + 2;
- public static final int BATCH_MAX_TIMEOUT = COALESCER_EVENT_START_INDEX + 3;
- private static final int TOTAL_COALESCER_EVENT_TYPES = 3;
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java
deleted file mode 100644
index 299d628..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.logging;
-
-import android.os.SystemProperties;
-import android.service.notification.NotificationListenerService.Ranking;
-import android.service.notification.StatusBarNotification;
-
-import com.android.systemui.DumpController;
-import com.android.systemui.log.SysuiLog;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * Logs systemui notification events for debugging and triaging purposes. Logs are dumped in
- * bugreports or on demand:
- * adb shell dumpsys activity service com.android.systemui/.SystemUIService \
- * dependency DumpController NotifLog
- */
-@Singleton
-public class NotifLog extends SysuiLog<NotifEvent> {
- private static final String TAG = "NotifLog";
- private static final boolean SHOW_NEM_LOGS =
- SystemProperties.getBoolean("persist.sysui.log.notif.nem", true);
- private static final boolean SHOW_LIST_BUILDER_LOGS =
- SystemProperties.getBoolean("persist.sysui.log.notif.listbuilder", true);
-
- private static final int MAX_DOZE_DEBUG_LOGS = 400;
- private static final int MAX_DOZE_LOGS = 50;
-
- private NotifEvent mRecycledEvent;
-
- @Inject
- public NotifLog(DumpController dumpController) {
- super(dumpController, TAG, MAX_DOZE_DEBUG_LOGS, MAX_DOZE_LOGS);
- }
-
- /**
- * Logs a {@link NotifEvent} with a notification, ranking and message.
- * Uses the last recycled event if available.
- * @return true if successfully logged, else false
- */
- public void log(@NotifEvent.EventType int eventType,
- StatusBarNotification sbn, Ranking ranking, String msg) {
- if (!mEnabled
- || (NotifEvent.isListBuilderEvent(eventType) && !SHOW_LIST_BUILDER_LOGS)
- || (NotifEvent.isNemEvent(eventType) && !SHOW_NEM_LOGS)) {
- return;
- }
-
- if (mRecycledEvent != null) {
- mRecycledEvent = log(mRecycledEvent.init(eventType, sbn, ranking, msg));
- } else {
- mRecycledEvent = log(new NotifEvent().init(eventType, sbn, ranking, msg));
- }
- }
-
- /**
- * Logs a {@link NotifEvent} with no extra information aside from the event type
- */
- public void log(@NotifEvent.EventType int eventType) {
- log(eventType, null, null, "");
- }
-
- /**
- * Logs a {@link NotifEvent} with a message
- */
- public void log(@NotifEvent.EventType int eventType, String msg) {
- log(eventType, null, null, msg);
- }
-
- /**
- * Logs a {@link NotifEvent} with a entry
- */
- public void log(@NotifEvent.EventType int eventType, NotificationEntry entry) {
- log(eventType, entry.getSbn(), entry.getRanking(), "");
- }
-
- /**
- * Logs a {@link NotifEvent} with a NotificationEntry and message
- */
- public void log(@NotifEvent.EventType int eventType, NotificationEntry entry, String msg) {
- log(eventType, entry.getSbn(), entry.getRanking(), msg);
- }
-
- /**
- * Logs a {@link NotifEvent} with a notification and message
- */
- public void log(@NotifEvent.EventType int eventType, StatusBarNotification sbn, String msg) {
- log(eventType, sbn, null, msg);
- }
-
- /**
- * Logs a {@link NotifEvent} with a ranking and message
- */
- public void log(@NotifEvent.EventType int eventType, Ranking ranking, String msg) {
- log(eventType, null, ranking, msg);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java
index 8280a63..5170d0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java
@@ -123,6 +123,14 @@
}
/**
+ * Request that all content views be rebound. This may happen if, for example, the underlying
+ * layout has changed.
+ */
+ public void rebindAllContentViews() {
+ mDirtyContentViews = mContentViews;
+ }
+
+ /**
* Clears all dirty content views so that they no longer need to be rebound.
*/
void clearDirtyContentViews() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 2907cd4..8dfcb0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -134,6 +134,8 @@
mBroadcastDispatcher.registerReceiver(
mReceiver, filter, null /* handler */, UserHandle.SYSTEM);
+ mSimpleUserSwitcher = shouldUseSimpleUserSwitcher();
+
mSecondaryUserServiceIntent = new Intent(context, SystemUISecondaryUserService.class);
filter = new IntentFilter();
@@ -258,22 +260,20 @@
&& mUserManager.canAddMoreUsers();
boolean createIsRestricted = !addUsersWhenLocked;
- if (!mSimpleUserSwitcher) {
- if (guestRecord == null) {
- if (canCreateGuest) {
- guestRecord = new UserRecord(null /* info */, null /* picture */,
- true /* isGuest */, false /* isCurrent */,
- false /* isAddUser */, createIsRestricted, canSwitchUsers);
- checkIfAddUserDisallowedByAdminOnly(guestRecord);
- records.add(guestRecord);
- }
- } else {
- int index = guestRecord.isCurrent ? 0 : records.size();
- records.add(index, guestRecord);
+ if (guestRecord == null) {
+ if (canCreateGuest) {
+ guestRecord = new UserRecord(null /* info */, null /* picture */,
+ true /* isGuest */, false /* isCurrent */,
+ false /* isAddUser */, createIsRestricted, canSwitchUsers);
+ checkIfAddUserDisallowedByAdminOnly(guestRecord);
+ records.add(guestRecord);
}
+ } else {
+ int index = guestRecord.isCurrent ? 0 : records.size();
+ records.add(index, guestRecord);
}
- if (!mSimpleUserSwitcher && canCreateUser) {
+ if (canCreateUser) {
UserRecord addUserRecord = new UserRecord(null /* info */, null /* picture */,
false /* isGuest */, false /* isCurrent */, true /* isAddUser */,
createIsRestricted, canSwitchUsers);
@@ -562,8 +562,7 @@
private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
public void onChange(boolean selfChange) {
- mSimpleUserSwitcher = Settings.Global.getInt(mContext.getContentResolver(),
- SIMPLE_USER_SWITCHER_GLOBAL_SETTING, 0) != 0;
+ mSimpleUserSwitcher = shouldUseSimpleUserSwitcher();
mAddUsersWhenLocked = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.ADD_USERS_WHEN_LOCKED, 0) != 0;
refreshUsers(UserHandle.USER_NULL);
@@ -579,6 +578,7 @@
final UserRecord u = mUsers.get(i);
pw.print(" "); pw.println(u.toString());
}
+ pw.println("mSimpleUserSwitcher=" + mSimpleUserSwitcher);
}
public String getCurrentUserName(Context context) {
@@ -717,6 +717,13 @@
}
}
+ private boolean shouldUseSimpleUserSwitcher() {
+ int defaultSimpleUserSwitcher = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_expandLockScreenUserSwitcher) ? 1 : 0;
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ SIMPLE_USER_SWITCHER_GLOBAL_SETTING, defaultSimpleUserSwitcher) != 0;
+ }
+
public void startActivity(Intent intent) {
mActivityStarter.startActivity(intent, true);
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
index a60ca62..49ada1a 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
@@ -158,7 +158,7 @@
String demoTime = "1010"; // 10:10, a classic choice of horologists
try {
- String[] versionParts = android.os.Build.VERSION.RELEASE.split("\\.");
+ String[] versionParts = android.os.Build.VERSION.RELEASE_OR_CODENAME.split("\\.");
int majorVersion = Integer.valueOf(versionParts[0]);
demoTime = String.format("%02d00", majorVersion % 24);
} catch (IllegalArgumentException ex) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt b/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt
new file mode 100644
index 0000000..70bcc21
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/FloatingContentCoordinator.kt
@@ -0,0 +1,320 @@
+package com.android.systemui.util
+
+import android.graphics.Rect
+import android.util.Log
+import com.android.systemui.util.FloatingContentCoordinator.FloatingContent
+import java.util.HashMap
+import javax.inject.Inject
+import javax.inject.Singleton
+
+/** Tag for debug logging. */
+private const val TAG = "FloatingCoordinator"
+
+/**
+ * Coordinates the positions and movement of floating content, such as PIP and Bubbles, to ensure
+ * that they don't overlap. If content does overlap due to content appearing or moving, the
+ * coordinator will ask content to move to resolve the conflict.
+ *
+ * After implementing [FloatingContent], content should call [onContentAdded] to begin coordination.
+ * Subsequently, call [onContentMoved] whenever the content moves, and the coordinator will move
+ * other content out of the way. [onContentRemoved] should be called when the content is removed or
+ * no longer visible.
+ */
+@Singleton
+class FloatingContentCoordinator @Inject constructor() {
+
+ /**
+ * Represents a piece of floating content, such as PIP or the Bubbles stack. Provides methods
+ * that allow the [FloatingContentCoordinator] to determine the current location of the content,
+ * as well as the ability to ask it to move out of the way of other content.
+ *
+ * The default implementation of [calculateNewBoundsOnOverlap] moves the content up or down,
+ * depending on the position of the conflicting content. You can override this method if you
+ * want your own custom conflict resolution logic.
+ */
+ interface FloatingContent {
+
+ /**
+ * Return the bounds claimed by this content. This should include the bounds occupied by the
+ * content itself, as well as any padding, if desired. The coordinator will ensure that no
+ * other content is located within these bounds.
+ *
+ * If the content is animating, this method should return the bounds to which the content is
+ * animating. If that animation is cancelled, or updated, be sure that your implementation
+ * of this method returns the appropriate bounds, and call [onContentMoved] so that the
+ * coordinator moves other content out of the way.
+ */
+ fun getFloatingBoundsOnScreen(): Rect
+
+ /**
+ * Return the area within which this floating content is allowed to move. When resolving
+ * conflicts, the coordinator will never ask your content to move to a position where any
+ * part of the content would be out of these bounds.
+ */
+ fun getAllowedFloatingBoundsRegion(): Rect
+
+ /**
+ * Called when the coordinator needs this content to move to the given bounds. It's up to
+ * you how to do that.
+ *
+ * Note that if you start an animation to these bounds, [getFloatingBoundsOnScreen] should
+ * return the destination bounds, not the in-progress animated bounds. This is so the
+ * coordinator knows where floating content is going to be and can resolve conflicts
+ * accordingly.
+ */
+ fun moveToBounds(bounds: Rect)
+
+ /**
+ * Called by the coordinator when it needs to find a new home for this floating content,
+ * because a new or moving piece of content is now overlapping with it.
+ *
+ * [findAreaForContentVertically] and [findAreaForContentAboveOrBelow] are helpful utility
+ * functions that will find new bounds for your content automatically. Unless you require
+ * specific conflict resolution logic, these should be sufficient. By default, this method
+ * delegates to [findAreaForContentVertically].
+ *
+ * @param overlappingContentBounds The bounds of the other piece of content, which
+ * necessitated this content's relocation. Your new position must not overlap with these
+ * bounds.
+ * @param otherContentBounds The bounds of any other pieces of floating content. Your new
+ * position must not overlap with any of these either. These bounds are guaranteed to be
+ * non-overlapping.
+ * @return The new bounds for this content.
+ */
+ @JvmDefault
+ fun calculateNewBoundsOnOverlap(
+ overlappingContentBounds: Rect,
+ otherContentBounds: List<Rect>
+ ): Rect {
+ return findAreaForContentVertically(
+ getFloatingBoundsOnScreen(),
+ overlappingContentBounds,
+ otherContentBounds,
+ getAllowedFloatingBoundsRegion())
+ }
+ }
+
+ /** The bounds of all pieces of floating content added to the coordinator. */
+ private val allContentBounds: MutableMap<FloatingContent, Rect> = HashMap()
+
+ /**
+ * Makes the coordinator aware of a new piece of floating content, and moves any existing
+ * content out of the way, if necessary.
+ *
+ * If you don't want your new content to move existing content, use [getOccupiedBounds] to find
+ * an unoccupied area, and move the content there before calling this method.
+ */
+ fun onContentAdded(newContent: FloatingContent) {
+ updateContentBounds()
+ allContentBounds[newContent] = newContent.getFloatingBoundsOnScreen()
+ maybeMoveConflictingContent(newContent)
+ }
+
+ /**
+ * Called to notify the coordinator that a piece of floating content has moved (or is animating)
+ * to a new position, and that any conflicting floating content should be moved out of the way.
+ *
+ * The coordinator will call [FloatingContent.getFloatingBoundsOnScreen] to find the new bounds
+ * for the moving content. If you're animating the content, be sure that your implementation of
+ * getFloatingBoundsOnScreen returns the bounds to which it's animating, not the content's
+ * current bounds.
+ *
+ * If the animation moving this content is cancelled or updated, you'll need to call this method
+ * again, to ensure that content is moved out of the way of the latest bounds.
+ *
+ * @param content The content that has moved.
+ */
+ @JvmOverloads
+ fun onContentMoved(content: FloatingContent) {
+ if (!allContentBounds.containsKey(content)) {
+ Log.wtf(TAG, "Received onContentMoved call before onContentAdded! " +
+ "This should never happen.")
+ return
+ }
+
+ updateContentBounds()
+ maybeMoveConflictingContent(content)
+ }
+
+ /**
+ * Called to notify the coordinator that a piece of floating content has been removed or is no
+ * longer visible.
+ */
+ fun onContentRemoved(removedContent: FloatingContent) {
+ allContentBounds.remove(removedContent)
+ }
+
+ /**
+ * Returns a set of Rects that represent the bounds of all of the floating content on the
+ * screen.
+ *
+ * [onContentAdded] will move existing content out of the way if the added content intersects
+ * existing content. That's fine - but if your specific starting position is not important, you
+ * can use this function to find unoccupied space for your content before calling
+ * [onContentAdded], so that moving existing content isn't necessary.
+ */
+ fun getOccupiedBounds(): Collection<Rect> {
+ return allContentBounds.values
+ }
+
+ /**
+ * Identifies any pieces of content that are now overlapping with the given content, and asks
+ * them to move out of the way.
+ */
+ private fun maybeMoveConflictingContent(fromContent: FloatingContent) {
+ val conflictingNewBounds = allContentBounds[fromContent]!!
+ allContentBounds
+ // Filter to content that intersects with the new bounds. That's content that needs
+ // to move.
+ .filter { (content, bounds) ->
+ content != fromContent && Rect.intersects(conflictingNewBounds, bounds) }
+ // Tell that content to get out of the way, and save the bounds it says it's moving
+ // (or animating) to.
+ .forEach { (content, bounds) ->
+ content.moveToBounds(
+ content.calculateNewBoundsOnOverlap(
+ conflictingNewBounds,
+ // Pass all of the content bounds except the bounds of the
+ // content we're asking to move, and the conflicting new bounds
+ // (since those are passed separately).
+ otherContentBounds = allContentBounds.values
+ .minus(bounds)
+ .minus(conflictingNewBounds)))
+ allContentBounds[content] = content.getFloatingBoundsOnScreen()
+ }
+ }
+
+ /**
+ * Update [allContentBounds] by calling [FloatingContent.getFloatingBoundsOnScreen] for all
+ * content and saving the result.
+ */
+ private fun updateContentBounds() {
+ allContentBounds.keys.forEach { allContentBounds[it] = it.getFloatingBoundsOnScreen() }
+ }
+
+ companion object {
+ /**
+ * Finds new bounds for the given content, either above or below its current position. The
+ * new bounds won't intersect with the newly overlapping rect or the exclusion rects, and
+ * will be within the allowed bounds unless no possible position exists.
+ *
+ * You can use this method to help find a new position for your content when the coordinator
+ * calls [FloatingContent.moveToAreaExcluding].
+ *
+ * @param contentRect The bounds of the content for which we're finding a new home.
+ * @param newlyOverlappingRect The bounds of the content that forced this relocation by
+ * intersecting with the content we now need to move. If the overlapping content is
+ * overlapping the top half of this content, we'll try to move this content downward if
+ * possible (since the other content is 'pushing' it down), and vice versa.
+ * @param exclusionRects Any other areas that we need to avoid when finding a new home for
+ * the content. These areas must be non-overlapping with each other.
+ * @param allowedBounds The area within which we're allowed to find new bounds for the
+ * content.
+ * @return New bounds for the content that don't intersect the exclusion rects or the
+ * newly overlapping rect, and that is within bounds unless no possible in-bounds position
+ * exists.
+ */
+ @JvmStatic
+ fun findAreaForContentVertically(
+ contentRect: Rect,
+ newlyOverlappingRect: Rect,
+ exclusionRects: Collection<Rect>,
+ allowedBounds: Rect
+ ): Rect {
+ // If the newly overlapping Rect's center is above the content's center, we'll prefer to
+ // find a space for this content that is below the overlapping content, since it's
+ // 'pushing' it down. This may not be possible due to to screen bounds, in which case
+ // we'll find space in the other direction.
+ val overlappingContentPushingDown =
+ newlyOverlappingRect.centerY() < contentRect.centerY()
+
+ // Filter to exclusion rects that are above or below the content that we're finding a
+ // place for. Then, split into two lists - rects above the content, and rects below it.
+ var (rectsToAvoidAbove, rectsToAvoidBelow) = exclusionRects
+ .filter { rectToAvoid -> rectsIntersectVertically(rectToAvoid, contentRect) }
+ .partition { rectToAvoid -> rectToAvoid.top < contentRect.top }
+
+ // Lazily calculate the closest possible new tops for the content, above and below its
+ // current location.
+ val newContentBoundsAbove by lazy { findAreaForContentAboveOrBelow(
+ contentRect,
+ exclusionRects = rectsToAvoidAbove.plus(newlyOverlappingRect),
+ findAbove = true) }
+ val newContentBoundsBelow by lazy { findAreaForContentAboveOrBelow(
+ contentRect,
+ exclusionRects = rectsToAvoidBelow.plus(newlyOverlappingRect),
+ findAbove = false) }
+
+ val positionAboveInBounds by lazy { allowedBounds.contains(newContentBoundsAbove) }
+ val positionBelowInBounds by lazy { allowedBounds.contains(newContentBoundsBelow) }
+
+ // Use the 'below' position if the content is being overlapped from the top, unless it's
+ // out of bounds. Also use it if the content is being overlapped from the bottom, but
+ // the 'above' position is out of bounds. Otherwise, use the 'above' position.
+ val usePositionBelow =
+ overlappingContentPushingDown && positionBelowInBounds ||
+ !overlappingContentPushingDown && !positionAboveInBounds
+
+ // Return the content rect, but offset to reflect the new position.
+ return if (usePositionBelow) newContentBoundsBelow else newContentBoundsAbove
+ }
+
+ /**
+ * Finds a new position for the given content, either above or below its current position
+ * depending on whether [findAbove] is true or false, respectively. This new position will
+ * not intersect with any of the [exclusionRects].
+ *
+ * This method is useful as a helper method for implementing your own conflict resolution
+ * logic. Otherwise, you'd want to use [findAreaForContentVertically], which takes screen
+ * bounds and conflicting bounds' location into account when deciding whether to move to new
+ * bounds above or below the current bounds.
+ *
+ * @param contentRect The content we're finding an area for.
+ * @param exclusionRects The areas we need to avoid when finding a new area for the content.
+ * These areas must be non-overlapping with each other.
+ * @param findAbove Whether we are finding an area above the content's current position,
+ * rather than an area below it.
+ */
+ fun findAreaForContentAboveOrBelow(
+ contentRect: Rect,
+ exclusionRects: Collection<Rect>,
+ findAbove: Boolean
+ ): Rect {
+ // Sort the rects, since we want to move the content as little as possible. We'll
+ // start with the rects closest to the content and move outward. If we're finding an
+ // area above the content, that means we sort in reverse order to search the rects
+ // from highest to lowest y-value.
+ val sortedExclusionRects =
+ exclusionRects.sortedBy { if (findAbove) -it.top else it.top }
+
+ val proposedNewBounds = Rect(contentRect)
+ for (exclusionRect in sortedExclusionRects) {
+ // If the proposed new bounds don't intersect with this exclusion rect, that
+ // means there's room for the content here. We know this because the rects are
+ // sorted and non-overlapping, so any subsequent exclusion rects would be higher
+ // (or lower) than this one and can't possibly intersect if this one doesn't.
+ if (!Rect.intersects(proposedNewBounds, exclusionRect)) {
+ break
+ } else {
+ // Otherwise, we need to keep searching for new bounds. If we're finding an
+ // area above, propose new bounds that place the content just above the
+ // exclusion rect. If we're finding an area below, propose new bounds that
+ // place the content just below the exclusion rect.
+ val verticalOffset =
+ if (findAbove) -contentRect.height() else exclusionRect.height()
+ proposedNewBounds.offsetTo(
+ proposedNewBounds.left,
+ exclusionRect.top + verticalOffset)
+ }
+ }
+
+ return proposedNewBounds
+ }
+
+ /** Returns whether or not the two Rects share any of the same space on the X axis. */
+ private fun rectsIntersectVertically(r1: Rect, r2: Rect): Boolean {
+ return (r1.left >= r2.left && r1.left <= r2.right) ||
+ (r1.right <= r2.right && r1.right >= r2.left)
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
index 1954b39..0e9a245 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
@@ -39,7 +39,7 @@
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.testing.ViewUtils;
-import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
import android.view.SurfaceView;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -54,7 +54,6 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
@RunWithLooper
@RunWith(AndroidTestingRunner.class)
@@ -77,8 +76,8 @@
private KeyguardSecurityCallback mKeyguardCallback;
@Mock
private KeyguardUpdateMonitor mUpdateMonitor;
- @Spy
- private StubTransaction mTransaction;
+ @Mock
+ private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
@Before
public void setUp() {
@@ -97,21 +96,20 @@
when(mKeyguardClient.asBinder()).thenReturn(mKeyguardClient);
mTestController = new AdminSecondaryLockScreenController(
- mContext, mParent, mUpdateMonitor, mKeyguardCallback, mHandler, mTransaction);
+ mContext, mParent, mUpdateMonitor, mKeyguardCallback, mHandler);
}
@Test
public void testShow() throws Exception {
doAnswer(invocation -> {
IKeyguardCallback callback = (IKeyguardCallback) invocation.getArguments()[1];
- callback.onSurfaceControlCreated(new SurfaceControl());
+ callback.onRemoteContentReady(mSurfacePackage);
return null;
}).when(mKeyguardClient).onSurfaceReady(any(), any(IKeyguardCallback.class));
mTestController.show(mServiceIntent);
verifySurfaceReady();
- verify(mTransaction).reparent(any(), any());
assertThat(mContext.isBound(mComponentName)).isTrue();
}
@@ -133,7 +131,7 @@
// Show the view first, then hide.
doAnswer(invocation -> {
IKeyguardCallback callback = (IKeyguardCallback) invocation.getArguments()[1];
- callback.onSurfaceControlCreated(new SurfaceControl());
+ callback.onRemoteContentReady(mSurfacePackage);
return null;
}).when(mKeyguardClient).onSurfaceReady(any(), any(IKeyguardCallback.class));
@@ -189,19 +187,4 @@
verify(mKeyguardCallback).dismiss(true, TARGET_USER_ID);
assertThat(mContext.isBound(mComponentName)).isFalse();
}
-
- /**
- * Stubbed {@link SurfaceControl.Transaction} class that can be used when unit testing to
- * avoid calls to native code.
- */
- private class StubTransaction extends SurfaceControl.Transaction {
- @Override
- public void apply() {
- }
-
- @Override
- public SurfaceControl.Transaction reparent(SurfaceControl sc, SurfaceControl newParent) {
- return this;
- }
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
index 486aac8..c6c7b87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
@@ -178,6 +178,20 @@
}
@Test
+ public void testCredentialUI_disablesClickingOnBackground() {
+ // In the credential view, clicking on the background (to cancel authentication) is not
+ // valid. Thus, the listener should be null, and it should not be in the accessibility
+ // hierarchy.
+ initializeContainer(Authenticators.DEVICE_CREDENTIAL);
+
+ mAuthContainer.onAttachedToWindowInternal();
+
+ verify(mAuthContainer.mBackgroundView).setOnClickListener(eq(null));
+ verify(mAuthContainer.mBackgroundView).setImportantForAccessibility(
+ eq(View.IMPORTANT_FOR_ACCESSIBILITY_NO));
+ }
+
+ @Test
public void testLayoutParams_hasSecureWindowFlag() {
final IBinder windowToken = mock(IBinder.class);
final WindowManager.LayoutParams layoutParams =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index d7f0f50..280d14e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -81,7 +81,6 @@
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.InjectionInflationController;
@@ -152,8 +151,6 @@
@Mock
private ShadeController mShadeController;
@Mock
- private RemoteInputUriController mRemoteInputUriController;
- @Mock
private NotificationRowComponent mNotificationRowComponent;
private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
@@ -226,8 +223,7 @@
mZenModeController,
mLockscreenUserManager,
mNotificationGroupManager,
- mNotificationEntryManager,
- mRemoteInputUriController);
+ mNotificationEntryManager);
mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
mBubbleController.setExpandListener(mBubbleExpandListener);
@@ -783,13 +779,11 @@
ZenModeController zenModeController,
NotificationLockscreenUserManager lockscreenUserManager,
NotificationGroupManager groupManager,
- NotificationEntryManager entryManager,
- RemoteInputUriController remoteInputUriController) {
+ NotificationEntryManager entryManager) {
super(context,
notificationShadeWindowController, statusBarStateController, shadeController,
data, Runnable::run, configurationController, interruptionStateProvider,
- zenModeController, lockscreenUserManager, groupManager, entryManager,
- remoteInputUriController);
+ zenModeController, lockscreenUserManager, groupManager, entryManager);
setInflateSynchronously(true);
}
}
@@ -806,7 +800,7 @@
}
/**
- * Sets the bubble metadata flags for this entry. These flags are normally set by
+ * Sets the bubble metadata flags for this entry. These ]flags are normally set by
* NotificationManagerService when the notification is sent, however, these tests do not
* go through that path so we set them explicitly when testing.
*/
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
index 897091f..e3bcdc8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
@@ -32,12 +32,13 @@
import com.android.systemui.DumpController
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
-import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.ControlStatus
+import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
@@ -82,7 +83,7 @@
private lateinit var broadcastReceiverCaptor: ArgumentCaptor<BroadcastReceiver>
private lateinit var delayableExecutor: FakeExecutor
- private lateinit var controller: ControlsController
+ private lateinit var controller: ControlsControllerImpl
companion object {
fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
@@ -416,5 +417,70 @@
verify(listingController).changeUser(UserHandle.of(otherUser))
assertTrue(controller.getFavoriteControls().isEmpty())
assertEquals(otherUser, controller.currentUserId)
+ assertTrue(controller.available)
}
-}
\ No newline at end of file
+
+ @Test
+ fun testDisableFeature_notAvailable() {
+ Settings.Secure.putIntForUser(mContext.contentResolver,
+ ControlsControllerImpl.CONTROLS_AVAILABLE, 0, user)
+ controller.settingObserver.onChange(false, ControlsControllerImpl.URI, 0)
+ assertFalse(controller.available)
+ }
+
+ @Test
+ fun testDisableFeature_clearFavorites() {
+ controller.changeFavoriteStatus(TEST_CONTROL_INFO, true)
+ assertFalse(controller.getFavoriteControls().isEmpty())
+
+ Settings.Secure.putIntForUser(mContext.contentResolver,
+ ControlsControllerImpl.CONTROLS_AVAILABLE, 0, user)
+ controller.settingObserver.onChange(false, ControlsControllerImpl.URI, user)
+ assertTrue(controller.getFavoriteControls().isEmpty())
+ }
+
+ @Test
+ fun testDisableFeature_noChangeForNotCurrentUser() {
+ controller.changeFavoriteStatus(TEST_CONTROL_INFO, true)
+ Settings.Secure.putIntForUser(mContext.contentResolver,
+ ControlsControllerImpl.CONTROLS_AVAILABLE, 0, otherUser)
+ controller.settingObserver.onChange(false, ControlsControllerImpl.URI, otherUser)
+
+ assertTrue(controller.available)
+ assertFalse(controller.getFavoriteControls().isEmpty())
+ }
+
+ @Test
+ fun testCorrectUserSettingOnUserChange() {
+ Settings.Secure.putIntForUser(mContext.contentResolver,
+ ControlsControllerImpl.CONTROLS_AVAILABLE, 0, otherUser)
+
+ val intent = Intent(Intent.ACTION_USER_SWITCHED).apply {
+ putExtra(Intent.EXTRA_USER_HANDLE, otherUser)
+ }
+ val pendingResult = mock(BroadcastReceiver.PendingResult::class.java)
+ `when`(pendingResult.sendingUserId).thenReturn(otherUser)
+ broadcastReceiverCaptor.value.pendingResult = pendingResult
+
+ broadcastReceiverCaptor.value.onReceive(mContext, intent)
+
+ assertFalse(controller.available)
+ }
+
+ @Test
+ fun testCountFavoritesForComponent_singleComponent() {
+ controller.changeFavoriteStatus(TEST_CONTROL_INFO, true)
+
+ assertEquals(1, controller.countFavoritesForComponent(TEST_COMPONENT))
+ assertEquals(0, controller.countFavoritesForComponent(TEST_COMPONENT_2))
+ }
+
+ @Test
+ fun testCountFavoritesForComponent_multipleComponents() {
+ controller.changeFavoriteStatus(TEST_CONTROL_INFO, true)
+ controller.changeFavoriteStatus(TEST_CONTROL_INFO_2, true)
+
+ assertEquals(1, controller.countFavoritesForComponent(TEST_COMPONENT))
+ assertEquals(1, controller.countFavoritesForComponent(TEST_COMPONENT_2))
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/RichEventTest.java b/packages/SystemUI/tests/src/com/android/systemui/log/RichEventTest.java
deleted file mode 100644
index 4a90bb9..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/log/RichEventTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.log;
-
-import static junit.framework.Assert.assertEquals;
-
-import android.testing.AndroidTestingRunner;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-
-import junit.framework.Assert;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-public class RichEventTest extends SysuiTestCase {
-
- private static final int TOTAL_EVENT_TYPES = 1;
-
- @Test
- public void testCreateRichEvent_invalidType() {
- try {
- // indexing for events starts at 0, so TOTAL_EVENT_TYPES is an invalid type
- new TestableRichEvent(Event.DEBUG, TOTAL_EVENT_TYPES, "msg");
- } catch (IllegalArgumentException e) {
- // expected
- return;
- }
-
- Assert.fail("Expected an invalidArgumentException since the event type was invalid.");
- }
-
- @Test
- public void testCreateRichEvent() {
- final int eventType = 0;
- RichEvent e = new TestableRichEvent(Event.DEBUG, eventType, "msg");
- assertEquals(e.getType(), eventType);
- }
-
- class TestableRichEvent extends RichEvent {
- TestableRichEvent(int logLevel, int type, String reason) {
- init(logLevel, type, reason);
- }
-
- @Override
- public String[] getEventLabels() {
- return new String[]{"ACTION_NAME"};
- }
- }
-
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java b/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java
deleted file mode 100644
index e7b317e..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.log;
-
-import static junit.framework.Assert.assertEquals;
-
-import android.testing.AndroidTestingRunner;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.DumpController;
-import com.android.systemui.SysuiTestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-public class SysuiLogTest extends SysuiTestCase {
- private static final String TEST_ID = "TestLogger";
- private static final String TEST_MSG = "msg";
- private static final int MAX_LOGS = 5;
-
- @Mock
- private DumpController mDumpController;
- private SysuiLog<Event> mSysuiLog;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- }
-
- @Test
- public void testLogDisabled_noLogsWritten() {
- mSysuiLog = new TestSysuiLog(mDumpController, TEST_ID, MAX_LOGS, false);
- assertEquals(null, mSysuiLog.mTimeline);
-
- mSysuiLog.log(createEvent(TEST_MSG));
- assertEquals(null, mSysuiLog.mTimeline);
- }
-
- @Test
- public void testLogEnabled_logWritten() {
- mSysuiLog = new TestSysuiLog(mDumpController, TEST_ID, MAX_LOGS, true);
- assertEquals(0, mSysuiLog.mTimeline.size());
-
- mSysuiLog.log(createEvent(TEST_MSG));
- assertEquals(1, mSysuiLog.mTimeline.size());
- }
-
- @Test
- public void testMaxLogs() {
- mSysuiLog = new TestSysuiLog(mDumpController, TEST_ID, MAX_LOGS, true);
- assertEquals(mSysuiLog.mTimeline.size(), 0);
-
- for (int i = 0; i < MAX_LOGS + 1; i++) {
- mSysuiLog.log(createEvent(TEST_MSG + i));
- }
-
- assertEquals(MAX_LOGS, mSysuiLog.mTimeline.size());
-
- // check the first message (msg0) was replaced with msg1:
- assertEquals(TEST_MSG + "1", mSysuiLog.mTimeline.getFirst().getMessage());
- }
-
- @Test
- public void testRecycleLogs() {
- // GIVEN a SysuiLog with one log
- mSysuiLog = new TestSysuiLog(mDumpController, TEST_ID, MAX_LOGS, true);
- Event e = createEvent(TEST_MSG); // msg
- mSysuiLog.log(e); // Logs: [msg]
-
- Event recycledEvent = null;
- // WHEN we add MAX_LOGS after the first log
- for (int i = 0; i < MAX_LOGS; i++) {
- recycledEvent = mSysuiLog.log(createEvent(TEST_MSG + i));
- }
- // Logs: [msg1, msg2, msg3, msg4]
-
- // THEN we see the recycledEvent is e
- assertEquals(e, recycledEvent);
- }
-
- private Event createEvent(String msg) {
- return new Event().init(msg);
- }
-
- public class TestSysuiLog extends SysuiLog<Event> {
- protected TestSysuiLog(DumpController dumpController, String id, int maxLogs,
- boolean enabled) {
- super(dumpController, id, maxLogs, enabled, false);
- }
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 0a3bc6d..1d4b4be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -53,8 +53,8 @@
import com.android.internal.app.IBatteryStats;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitor.BatteryStatus;
import com.android.settingslib.Utils;
+import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dock.DockManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index b51581f..07f6936 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -79,7 +79,6 @@
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
-import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController;
@@ -139,7 +138,7 @@
@Mock private NotificationRemoteInputManager mRemoteInputManager;
@Mock private DeviceProvisionedController mDeviceProvisionedController;
@Mock private RowInflaterTask mAsyncInflationTask;
- @Mock private NotifLog mNotifLog;
+ @Mock private NotificationEntryManagerLogger mLogger;
@Mock private FeatureFlags mFeatureFlags;
@Mock private LeakDetector mLeakDetector;
@Mock private ActivatableNotificationViewController mActivatableNotificationViewController;
@@ -234,14 +233,14 @@
when(mFeatureFlags.isNewNotifPipelineEnabled()).thenReturn(false);
when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
mEntryManager = new TestableNotificationEntryManager(
- mNotifLog,
+ mLogger,
mGroupManager,
new NotificationRankingManager(
() -> mock(NotificationMediaManager.class),
mGroupManager,
mHeadsUpManager,
mock(NotificationFilter.class),
- mNotifLog,
+ mLogger,
mock(NotificationSectionsFeatureManager.class),
mock(PeopleNotificationIdentifier.class),
mock(HighPriorityProvider.class)),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
index a9f9db6..0e730e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
@@ -22,7 +22,6 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder
-import com.android.systemui.statusbar.notification.logging.NotifLog
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.NotificationGroupManager
@@ -34,7 +33,7 @@
* Enable some test capabilities for NEM without making everything public on the base class
*/
class TestableNotificationEntryManager(
- log: NotifLog,
+ logger: NotificationEntryManagerLogger,
gm: NotificationGroupManager,
rm: NotificationRankingManager,
ke: KeyguardEnvironment,
@@ -43,7 +42,7 @@
notificationRemoteInputManagerLazy: dagger.Lazy<NotificationRemoteInputManager>,
leakDetector: LeakDetector,
fgsFeatureController: ForegroundServiceDismissalFeatureController
-) : NotificationEntryManager(log, gm, rm, ke, ff, rb,
+) : NotificationEntryManager(logger, gm, rm, ke, ff, rb,
notificationRemoteInputManagerLazy, leakDetector, fgsFeatureController) {
public var countDownLatch: CountDownLatch = CountDownLatch(1)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
index 7ab4846..c6b496d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
@@ -27,10 +27,10 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking
import com.android.systemui.statusbar.NotificationMediaManager
+import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger
import com.android.systemui.statusbar.notification.NotificationFilter
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
-import com.android.systemui.statusbar.notification.logging.NotifLog
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
@@ -62,7 +62,7 @@
mock(NotificationGroupManager::class.java),
mock(HeadsUpManager::class.java),
mock(NotificationFilter::class.java),
- mock(NotifLog::class.java),
+ mock(NotificationEntryManagerLogger::class.java),
mock(NotificationSectionsFeatureManager::class.java),
personNotificationIdentifier,
HighPriorityProvider(personNotificationIdentifier)
@@ -189,7 +189,7 @@
groupManager: NotificationGroupManager,
headsUpManager: HeadsUpManager,
filter: NotificationFilter,
- notifLog: NotifLog,
+ logger: NotificationEntryManagerLogger,
sectionsFeatureManager: NotificationSectionsFeatureManager,
peopleNotificationIdentifier: PeopleNotificationIdentifier,
highPriorityProvider: HighPriorityProvider
@@ -198,7 +198,7 @@
groupManager,
headsUpManager,
filter,
- notifLog,
+ logger,
sectionsFeatureManager,
peopleNotificationIdentifier,
highPriorityProvider
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
index 66aa5e1..775f722 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
@@ -67,7 +67,7 @@
}
@Test
- public void testSetShouldContentViewsBeBound_bindsContent() {
+ public void testRequireContentViews() {
// WHEN inflation flags are set and pipeline is invalidated.
final int flags = FLAG_CONTENT_VIEW_CONTRACTED | FLAG_CONTENT_VIEW_EXPANDED;
RowContentBindParams params = mRowContentBindStage.getStageParams(mEntry);
@@ -85,7 +85,7 @@
}
@Test
- public void testSetShouldContentViewsBeBound_unbindsContent() {
+ public void testFreeContentViews() {
// GIVEN a view with all content bound.
RowContentBindParams params = mRowContentBindStage.getStageParams(mEntry);
params.requireContentViews(FLAG_CONTENT_VIEW_ALL);
@@ -100,6 +100,28 @@
}
@Test
+ public void testRebindAllContentViews() {
+ // GIVEN a view with content bound.
+ RowContentBindParams params = mRowContentBindStage.getStageParams(mEntry);
+ final int flags = FLAG_CONTENT_VIEW_CONTRACTED | FLAG_CONTENT_VIEW_EXPANDED;
+ params.requireContentViews(flags);
+ params.clearDirtyContentViews();
+
+ // WHEN we request rebind and stage executed.
+ params.rebindAllContentViews();
+ mRowContentBindStage.executeStage(mEntry, mRow, (en) -> { });
+
+ // THEN binder binds inflation flags.
+ verify(mBinder).bindContent(
+ eq(mEntry),
+ any(),
+ eq(flags),
+ any(),
+ anyBoolean(),
+ any());
+ }
+
+ @Test
public void testSetUseLowPriority() {
// GIVEN a view with all content bound.
RowContentBindParams params = mRowContentBindStage.getStageParams(mEntry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 70d76f0..b16e52c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -65,6 +65,7 @@
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
import com.android.systemui.statusbar.notification.TestableNotificationEntryManager;
@@ -74,7 +75,6 @@
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
-import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.FooterView;
@@ -163,14 +163,14 @@
ArgumentCaptor<UserChangedListener> userChangedCaptor = ArgumentCaptor
.forClass(UserChangedListener.class);
mEntryManager = new TestableNotificationEntryManager(
- mock(NotifLog.class),
+ mock(NotificationEntryManagerLogger.class),
mock(NotificationGroupManager.class),
new NotificationRankingManager(
() -> mock(NotificationMediaManager.class),
mGroupManager,
mHeadsUpManager,
mock(NotificationFilter.class),
- mock(NotifLog.class),
+ mock(NotificationEntryManagerLogger.class),
mock(NotificationSectionsFeatureManager.class),
mock(PeopleNotificationIdentifier.class),
mock(HighPriorityProvider.class)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt
new file mode 100644
index 0000000..8eecde1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt
@@ -0,0 +1,218 @@
+package com.android.systemui.util
+
+import android.graphics.Rect
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class FloatingContentCoordinatorTest : SysuiTestCase() {
+
+ private val screenBounds = Rect(0, 0, 1000, 1000)
+
+ private val rect100px = Rect()
+ private val rect100pxFloating = FloatingRect(rect100px)
+
+ private val rect200px = Rect()
+ private val rect200pxFloating = FloatingRect(rect200px)
+
+ private val rect300px = Rect()
+ private val rect300pxFloating = FloatingRect(rect300px)
+
+ private val floatingCoordinator = FloatingContentCoordinator()
+
+ @Before
+ fun setup() {
+ rect100px.set(0, 0, 100, 100)
+ rect200px.set(0, 0, 200, 200)
+ rect300px.set(0, 0, 300, 300)
+ }
+
+ @After
+ fun tearDown() {
+ // We need to remove this stuff since it's a singleton object and it'll be there for the
+ // next test.
+ floatingCoordinator.onContentRemoved(rect100pxFloating)
+ floatingCoordinator.onContentRemoved(rect200pxFloating)
+ floatingCoordinator.onContentRemoved(rect300pxFloating)
+ }
+
+ @Test
+ fun testOnContentAdded() {
+ // Add rect1, and verify that the coordinator didn't move it.
+ floatingCoordinator.onContentAdded(rect100pxFloating)
+ assertEquals(rect100px.top, 0)
+
+ // Add rect2, which intersects rect1. Verify that rect2 was not moved, since newly added
+ // content is allowed to remain where it is. rect1 should have been moved below rect2
+ // since it was in the way.
+ floatingCoordinator.onContentAdded(rect200pxFloating)
+ assertEquals(rect200px.top, 0)
+ assertEquals(rect100px.top, 200)
+
+ verifyRectSizes()
+ }
+
+ @Test
+ fun testOnContentRemoved() {
+ // Add rect1, and remove it. Then add rect2. Since rect1 was removed before that, it should
+ // no longer be considered in the way, so it shouldn't move when rect2 is added.
+ floatingCoordinator.onContentAdded(rect100pxFloating)
+ floatingCoordinator.onContentRemoved(rect100pxFloating)
+ floatingCoordinator.onContentAdded(rect200pxFloating)
+
+ assertEquals(rect100px.top, 0)
+ assertEquals(rect200px.top, 0)
+
+ verifyRectSizes()
+ }
+
+ @Test
+ fun testOnContentMoved_twoRects() {
+ // Add rect1, which is at y = 0.
+ floatingCoordinator.onContentAdded(rect100pxFloating)
+
+ // Move rect2 down to 500px, where it won't conflict with rect1.
+ rect200px.offsetTo(0, 500)
+ floatingCoordinator.onContentAdded(rect200pxFloating)
+
+ // Then, move it to 0px where it will absolutely conflict with rect1.
+ rect200px.offsetTo(0, 0)
+ floatingCoordinator.onContentMoved(rect200pxFloating)
+
+ // The coordinator should have left rect2 alone, and moved rect1 below it. rect1 should now
+ // be at y = 200.
+ assertEquals(rect200px.top, 0)
+ assertEquals(rect100px.top, 200)
+
+ verifyRectSizes()
+
+ // Move rect2 to y = 275px. Since this puts it at the bottom half of rect1, it should push
+ // rect1 upward and leave rect2 alone.
+ rect200px.offsetTo(0, 275)
+ floatingCoordinator.onContentMoved(rect200pxFloating)
+
+ assertEquals(rect200px.top, 275)
+ assertEquals(rect100px.top, 175)
+
+ verifyRectSizes()
+
+ // Move rect2 to y = 110px. This makes it intersect rect1 again, but above its center of
+ // mass. That means rect1 should be pushed downward.
+ rect200px.offsetTo(0, 110)
+ floatingCoordinator.onContentMoved(rect200pxFloating)
+
+ assertEquals(rect200px.top, 110)
+ assertEquals(rect100px.top, 310)
+
+ verifyRectSizes()
+ }
+
+ @Test
+ fun testOnContentMoved_threeRects() {
+ floatingCoordinator.onContentAdded(rect100pxFloating)
+
+ // Add rect2, which should displace rect1 to y = 200
+ floatingCoordinator.onContentAdded(rect200pxFloating)
+ assertEquals(rect200px.top, 0)
+ assertEquals(rect100px.top, 200)
+
+ // Add rect3, which should completely cover both rect1 and rect2. That should cause them to
+ // move away. The order in which they do so is non-deterministic, so just make sure none of
+ // the three Rects intersect.
+ floatingCoordinator.onContentAdded(rect300pxFloating)
+
+ assertFalse(Rect.intersects(rect100px, rect200px))
+ assertFalse(Rect.intersects(rect100px, rect300px))
+ assertFalse(Rect.intersects(rect200px, rect300px))
+
+ // Move rect2 to intersect both rect1 and rect3.
+ rect200px.offsetTo(0, 150)
+ floatingCoordinator.onContentMoved(rect200pxFloating)
+
+ assertFalse(Rect.intersects(rect100px, rect200px))
+ assertFalse(Rect.intersects(rect100px, rect300px))
+ assertFalse(Rect.intersects(rect200px, rect300px))
+ }
+
+ @Test
+ fun testOnContentMoved_respectsUpperBounds() {
+ // Add rect1, which is at y = 0.
+ floatingCoordinator.onContentAdded(rect100pxFloating)
+
+ // Move rect2 down to 500px, where it won't conflict with rect1.
+ rect200px.offsetTo(0, 500)
+ floatingCoordinator.onContentAdded(rect200pxFloating)
+
+ // Then, move it to 90px where it will conflict with rect1, but with a center of mass below
+ // that of rect1's. This would normally mean that rect1 moves upward. However, since it's at
+ // the top of the screen, it should go downward instead.
+ rect200px.offsetTo(0, 90)
+ floatingCoordinator.onContentMoved(rect200pxFloating)
+
+ // rect2 should have been left alone, rect1 is now below rect2 at y = 290px even though it
+ // was intersected from below.
+ assertEquals(rect200px.top, 90)
+ assertEquals(rect100px.top, 290)
+ }
+
+ @Test
+ fun testOnContentMoved_respectsLowerBounds() {
+ // Put rect1 at the bottom of the screen and add it.
+ rect100px.offsetTo(0, screenBounds.bottom - 100)
+ floatingCoordinator.onContentAdded(rect100pxFloating)
+
+ // Put rect2 at the bottom as well. Since its center of mass is above rect1's, rect1 would
+ // normally move downward. Since it's at the bottom of the screen, it should go upward
+ // instead.
+ rect200px.offsetTo(0, 800)
+ floatingCoordinator.onContentAdded(rect200pxFloating)
+
+ assertEquals(rect200px.top, 800)
+ assertEquals(rect100px.top, 700)
+ }
+
+ /**
+ * Tests that the rect sizes didn't change when the coordinator manipulated them. This allows us
+ * to assert only the value of rect.top in tests, since if top, width, and height are correct,
+ * that means top/left/right/bottom are all correct.
+ */
+ private fun verifyRectSizes() {
+ assertEquals(100, rect100px.width())
+ assertEquals(200, rect200px.width())
+ assertEquals(300, rect300px.width())
+
+ assertEquals(100, rect100px.height())
+ assertEquals(200, rect200px.height())
+ assertEquals(300, rect300px.height())
+ }
+
+ /**
+ * Helper class that uses [floatingCoordinator.findAreaForContentVertically] to move a
+ * Rect when needed.
+ */
+ inner class FloatingRect(
+ private val underlyingRect: Rect
+ ) : FloatingContentCoordinator.FloatingContent {
+ override fun moveToBounds(bounds: Rect) {
+ underlyingRect.set(bounds)
+ }
+
+ override fun getAllowedFloatingBoundsRegion(): Rect {
+ return screenBounds
+ }
+
+ override fun getFloatingBoundsOnScreen(): Rect {
+ return underlyingRect
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index 07abe1a..39c402b 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -272,13 +272,6 @@
mStateReceiver = new StateReceiver();
- mNetdCallback = new NetdCallback();
- try {
- mNetd.registerUnsolicitedEventListener(mNetdCallback);
- } catch (RemoteException e) {
- mLog.e("Unable to register netd UnsolicitedEventListener");
- }
-
final UserManager userManager = (UserManager) mContext.getSystemService(
Context.USER_SERVICE);
mTetheringRestriction = new UserRestrictionActionListener(userManager, this);
@@ -287,6 +280,14 @@
// Load tethering configuration.
updateConfiguration();
+ // NetdCallback should be registered after updateConfiguration() to ensure
+ // TetheringConfiguration is created.
+ mNetdCallback = new NetdCallback();
+ try {
+ mNetd.registerUnsolicitedEventListener(mNetdCallback);
+ } catch (RemoteException e) {
+ mLog.e("Unable to register netd UnsolicitedEventListener");
+ }
startStateMachineUpdaters(mHandler);
startTrackDefaultNetwork();
diff --git a/packages/overlays/Android.mk b/packages/overlays/Android.mk
index fc7709c..dcdb80b 100644
--- a/packages/overlays/Android.mk
+++ b/packages/overlays/Android.mk
@@ -28,6 +28,7 @@
DisplayCutoutEmulationDoubleOverlay \
DisplayCutoutEmulationHoleOverlay \
DisplayCutoutEmulationTallOverlay \
+ DisplayCutoutEmulationWaterfallOverlay \
FontNotoSerifSourceOverlay \
IconPackCircularAndroidOverlay \
IconPackCircularLauncherOverlay \
diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/Android.mk
new file mode 100644
index 0000000..b6b6dd1
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := DisplayCutoutEmulationWaterfall
+
+
+LOCAL_PRODUCT_MODULE := true
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := DisplayCutoutEmulationWaterfallOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/AndroidManifest.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..2d5bb14
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.internal.display.cutout.emulation.waterfall"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay android:targetPackage="android"
+ android:category="com.android.internal.display_cutout_emulation"
+ android:priority="1"/>
+
+ <application android:label="@string/display_cutout_emulation_overlay" android:hasCode="false"/>
+</manifest>
diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-land/config.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-land/config.xml
new file mode 100644
index 0000000..df2f3d1
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-land/config.xml
@@ -0,0 +1,22 @@
+<!--
+ ~ 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>
+ <!-- Can't link to other dimensions here, but this should be status_bar_height_landscape -->
+ <dimen name="quick_qs_offset_height">48dp</dimen>
+ <!-- Total height of QQS in landscape; quick_qs_offset_height + 128 -->
+ <dimen name="quick_qs_total_height">176dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values/config.xml
new file mode 100644
index 0000000..6f692c8
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values/config.xml
@@ -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.
+ -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Height of the status bar in portrait. The height should be
+ Max((status bar content height + waterfall top size), top cutout size) -->
+ <dimen name="status_bar_height_portrait">28dp</dimen>
+ <!-- Max((28 + 20), 0) = 48 -->
+ <dimen name="status_bar_height_landscape">48dp</dimen>
+ <!-- Height of area above QQS where battery/time go (equal to status bar height if > 48dp) -->
+ <dimen name="quick_qs_offset_height">28dp</dimen>
+ <!-- Total height of QQS (quick_qs_offset_height + 128) -->
+ <dimen name="quick_qs_total_height">156dp</dimen>
+
+ <dimen name="waterfall_display_left_edge_size">20dp</dimen>
+ <dimen name="waterfall_display_top_edge_size">0dp</dimen>
+ <dimen name="waterfall_display_right_edge_size">20dp</dimen>
+ <dimen name="waterfall_display_bottom_edge_size">0dp</dimen>
+</resources>
+
+
diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values/strings.xml
new file mode 100644
index 0000000..ed073d0
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <string name="display_cutout_emulation_overlay">Waterfall cutout</string>
+
+</resources>
\ No newline at end of file
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index a5877cc..565ee63 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -16,6 +16,8 @@
package com.android.server.accessibility;
+import static android.accessibilityservice.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE_ID;
+import static android.accessibilityservice.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER;
import static android.accessibilityservice.AccessibilityServiceInfo.DEFAULT;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS;
@@ -36,10 +38,11 @@
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
-import android.graphics.Bitmap;
+import android.graphics.GraphicBuffer;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
+import android.hardware.HardwareBuffer;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
import android.os.Binder;
@@ -50,6 +53,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
+import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -71,6 +75,7 @@
import com.android.internal.compat.IPlatformCompat;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection;
import com.android.server.wm.ActivityTaskManagerInternal;
@@ -106,6 +111,8 @@
private final PowerManager mPowerManager;
private final IPlatformCompat mIPlatformCompat;
+ private final Handler mMainHandler;
+
// Handler for scheduling method invocations on the main thread.
public final InvocationHandler mInvocationHandler;
@@ -238,6 +245,7 @@
mSecurityPolicy = securityPolicy;
mSystemActionPerformer = systemActionPerfomer;
mSystemSupport = systemSupport;
+ mMainHandler = mainHandler;
mInvocationHandler = new InvocationHandler(mainHandler.getLooper());
mA11yWindowManager = a11yWindowManager;
mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
@@ -959,52 +967,72 @@
mInvocationHandler.setSoftKeyboardCallbackEnabled(enabled);
}
- @Nullable
@Override
- public Bitmap takeScreenshot(int displayId) {
+ public void takeScreenshot(int displayId, RemoteCallback callback) {
synchronized (mLock) {
if (!hasRightsToCurrentUserLocked()) {
- return null;
+ sendScreenshotResult(true, null, callback);
+ return;
}
if (!mSecurityPolicy.canTakeScreenshotLocked(this)) {
- return null;
+ sendScreenshotResult(true, null, callback);
+ throw new SecurityException("Services don't have the capability of taking"
+ + " the screenshot.");
}
}
if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
- return null;
+ sendScreenshotResult(true, null, callback);
+ return;
}
final Display display = DisplayManagerGlobal.getInstance()
.getRealDisplay(displayId);
if (display == null) {
- return null;
+ sendScreenshotResult(true, null, callback);
+ return;
}
- final Point displaySize = new Point();
- display.getRealSize(displaySize);
- final int rotation = display.getRotation();
- Bitmap screenShot = null;
+ sendScreenshotResult(false, display, callback);
+ }
+ private void sendScreenshotResult(boolean noResult, Display display, RemoteCallback callback) {
+ final boolean noScreenshot = noResult;
final long identity = Binder.clearCallingIdentity();
try {
- final Rect crop = new Rect(0, 0, displaySize.x, displaySize.y);
- // TODO (b/145893483): calling new API with the display as a parameter
- // when surface control supported.
- screenShot = SurfaceControl.screenshot(crop, displaySize.x, displaySize.y,
- rotation);
- if (screenShot != null) {
- // Optimization for telling the bitmap that all of the pixels are known to be
- // opaque (false). This is meant as a drawing hint, as in some cases a bitmap
- // that is known to be opaque can take a faster drawing case than one that may
- // have non-opaque per-pixel alpha values.
- screenShot.setHasAlpha(false);
- }
+ mMainHandler.post(PooledLambda.obtainRunnable((nonArg) -> {
+ if (noScreenshot) {
+ callback.sendResult(null);
+ return;
+ }
+ final Point displaySize = new Point();
+ // TODO (b/145893483): calling new API with the display as a parameter
+ // when surface control supported.
+ final IBinder token = SurfaceControl.getInternalDisplayToken();
+ final Rect crop = new Rect(0, 0, displaySize.x, displaySize.y);
+ final int rotation = display.getRotation();
+ display.getRealSize(displaySize);
+
+ final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer =
+ SurfaceControl.screenshotToBufferWithSecureLayersUnsafe(token, crop,
+ displaySize.x, displaySize.y, false,
+ rotation);
+ final GraphicBuffer graphicBuffer = screenshotBuffer.getGraphicBuffer();
+ final HardwareBuffer hardwareBuffer =
+ HardwareBuffer.createFromGraphicBuffer(graphicBuffer);
+ final int colorSpaceId = screenshotBuffer.getColorSpace().getId();
+
+ // Send back the result.
+ final Bundle payload = new Bundle();
+ payload.putParcelable(KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER,
+ hardwareBuffer);
+ payload.putInt(KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE_ID, colorSpaceId);
+ callback.sendResult(payload);
+ }, null).recycleOnUse());
} finally {
Binder.restoreCallingIdentity(identity);
}
- return screenShot;
}
@Override
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 25911a7..edb4445 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -16,8 +16,6 @@
package com.android.server.accessibility;
-import static android.accessibilityservice.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT;
-
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.Manifest;
@@ -27,20 +25,16 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ParceledListSlice;
-import android.graphics.Bitmap;
import android.os.Binder;
-import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Process;
-import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
import android.view.Display;
-import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
@@ -393,15 +387,4 @@
}
}
}
-
- @Override
- public void takeScreenshotWithCallback(int displayId, RemoteCallback callback) {
- mMainHandler.post(PooledLambda.obtainRunnable((nonArg) -> {
- final Bitmap screenshot = super.takeScreenshot(displayId);
- // Send back the result.
- final Bundle payload = new Bundle();
- payload.putParcelable(KEY_ACCESSIBILITY_SCREENSHOT, screenshot);
- callback.sendResult(payload);
- }, null).recycleOnUse());
- }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
index 5d9af26..d1c3a02 100644
--- a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
@@ -328,6 +328,6 @@
public void onFingerprintGesture(int gesture) {}
@Override
- public void takeScreenshotWithCallback(int displayId, RemoteCallback callback) {}
+ public void takeScreenshot(int displayId, RemoteCallback callback) {}
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
index 5d170d3..b74be7e 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
@@ -30,6 +30,13 @@
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_RIGHT;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_UP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_TRIPLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_DOUBLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SINGLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_DOWN;
+import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_LEFT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_RIGHT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_UP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_TRIPLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_DOUBLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_DOUBLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN;
@@ -133,6 +140,13 @@
new MultiFingerMultiTap(mContext, 3, 2, GESTURE_3_FINGER_DOUBLE_TAP, this));
mMultiFingerGestures.add(
new MultiFingerMultiTap(mContext, 3, 3, GESTURE_3_FINGER_TRIPLE_TAP, this));
+ // Four-finger taps.
+ mMultiFingerGestures.add(
+ new MultiFingerMultiTap(mContext, 4, 1, GESTURE_4_FINGER_SINGLE_TAP, this));
+ mMultiFingerGestures.add(
+ new MultiFingerMultiTap(mContext, 4, 2, GESTURE_4_FINGER_DOUBLE_TAP, this));
+ mMultiFingerGestures.add(
+ new MultiFingerMultiTap(mContext, 4, 3, GESTURE_4_FINGER_TRIPLE_TAP, this));
// Two-finger swipes.
mMultiFingerGestures.add(
new MultiFingerSwipe(context, 2, DOWN, GESTURE_2_FINGER_SWIPE_DOWN, this));
@@ -151,6 +165,15 @@
new MultiFingerSwipe(context, 3, RIGHT, GESTURE_3_FINGER_SWIPE_RIGHT, this));
mMultiFingerGestures.add(
new MultiFingerSwipe(context, 3, UP, GESTURE_3_FINGER_SWIPE_UP, this));
+ // Four-finger swipes.
+ mMultiFingerGestures.add(
+ new MultiFingerSwipe(context, 4, DOWN, GESTURE_4_FINGER_SWIPE_DOWN, this));
+ mMultiFingerGestures.add(
+ new MultiFingerSwipe(context, 4, LEFT, GESTURE_4_FINGER_SWIPE_LEFT, this));
+ mMultiFingerGestures.add(
+ new MultiFingerSwipe(context, 4, RIGHT, GESTURE_4_FINGER_SWIPE_RIGHT, this));
+ mMultiFingerGestures.add(
+ new MultiFingerSwipe(context, 4, UP, GESTURE_4_FINGER_SWIPE_UP, this));
}
/**
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
index 8249239..a14584a 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
@@ -139,7 +139,7 @@
final int actionIndex = getActionIndex(rawEvent);
final int pointerId = rawEvent.getPointerId(actionIndex);
int pointerIndex = rawEvent.getPointerCount() - 1;
- if (pointerId < 0 || pointerId > rawEvent.getPointerCount() - 1) {
+ if (pointerId < 0) {
// Nonsensical pointer id.
cancelGesture(event, rawEvent, policyFlags);
return;
@@ -185,7 +185,7 @@
}
final int actionIndex = getActionIndex(rawEvent);
final int pointerId = rawEvent.getPointerId(actionIndex);
- if (pointerId < 0 || pointerId > rawEvent.getPointerCount() - 1) {
+ if (pointerId < 0) {
// Nonsensical pointer id.
cancelGesture(event, rawEvent, policyFlags);
return;
@@ -224,7 +224,7 @@
mCurrentFingerCount -= 1;
final int actionIndex = getActionIndex(event);
final int pointerId = event.getPointerId(actionIndex);
- if (pointerId < 0 || pointerId > rawEvent.getPointerCount() - 1) {
+ if (pointerId < 0) {
// Nonsensical pointer id.
cancelGesture(event, rawEvent, policyFlags);
return;
@@ -250,11 +250,29 @@
@Override
protected void onMove(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
- for (int pointerIndex = 0; pointerIndex < rawEvent.getPointerCount(); ++pointerIndex) {
+ for (int pointerIndex = 0; pointerIndex < mTargetFingerCount; ++pointerIndex) {
+ if (mPointerIds[pointerIndex] == INVALID_POINTER_ID) {
+ // Fingers have started to move before the required number of fingers are down.
+ // However, they can still move less than the touch slop and still be considered
+ // touching, not moving.
+ // So we just ignore fingers that haven't been assigned a pointer id and process
+ // those who have.
+ continue;
+ }
if (DEBUG) {
Slog.d(getGestureName(), "Processing move on finger " + pointerIndex);
}
int index = rawEvent.findPointerIndex(mPointerIds[pointerIndex]);
+ if (index < 0) {
+ // This finger is not present in this event. It could have gone up just before this
+ // movement.
+ if (DEBUG) {
+ Slog.d(
+ getGestureName(),
+ "Finger " + pointerIndex + " not found in this event. skipping.");
+ }
+ continue;
+ }
final float x = rawEvent.getX(index);
final float y = rawEvent.getY(index);
if (x < 0f || y < 0f) {
diff --git a/services/core/Android.bp b/services/core/Android.bp
index a603fa9..f33237f 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -115,8 +115,8 @@
"android.hardware.health-V2.0-java",
"android.hardware.light-java",
"android.hardware.weaver-V1.0-java",
- "android.hardware.biometrics.face-V1.0-java",
- "android.hardware.biometrics.fingerprint-V2.1-java",
+ "android.hardware.biometrics.face-V1.1-java",
+ "android.hardware.biometrics.fingerprint-V2.2-java",
"android.hardware.oemlock-V1.0-java",
"android.hardware.configstore-V1.0-java",
"android.hardware.contexthub-V1.0-java",
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index ec3dbe9..caacf13 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -602,7 +602,7 @@
private Set<String> mWolSupportedInterfaces;
- private TelephonyManager mTelephonyManager;
+ private final TelephonyManager mTelephonyManager;
private final AppOpsManager mAppOpsManager;
private final LocationPermissionChecker mLocationPermissionChecker;
@@ -961,6 +961,7 @@
mDeps = Objects.requireNonNull(deps, "missing Dependencies");
mSystemProperties = mDeps.getSystemProperties();
mNetIdManager = mDeps.makeNetIdManager();
+ mContext = Objects.requireNonNull(context, "missing Context");
mMetricsLog = logger;
mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
@@ -989,7 +990,6 @@
mLingerDelayMs = mSystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS);
- mContext = Objects.requireNonNull(context, "missing Context");
mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService");
mStatsService = Objects.requireNonNull(statsService, "missing INetworkStatsService");
mPolicyManager = Objects.requireNonNull(policyManager, "missing INetworkPolicyManager");
@@ -1169,6 +1169,7 @@
int transportType, NetworkRequest.Type type) {
final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
if (transportType > -1) {
netCap.addTransportType(transportType);
}
@@ -1699,10 +1700,12 @@
return newLp;
}
- private void restrictRequestUidsForCaller(NetworkCapabilities nc) {
+ private void restrictRequestUidsForCallerAndSetRequestorInfo(NetworkCapabilities nc,
+ int callerUid, String callerPackageName) {
if (!checkSettingsPermission()) {
- nc.setSingleUid(Binder.getCallingUid());
+ nc.setSingleUid(callerUid);
}
+ nc.setRequestorUidAndPackageName(callerUid, callerPackageName);
nc.setAdministratorUids(Collections.EMPTY_LIST);
// Clear owner UID; this can never come from an app.
@@ -5304,7 +5307,7 @@
// This checks that the passed capabilities either do not request a
// specific SSID/SignalStrength, or the calling app has permission to do so.
private void ensureSufficientPermissionsForRequest(NetworkCapabilities nc,
- int callerPid, int callerUid) {
+ int callerPid, int callerUid, String callerPackageName) {
if (null != nc.getSSID() && !checkSettingsPermission(callerPid, callerUid)) {
throw new SecurityException("Insufficient permissions to request a specific SSID");
}
@@ -5314,6 +5317,7 @@
throw new SecurityException(
"Insufficient permissions to request a specific signal strength");
}
+ mAppOpsManager.checkPackage(callerUid, callerPackageName);
}
private ArrayList<Integer> getSignalStrengthThresholds(NetworkAgentInfo nai) {
@@ -5360,7 +5364,6 @@
return;
}
MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(ns);
- ns.assertValidFromUid(Binder.getCallingUid());
}
private void ensureValid(NetworkCapabilities nc) {
@@ -5372,7 +5375,9 @@
@Override
public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
- Messenger messenger, int timeoutMs, IBinder binder, int legacyType) {
+ Messenger messenger, int timeoutMs, IBinder binder, int legacyType,
+ @NonNull String callingPackageName) {
+ final int callingUid = Binder.getCallingUid();
final NetworkRequest.Type type = (networkCapabilities == null)
? NetworkRequest.Type.TRACK_DEFAULT
: NetworkRequest.Type.REQUEST;
@@ -5380,7 +5385,7 @@
// the default network request. This allows callers to keep track of
// the system default network.
if (type == NetworkRequest.Type.TRACK_DEFAULT) {
- networkCapabilities = createDefaultNetworkCapabilitiesForUid(Binder.getCallingUid());
+ networkCapabilities = createDefaultNetworkCapabilitiesForUid(callingUid);
enforceAccessPermission();
} else {
networkCapabilities = new NetworkCapabilities(networkCapabilities);
@@ -5392,13 +5397,14 @@
}
ensureRequestableCapabilities(networkCapabilities);
ensureSufficientPermissionsForRequest(networkCapabilities,
- Binder.getCallingPid(), Binder.getCallingUid());
+ Binder.getCallingPid(), callingUid, callingPackageName);
// Set the UID range for this request to the single UID of the requester, or to an empty
// set of UIDs if the caller has the appropriate permission and UIDs have not been set.
// This will overwrite any allowed UIDs in the requested capabilities. Though there
// are no visible methods to set the UIDs, an app could use reflection to try and get
// networks for other apps so it's essential that the UIDs are overwritten.
- restrictRequestUidsForCaller(networkCapabilities);
+ restrictRequestUidsForCallerAndSetRequestorInfo(networkCapabilities,
+ callingUid, callingPackageName);
if (timeoutMs < 0) {
throw new IllegalArgumentException("Bad timeout specified");
@@ -5473,16 +5479,18 @@
@Override
public NetworkRequest pendingRequestForNetwork(NetworkCapabilities networkCapabilities,
- PendingIntent operation) {
+ PendingIntent operation, @NonNull String callingPackageName) {
Objects.requireNonNull(operation, "PendingIntent cannot be null.");
+ final int callingUid = Binder.getCallingUid();
networkCapabilities = new NetworkCapabilities(networkCapabilities);
enforceNetworkRequestPermissions(networkCapabilities);
enforceMeteredApnPolicy(networkCapabilities);
ensureRequestableCapabilities(networkCapabilities);
ensureSufficientPermissionsForRequest(networkCapabilities,
- Binder.getCallingPid(), Binder.getCallingUid());
+ Binder.getCallingPid(), callingUid, callingPackageName);
ensureValidNetworkSpecifier(networkCapabilities);
- restrictRequestUidsForCaller(networkCapabilities);
+ restrictRequestUidsForCallerAndSetRequestorInfo(networkCapabilities,
+ callingUid, callingPackageName);
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
nextNetworkRequestId(), NetworkRequest.Type.REQUEST);
@@ -5530,15 +5538,16 @@
@Override
public NetworkRequest listenForNetwork(NetworkCapabilities networkCapabilities,
- Messenger messenger, IBinder binder) {
+ Messenger messenger, IBinder binder, @NonNull String callingPackageName) {
+ final int callingUid = Binder.getCallingUid();
if (!hasWifiNetworkListenPermission(networkCapabilities)) {
enforceAccessPermission();
}
NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
ensureSufficientPermissionsForRequest(networkCapabilities,
- Binder.getCallingPid(), Binder.getCallingUid());
- restrictRequestUidsForCaller(nc);
+ Binder.getCallingPid(), callingUid, callingPackageName);
+ restrictRequestUidsForCallerAndSetRequestorInfo(nc, callingUid, callingPackageName);
// Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so
// make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get
// onLost and onAvailable callbacks when networks move in and out of the background.
@@ -5558,17 +5567,17 @@
@Override
public void pendingListenForNetwork(NetworkCapabilities networkCapabilities,
- PendingIntent operation) {
+ PendingIntent operation, @NonNull String callingPackageName) {
Objects.requireNonNull(operation, "PendingIntent cannot be null.");
+ final int callingUid = Binder.getCallingUid();
if (!hasWifiNetworkListenPermission(networkCapabilities)) {
enforceAccessPermission();
}
ensureValid(networkCapabilities);
ensureSufficientPermissionsForRequest(networkCapabilities,
- Binder.getCallingPid(), Binder.getCallingUid());
-
+ Binder.getCallingPid(), callingUid, callingPackageName);
final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
- restrictRequestUidsForCaller(nc);
+ restrictRequestUidsForCallerAndSetRequestorInfo(nc, callingUid, callingPackageName);
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
@@ -6581,6 +6590,7 @@
}
private ArrayMap<NetworkRequestInfo, NetworkAgentInfo> computeRequestReassignmentForNetwork(
+ @NonNull final NetworkReassignment changes,
@NonNull final NetworkAgentInfo newNetwork) {
final int score = newNetwork.getCurrentScore();
final ArrayMap<NetworkRequestInfo, NetworkAgentInfo> reassignedRequests = new ArrayMap<>();
@@ -6591,7 +6601,10 @@
// requests or not, and doesn't affect the network's score.
if (nri.request.isListen()) continue;
- final NetworkAgentInfo currentNetwork = nri.mSatisfier;
+ // The reassignment has been seeded with the initial assignment, therefore
+ // getReassignment can't be null and mNewNetwork is only null if there was no
+ // satisfier in the first place or there was an explicit reassignment to null.
+ final NetworkAgentInfo currentNetwork = changes.getReassignment(nri).mNewNetwork;
final boolean satisfies = newNetwork.satisfies(nri.request);
if (newNetwork == currentNetwork && satisfies) continue;
@@ -6641,7 +6654,7 @@
if (VDBG || DDBG) log("rematching " + newNetwork.name());
final ArrayMap<NetworkRequestInfo, NetworkAgentInfo> reassignedRequests =
- computeRequestReassignmentForNetwork(newNetwork);
+ computeRequestReassignmentForNetwork(changes, newNetwork);
// Find and migrate to this Network any NetworkRequests for
// which this network is now the best.
@@ -7855,12 +7868,13 @@
throw new IllegalArgumentException("ConnectivityManager.TYPE_* are deprecated."
+ " Please use NetworkCapabilities instead.");
}
- mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackageName);
+ final int callingUid = Binder.getCallingUid();
+ mAppOpsManager.checkPackage(callingUid, callingPackageName);
// This NetworkCapabilities is only used for matching to Networks. Clear out its owner uid
// and administrator uids to be safe.
final NetworkCapabilities nc = new NetworkCapabilities(request.networkCapabilities);
- restrictRequestUidsForCaller(nc);
+ restrictRequestUidsForCallerAndSetRequestorInfo(nc, callingUid, callingPackageName);
final NetworkRequest requestWithId =
new NetworkRequest(
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 50843b0..63cddac 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -30,6 +30,7 @@
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -305,11 +306,7 @@
public void onOpChanged(int op, String packageName) {
// onOpChanged invoked on ui thread, move to our thread to reduce risk
// of blocking ui thread
- mHandler.post(() -> {
- synchronized (mLock) {
- onAppOpChangedLocked();
- }
- });
+ mHandler.post(() -> onAppOpChanged(packageName));
}
});
mPackageManager.addOnPermissionsChangeListener(
@@ -392,13 +389,26 @@
}
}
- @GuardedBy("mLock")
- private void onAppOpChangedLocked() {
- for (Receiver receiver : mReceivers.values()) {
- receiver.updateMonitoring(true);
- }
- for (LocationProviderManager manager : mProviderManagers) {
- applyRequirementsLocked(manager);
+ private void onAppOpChanged(String packageName) {
+ synchronized (mLock) {
+ for (Receiver receiver : mReceivers.values()) {
+ if (receiver.mCallerIdentity.mPackageName.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.mPackageName.equals(packageName)) {
+ affectedProviders.add(provider);
+ }
+ }
+ }
+ for (String provider : affectedProviders) {
+ applyRequirementsLocked(provider);
+ }
}
}
@@ -2161,10 +2171,10 @@
@Override
public boolean injectLocation(Location location) {
- mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
- "Location Hardware permission not granted to inject location");
- mContext.enforceCallingPermission(ACCESS_FINE_LOCATION,
- "Access Fine Location permission not granted to inject Location");
+ mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE, null);
+ mContext.enforceCallingPermission(ACCESS_FINE_LOCATION, null);
+
+ Preconditions.checkArgument(location.isComplete());
synchronized (mLock) {
LocationProviderManager manager = getLocationProviderManager(location.getProvider());
@@ -2410,20 +2420,15 @@
@Override
public boolean isLocationEnabledForUser(int userId) {
- if (UserHandle.getCallingUserId() != userId) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS,
- null);
- }
-
+ userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+ userId, false, false, "isLocationEnabledForUser", null);
return mSettingsHelper.isLocationEnabled(userId);
}
@Override
public boolean isProviderEnabledForUser(String providerName, int userId) {
- if (UserHandle.getCallingUserId() != userId) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS,
- null);
- }
+ userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+ userId, false, false, "isProviderEnabledForUser", null);
// Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
// so we discourage its use
@@ -2732,6 +2737,9 @@
@Override
public void setTestProviderLocation(String provider, Location location, String packageName) {
+ Preconditions.checkArgument(location.isComplete(),
+ "incomplete location object, missing timestamp or accuracy?");
+
if (mAppOps.checkOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(), packageName)
!= AppOpsManager.MODE_ALLOWED) {
return;
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index b19a37e..f872c6b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -50,7 +50,7 @@
static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
static final boolean DEBUG_BROADCAST_DEFERRAL = DEBUG_BROADCAST || false;
static final boolean DEBUG_COMPACTION = DEBUG_ALL || false;
- static final boolean DEBUG_FREEZER = DEBUG_ALL || false;
+ static final boolean DEBUG_FREEZER = DEBUG_ALL || true;
static final boolean DEBUG_LRU = DEBUG_ALL || false;
static final boolean DEBUG_MU = DEBUG_ALL || false;
static final boolean DEBUG_NETWORK = DEBUG_ALL || false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 12b1cbf..3ad96ea 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2617,7 +2617,7 @@
mProcessCpuThread.start();
mBatteryStatsService.publish();
- mAppOpsService.publish(mContext);
+ mAppOpsService.publish();
Slog.d("AppOps", "AppOpsService published");
LocalServices.addService(ActivityManagerInternal.class, mInternal);
mActivityTaskManager.onActivityManagerInternalAdded();
@@ -19510,7 +19510,7 @@
}
public AppOpsService getAppOpsService(File file, Handler handler) {
- return new AppOpsService(file, handler);
+ return new AppOpsService(file, handler, getContext());
}
public Handler getUiHandler(ActivityManagerService service) {
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 313c185..d047a3c 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -442,7 +442,7 @@
*/
@GuardedBy("mPhenotypeFlagLock")
private void updateUseFreezer() {
- if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
KEY_USE_FREEZER, DEFAULT_USE_FREEZER)) {
mUseFreezer = isFreezerSupported();
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index a0589c5..06561f5 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -19,11 +19,15 @@
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.AppOpsManager.CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE;
import static android.app.AppOpsManager.FILTER_BY_FEATURE_ID;
import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
import static android.app.AppOpsManager.FILTER_BY_UID;
import static android.app.AppOpsManager.HistoricalOpsRequestFilter;
+import static android.app.AppOpsManager.KEY_BG_STATE_SETTLE_TIME;
+import static android.app.AppOpsManager.KEY_FG_SERVICE_STATE_SETTLE_TIME;
+import static android.app.AppOpsManager.KEY_TOP_STATE_SETTLE_TIME;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.NoteOpEvent;
import static android.app.AppOpsManager.OP_CAMERA;
@@ -41,6 +45,7 @@
import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
import static android.app.AppOpsManager.UID_STATE_TOP;
+import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES;
import static android.app.AppOpsManager._NUM_OP;
import static android.app.AppOpsManager.extractFlagsFromKey;
import static android.app.AppOpsManager.extractUidStateFromKey;
@@ -53,6 +58,10 @@
import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
import static android.os.Process.STATSD_UID;
+import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS;
+
+import static java.lang.Long.max;
+
import android.Manifest;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -70,6 +79,7 @@
import android.app.AppOpsManagerInternal;
import android.app.AppOpsManagerInternal.CheckOpsDelegate;
import android.app.AsyncNotedAppOp;
+import android.compat.Compatibility;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -129,7 +139,6 @@
import com.android.internal.app.IAppOpsService;
import com.android.internal.os.Zygote;
import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
@@ -216,7 +225,7 @@
//TODO: remove this when development is done.
private static final int TEMP_PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1 << 31;
- Context mContext;
+ final Context mContext;
final AtomicFile mFile;
final Handler mHandler;
@@ -291,8 +300,11 @@
@GuardedBy("this")
private CheckOpsDelegate mCheckOpsDelegate;
- @GuardedBy("this")
- private SparseArray<List<Integer>> mSwitchOpToOps;
+ /**
+ * Reverse lookup for {@link AppOpsManager#opToSwitch(int)}. Initialized once and never
+ * changed
+ */
+ private final SparseArray<int[]> mSwitchedOps = new SparseArray<>();
private ActivityManagerInternal mActivityManagerInternal;
@@ -343,30 +355,25 @@
*/
@VisibleForTesting
final class Constants extends ContentObserver {
- // Key names stored in the settings value.
- private static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
- private static final String KEY_FG_SERVICE_STATE_SETTLE_TIME
- = "fg_service_state_settle_time";
- private static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time";
/**
* How long we want for a drop in uid state from top to settle before applying it.
* @see Settings.Global#APP_OPS_CONSTANTS
- * @see #KEY_TOP_STATE_SETTLE_TIME
+ * @see AppOpsManager#KEY_TOP_STATE_SETTLE_TIME
*/
public long TOP_STATE_SETTLE_TIME;
/**
* How long we want for a drop in uid state from foreground to settle before applying it.
* @see Settings.Global#APP_OPS_CONSTANTS
- * @see #KEY_FG_SERVICE_STATE_SETTLE_TIME
+ * @see AppOpsManager#KEY_FG_SERVICE_STATE_SETTLE_TIME
*/
public long FG_SERVICE_STATE_SETTLE_TIME;
/**
* How long we want for a drop in uid state from background to settle before applying it.
* @see Settings.Global#APP_OPS_CONSTANTS
- * @see #KEY_BG_STATE_SETTLE_TIME
+ * @see AppOpsManager#KEY_BG_STATE_SETTLE_TIME
*/
public long BG_STATE_SETTLE_TIME;
@@ -1191,17 +1198,22 @@
final AudioRestrictionManager mAudioRestrictionManager = new AudioRestrictionManager();
final class ModeCallback implements DeathRecipient {
+ /** If mWatchedOpCode==ALL_OPS notify for ops affected by the switch-op */
+ public static final int ALL_OPS = -2;
+
final IAppOpsCallback mCallback;
final int mWatchingUid;
final int mFlags;
+ final int mWatchedOpCode;
final int mCallingUid;
final int mCallingPid;
- ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int callingUid,
- int callingPid) {
+ ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int watchedOp,
+ int callingUid, int callingPid) {
mCallback = callback;
mWatchingUid = watchingUid;
mFlags = flags;
+ mWatchedOpCode = watchedOp;
mCallingUid = callingUid;
mCallingPid = callingPid;
try {
@@ -1224,6 +1236,10 @@
UserHandle.formatUid(sb, mWatchingUid);
sb.append(" flags=0x");
sb.append(Integer.toHexString(mFlags));
+ if (mWatchedOpCode != OP_NONE) {
+ sb.append(" op=");
+ sb.append(opToName(mWatchedOpCode));
+ }
sb.append(" from uid=");
UserHandle.formatUid(sb, mCallingUid);
sb.append(" pid=");
@@ -1337,16 +1353,23 @@
featureOp.onClientDeath(clientId);
}
- public AppOpsService(File storagePath, Handler handler) {
+ public AppOpsService(File storagePath, Handler handler, Context context) {
+ mContext = context;
+
LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
mFile = new AtomicFile(storagePath, "appops");
mHandler = handler;
mConstants = new Constants(mHandler);
readState();
+
+ for (int switchedCode = 0; switchedCode < _NUM_OP; switchedCode++) {
+ int switchCode = AppOpsManager.opToSwitch(switchedCode);
+ mSwitchedOps.put(switchCode,
+ ArrayUtils.appendInt(mSwitchedOps.get(switchCode), switchedCode));
+ }
}
- public void publish(Context context) {
- mContext = context;
+ public void publish() {
ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
}
@@ -1616,6 +1639,19 @@
}
}
+ /**
+ * Update the pending state for the uid
+ *
+ * @param currentTime The current elapsed real time
+ * @param uid The uid that has a pending state
+ */
+ private void updatePendingState(long currentTime, int uid) {
+ synchronized (this) {
+ mLastRealtime = max(currentTime, mLastRealtime);
+ updatePendingStateIfNeededLocked(mUidStates.get(uid));
+ }
+ }
+
public void updateUidProcState(int uid, int procState,
@ActivityManager.ProcessCapability int capability) {
synchronized (this) {
@@ -1647,7 +1683,12 @@
} else {
settleTime = mConstants.BG_STATE_SETTLE_TIME;
}
- uidState.pendingStateCommitTime = SystemClock.elapsedRealtime() + settleTime;
+ final long commitTime = SystemClock.elapsedRealtime() + settleTime;
+ uidState.pendingStateCommitTime = commitTime;
+
+ mHandler.sendMessageDelayed(
+ PooledLambda.obtainMessage(AppOpsService::updatePendingState, this,
+ commitTime + 1, uid), settleTime + 1);
}
if (uidState.pkgOps != null) {
@@ -2014,6 +2055,19 @@
uidState.evalForegroundOps(mOpModeWatchers);
}
+ notifyOpChangedForAllPkgsInUid(code, uid, false, callbackToIgnore);
+ notifyOpChangedSync(code, uid, null, mode);
+ }
+
+ /**
+ * Notify that an op changed for all packages in an uid.
+ *
+ * @param code The op that changed
+ * @param uid The uid the op was changed for
+ * @param onlyForeground Only notify watchers that watch for foreground changes
+ */
+ private void notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground,
+ @Nullable IAppOpsCallback callbackToIgnore) {
String[] uidPackageNames = getPackagesForUid(uid);
ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null;
@@ -2023,6 +2077,10 @@
final int callbackCount = callbacks.size();
for (int i = 0; i < callbackCount; i++) {
ModeCallback callback = callbacks.valueAt(i);
+ if (onlyForeground && (callback.mFlags & WATCH_FOREGROUND_CHANGES) == 0) {
+ continue;
+ }
+
ArraySet<String> changedPackages = new ArraySet<>();
Collections.addAll(changedPackages, uidPackageNames);
if (callbackSpecs == null) {
@@ -2041,6 +2099,10 @@
final int callbackCount = callbacks.size();
for (int i = 0; i < callbackCount; i++) {
ModeCallback callback = callbacks.valueAt(i);
+ if (onlyForeground && (callback.mFlags & WATCH_FOREGROUND_CHANGES) == 0) {
+ continue;
+ }
+
ArraySet<String> changedPackages = callbackSpecs.get(callback);
if (changedPackages == null) {
changedPackages = new ArraySet<>();
@@ -2057,7 +2119,6 @@
}
if (callbackSpecs == null) {
- notifyOpChangedSync(code, uid, null, mode);
return;
}
@@ -2079,23 +2140,24 @@
}
}
}
-
- notifyOpChangedSync(code, uid, null, mode);
}
private void updatePermissionRevokedCompat(int uid, int switchCode, int mode) {
PackageManager packageManager = mContext.getPackageManager();
+ if (packageManager == null) {
+ // This can only happen during early boot. At this time the permission state and appop
+ // state are in sync
+ return;
+ }
+
String[] packageNames = packageManager.getPackagesForUid(uid);
if (ArrayUtils.isEmpty(packageNames)) {
return;
}
String packageName = packageNames[0];
- List<Integer> ops = getSwitchOpToOps().get(switchCode);
- int opsSize = CollectionUtils.size(ops);
- for (int i = 0; i < opsSize; i++) {
- int code = ops.get(i);
-
+ int[] ops = mSwitchedOps.get(switchCode);
+ for (int code : ops) {
String permissionName = AppOpsManager.opToPermission(code);
if (permissionName == null) {
continue;
@@ -2173,25 +2235,6 @@
}
}
- @NonNull
- private SparseArray<List<Integer>> getSwitchOpToOps() {
- synchronized (this) {
- if (mSwitchOpToOps == null) {
- mSwitchOpToOps = new SparseArray<>();
- for (int op = 0; op < _NUM_OP; op++) {
- int switchOp = AppOpsManager.opToSwitch(op);
- List<Integer> ops = mSwitchOpToOps.get(switchOp);
- if (ops == null) {
- ops = new ArrayList<>();
- mSwitchOpToOps.put(switchOp, ops);
- }
- ops.add(op);
- }
- }
- return mSwitchOpToOps;
- }
- }
-
private void notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode) {
final StorageManagerInternal storageManagerInternal =
LocalServices.getService(StorageManagerInternal.class);
@@ -2292,16 +2335,29 @@
if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
return;
}
- // There are features watching for mode changes such as window manager
- // and location manager which are in our process. The callbacks in these
- // features may require permissions our remote caller does not have.
- final long identity = Binder.clearCallingIdentity();
- try {
- callback.mCallback.opChanged(code, uid, packageName);
- } catch (RemoteException e) {
- /* ignore */
- } finally {
- Binder.restoreCallingIdentity(identity);
+
+ // See CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE
+ int[] switchedCodes;
+ if (callback.mWatchedOpCode == ALL_OPS) {
+ switchedCodes = mSwitchedOps.get(code);
+ } else if (callback.mWatchedOpCode == OP_NONE) {
+ switchedCodes = new int[]{code};
+ } else {
+ switchedCodes = new int[]{callback.mWatchedOpCode};
+ }
+
+ for (int switchedCode : switchedCodes) {
+ // There are features watching for mode changes such as window manager
+ // and location manager which are in our process. The callbacks in these
+ // features may require permissions our remote caller does not have.
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ callback.mCallback.opChanged(switchedCode, uid, packageName);
+ } catch (RemoteException e) {
+ /* ignore */
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
@@ -2496,17 +2552,32 @@
return;
}
synchronized (this) {
- op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
+ int switchOp = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
+
+ // See CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE
+ int notifiedOps;
+ if (Compatibility.isChangeEnabled(
+ CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE)) {
+ if (op == OP_NONE) {
+ notifiedOps = ALL_OPS;
+ } else {
+ notifiedOps = op;
+ }
+ } else {
+ notifiedOps = switchOp;
+ }
+
ModeCallback cb = mModeWatchers.get(callback.asBinder());
if (cb == null) {
- cb = new ModeCallback(callback, watchedUid, flags, callingUid, callingPid);
+ cb = new ModeCallback(callback, watchedUid, flags, notifiedOps, callingUid,
+ callingPid);
mModeWatchers.put(callback.asBinder(), cb);
}
- if (op != AppOpsManager.OP_NONE) {
- ArraySet<ModeCallback> cbs = mOpModeWatchers.get(op);
+ if (switchOp != AppOpsManager.OP_NONE) {
+ ArraySet<ModeCallback> cbs = mOpModeWatchers.get(switchOp);
if (cbs == null) {
cbs = new ArraySet<>();
- mOpModeWatchers.put(op, cbs);
+ mOpModeWatchers.put(switchOp, cbs);
}
cbs.add(cb);
}
@@ -3325,6 +3396,18 @@
uidState = new UidState(uid);
mUidStates.put(uid, uidState);
} else {
+ updatePendingStateIfNeededLocked(uidState);
+ }
+ return uidState;
+ }
+
+ /**
+ * Check if the pending state should be updated and do so if needed
+ *
+ * @param uidState The uidState that might have a pending state
+ */
+ private void updatePendingStateIfNeededLocked(@NonNull UidState uidState) {
+ if (uidState != null) {
if (uidState.pendingStateCommitTime != 0) {
if (uidState.pendingStateCommitTime < mLastRealtime) {
commitUidPendingStateLocked(uidState);
@@ -3336,7 +3419,6 @@
}
}
}
- return uidState;
}
private void commitUidPendingStateLocked(UidState uidState) {
@@ -3356,24 +3438,28 @@
&& uidState.appWidgetVisible == uidState.pendingAppWidgetVisible) {
continue;
}
- final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
- if (callbacks != null) {
- for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
- final ModeCallback callback = callbacks.valueAt(cbi);
- if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
- || !callback.isWatchingUid(uidState.uid)) {
- continue;
- }
- boolean doAllPackages = uidState.opModes != null
- && uidState.opModes.indexOfKey(code) >= 0
- && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND;
- if (uidState.pkgOps != null) {
+
+ if (uidState.opModes != null
+ && uidState.opModes.indexOfKey(code) >= 0
+ && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND) {
+ mHandler.sendMessage(PooledLambda.obtainMessage(
+ AppOpsService::notifyOpChangedForAllPkgsInUid,
+ this, code, uidState.uid, true, null));
+ } else {
+ final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
+ if (callbacks != null) {
+ for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
+ final ModeCallback callback = callbacks.valueAt(cbi);
+ if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
+ || !callback.isWatchingUid(uidState.uid)) {
+ continue;
+ }
for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
if (op == null) {
continue;
}
- if (doAllPackages || op.mode == AppOpsManager.MODE_FOREGROUND) {
+ if (op.mode == AppOpsManager.MODE_FOREGROUND) {
mHandler.sendMessage(PooledLambda.obtainMessage(
AppOpsService::notifyOpChanged,
this, callback, code, uidState.uid,
@@ -3798,11 +3884,7 @@
if (tagName.equals("op")) {
final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
- UidState uidState = getUidStateLocked(uid, true);
- if (uidState.opModes == null) {
- uidState.opModes = new SparseIntArray();
- }
- uidState.opModes.put(code, mode);
+ setUidMode(code, uid, mode);
} else {
Slog.w(TAG, "Unknown element under <uid-ops>: "
+ parser.getName());
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 0d88388..0f54984 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -99,6 +99,33 @@
public String[] getConfiguration(Context context) {
return context.getResources().getStringArray(R.array.config_biometric_sensors);
}
+
+ /**
+ * Allows us to mock FingerprintService for testing
+ */
+ @VisibleForTesting
+ public IFingerprintService getFingerprintService() {
+ return IFingerprintService.Stub.asInterface(
+ ServiceManager.getService(Context.FINGERPRINT_SERVICE));
+ }
+
+ /**
+ * Allows us to mock FaceService for testing
+ */
+ @VisibleForTesting
+ public IFaceService getFaceService() {
+ return IFaceService.Stub.asInterface(
+ ServiceManager.getService(Context.FACE_SERVICE));
+ }
+
+ /**
+ * Allows us to mock IrisService for testing
+ */
+ @VisibleForTesting
+ public IIrisService getIrisService() {
+ return IIrisService.Stub.asInterface(
+ ServiceManager.getService(Context.IRIS_SERVICE));
+ }
}
private final class AuthServiceImpl extends IAuthService.Stub {
@@ -178,7 +205,6 @@
mInjector = injector;
mImpl = new AuthServiceImpl();
- final PackageManager pm = context.getPackageManager();
}
private void registerAuthenticator(SensorConfig config) throws RemoteException {
@@ -191,18 +217,36 @@
switch (config.mModality) {
case TYPE_FINGERPRINT:
- authenticator = new FingerprintAuthenticator(IFingerprintService.Stub.asInterface(
- ServiceManager.getService(Context.FINGERPRINT_SERVICE)));
+ final IFingerprintService fingerprintService = mInjector.getFingerprintService();
+ if (fingerprintService == null) {
+ Slog.e(TAG, "Attempting to register with null FingerprintService. Please check"
+ + " your device configuration.");
+ return;
+ }
+
+ authenticator = new FingerprintAuthenticator(fingerprintService);
break;
case TYPE_FACE:
- authenticator = new FaceAuthenticator(IFaceService.Stub.asInterface(
- ServiceManager.getService(Context.FACE_SERVICE)));
+ final IFaceService faceService = mInjector.getFaceService();
+ if (faceService == null) {
+ Slog.e(TAG, "Attempting to register with null FaceService. Please check your"
+ + " device configuration.");
+ return;
+ }
+
+ authenticator = new FaceAuthenticator(faceService);
break;
case TYPE_IRIS:
- authenticator = new IrisAuthenticator(IIrisService.Stub.asInterface(
- ServiceManager.getService(Context.IRIS_SERVICE)));
+ final IIrisService irisService = mInjector.getIrisService();
+ if (irisService == null) {
+ Slog.e(TAG, "Attempting to register with null IrisService. Please check your"
+ + " device configuration.");
+ return;
+ }
+
+ authenticator = new IrisAuthenticator(irisService);
break;
default:
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
index 766e5c4..7bbda9f 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
@@ -20,11 +20,14 @@
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.IBiometricNativeHandle;
import android.os.IBinder;
+import android.os.NativeHandle;
import android.os.RemoteException;
import android.security.KeyStore;
import android.util.Slog;
+import java.io.IOException;
import java.util.ArrayList;
/**
@@ -41,6 +44,7 @@
public static final int LOCKOUT_PERMANENT = 2;
private final boolean mRequireConfirmation;
+ private final NativeHandle mWindowId;
// We need to track this state since it's possible for applications to request for
// authentication while the device is already locked out. In that case, the client is created
@@ -69,11 +73,25 @@
public AuthenticationClient(Context context, Constants constants,
BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
BiometricServiceBase.ServiceListener listener, int targetUserId, int groupId, long opId,
- boolean restricted, String owner, int cookie, boolean requireConfirmation) {
+ boolean restricted, String owner, int cookie, boolean requireConfirmation,
+ IBiometricNativeHandle windowId) {
super(context, constants, daemon, halDeviceId, token, listener, targetUserId, groupId,
restricted, owner, cookie);
mOpId = opId;
mRequireConfirmation = requireConfirmation;
+ mWindowId = Utils.dupNativeHandle(windowId);
+ }
+
+ @Override
+ public void destroy() {
+ if (mWindowId != null && mWindowId.getFileDescriptors() != null) {
+ try {
+ mWindowId.close();
+ } catch (IOException e) {
+ Slog.e(getLogTag(), "Failed to close windowId NativeHandle: ", e);
+ }
+ }
+ super.destroy();
}
protected long getStartTimeMs() {
@@ -233,7 +251,7 @@
onStart();
try {
mStartTimeMs = System.currentTimeMillis();
- final int result = getDaemonWrapper().authenticate(mOpId, getGroupId());
+ final int result = getDaemonWrapper().authenticate(mOpId, getGroupId(), mWindowId);
if (result != 0) {
Slog.w(getLogTag(), "startAuthentication failed, result=" + result);
mMetricsLogger.histogram(mConstants.tagAuthStartError(), result);
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index 687d935..0e70994 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -32,6 +32,7 @@
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.IBiometricNativeHandle;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.biometrics.IBiometricServiceReceiverInternal;
@@ -43,6 +44,7 @@
import android.os.IBinder;
import android.os.IHwBinder;
import android.os.IRemoteCallback;
+import android.os.NativeHandle;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
@@ -220,9 +222,10 @@
public AuthenticationClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
IBinder token, ServiceListener listener, int targetUserId, int groupId, long opId,
- boolean restricted, String owner, int cookie, boolean requireConfirmation) {
+ boolean restricted, String owner, int cookie, boolean requireConfirmation,
+ IBiometricNativeHandle windowId) {
super(context, getConstants(), daemon, halDeviceId, token, listener, targetUserId,
- groupId, opId, restricted, owner, cookie, requireConfirmation);
+ groupId, opId, restricted, owner, cookie, requireConfirmation, windowId);
}
@Override
@@ -283,10 +286,10 @@
public EnrollClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
IBinder token, ServiceListener listener, int userId, int groupId,
byte[] cryptoToken, boolean restricted, String owner,
- final int[] disabledFeatures, int timeoutSec) {
+ final int[] disabledFeatures, int timeoutSec, IBiometricNativeHandle windowId) {
super(context, getConstants(), daemon, halDeviceId, token, listener,
userId, groupId, cryptoToken, restricted, owner, getBiometricUtils(),
- disabledFeatures, timeoutSec);
+ disabledFeatures, timeoutSec, windowId);
}
@Override
@@ -472,12 +475,13 @@
*/
protected interface DaemonWrapper {
int ERROR_ESRCH = 3; // Likely HAL is dead. see errno.h.
- int authenticate(long operationId, int groupId) throws RemoteException;
+ int authenticate(long operationId, int groupId, NativeHandle windowId)
+ throws RemoteException;
int cancel() throws RemoteException;
int remove(int groupId, int biometricId) throws RemoteException;
int enumerate() throws RemoteException;
int enroll(byte[] token, int groupId, int timeout,
- ArrayList<Integer> disabledFeatures) throws RemoteException;
+ ArrayList<Integer> disabledFeatures, NativeHandle windowId) throws RemoteException;
void resetLockout(byte[] token) throws RemoteException;
}
diff --git a/services/core/java/com/android/server/biometrics/EnrollClient.java b/services/core/java/com/android/server/biometrics/EnrollClient.java
index 7ebb7c0..684795e 100644
--- a/services/core/java/com/android/server/biometrics/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/EnrollClient.java
@@ -20,10 +20,13 @@
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.IBiometricNativeHandle;
import android.os.IBinder;
+import android.os.NativeHandle;
import android.os.RemoteException;
import android.util.Slog;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -35,6 +38,7 @@
private final BiometricUtils mBiometricUtils;
private final int[] mDisabledFeatures;
private final int mTimeoutSec;
+ private final NativeHandle mWindowId;
private long mEnrollmentStartTimeMs;
@@ -44,13 +48,26 @@
BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
BiometricServiceBase.ServiceListener listener, int userId, int groupId,
byte[] cryptoToken, boolean restricted, String owner, BiometricUtils utils,
- final int[] disabledFeatures, int timeoutSec) {
+ final int[] disabledFeatures, int timeoutSec, IBiometricNativeHandle windowId) {
super(context, constants, daemon, halDeviceId, token, listener, userId, groupId, restricted,
owner, 0 /* cookie */);
mBiometricUtils = utils;
mCryptoToken = Arrays.copyOf(cryptoToken, cryptoToken.length);
mDisabledFeatures = Arrays.copyOf(disabledFeatures, disabledFeatures.length);
mTimeoutSec = timeoutSec;
+ mWindowId = Utils.dupNativeHandle(windowId);
+ }
+
+ @Override
+ public void destroy() {
+ if (mWindowId != null && mWindowId.getFileDescriptors() != null) {
+ try {
+ mWindowId.close();
+ } catch (IOException e) {
+ Slog.e(getLogTag(), "Failed to close windowId NativeHandle: ", e);
+ }
+ }
+ super.destroy();
}
@Override
@@ -102,7 +119,7 @@
}
final int result = getDaemonWrapper().enroll(mCryptoToken, getGroupId(), mTimeoutSec,
- disabledFeatures);
+ disabledFeatures, mWindowId);
if (result != 0) {
Slog.w(getLogTag(), "startEnroll failed, result=" + result);
mMetricsLogger.histogram(mConstants.tagEnrollStartError(), result);
diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java
index 389763b..2d4ab63 100644
--- a/services/core/java/com/android/server/biometrics/Utils.java
+++ b/services/core/java/com/android/server/biometrics/Utils.java
@@ -23,12 +23,17 @@
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricPrompt.AuthenticationResultType;
+import android.hardware.biometrics.IBiometricNativeHandle;
import android.os.Build;
import android.os.Bundle;
+import android.os.NativeHandle;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
+import java.io.FileDescriptor;
+import java.io.IOException;
+
public class Utils {
public static boolean isDebugEnabled(Context context, int targetUserId) {
if (targetUserId == UserHandle.USER_NULL) {
@@ -237,4 +242,31 @@
throw new IllegalArgumentException("Unsupported dismissal reason: " + reason);
}
}
+
+ /**
+ * Converts an {@link IBiometricNativeHandle} to a {@link NativeHandle} by duplicating the
+ * the underlying file descriptors.
+ *
+ * Both the original and new handle must be closed after use.
+ *
+ * @param h {@link IBiometricNativeHandle} received as a binder call argument. Usually used to
+ * identify a WindowManager window. Can be null.
+ * @return A {@link NativeHandle} representation of {@code h}. Will be null if either {@code h}
+ * or its contents are null.
+ */
+ public static NativeHandle dupNativeHandle(IBiometricNativeHandle h) {
+ NativeHandle handle = null;
+ if (h != null && h.fds != null && h.ints != null) {
+ FileDescriptor[] fds = new FileDescriptor[h.fds.length];
+ for (int i = 0; i < h.fds.length; ++i) {
+ try {
+ fds[i] = h.fds[i].dup().getFileDescriptor();
+ } catch (IOException e) {
+ return null;
+ }
+ }
+ handle = new NativeHandle(fds, h.ints, true /* own */);
+ }
+ return handle;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index b512475..31c3d4d 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -34,6 +34,7 @@
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.IBiometricNativeHandle;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.biometrics.IBiometricServiceReceiverInternal;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
@@ -214,9 +215,10 @@
public FaceAuthClient(Context context,
DaemonWrapper daemon, long halDeviceId, IBinder token,
ServiceListener listener, int targetUserId, int groupId, long opId,
- boolean restricted, String owner, int cookie, boolean requireConfirmation) {
+ boolean restricted, String owner, int cookie, boolean requireConfirmation,
+ IBiometricNativeHandle windowId) {
super(context, daemon, halDeviceId, token, listener, targetUserId, groupId, opId,
- restricted, owner, cookie, requireConfirmation);
+ restricted, owner, cookie, requireConfirmation, windowId);
}
@Override
@@ -373,7 +375,7 @@
@Override // Binder call
public void enroll(int userId, final IBinder token, final byte[] cryptoToken,
final IFaceServiceReceiver receiver, final String opPackageName,
- final int[] disabledFeatures) {
+ final int[] disabledFeatures, IBiometricNativeHandle windowId) {
checkPermission(MANAGE_BIOMETRIC);
updateActiveGroup(userId, opPackageName);
@@ -384,7 +386,7 @@
final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId,
0 /* groupId */, cryptoToken, restricted, opPackageName, disabledFeatures,
- ENROLL_TIMEOUT_SEC) {
+ ENROLL_TIMEOUT_SEC, windowId) {
@Override
public int[] getAcquireIgnorelist() {
@@ -411,6 +413,14 @@
}
@Override // Binder call
+ public void enrollRemotely(int userId, final IBinder token, final byte[] cryptoToken,
+ final IFaceServiceReceiver receiver, final String opPackageName,
+ final int[] disabledFeatures) {
+ checkPermission(MANAGE_BIOMETRIC);
+ // TODO(b/145027036): Implement this.
+ }
+
+ @Override // Binder call
public void cancelEnrollment(final IBinder token) {
checkPermission(MANAGE_BIOMETRIC);
cancelEnrollmentInternal(token);
@@ -426,7 +436,7 @@
final AuthenticationClientImpl client = new FaceAuthClient(getContext(),
mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName,
- 0 /* cookie */, false /* requireConfirmation */);
+ 0 /* cookie */, false /* requireConfirmation */, null /* windowId */);
authenticateInternal(client, opId, opPackageName);
}
@@ -442,7 +452,7 @@
mDaemonWrapper, mHalDeviceId, token,
new BiometricPromptServiceListenerImpl(wrapperReceiver),
mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName, cookie,
- requireConfirmation);
+ requireConfirmation, null /* windowId */);
authenticateInternal(client, opId, opPackageName, callingUid, callingPid,
callingUserId);
}
@@ -985,7 +995,8 @@
*/
private final DaemonWrapper mDaemonWrapper = new DaemonWrapper() {
@Override
- public int authenticate(long operationId, int groupId) throws RemoteException {
+ public int authenticate(long operationId, int groupId, NativeHandle windowId)
+ throws RemoteException {
IBiometricsFace daemon = getFaceDaemon();
if (daemon == null) {
Slog.w(TAG, "authenticate(): no face HAL!");
@@ -1026,7 +1037,7 @@
@Override
public int enroll(byte[] cryptoToken, int groupId, int timeout,
- ArrayList<Integer> disabledFeatures) throws RemoteException {
+ ArrayList<Integer> disabledFeatures, NativeHandle windowId) throws RemoteException {
IBiometricsFace daemon = getFaceDaemon();
if (daemon == null) {
Slog.w(TAG, "enroll(): no face HAL!");
@@ -1036,7 +1047,17 @@
for (int i = 0; i < cryptoToken.length; i++) {
token.add(cryptoToken[i]);
}
- return daemon.enroll(token, timeout, disabledFeatures);
+ android.hardware.biometrics.face.V1_1.IBiometricsFace daemon11 =
+ android.hardware.biometrics.face.V1_1.IBiometricsFace.castFrom(
+ daemon);
+ if (daemon11 != null) {
+ return daemon11.enroll_1_1(token, timeout, disabledFeatures, windowId);
+ } else if (windowId == null) {
+ return daemon.enroll(token, timeout, disabledFeatures);
+ } else {
+ Slog.e(TAG, "enroll(): windowId is only supported in @1.1 HAL");
+ return ERROR_ESRCH;
+ }
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintAuthenticator.java
index 6150de1..7a4e62e 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintAuthenticator.java
@@ -38,7 +38,7 @@
String opPackageName, int cookie, int callingUid, int callingPid, int callingUserId)
throws RemoteException {
mFingerprintService.prepareForAuthentication(token, sessionId, userId, wrapperReceiver,
- opPackageName, cookie, callingUid, callingPid, callingUserId);
+ opPackageName, cookie, callingUid, callingPid, callingUserId, null /* windowId */);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index 44797ad..57d1867 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -37,6 +37,7 @@
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.IBiometricNativeHandle;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.biometrics.IBiometricServiceReceiverInternal;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
@@ -50,6 +51,7 @@
import android.os.Build;
import android.os.Environment;
import android.os.IBinder;
+import android.os.NativeHandle;
import android.os.RemoteException;
import android.os.SELinux;
import android.os.SystemClock;
@@ -132,9 +134,9 @@
DaemonWrapper daemon, long halDeviceId, IBinder token,
ServiceListener listener, int targetUserId, int groupId, long opId,
boolean restricted, String owner, int cookie,
- boolean requireConfirmation) {
+ boolean requireConfirmation, IBiometricNativeHandle windowId) {
super(context, daemon, halDeviceId, token, listener, targetUserId, groupId, opId,
- restricted, owner, cookie, requireConfirmation);
+ restricted, owner, cookie, requireConfirmation, windowId);
}
@Override
@@ -198,7 +200,7 @@
@Override // Binder call
public void enroll(final IBinder token, final byte[] cryptoToken, final int userId,
final IFingerprintServiceReceiver receiver, final int flags,
- final String opPackageName) {
+ final String opPackageName, IBiometricNativeHandle windowId) {
checkPermission(MANAGE_FINGERPRINT);
final boolean restricted = isRestricted();
@@ -206,7 +208,7 @@
final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId, groupId,
cryptoToken, restricted, opPackageName, new int[0] /* disabledFeatures */,
- ENROLL_TIMEOUT_SEC) {
+ ENROLL_TIMEOUT_SEC, windowId) {
@Override
public boolean shouldVibrate() {
return true;
@@ -230,20 +232,22 @@
@Override // Binder call
public void authenticate(final IBinder token, final long opId, final int groupId,
final IFingerprintServiceReceiver receiver, final int flags,
- final String opPackageName) {
+ final String opPackageName, IBiometricNativeHandle windowId) {
updateActiveGroup(groupId, opPackageName);
final boolean restricted = isRestricted();
final AuthenticationClientImpl client = new FingerprintAuthClient(getContext(),
mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
mCurrentUserId, groupId, opId, restricted, opPackageName,
- 0 /* cookie */, false /* requireConfirmation */);
+ 0 /* cookie */, false /* requireConfirmation */,
+ windowId);
authenticateInternal(client, opId, opPackageName);
}
@Override // Binder call
public void prepareForAuthentication(IBinder token, long opId, int groupId,
IBiometricServiceReceiverInternal wrapperReceiver, String opPackageName,
- int cookie, int callingUid, int callingPid, int callingUserId) {
+ int cookie, int callingUid, int callingPid, int callingUserId,
+ IBiometricNativeHandle windowId) {
checkPermission(MANAGE_BIOMETRIC);
updateActiveGroup(groupId, opPackageName);
final boolean restricted = true; // BiometricPrompt is always restricted
@@ -251,7 +255,8 @@
mDaemonWrapper, mHalDeviceId, token,
new BiometricPromptServiceListenerImpl(wrapperReceiver),
mCurrentUserId, groupId, opId, restricted, opPackageName, cookie,
- false /* requireConfirmation */);
+ false /* requireConfirmation */,
+ windowId);
authenticateInternal(client, opId, opPackageName, callingUid, callingPid,
callingUserId);
}
@@ -654,13 +659,24 @@
*/
private final DaemonWrapper mDaemonWrapper = new DaemonWrapper() {
@Override
- public int authenticate(long operationId, int groupId) throws RemoteException {
+ public int authenticate(long operationId, int groupId, NativeHandle windowId)
+ throws RemoteException {
IBiometricsFingerprint daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "authenticate(): no fingerprint HAL!");
return ERROR_ESRCH;
}
- return daemon.authenticate(operationId, groupId);
+ android.hardware.biometrics.fingerprint.V2_2.IBiometricsFingerprint daemon22 =
+ android.hardware.biometrics.fingerprint.V2_2.IBiometricsFingerprint.castFrom(
+ daemon);
+ if (daemon22 != null) {
+ return daemon22.authenticate_2_2(operationId, groupId, windowId);
+ } else if (windowId == null) {
+ return daemon.authenticate(operationId, groupId);
+ } else {
+ Slog.e(TAG, "authenticate(): windowId is only supported in @2.2 HAL");
+ return ERROR_ESRCH;
+ }
}
@Override
@@ -695,13 +711,27 @@
@Override
public int enroll(byte[] cryptoToken, int groupId, int timeout,
- ArrayList<Integer> disabledFeatures) throws RemoteException {
+ ArrayList<Integer> disabledFeatures, NativeHandle windowId) throws RemoteException {
IBiometricsFingerprint daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "enroll(): no fingerprint HAL!");
return ERROR_ESRCH;
}
- return daemon.enroll(cryptoToken, groupId, timeout);
+ android.hardware.biometrics.fingerprint.V2_2.IBiometricsFingerprint daemon22 =
+ android.hardware.biometrics.fingerprint.V2_2.IBiometricsFingerprint.castFrom(
+ daemon);
+ if (daemon22 != null) {
+ ArrayList<Byte> cryptoTokenAsList = new ArrayList<>(cryptoToken.length);
+ for (byte b : cryptoToken) {
+ cryptoTokenAsList.add(b);
+ }
+ return daemon22.enroll_2_2(cryptoTokenAsList, groupId, timeout, windowId);
+ } else if (windowId == null) {
+ return daemon.enroll(cryptoToken, groupId, timeout);
+ } else {
+ Slog.e(TAG, "enroll(): windowId is only supported in @2.2 HAL");
+ return ERROR_ESRCH;
+ }
}
@Override
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 2fc9d04..af47430 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -16,6 +16,12 @@
package com.android.server.compat;
+import static android.Manifest.permission.LOG_COMPAT_CHANGE;
+import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG;
+import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.content.Context;
@@ -67,12 +73,14 @@
@Override
public void reportChange(long changeId, ApplicationInfo appInfo) {
+ checkCompatChangeLogPermission();
reportChange(changeId, appInfo.uid,
ChangeReporter.STATE_LOGGED);
}
@Override
public void reportChangeByPackageName(long changeId, String packageName, int userId) {
+ checkCompatChangeLogPermission();
ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
if (appInfo == null) {
return;
@@ -82,11 +90,13 @@
@Override
public void reportChangeByUid(long changeId, int uid) {
+ checkCompatChangeLogPermission();
reportChange(changeId, uid, ChangeReporter.STATE_LOGGED);
}
@Override
public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
+ checkCompatChangeReadAndLogPermission();
if (mCompatConfig.isChangeEnabled(changeId, appInfo)) {
reportChange(changeId, appInfo.uid,
ChangeReporter.STATE_ENABLED);
@@ -98,7 +108,9 @@
}
@Override
- public boolean isChangeEnabledByPackageName(long changeId, String packageName, int userId) {
+ public boolean isChangeEnabledByPackageName(long changeId, String packageName,
+ @UserIdInt int userId) {
+ checkCompatChangeReadAndLogPermission();
ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
if (appInfo == null) {
return true;
@@ -108,6 +120,7 @@
@Override
public boolean isChangeEnabledByUid(long changeId, int uid) {
+ checkCompatChangeReadAndLogPermission();
String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
if (packages == null || packages.length == 0) {
return true;
@@ -140,6 +153,7 @@
@Override
public void setOverrides(CompatibilityChangeConfig overrides, String packageName)
throws RemoteException, SecurityException {
+ checkCompatChangeOverridePermission();
mCompatConfig.addOverrides(overrides, packageName);
killPackage(packageName);
}
@@ -147,11 +161,13 @@
@Override
public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName)
throws RemoteException, SecurityException {
+ checkCompatChangeOverridePermission();
mCompatConfig.addOverrides(overrides, packageName);
}
@Override
public void clearOverrides(String packageName) throws RemoteException, SecurityException {
+ checkCompatChangeOverridePermission();
mCompatConfig.removePackageOverrides(packageName);
killPackage(packageName);
}
@@ -159,12 +175,14 @@
@Override
public void clearOverridesForTest(String packageName)
throws RemoteException, SecurityException {
+ checkCompatChangeOverridePermission();
mCompatConfig.removePackageOverrides(packageName);
}
@Override
public boolean clearOverride(long changeId, String packageName)
throws RemoteException, SecurityException {
+ checkCompatChangeOverridePermission();
boolean existed = mCompatConfig.removeOverride(changeId, packageName);
killPackage(packageName);
return existed;
@@ -172,11 +190,13 @@
@Override
public CompatibilityChangeConfig getAppConfig(ApplicationInfo appInfo) {
+ checkCompatChangeReadAndLogPermission();
return mCompatConfig.getAppConfig(appInfo);
}
@Override
public CompatibilityChangeInfo[] listAllChanges() {
+ checkCompatChangeReadPermission();
return mCompatConfig.dumpChanges();
}
@@ -215,6 +235,7 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ checkCompatChangeReadAndLogPermission();
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return;
mCompatConfig.dumpConfig(pw);
}
@@ -272,4 +293,30 @@
Binder.restoreCallingIdentity(identity);
}
}
+
+ private void checkCompatChangeLogPermission() throws SecurityException {
+ if (mContext.checkCallingOrSelfPermission(LOG_COMPAT_CHANGE)
+ != PERMISSION_GRANTED) {
+ throw new SecurityException("Cannot log compat change usage");
+ }
+ }
+
+ private void checkCompatChangeReadPermission() throws SecurityException {
+ if (mContext.checkCallingOrSelfPermission(READ_COMPAT_CHANGE_CONFIG)
+ != PERMISSION_GRANTED) {
+ throw new SecurityException("Cannot read compat change");
+ }
+ }
+
+ private void checkCompatChangeOverridePermission() throws SecurityException {
+ if (mContext.checkCallingOrSelfPermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
+ != PERMISSION_GRANTED) {
+ throw new SecurityException("Cannot override compat change");
+ }
+ }
+
+ private void checkCompatChangeReadAndLogPermission() throws SecurityException {
+ checkCompatChangeReadPermission();
+ checkCompatChangeLogPermission();
+ }
}
diff --git a/services/core/java/com/android/server/compat/PlatformCompatNative.java b/services/core/java/com/android/server/compat/PlatformCompatNative.java
index 85dfbf4..5d7af65 100644
--- a/services/core/java/com/android/server/compat/PlatformCompatNative.java
+++ b/services/core/java/com/android/server/compat/PlatformCompatNative.java
@@ -16,6 +16,8 @@
package com.android.server.compat;
+import android.annotation.UserIdInt;
+
import com.android.internal.compat.IPlatformCompatNative;
/**
@@ -39,7 +41,8 @@
}
@Override
- public boolean isChangeEnabledByPackageName(long changeId, String packageName, int userId) {
+ public boolean isChangeEnabledByPackageName(long changeId, String packageName,
+ @UserIdInt int userId) {
return mPlatformCompat.isChangeEnabledByPackageName(changeId, packageName, userId);
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 89af5b5..cb88c4e 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -49,6 +49,7 @@
import android.net.ConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.IpPrefix;
+import android.net.IpSecManager;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.LocalSocket;
@@ -180,7 +181,10 @@
private boolean mIsPackageTargetingAtLeastQ;
private String mInterface;
private Connection mConnection;
- private LegacyVpnRunner mLegacyVpnRunner;
+
+ /** Tracks the runners for all VPN types managed by the platform (eg. LegacyVpn, PlatformVpn) */
+ private VpnRunner mVpnRunner;
+
private PendingIntent mStatusIntent;
private volatile boolean mEnableTeardown = true;
private final INetworkManagementService mNetd;
@@ -762,7 +766,7 @@
mNetworkCapabilities.setUids(null);
}
- // Revoke the connection or stop LegacyVpnRunner.
+ // Revoke the connection or stop the VpnRunner.
if (mConnection != null) {
try {
mConnection.mService.transact(IBinder.LAST_CALL_TRANSACTION,
@@ -772,9 +776,9 @@
}
mContext.unbindService(mConnection);
mConnection = null;
- } else if (mLegacyVpnRunner != null) {
- mLegacyVpnRunner.exit();
- mLegacyVpnRunner = null;
+ } else if (mVpnRunner != null) {
+ mVpnRunner.exit();
+ mVpnRunner = null;
}
try {
@@ -1510,8 +1514,8 @@
@Override
public void interfaceStatusChanged(String interfaze, boolean up) {
synchronized (Vpn.this) {
- if (!up && mLegacyVpnRunner != null) {
- mLegacyVpnRunner.check(interfaze);
+ if (!up && mVpnRunner != null && mVpnRunner instanceof LegacyVpnRunner) {
+ ((LegacyVpnRunner) mVpnRunner).exitIfOuterInterfaceIs(interfaze);
}
}
}
@@ -1528,9 +1532,10 @@
mContext.unbindService(mConnection);
mConnection = null;
agentDisconnect();
- } else if (mLegacyVpnRunner != null) {
- mLegacyVpnRunner.exit();
- mLegacyVpnRunner = null;
+ } else if (mVpnRunner != null) {
+ // agentDisconnect must be called from mVpnRunner.exit()
+ mVpnRunner.exit();
+ mVpnRunner = null;
}
}
}
@@ -1913,23 +1918,40 @@
private synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd,
VpnProfile profile) {
- stopLegacyVpnPrivileged();
+ stopVpnRunnerPrivileged();
// Prepare for the new request.
prepareInternal(VpnConfig.LEGACY_VPN);
updateState(DetailedState.CONNECTING, "startLegacyVpn");
// Start a new LegacyVpnRunner and we are done!
- mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd, profile);
- mLegacyVpnRunner.start();
+ mVpnRunner = new LegacyVpnRunner(config, racoon, mtpd, profile);
+ mVpnRunner.start();
}
- /** Stop legacy VPN. Permissions must be checked by callers. */
- public synchronized void stopLegacyVpnPrivileged() {
- if (mLegacyVpnRunner != null) {
- mLegacyVpnRunner.exit();
- mLegacyVpnRunner = null;
+ /**
+ * Checks if this the currently running VPN (if any) was started by the Settings app
+ *
+ * <p>This includes both Legacy VPNs and Platform VPNs.
+ */
+ private boolean isSettingsVpnLocked() {
+ return mVpnRunner != null && VpnConfig.LEGACY_VPN.equals(mPackage);
+ }
+ /** Stop VPN runner. Permissions must be checked by callers. */
+ public synchronized void stopVpnRunnerPrivileged() {
+ if (!isSettingsVpnLocked()) {
+ return;
+ }
+
+ final boolean isLegacyVpn = mVpnRunner instanceof LegacyVpnRunner;
+
+ mVpnRunner.exit();
+ mVpnRunner = null;
+
+ // LegacyVpn uses daemons that must be shut down before new ones are brought up.
+ // The same limitation does not apply to Platform VPNs.
+ if (isLegacyVpn) {
synchronized (LegacyVpnRunner.TAG) {
// wait for old thread to completely finish before spinning up
// new instance, otherwise state updates can be out of order.
@@ -1951,7 +1973,7 @@
* Callers are responsible for checking permissions if needed.
*/
private synchronized LegacyVpnInfo getLegacyVpnInfoPrivileged() {
- if (mLegacyVpnRunner == null) return null;
+ if (!isSettingsVpnLocked()) return null;
final LegacyVpnInfo info = new LegacyVpnInfo();
info.key = mConfig.user;
@@ -1962,14 +1984,53 @@
return info;
}
- public VpnConfig getLegacyVpnConfig() {
- if (mLegacyVpnRunner != null) {
+ public synchronized VpnConfig getLegacyVpnConfig() {
+ if (isSettingsVpnLocked()) {
return mConfig;
} else {
return null;
}
}
+ /** This class represents the common interface for all VPN runners. */
+ private abstract class VpnRunner extends Thread {
+
+ protected VpnRunner(String name) {
+ super(name);
+ }
+
+ public abstract void run();
+
+ protected abstract void exit();
+ }
+
+ private class IkeV2VpnRunner extends VpnRunner {
+ private static final String TAG = "IkeV2VpnRunner";
+
+ private final IpSecManager mIpSecManager;
+ private final VpnProfile mProfile;
+
+ IkeV2VpnRunner(VpnProfile profile) {
+ super(TAG);
+ mProfile = profile;
+
+ // TODO: move this to startVpnRunnerPrivileged()
+ mConfig = new VpnConfig();
+ mIpSecManager = mContext.getSystemService(IpSecManager.class);
+ }
+
+ @Override
+ public void run() {
+ // TODO: Build IKE config, start IKE session
+ }
+
+ @Override
+ public void exit() {
+ // TODO: Teardown IKE session & any resources.
+ agentDisconnect();
+ }
+ }
+
/**
* Bringing up a VPN connection takes time, and that is all this thread
* does. Here we have plenty of time. The only thing we need to take
@@ -1977,7 +2038,7 @@
* requests will pile up. This could be done in a Handler as a state
* machine, but it is much easier to read in the current form.
*/
- private class LegacyVpnRunner extends Thread {
+ private class LegacyVpnRunner extends VpnRunner {
private static final String TAG = "LegacyVpnRunner";
private final String[] mDaemons;
@@ -2047,13 +2108,21 @@
mContext.registerReceiver(mBroadcastReceiver, filter);
}
- public void check(String interfaze) {
+ /**
+ * Checks if the parameter matches the underlying interface
+ *
+ * <p>If the underlying interface is torn down, the LegacyVpnRunner also should be. It has
+ * no ability to migrate between interfaces (or Networks).
+ */
+ public void exitIfOuterInterfaceIs(String interfaze) {
if (interfaze.equals(mOuterInterface)) {
Log.i(TAG, "Legacy VPN is going down with " + interfaze);
exit();
}
}
+ /** Tears down this LegacyVpn connection */
+ @Override
public void exit() {
// We assume that everything is reset after stopping the daemons.
interrupt();
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index 9754b6d..0450647 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -39,13 +39,20 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageUserState;
import android.content.pm.ParceledListSlice;
import android.content.pm.Signature;
+import android.content.pm.SigningInfo;
+import android.content.pm.parsing.ApkParseUtils;
+import android.content.pm.parsing.PackageInfoUtils;
+import android.content.pm.parsing.ParsedPackage;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
@@ -67,6 +74,7 @@
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
@@ -121,11 +129,11 @@
IntegrityFileManager.getInstance(),
handlerThread.getThreadHandler(),
Settings.Global.getInt(
- context.getContentResolver(),
- Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER,
- 0)
- == 1
- );
+ context.getContentResolver(),
+ Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER,
+ 0)
+ == 1
+ );
}
@VisibleForTesting
@@ -260,16 +268,25 @@
return;
}
- String appCert = getCertificateFingerprint(packageInfo);
+ List<String> appCertificates = getCertificateFingerprint(packageInfo);
+ List<String> installerCertificates =
+ getInstallerCertificateFingerprint(installerPackageName);
+
+ // TODO (b/148373316): Figure out what field contains which fields are populated for
+ // rotated and the multiple signers. Until then, return the first certificate.
+ String appCert = appCertificates.isEmpty() ? "" : appCertificates.get(0);
+ String installerCert =
+ installerCertificates.isEmpty() ? "" : installerCertificates.get(0);
+
+ Slog.w(TAG, appCertificates.toString());
AppInstallMetadata.Builder builder = new AppInstallMetadata.Builder();
builder.setPackageName(getPackageNameNormalized(packageName));
- builder.setAppCertificate(appCert == null ? "" : appCert);
+ builder.setAppCertificate(appCert);
builder.setVersionCode(intent.getLongExtra(EXTRA_LONG_VERSION_CODE, -1));
builder.setInstallerName(getPackageNameNormalized(installerPackageName));
- builder.setInstallerCertificate(
- getInstallerCertificateFingerprint(installerPackageName));
+ builder.setInstallerCertificate(installerCert);
builder.setIsPreInstalled(isSystemApp(packageName));
AppInstallMetadata appInstallMetadata = builder.build();
@@ -320,7 +337,7 @@
* Verify the UID and return the installer package name.
*
* @return the package name of the installer, or null if it cannot be determined or it is
- * installed via adb.
+ * installed via adb.
*/
@Nullable
private String getInstallerPackageName(Intent intent) {
@@ -399,25 +416,29 @@
}
}
- private String getCertificateFingerprint(@NonNull PackageInfo packageInfo) {
- return getFingerprint(getSignature(packageInfo));
- }
-
- private String getInstallerCertificateFingerprint(String installer) {
+ private List<String> getInstallerCertificateFingerprint(String installer) {
if (installer.equals(ADB_INSTALLER) || installer.equals(UNKNOWN_INSTALLER)) {
- return INSTALLER_CERT_NOT_APPLICABLE;
+ return Collections.emptyList();
}
try {
PackageInfo installerInfo =
mContext.getPackageManager()
- .getPackageInfo(installer, PackageManager.GET_SIGNATURES);
+ .getPackageInfo(installer, PackageManager.GET_SIGNING_CERTIFICATES);
return getCertificateFingerprint(installerInfo);
} catch (PackageManager.NameNotFoundException e) {
Slog.i(TAG, "Installer package " + installer + " not found.");
- return "";
+ return Collections.emptyList();
}
}
+ private List<String> getCertificateFingerprint(@NonNull PackageInfo packageInfo) {
+ ArrayList<String> certificateFingerprints = new ArrayList();
+ for (Signature signature : getSignatures(packageInfo)) {
+ certificateFingerprints.add(getFingerprint(signature));
+ }
+ return certificateFingerprints;
+ }
+
/** Get the allowed installers and their associated certificate hashes from <meta-data> tag. */
private Map<String, String> getAllowedInstallers(@NonNull PackageInfo packageInfo) {
Map<String, String> packageCertMap = new HashMap<>();
@@ -445,12 +466,15 @@
return packageCertMap;
}
- private static Signature getSignature(@NonNull PackageInfo packageInfo) {
- if (packageInfo.signatures == null || packageInfo.signatures.length < 1) {
+ private static Signature[] getSignatures(@NonNull PackageInfo packageInfo) {
+ SigningInfo signingInfo = packageInfo.signingInfo;
+
+ if (signingInfo == null || signingInfo.getApkContentsSigners().length < 1) {
throw new IllegalArgumentException("Package signature not found in " + packageInfo);
}
- // Only the first element is guaranteed to be present.
- return packageInfo.signatures[0];
+
+ // We are only interested in evaluating the active signatures.
+ return signingInfo.getApkContentsSigners();
}
private static String getFingerprint(Signature cert) {
@@ -489,20 +513,14 @@
if (installationPath == null) {
throw new IllegalArgumentException("Installation path is null, package not found");
}
- PackageInfo packageInfo;
+
+ PackageParser parser = new PackageParser();
try {
- // The installation path will be a directory for a multi-apk install on L+
- if (installationPath.isDirectory()) {
- packageInfo = getMultiApkInfo(installationPath);
- } else {
- packageInfo =
- mContext.getPackageManager()
- .getPackageArchiveInfo(
- installationPath.getPath(),
- PackageManager.GET_SIGNATURES
- | PackageManager.GET_META_DATA);
- }
- return packageInfo;
+ ParsedPackage pkg = parser.parseParsedPackage(installationPath, 0, false);
+ int flags = PackageManager.GET_SIGNING_CERTIFICATES | PackageManager.GET_META_DATA;
+ ApkParseUtils.collectCertificates(pkg, false);
+ return PackageInfoUtils.generate(pkg, null, flags, 0, 0, null, new PackageUserState(),
+ UserHandle.getCallingUserId());
} catch (Exception e) {
throw new IllegalArgumentException("Exception reading " + dataUri, e);
}
@@ -515,7 +533,8 @@
mContext.getPackageManager()
.getPackageArchiveInfo(
baseFile.getAbsolutePath(),
- PackageManager.GET_SIGNATURES | PackageManager.GET_META_DATA);
+ PackageManager.GET_SIGNING_CERTIFICATES
+ | PackageManager.GET_META_DATA);
if (basePackageInfo == null) {
for (File apkFile : multiApkDirectory.listFiles()) {
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index 7b17b4e..8358884 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -63,7 +63,6 @@
public abstract void sendControlRequest(String routeId, Intent request);
public abstract void requestSetVolume(String routeId, int volume);
- public abstract void requestUpdateVolume(String routeId, int delta);
@NonNull
public String getUniqueId() {
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
index e22ea46..d08fb71 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
@@ -138,14 +138,6 @@
}
}
- @Override
- public void requestUpdateVolume(String routeId, int delta) {
- if (mConnectionReady) {
- mActiveConnection.requestUpdateVolume(routeId, delta);
- updateBinding();
- }
- }
-
public boolean hasComponentName(String packageName, String className) {
return mComponentName.getPackageName().equals(packageName)
&& mComponentName.getClassName().equals(className);
@@ -518,14 +510,6 @@
}
}
- public void requestUpdateVolume(String routeId, int delta) {
- try {
- mProvider.requestUpdateVolume(routeId, delta);
- } catch (RemoteException ex) {
- Slog.e(TAG, "Failed to deliver request to request update volume.", ex);
- }
- }
-
@Override
public void binderDied() {
mHandler.post(() -> onConnectionDied(Connection.this));
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 358cc29..b113322 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -334,20 +334,6 @@
}
}
- public void requestUpdateVolume2(IMediaRouter2Client client, MediaRoute2Info route, int delta) {
- Objects.requireNonNull(client, "client must not be null");
- Objects.requireNonNull(route, "route must not be null");
-
- final long token = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- requestUpdateVolumeLocked(client, route, delta);
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
public void requestCreateClientSession(IMediaRouter2Manager manager, String packageName,
MediaRoute2Info route, int requestId) {
final long token = Binder.clearCallingIdentity();
@@ -375,21 +361,6 @@
}
}
- public void requestUpdateVolume2Manager(IMediaRouter2Manager manager,
- MediaRoute2Info route, int delta) {
- Objects.requireNonNull(manager, "manager must not be null");
- Objects.requireNonNull(route, "route must not be null");
-
- final long token = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- requestUpdateVolumeLocked(manager, route, delta);
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
@NonNull
public List<RoutingSessionInfo> getActiveSessions(IMediaRouter2Manager manager) {
final long token = Binder.clearCallingIdentity();
@@ -628,18 +599,6 @@
}
}
- private void requestUpdateVolumeLocked(IMediaRouter2Client client, MediaRoute2Info route,
- int delta) {
- final IBinder binder = client.asBinder();
- Client2Record clientRecord = mAllClientRecords.get(binder);
-
- if (clientRecord != null) {
- clientRecord.mUserRecord.mHandler.sendMessage(
- obtainMessage(UserHandler::requestUpdateVolume,
- clientRecord.mUserRecord.mHandler, route, delta));
- }
- }
-
private void registerManagerLocked(IMediaRouter2Manager manager,
int uid, int pid, String packageName, int userId, boolean trusted) {
final IBinder binder = manager.asBinder();
@@ -713,18 +672,6 @@
}
}
- private void requestUpdateVolumeLocked(IMediaRouter2Manager manager, MediaRoute2Info route,
- int delta) {
- final IBinder binder = manager.asBinder();
- ManagerRecord managerRecord = mAllManagerRecords.get(binder);
-
- if (managerRecord != null) {
- managerRecord.mUserRecord.mHandler.sendMessage(
- obtainMessage(UserHandler::requestUpdateVolume,
- managerRecord.mUserRecord.mHandler, route, delta));
- }
- }
-
private List<RoutingSessionInfo> getActiveSessionsLocked(IMediaRouter2Manager manager) {
final IBinder binder = manager.asBinder();
ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -1459,13 +1406,6 @@
}
}
- private void requestUpdateVolume(MediaRoute2Info route, int delta) {
- final MediaRoute2Provider provider = findProvider(route.getProviderId());
- if (provider != null) {
- provider.requestUpdateVolume(route.getOriginalId(), delta);
- }
- }
-
private List<IMediaRouter2Client> getClients() {
final List<IMediaRouter2Client> clients = new ArrayList<>();
MediaRouter2ServiceImpl service = mServiceRef.get();
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index e1d3803..57f0328 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -539,12 +539,6 @@
// Binder call
@Override
- public void requestUpdateVolume2(IMediaRouter2Client client, MediaRoute2Info route, int delta) {
- mService2.requestUpdateVolume2(client, route, delta);
- }
-
- // Binder call
- @Override
public void requestSetVolume2Manager(IMediaRouter2Manager manager,
MediaRoute2Info route, int volume) {
mService2.requestSetVolume2Manager(manager, route, volume);
@@ -552,13 +546,6 @@
// Binder call
@Override
- public void requestUpdateVolume2Manager(IMediaRouter2Manager manager,
- MediaRoute2Info route, int delta) {
- mService2.requestUpdateVolume2Manager(manager, route, delta);
- }
-
- // Binder call
- @Override
public List<RoutingSessionInfo> getActiveSessions(IMediaRouter2Manager manager) {
return mService2.getActiveSessions(manager);
}
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index 798a781..888f7ce 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -153,11 +153,6 @@
public void requestSetVolume(String routeId, int volume) {
}
- //TODO: implement method
- @Override
- public void requestUpdateVolume(String routeId, int delta) {
- }
-
private void initializeDefaultRoute() {
mDefaultRoute = new MediaRoute2Info.Builder(
DEFAULT_ROUTE_ID,
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index ef8f647..3cafaff 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -138,7 +138,7 @@
if (egressDisconnected || egressChanged) {
mAcceptedEgressIface = null;
- mVpn.stopLegacyVpnPrivileged();
+ mVpn.stopVpnRunnerPrivileged();
}
if (egressDisconnected) {
hideNotification();
@@ -218,7 +218,7 @@
mAcceptedEgressIface = null;
mErrorCount = 0;
- mVpn.stopLegacyVpnPrivileged();
+ mVpn.stopVpnRunnerPrivileged();
mVpn.setLockdown(false);
hideNotification();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b52289e..f071135 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2681,18 +2681,24 @@
@Override
public void enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration,
int displayId, @Nullable ITransientNotificationCallback callback) {
- enqueueToast(pkg, token, text, null, duration, displayId, callback);
+ enqueueToast(pkg, token, text, null, duration, displayId, callback, false);
}
@Override
public void enqueueToast(String pkg, IBinder token, ITransientNotification callback,
int duration, int displayId) {
- enqueueToast(pkg, token, null, callback, duration, displayId, null);
+ enqueueToast(pkg, token, null, callback, duration, displayId, null, true);
+ }
+
+ @Override
+ public void enqueueTextOrCustomToast(String pkg, IBinder token,
+ ITransientNotification callback, int duration, int displayId, boolean isCustom) {
+ enqueueToast(pkg, token, null, callback, duration, displayId, null, isCustom);
}
private void enqueueToast(String pkg, IBinder token, @Nullable CharSequence text,
@Nullable ITransientNotification callback, int duration, int displayId,
- @Nullable ITransientNotificationCallback textCallback) {
+ @Nullable ITransientNotificationCallback textCallback, boolean isCustom) {
if (DBG) {
Slog.i(TAG, "enqueueToast pkg=" + pkg + " token=" + token
+ " duration=" + duration + " displayId=" + displayId);
@@ -2730,7 +2736,7 @@
return;
}
- if (callback != null && !appIsForeground && !isSystemToast) {
+ if (callback != null && !appIsForeground && !isSystemToast && isCustom) {
boolean block;
long id = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
index 639cc70..90fc59a 100644
--- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
+++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
@@ -38,6 +38,8 @@
import android.util.LruCache;
import android.util.Slog;
+import libcore.util.EmptyArray;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
@@ -301,7 +303,7 @@
for (String person: second) {
people.add(person);
}
- return (String[]) people.toArray();
+ return people.toArray(EmptyArray.STRING);
}
@Nullable
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 40ea6cf..b98bb08 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -234,12 +234,12 @@
}
public void moveCompleteApp(String fromUuid, String toUuid, String packageName,
- String dataAppName, int appId, String seInfo, int targetSdkVersion)
- throws InstallerException {
+ String dataAppName, int appId, String seInfo, int targetSdkVersion,
+ String fromCodePath) throws InstallerException {
if (!checkBeforeRemote()) return;
try {
mInstalld.moveCompleteApp(fromUuid, toUuid, packageName, dataAppName, appId, seInfo,
- targetSdkVersion);
+ targetSdkVersion, fromCodePath);
} catch (Exception e) {
throw InstallerException.from(e);
}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 7bb782b..3e64e98 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -29,12 +29,14 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
+import android.content.LocusId;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ILauncherApps;
import android.content.pm.IOnAppsChangedListener;
import android.content.pm.IPackageInstallerCallback;
import android.content.pm.IPackageManager;
+import android.content.pm.IShortcutChangeCallback;
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.ShortcutQuery;
import android.content.pm.PackageInfo;
@@ -661,8 +663,8 @@
@Override
public ParceledListSlice getShortcuts(String callingPackage, long changedSince,
- String packageName, List shortcutIds, ComponentName componentName, int flags,
- UserHandle targetUser) {
+ String packageName, List shortcutIds, List<LocusId> locusIds,
+ ComponentName componentName, int flags, UserHandle targetUser) {
ensureShortcutPermission(callingPackage);
if (!canAccessProfile(targetUser.getIdentifier(), "Cannot get shortcuts")) {
return new ParceledListSlice<>(Collections.EMPTY_LIST);
@@ -671,16 +673,31 @@
throw new IllegalArgumentException(
"To query by shortcut ID, package name must also be set");
}
+ if (locusIds != null && packageName == null) {
+ throw new IllegalArgumentException(
+ "To query by locus ID, package name must also be set");
+ }
// TODO(b/29399275): Eclipse compiler requires explicit List<ShortcutInfo> cast below.
return new ParceledListSlice<>((List<ShortcutInfo>)
mShortcutServiceInternal.getShortcuts(getCallingUserId(),
- callingPackage, changedSince, packageName, shortcutIds,
+ callingPackage, changedSince, packageName, shortcutIds, locusIds,
componentName, flags, targetUser.getIdentifier(),
injectBinderCallingPid(), injectBinderCallingUid()));
}
@Override
+ public void registerShortcutChangeCallback(String callingPackage, long changedSince,
+ String packageName, List shortcutIds, List<LocusId> locusIds,
+ ComponentName componentName, int flags, IShortcutChangeCallback callback,
+ int callbackId) {
+ }
+
+ @Override
+ public void unregisterShortcutChangeCallback(String callingPackage, int callbackId) {
+ }
+
+ @Override
public void pinShortcuts(String callingPackage, String packageName, List<String> ids,
UserHandle targetUser) {
ensureShortcutPermission(callingPackage);
@@ -1137,7 +1154,7 @@
mShortcutServiceInternal.getShortcuts(launcherUserId,
cookie.packageName,
/* changedSince= */ 0, packageName, /* shortcutIds=*/ null,
- /* component= */ null,
+ /* locusIds=*/ null, /* component= */ null,
ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY
| ShortcutQuery.FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED
, userId, cookie.callingPid, cookie.callingUid);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 9116c40..33ef2d4 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -129,6 +129,13 @@
/** Upper bound on number of historical sessions for a UID */
private static final long MAX_HISTORICAL_SESSIONS = 1048576;
+ /**
+ * Allow verification-skipping if it's a development app installed through ADB with
+ * disable verification flag specified.
+ */
+ private static final int ADB_DEV_MODE = PackageManager.INSTALL_FROM_ADB
+ | PackageManager.INSTALL_ALLOW_TEST;
+
private final Context mContext;
private final PackageManagerService mPm;
private final ApexManager mApexManager;
@@ -531,8 +538,10 @@
params.installFlags &= ~PackageManager.INSTALL_REQUEST_DOWNGRADE;
}
- if (callingUid != Process.SYSTEM_UID) {
- // Only system_server can use INSTALL_DISABLE_VERIFICATION.
+ if (callingUid != Process.SYSTEM_UID
+ && (params.installFlags & ADB_DEV_MODE) != ADB_DEV_MODE) {
+ // Only system_server or tools under specific conditions (test app installed
+ // through ADB, and verification disabled flag specified) can disable verification.
params.installFlags &= ~PackageManager.INSTALL_DISABLE_VERIFICATION;
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index bf7bebd..0cf8b42 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -129,6 +129,7 @@
import com.android.server.security.VerityUtils;
import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -212,7 +213,8 @@
private static final String ATTR_SIGNATURE = "signature";
private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill";
- private static final int[] EMPTY_CHILD_SESSION_ARRAY = {};
+ private static final int[] EMPTY_CHILD_SESSION_ARRAY = EmptyArray.INT;
+ private static final FileInfo[] EMPTY_FILE_INFO_ARRAY = {};
private static final String SYSTEM_DATA_LOADER_PACKAGE = "android";
@@ -375,8 +377,6 @@
// TODO(b/146080380): merge file list with Callback installation.
private IncrementalFileStorages mIncrementalFileStorages;
- private static final String[] EMPTY_STRING_ARRAY = new String[]{};
-
private static final FileFilter sAddedApkFilter = new FileFilter() {
@Override
public boolean accept(File file) {
@@ -558,10 +558,22 @@
mStagedSessionErrorMessage =
stagedSessionErrorMessage != null ? stagedSessionErrorMessage : "";
- if (isStreamingInstallation()
- && this.params.dataLoaderParams.getComponentName().getPackageName()
- == SYSTEM_DATA_LOADER_PACKAGE) {
- assertShellOrSystemCalling("System data loaders");
+ if (isDataLoaderInstallation()) {
+ if (isApexInstallation()) {
+ throw new IllegalArgumentException(
+ "DataLoader installation of APEX modules is not allowed.");
+ }
+ }
+
+ if (isStreamingInstallation()) {
+ if (!isIncrementalInstallationAllowed(mPackageName)) {
+ throw new IllegalArgumentException(
+ "Incremental installation of this package is not allowed.");
+ }
+ if (this.params.dataLoaderParams.getComponentName().getPackageName()
+ == SYSTEM_DATA_LOADER_PACKAGE) {
+ assertShellOrSystemCalling("System data loaders");
+ }
}
}
@@ -719,7 +731,7 @@
if (!isDataLoaderInstallation()) {
String[] result = stageDir.list();
if (result == null) {
- result = EMPTY_STRING_ARRAY;
+ result = EmptyArray.STRING;
}
return result;
}
@@ -1174,6 +1186,19 @@
}
/**
+ * Checks if the package can be installed on IncFs.
+ */
+ private static boolean isIncrementalInstallationAllowed(String packageName) {
+ final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+ final AndroidPackage existingPackage = pmi.getPackage(packageName);
+ if (existingPackage == null) {
+ return true;
+ }
+
+ return !PackageManagerService.isSystemApp(existingPackage);
+ }
+
+ /**
* If this was not already called, the session will be sealed.
*
* This method may be called multiple times to update the status receiver validate caller
@@ -1362,14 +1387,10 @@
return false;
}
- final PackageInfo pkgInfo = mPm.getPackageInfo(
- params.appPackageName, PackageManager.GET_SIGNATURES
- | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
-
if (isApexInstallation()) {
validateApexInstallLocked();
} else {
- validateApkInstallLocked(pkgInfo);
+ validateApkInstallLocked();
}
}
@@ -1786,8 +1807,7 @@
* {@link PackageManagerService}.
*/
@GuardedBy("mLock")
- private void validateApkInstallLocked(@Nullable PackageInfo pkgInfo)
- throws PackageManagerException {
+ private void validateApkInstallLocked() throws PackageManagerException {
ApkLite baseApk = null;
mPackageName = null;
mVersionCode = -1;
@@ -1797,6 +1817,10 @@
mResolvedStagedFiles.clear();
mResolvedInheritedFiles.clear();
+ final PackageInfo pkgInfo = mPm.getPackageInfo(
+ params.appPackageName, PackageManager.GET_SIGNATURES
+ | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
+
// Partial installs must be consistent with existing install
if (params.mode == SessionParams.MODE_INHERIT_EXISTING
&& (pkgInfo == null || pkgInfo.applicationInfo == null)) {
@@ -3096,7 +3120,8 @@
}
if (grantedRuntimePermissions.size() > 0) {
- params.grantedRuntimePermissions = (String[]) grantedRuntimePermissions.toArray();
+ params.grantedRuntimePermissions =
+ grantedRuntimePermissions.toArray(EmptyArray.STRING);
}
if (whitelistedRestrictedPermissions.size() > 0) {
@@ -3115,7 +3140,7 @@
FileInfo[] fileInfosArray = null;
if (!files.isEmpty()) {
- fileInfosArray = (FileInfo[]) files.toArray();
+ fileInfosArray = files.toArray(EMPTY_FILE_INFO_ARRAY);
}
InstallSource installSource = InstallSource.create(installInitiatingPackageName,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8e5ff66..42b2483 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -150,6 +150,7 @@
import android.content.pm.AuxiliaryResolveInfo;
import android.content.pm.ChangedPackages;
import android.content.pm.ComponentInfo;
+import android.content.pm.DataLoaderType;
import android.content.pm.FallbackCategoryProvider;
import android.content.pm.FeatureInfo;
import android.content.pm.IDexModuleRegisterCallback;
@@ -1658,7 +1659,8 @@
handlePackagePostInstall(parentRes, grantPermissions,
killApp, virtualPreload, grantedPermissions,
whitelistedRestrictedPermissions, didRestore,
- args.installSource.installerPackageName, args.observer);
+ args.installSource.installerPackageName, args.observer,
+ args.mDataLoaderType);
// Handle the child packages
final int childCount = (parentRes.addedChildPackages != null)
@@ -1668,7 +1670,8 @@
handlePackagePostInstall(childRes, grantPermissions,
killApp, virtualPreload, grantedPermissions,
whitelistedRestrictedPermissions, false /*didRestore*/,
- args.installSource.installerPackageName, args.observer);
+ args.installSource.installerPackageName, args.observer,
+ args.mDataLoaderType);
}
// Log tracing if needed
@@ -1995,7 +1998,7 @@
boolean killApp, boolean virtualPreload,
String[] grantedPermissions, List<String> whitelistedRestrictedPermissions,
boolean launchedForRestore, String installerPackage,
- IPackageInstallObserver2 installObserver) {
+ IPackageInstallObserver2 installObserver, int dataLoaderType) {
final boolean succeeded = res.returnCode == PackageManager.INSTALL_SUCCEEDED;
final boolean update = res.removedInfo != null && res.removedInfo.removedPackage != null;
@@ -2096,11 +2099,14 @@
if (update) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
+ extras.putInt(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType);
+ // Send to all running apps.
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
null /*targetPackage*/, null /*finishedReceiver*/,
updateUserIds, instantUserIds);
if (installerPackageName != null) {
+ // Send to the installer, even if it's not running.
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
installerPackageName, null /*finishedReceiver*/,
@@ -13344,42 +13350,53 @@
*
* @return true if verification should be performed
*/
- private boolean isVerificationEnabled(int userId, int installFlags, int installerUid) {
+ private boolean isVerificationEnabled(
+ PackageInfoLite pkgInfoLite, int userId, int installFlags, int installerUid) {
if (!DEFAULT_VERIFY_ENABLE) {
return false;
}
- if ((installFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0) {
- return false;
- }
-
// Check if installing from ADB
if ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0) {
if (isUserRestricted(userId, UserManager.ENSURE_VERIFY_APPS)) {
return true;
}
- // Check if the developer does not want package verification for ADB installs
+ // Check if the developer wants to skip verification for ADB installs
+ if ((installFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0) {
+ synchronized (mLock) {
+ if (mSettings.mPackages.get(pkgInfoLite.packageName) == null) {
+ // Always verify fresh install
+ return true;
+ }
+ }
+ // Only skip when apk is debuggable
+ return !pkgInfoLite.debuggable;
+ }
return Global.getInt(mContext.getContentResolver(),
Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) != 0;
- } else {
- // only when not installed from ADB, skip verification for instant apps when
- // the installer and verifier are the same.
- if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
- if (mInstantAppInstallerActivity != null
- && mInstantAppInstallerActivity.packageName.equals(
- mRequiredVerifierPackage)) {
- try {
- mInjector.getAppOpsManager()
- .checkPackage(installerUid, mRequiredVerifierPackage);
- if (DEBUG_VERIFY) {
- Slog.i(TAG, "disable verification for instant app");
- }
- return false;
- } catch (SecurityException ignore) { }
- }
- }
- return true;
}
+
+ if ((installFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0) {
+ return false;
+ }
+
+ // only when not installed from ADB, skip verification for instant apps when
+ // the installer and verifier are the same.
+ if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
+ if (mInstantAppInstallerActivity != null
+ && mInstantAppInstallerActivity.packageName.equals(
+ mRequiredVerifierPackage)) {
+ try {
+ mInjector.getAppOpsManager()
+ .checkPackage(installerUid, mRequiredVerifierPackage);
+ if (DEBUG_VERIFY) {
+ Slog.i(TAG, "disable verification for instant app");
+ }
+ return false;
+ } catch (SecurityException ignore) { }
+ }
+ }
+ return true;
}
/**
@@ -13978,9 +13995,11 @@
final int appId;
final String seinfo;
final int targetSdkVersion;
+ final String fromCodePath;
public MoveInfo(int moveId, String fromUuid, String toUuid, String packageName,
- String dataAppName, int appId, String seinfo, int targetSdkVersion) {
+ String dataAppName, int appId, String seinfo, int targetSdkVersion,
+ String fromCodePath) {
this.moveId = moveId;
this.fromUuid = fromUuid;
this.toUuid = toUuid;
@@ -13989,6 +14008,7 @@
this.appId = appId;
this.seinfo = seinfo;
this.targetSdkVersion = targetSdkVersion;
+ this.fromCodePath = fromCodePath;
}
}
@@ -14114,13 +14134,14 @@
MultiPackageInstallParams mParentInstallParams;
final long requiredInstalledVersionCode;
final boolean forceQueryableOverride;
+ final int mDataLoaderType;
InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
int installFlags, InstallSource installSource, String volumeUuid,
VerificationInfo verificationInfo, UserHandle user, String packageAbiOverride,
String[] grantedPermissions, List<String> whitelistedRestrictedPermissions,
SigningDetails signingDetails, int installReason,
- long requiredInstalledVersionCode) {
+ long requiredInstalledVersionCode, int dataLoaderType) {
super(user);
this.origin = origin;
this.move = move;
@@ -14136,40 +14157,42 @@
this.installReason = installReason;
this.requiredInstalledVersionCode = requiredInstalledVersionCode;
this.forceQueryableOverride = false;
+ this.mDataLoaderType = dataLoaderType;
}
InstallParams(ActiveInstallSession activeInstallSession) {
super(activeInstallSession.getUser());
+ final PackageInstaller.SessionParams sessionParams =
+ activeInstallSession.getSessionParams();
if (DEBUG_INSTANT) {
- if ((activeInstallSession.getSessionParams().installFlags
+ if ((sessionParams.installFlags
& PackageManager.INSTALL_INSTANT_APP) != 0) {
Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
}
}
verificationInfo = new VerificationInfo(
- activeInstallSession.getSessionParams().originatingUri,
- activeInstallSession.getSessionParams().referrerUri,
- activeInstallSession.getSessionParams().originatingUid,
+ sessionParams.originatingUri,
+ sessionParams.referrerUri,
+ sessionParams.originatingUid,
activeInstallSession.getInstallerUid());
origin = OriginInfo.fromStagedFile(activeInstallSession.getStagedDir());
move = null;
installReason = fixUpInstallReason(
activeInstallSession.getInstallSource().installerPackageName,
activeInstallSession.getInstallerUid(),
- activeInstallSession.getSessionParams().installReason);
+ sessionParams.installReason);
observer = activeInstallSession.getObserver();
- installFlags = activeInstallSession.getSessionParams().installFlags;
+ installFlags = sessionParams.installFlags;
installSource = activeInstallSession.getInstallSource();
- volumeUuid = activeInstallSession.getSessionParams().volumeUuid;
- packageAbiOverride = activeInstallSession.getSessionParams().abiOverride;
- grantedRuntimePermissions = activeInstallSession.getSessionParams()
- .grantedRuntimePermissions;
- whitelistedRestrictedPermissions = activeInstallSession.getSessionParams()
- .whitelistedRestrictedPermissions;
+ volumeUuid = sessionParams.volumeUuid;
+ packageAbiOverride = sessionParams.abiOverride;
+ grantedRuntimePermissions = sessionParams.grantedRuntimePermissions;
+ whitelistedRestrictedPermissions = sessionParams.whitelistedRestrictedPermissions;
signingDetails = activeInstallSession.getSigningDetails();
- requiredInstalledVersionCode = activeInstallSession.getSessionParams()
- .requiredInstalledVersionCode;
- forceQueryableOverride = activeInstallSession.getSessionParams().forceQueryableOverride;
+ requiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode;
+ forceQueryableOverride = sessionParams.forceQueryableOverride;
+ mDataLoaderType = (sessionParams.dataLoaderParams != null)
+ ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
}
@Override
@@ -14537,7 +14560,7 @@
verificationInfo == null ? -1 : verificationInfo.installerUid;
if (!origin.existing && requiredUid != -1
&& isVerificationEnabled(
- verifierUser.getIdentifier(), installFlags, installerUid)) {
+ pkgLite, verifierUser.getIdentifier(), installFlags, installerUid)) {
final Intent verification = new Intent(
Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@@ -14772,6 +14795,7 @@
final int installReason;
final boolean forceQueryableOverride;
@Nullable final MultiPackageInstallParams mMultiPackageInstallParams;
+ final int mDataLoaderType;
// The list of instruction sets supported by this app. This is currently
// only used during the rmdex() phase to clean up resources. We can get rid of this
@@ -14785,7 +14809,7 @@
List<String> whitelistedRestrictedPermissions,
String traceMethod, int traceCookie, SigningDetails signingDetails,
int installReason, boolean forceQueryableOverride,
- MultiPackageInstallParams multiPackageInstallParams) {
+ MultiPackageInstallParams multiPackageInstallParams, int dataLoaderType) {
this.origin = origin;
this.move = move;
this.installFlags = installFlags;
@@ -14803,6 +14827,7 @@
this.installReason = installReason;
this.forceQueryableOverride = forceQueryableOverride;
this.mMultiPackageInstallParams = multiPackageInstallParams;
+ this.mDataLoaderType = dataLoaderType;
}
/** New install */
@@ -14812,7 +14837,8 @@
params.getUser(), null /*instructionSets*/, params.packageAbiOverride,
params.grantedRuntimePermissions, params.whitelistedRestrictedPermissions,
params.traceMethod, params.traceCookie, params.signingDetails,
- params.installReason, params.forceQueryableOverride, params.mParentInstallParams);
+ params.installReason, params.forceQueryableOverride,
+ params.mParentInstallParams, params.mDataLoaderType);
}
abstract int copyApk();
@@ -14903,7 +14929,8 @@
super(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY,
null, null, instructionSets, null, null, null, null, 0,
PackageParser.SigningDetails.UNKNOWN,
- PackageManager.INSTALL_REASON_UNKNOWN, false, null /* parent */);
+ PackageManager.INSTALL_REASON_UNKNOWN, false, null /* parent */,
+ DataLoaderType.NONE);
this.codeFile = (codePath != null) ? new File(codePath) : null;
this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
}
@@ -14983,9 +15010,7 @@
try {
makeDirRecursive(afterCodeFile.getParentFile(), 0775);
if (onIncremental) {
- // TODO(b/147371381): fix incremental installation
- mIncrementalManager.rename(beforeCodeFile.getAbsolutePath(),
- afterCodeFile.getAbsolutePath());
+ mIncrementalManager.renameCodePath(beforeCodeFile, afterCodeFile);
} else {
Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
}
@@ -15104,7 +15129,8 @@
synchronized (mInstaller) {
try {
mInstaller.moveCompleteApp(move.fromUuid, move.toUuid, move.packageName,
- move.dataAppName, move.appId, move.seinfo, move.targetSdkVersion);
+ move.dataAppName, move.appId, move.seinfo, move.targetSdkVersion,
+ move.fromCodePath);
} catch (InstallerException e) {
Slog.w(TAG, "Failed to move app", e);
return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
@@ -22054,6 +22080,7 @@
final PackageFreezer freezer;
final int[] installedUserIds;
final boolean isCurrentLocationExternal;
+ final String fromCodePath;
// reader
synchronized (mLock) {
@@ -22110,6 +22137,7 @@
targetSdkVersion = pkg.getTargetSdkVersion();
freezer = freezePackage(packageName, "movePackageInternal");
installedUserIds = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
+ fromCodePath = pkg.getCodePath();
}
final Bundle extras = new Bundle();
@@ -22238,7 +22266,7 @@
final String dataAppName = codeFile.getName();
move = new MoveInfo(moveId, currentVolumeUuid, volumeUuid, packageName,
- dataAppName, appId, seinfo, targetSdkVersion);
+ dataAppName, appId, seinfo, targetSdkVersion, fromCodePath);
} else {
move = null;
}
@@ -22251,7 +22279,8 @@
installSource, volumeUuid, null /*verificationInfo*/, user,
packageAbiOverride, null /*grantedPermissions*/,
null /*whitelistedRestrictedPermissions*/, PackageParser.SigningDetails.UNKNOWN,
- PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.VERSION_CODE_HIGHEST);
+ PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.VERSION_CODE_HIGHEST,
+ DataLoaderType.NONE);
params.setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
@@ -22757,6 +22786,11 @@
private class PackageManagerNative extends IPackageManagerNative.Stub {
@Override
+ public String[] getAllPackages() {
+ return PackageManagerService.this.getAllPackages().toArray(new String[0]);
+ }
+
+ @Override
public String[] getNamesForUids(int[] uids) throws RemoteException {
final String[] results = PackageManagerService.this.getNamesForUids(uids);
// massage results so they can be parsed by the native binder
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 71a5545..9395c97 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -794,6 +794,7 @@
ret.verifiers = pkg.verifiers;
ret.recommendedInstallLocation = recommendedInstallLocation;
ret.multiArch = pkg.multiArch;
+ ret.debuggable = pkg.debuggable;
return ret;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index bb69680..cb94043 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2757,6 +2757,9 @@
case "--no-wait":
params.mWaitForStagedSessionReady = false;
break;
+ case "--skip-verification":
+ sessionParams.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;
+ break;
default:
throw new IllegalArgumentException("Unknown option " + opt);
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index c31aa24..d16c074 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -33,6 +33,7 @@
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
+import android.content.LocusId;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
@@ -2589,7 +2590,7 @@
public List<ShortcutInfo> getShortcuts(int launcherUserId,
@NonNull String callingPackage, long changedSince,
@Nullable String packageName, @Nullable List<String> shortcutIds,
- @Nullable ComponentName componentName,
+ @Nullable List<LocusId> locusIds, @Nullable ComponentName componentName,
int queryFlags, int userId, int callingPid, int callingUid) {
final ArrayList<ShortcutInfo> ret = new ArrayList<>();
@@ -2610,15 +2611,16 @@
if (packageName != null) {
getShortcutsInnerLocked(launcherUserId,
- callingPackage, packageName, shortcutIds, changedSince,
+ callingPackage, packageName, shortcutIds, locusIds, changedSince,
componentName, queryFlags, userId, ret, cloneFlag,
callingPid, callingUid);
} else {
final List<String> shortcutIdsF = shortcutIds;
+ final List<LocusId> locusIdsF = locusIds;
getUserShortcutsLocked(userId).forAllPackages(p -> {
getShortcutsInnerLocked(launcherUserId,
- callingPackage, p.getPackageName(), shortcutIdsF, changedSince,
- componentName, queryFlags, userId, ret, cloneFlag,
+ callingPackage, p.getPackageName(), shortcutIdsF, locusIdsF,
+ changedSince, componentName, queryFlags, userId, ret, cloneFlag,
callingPid, callingUid);
});
}
@@ -2628,12 +2630,15 @@
@GuardedBy("ShortcutService.this.mLock")
private void getShortcutsInnerLocked(int launcherUserId, @NonNull String callingPackage,
- @Nullable String packageName, @Nullable List<String> shortcutIds, long changedSince,
+ @Nullable String packageName, @Nullable List<String> shortcutIds,
+ @Nullable List<LocusId> locusIds, long changedSince,
@Nullable ComponentName componentName, int queryFlags,
int userId, ArrayList<ShortcutInfo> ret, int cloneFlag,
int callingPid, int callingUid) {
final ArraySet<String> ids = shortcutIds == null ? null
: new ArraySet<>(shortcutIds);
+ final ArraySet<LocusId> locIds = locusIds == null ? null
+ : new ArraySet<>(locusIds);
final ShortcutUser user = getUserShortcutsLocked(userId);
final ShortcutPackage p = user.getPackageShortcutsIfExists(packageName);
@@ -2660,6 +2665,9 @@
if (ids != null && !ids.contains(si.getId())) {
return false;
}
+ if (locIds != null && !locIds.contains(si.getLocusId())) {
+ return false;
+ }
if (componentName != null) {
if (si.getActivity() != null
&& !si.getActivity().equals(componentName)) {
diff --git a/services/core/java/com/android/server/policy/LegacyGlobalActions.java b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
index 6daf516..6eba59a 100644
--- a/services/core/java/com/android/server/policy/LegacyGlobalActions.java
+++ b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
@@ -402,7 +402,7 @@
public String getStatus() {
return mContext.getString(
com.android.internal.R.string.bugreport_status,
- Build.VERSION.RELEASE,
+ Build.VERSION.RELEASE_OR_CODENAME,
Build.ID);
}
}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 96f1219..5c79f6e 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -2480,7 +2480,7 @@
.writeString(Build.BRAND)
.writeString(Build.PRODUCT)
.writeString(Build.DEVICE)
- .writeString(Build.VERSION.RELEASE)
+ .writeString(Build.VERSION.RELEASE_OR_CODENAME)
.writeString(Build.ID)
.writeString(Build.VERSION.INCREMENTAL)
.writeString(Build.TYPE)
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 0bb0f94..ed6424c 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -21,7 +21,7 @@
import android.app.timedetector.ITimeDetectorService;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
-import android.app.timedetector.PhoneTimeSuggestion;
+import android.app.timedetector.TelephonyTimeSuggestion;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
@@ -94,11 +94,11 @@
}
@Override
- public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSignal) {
- enforceSuggestPhoneTimePermission();
+ public void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion timeSignal) {
+ enforceSuggestTelephonyTimePermission();
Objects.requireNonNull(timeSignal);
- mHandler.post(() -> mTimeDetectorStrategy.suggestPhoneTime(timeSignal));
+ mHandler.post(() -> mTimeDetectorStrategy.suggestTelephonyTime(timeSignal));
}
@Override
@@ -131,10 +131,10 @@
mTimeDetectorStrategy.dump(pw, args);
}
- private void enforceSuggestPhoneTimePermission() {
+ private void enforceSuggestTelephonyTimePermission() {
mContext.enforceCallingPermission(
- android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE,
- "suggest phone time and time zone");
+ android.Manifest.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE,
+ "suggest telephony time and time zone");
}
private void enforceSuggestManualTimePermission() {
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index a7c3b4d..a5fba4e 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -20,7 +20,7 @@
import android.annotation.Nullable;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
-import android.app.timedetector.PhoneTimeSuggestion;
+import android.app.timedetector.TelephonyTimeSuggestion;
import android.os.TimestampedValue;
import java.io.PrintWriter;
@@ -78,7 +78,7 @@
void initialize(@NonNull Callback callback);
/** Process the suggested time from telephony sources. */
- void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion);
+ void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion timeSuggestion);
/** Process the suggested manually entered time. */
void suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion);
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index 19435ee..8c54fa9 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -22,7 +22,7 @@
import android.app.AlarmManager;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
-import android.app.timedetector.PhoneTimeSuggestion;
+import android.app.timedetector.TelephonyTimeSuggestion;
import android.os.TimestampedValue;
import android.util.LocalLog;
import android.util.Slog;
@@ -38,9 +38,9 @@
import java.lang.annotation.RetentionPolicy;
/**
- * An implementation of {@link TimeDetectorStrategy} that passes phone and manual suggestions to
- * {@link AlarmManager}. When there are multiple phone sources, the one with the lowest ID is used
- * unless the data becomes too stale.
+ * An implementation of {@link TimeDetectorStrategy} that passes telephony and manual suggestions to
+ * {@link AlarmManager}. When there are multiple telephony sources, the one with the lowest ID is
+ * used unless the data becomes too stale.
*
* <p>Most public methods are marked synchronized to ensure thread safety around internal state.
*/
@@ -50,23 +50,26 @@
private static final String LOG_TAG = "SimpleTimeDetectorStrategy";
/** A score value used to indicate "no score", either due to validation failure or age. */
- private static final int PHONE_INVALID_SCORE = -1;
- /** The number of buckets phone suggestions can be put in by age. */
- private static final int PHONE_BUCKET_COUNT = 24;
+ private static final int TELEPHONY_INVALID_SCORE = -1;
+ /** The number of buckets telephony suggestions can be put in by age. */
+ private static final int TELEPHONY_BUCKET_COUNT = 24;
/** Each bucket is this size. All buckets are equally sized. */
@VisibleForTesting
- static final int PHONE_BUCKET_SIZE_MILLIS = 60 * 60 * 1000;
- /** Phone and network suggestions older than this value are considered too old to be used. */
+ static final int TELEPHONY_BUCKET_SIZE_MILLIS = 60 * 60 * 1000;
+ /**
+ * Telephony and network suggestions older than this value are considered too old to be used.
+ */
@VisibleForTesting
- static final long MAX_UTC_TIME_AGE_MILLIS = PHONE_BUCKET_COUNT * PHONE_BUCKET_SIZE_MILLIS;
+ static final long MAX_UTC_TIME_AGE_MILLIS =
+ TELEPHONY_BUCKET_COUNT * TELEPHONY_BUCKET_SIZE_MILLIS;
- @IntDef({ ORIGIN_PHONE, ORIGIN_MANUAL, ORIGIN_NETWORK })
+ @IntDef({ ORIGIN_TELEPHONY, ORIGIN_MANUAL, ORIGIN_NETWORK })
@Retention(RetentionPolicy.SOURCE)
public @interface Origin {}
/** Used when a time value originated from a telephony signal. */
@Origin
- private static final int ORIGIN_PHONE = 1;
+ private static final int ORIGIN_TELEPHONY = 1;
/** Used when a time value originated from a user / manual settings. */
@Origin
@@ -83,7 +86,9 @@
*/
private static final long SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS = 2 * 1000;
- /** The number of previous phone suggestions to keep for each ID (for use during debugging). */
+ /**
+ * The number of previous telephony suggestions to keep for each ID (for use during debugging).
+ */
private static final int KEEP_SUGGESTION_HISTORY_SIZE = 30;
// A log for changes made to the system clock and why.
@@ -106,7 +111,7 @@
* stable.
*/
@GuardedBy("this")
- private final ArrayMapWithHistory<Integer, PhoneTimeSuggestion> mSuggestionBySlotIndex =
+ private final ArrayMapWithHistory<Integer, TelephonyTimeSuggestion> mSuggestionBySlotIndex =
new ArrayMapWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
@GuardedBy("this")
@@ -144,7 +149,7 @@
}
@Override
- public synchronized void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
+ public synchronized void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion timeSuggestion) {
// Empty time suggestion means that telephony network connectivity has been lost.
// The passage of time is relentless, and we don't expect our users to use a time machine,
// so we can continue relying on previous suggestions when we lose connectivity. This is
@@ -157,13 +162,13 @@
// Perform validation / input filtering and record the validated suggestion against the
// slotIndex.
- if (!validateAndStorePhoneSuggestion(timeSuggestion)) {
+ if (!validateAndStoreTelephonySuggestion(timeSuggestion)) {
return;
}
// Now perform auto time detection. The new suggestion may be used to modify the system
// clock.
- String reason = "New phone time suggested. timeSuggestion=" + timeSuggestion;
+ String reason = "New telephony time suggested. timeSuggestion=" + timeSuggestion;
doAutoTimeDetection(reason);
}
@@ -201,7 +206,7 @@
mTimeChangesLog.dump(ipw);
ipw.decreaseIndent(); // level 2
- ipw.println("Phone suggestion history:");
+ ipw.println("Telephony suggestion history:");
ipw.increaseIndent(); // level 2
mSuggestionBySlotIndex.dump(ipw);
ipw.decreaseIndent(); // level 2
@@ -216,7 +221,8 @@
}
@GuardedBy("this")
- private boolean validateAndStorePhoneSuggestion(@NonNull PhoneTimeSuggestion suggestion) {
+ private boolean validateAndStoreTelephonySuggestion(
+ @NonNull TelephonyTimeSuggestion suggestion) {
TimestampedValue<Long> newUtcTime = suggestion.getUtcTime();
if (!validateSuggestionTime(newUtcTime, suggestion)) {
// There's probably nothing useful we can do: elsewhere we assume that reference
@@ -225,7 +231,7 @@
}
int slotIndex = suggestion.getSlotIndex();
- PhoneTimeSuggestion previousSuggestion = mSuggestionBySlotIndex.get(slotIndex);
+ TelephonyTimeSuggestion previousSuggestion = mSuggestionBySlotIndex.get(slotIndex);
if (previousSuggestion != null) {
// We can log / discard suggestions with obvious issues with the reference time clock.
if (previousSuggestion.getUtcTime() == null
@@ -241,7 +247,7 @@
newUtcTime, previousSuggestion.getUtcTime());
if (referenceTimeDifference < 0) {
// The reference time is before the previously received suggestion. Ignore it.
- Slog.w(LOG_TAG, "Out of order phone suggestion received."
+ Slog.w(LOG_TAG, "Out of order telephony suggestion received."
+ " referenceTimeDifference=" + referenceTimeDifference
+ " previousSuggestion=" + previousSuggestion
+ " suggestion=" + suggestion);
@@ -282,18 +288,18 @@
// Android devices currently prioritize any telephony over network signals. There are
// carrier compliance tests that would need to be changed before we could ignore NITZ or
- // prefer NTP generally. This check is cheap on devices without phone hardware.
- PhoneTimeSuggestion bestPhoneSuggestion = findBestPhoneSuggestion();
- if (bestPhoneSuggestion != null) {
- final TimestampedValue<Long> newUtcTime = bestPhoneSuggestion.getUtcTime();
- String cause = "Found good phone suggestion."
- + ", bestPhoneSuggestion=" + bestPhoneSuggestion
+ // prefer NTP generally. This check is cheap on devices without telephony hardware.
+ TelephonyTimeSuggestion bestTelephonySuggestion = findBestTelephonySuggestion();
+ if (bestTelephonySuggestion != null) {
+ final TimestampedValue<Long> newUtcTime = bestTelephonySuggestion.getUtcTime();
+ String cause = "Found good telephony suggestion."
+ + ", bestTelephonySuggestion=" + bestTelephonySuggestion
+ ", detectionReason=" + detectionReason;
- setSystemClockIfRequired(ORIGIN_PHONE, newUtcTime, cause);
+ setSystemClockIfRequired(ORIGIN_TELEPHONY, newUtcTime, cause);
return;
}
- // There is no good phone suggestion, try network.
+ // There is no good telephony suggestion, try network.
NetworkTimeSuggestion networkSuggestion = findLatestValidNetworkSuggestion();
if (networkSuggestion != null) {
final TimestampedValue<Long> newUtcTime = networkSuggestion.getUtcTime();
@@ -305,18 +311,18 @@
}
if (DBG) {
- Slog.d(LOG_TAG, "Could not determine time: No best phone or network suggestion."
+ Slog.d(LOG_TAG, "Could not determine time: No best telephony or network suggestion."
+ " detectionReason=" + detectionReason);
}
}
@GuardedBy("this")
@Nullable
- private PhoneTimeSuggestion findBestPhoneSuggestion() {
+ private TelephonyTimeSuggestion findBestTelephonySuggestion() {
long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
- // Phone time suggestions are assumed to be derived from NITZ or NITZ-like signals. These
- // have a number of limitations:
+ // Telephony time suggestions are assumed to be derived from NITZ or NITZ-like signals.
+ // These have a number of limitations:
// 1) No guarantee of accuracy ("accuracy of the time information is in the order of
// minutes") [1]
// 2) No guarantee of regular signals ("dependent on the handset crossing radio network
@@ -335,8 +341,8 @@
// For simplicity, we try to value recency, then consistency of slotIndex.
//
// The heuristic works as follows:
- // Recency: The most recent suggestion from each phone is scored. The score is based on a
- // discrete age bucket, i.e. so signals received around the same time will be in the same
+ // Recency: The most recent suggestion from each slotIndex is scored. The score is based on
+ // a discrete age bucket, i.e. so signals received around the same time will be in the same
// bucket, thus applying a loose reference time ordering. The suggestion with the highest
// score is used.
// Consistency: If there a multiple suggestions with the same score, the suggestion with the
@@ -345,11 +351,11 @@
// In the trivial case with a single ID this will just mean that the latest received
// suggestion is used.
- PhoneTimeSuggestion bestSuggestion = null;
- int bestScore = PHONE_INVALID_SCORE;
+ TelephonyTimeSuggestion bestSuggestion = null;
+ int bestScore = TELEPHONY_INVALID_SCORE;
for (int i = 0; i < mSuggestionBySlotIndex.size(); i++) {
Integer slotIndex = mSuggestionBySlotIndex.keyAt(i);
- PhoneTimeSuggestion candidateSuggestion = mSuggestionBySlotIndex.valueAt(i);
+ TelephonyTimeSuggestion candidateSuggestion = mSuggestionBySlotIndex.valueAt(i);
if (candidateSuggestion == null) {
// Unexpected - null suggestions should never be stored.
Slog.w(LOG_TAG, "Latest suggestion unexpectedly null for slotIndex."
@@ -362,8 +368,9 @@
continue;
}
- int candidateScore = scorePhoneSuggestion(elapsedRealtimeMillis, candidateSuggestion);
- if (candidateScore == PHONE_INVALID_SCORE) {
+ int candidateScore =
+ scoreTelephonySuggestion(elapsedRealtimeMillis, candidateSuggestion);
+ if (candidateScore == TELEPHONY_INVALID_SCORE) {
// Expected: This means the suggestion is obviously invalid or just too old.
continue;
}
@@ -384,8 +391,8 @@
return bestSuggestion;
}
- private static int scorePhoneSuggestion(
- long elapsedRealtimeMillis, @NonNull PhoneTimeSuggestion timeSuggestion) {
+ private static int scoreTelephonySuggestion(
+ long elapsedRealtimeMillis, @NonNull TelephonyTimeSuggestion timeSuggestion) {
// Validate first.
TimestampedValue<Long> utcTime = timeSuggestion.getUtcTime();
@@ -393,21 +400,21 @@
Slog.w(LOG_TAG, "Existing suggestion found to be invalid "
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ ", timeSuggestion=" + timeSuggestion);
- return PHONE_INVALID_SCORE;
+ return TELEPHONY_INVALID_SCORE;
}
// The score is based on the age since receipt. Suggestions are bucketed so two
// suggestions in the same bucket from different slotIndexs are scored the same.
long ageMillis = elapsedRealtimeMillis - utcTime.getReferenceTimeMillis();
- // Turn the age into a discrete value: 0 <= bucketIndex < PHONE_BUCKET_COUNT.
- int bucketIndex = (int) (ageMillis / PHONE_BUCKET_SIZE_MILLIS);
- if (bucketIndex >= PHONE_BUCKET_COUNT) {
- return PHONE_INVALID_SCORE;
+ // Turn the age into a discrete value: 0 <= bucketIndex < TELEPHONY_BUCKET_COUNT.
+ int bucketIndex = (int) (ageMillis / TELEPHONY_BUCKET_SIZE_MILLIS);
+ if (bucketIndex >= TELEPHONY_BUCKET_COUNT) {
+ return TELEPHONY_INVALID_SCORE;
}
// We want the lowest bucket index to have the highest score. 0 > score >= BUCKET_COUNT.
- return PHONE_BUCKET_COUNT - bucketIndex;
+ return TELEPHONY_BUCKET_COUNT - bucketIndex;
}
/** Returns the latest, valid, network suggestion. Returns {@code null} if there isn't one. */
@@ -537,13 +544,13 @@
}
/**
- * Returns the current best phone suggestion. Not intended for general use: it is used during
- * tests to check strategy behavior.
+ * Returns the current best telephony suggestion. Not intended for general use: it is used
+ * during tests to check strategy behavior.
*/
@VisibleForTesting
@Nullable
- public synchronized PhoneTimeSuggestion findBestPhoneSuggestionForTests() {
- return findBestPhoneSuggestion();
+ public synchronized TelephonyTimeSuggestion findBestTelephonySuggestionForTests() {
+ return findBestTelephonySuggestion();
}
/**
@@ -561,7 +568,7 @@
*/
@VisibleForTesting
@Nullable
- public synchronized PhoneTimeSuggestion getLatestPhoneSuggestion(int slotIndex) {
+ public synchronized TelephonyTimeSuggestion getLatestTelephonySuggestion(int slotIndex) {
return mSuggestionBySlotIndex.get(slotIndex);
}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index 381ee10..57b6ec9 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -20,7 +20,7 @@
import android.annotation.Nullable;
import android.app.timezonedetector.ITimeZoneDetectorService;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
-import android.app.timezonedetector.PhoneTimeZoneSuggestion;
+import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
@@ -101,11 +101,11 @@
}
@Override
- public void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion timeZoneSuggestion) {
- enforceSuggestPhoneTimeZonePermission();
+ public void suggestTelephonyTimeZone(@NonNull TelephonyTimeZoneSuggestion timeZoneSuggestion) {
+ enforceSuggestTelephonyTimeZonePermission();
Objects.requireNonNull(timeZoneSuggestion);
- mHandler.post(() -> mTimeZoneDetectorStrategy.suggestPhoneTimeZone(timeZoneSuggestion));
+ mHandler.post(() -> mTimeZoneDetectorStrategy.suggestTelephonyTimeZone(timeZoneSuggestion));
}
@Override
@@ -122,10 +122,10 @@
mHandler.post(mTimeZoneDetectorStrategy::handleAutoTimeZoneDetectionChanged);
}
- private void enforceSuggestPhoneTimeZonePermission() {
+ private void enforceSuggestTelephonyTimeZonePermission() {
mContext.enforceCallingPermission(
- android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE,
- "suggest phone time and time zone");
+ android.Manifest.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE,
+ "suggest telephony time and time zone");
}
private void enforceSuggestManualTimeZonePermission() {
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
index 1d439e9..0eb27cc 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
@@ -17,7 +17,7 @@
import android.annotation.NonNull;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
-import android.app.timezonedetector.PhoneTimeZoneSuggestion;
+import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
import java.io.PrintWriter;
@@ -38,13 +38,13 @@
/**
* Suggests a time zone for the device, or withdraws a previous suggestion if
- * {@link PhoneTimeZoneSuggestion#getZoneId()} is {@code null}. The suggestion is scoped to a
- * specific {@link PhoneTimeZoneSuggestion#getSlotIndex() phone}.
- * See {@link PhoneTimeZoneSuggestion} for an explanation of the metadata associated with a
+ * {@link TelephonyTimeZoneSuggestion#getZoneId()} is {@code null}. The suggestion is scoped to
+ * a specific {@link TelephonyTimeZoneSuggestion#getSlotIndex() slotIndex}.
+ * See {@link TelephonyTimeZoneSuggestion} for an explanation of the metadata associated with a
* suggestion. The strategy uses suggestions to decide whether to modify the device's time zone
* setting and what to set it to.
*/
- void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion suggestion);
+ void suggestTelephonyTimeZone(@NonNull TelephonyTimeZoneSuggestion suggestion);
/**
* Called when there has been a change to the automatic time zone detection setting.
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
index f85f9fe..652dbe15 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
@@ -15,17 +15,17 @@
*/
package com.android.server.timezonedetector;
-import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID;
-import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY;
-import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
-import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
-import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID;
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY;
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
-import android.app.timezonedetector.PhoneTimeZoneSuggestion;
+import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
import android.content.Context;
import android.util.LocalLog;
import android.util.Slog;
@@ -44,11 +44,11 @@
* suggestions. Suggestions are acted on or ignored as needed, dependent on the current "auto time
* zone detection" setting.
*
- * <p>For automatic detection it keeps track of the most recent suggestion from each phone it uses
- * the best suggestion based on a scoring algorithm. If several phones provide the same score then
- * the phone with the lowest numeric ID "wins". If the situation changes and it is no longer
- * possible to be confident about the time zone, phones must submit an empty suggestion in order to
- * "withdraw" their previous suggestion.
+ * <p>For automatic detection, it keeps track of the most recent telephony suggestion from each
+ * slotIndex and it uses the best suggestion based on a scoring algorithm. If several slotIndexes
+ * provide the same score then the slotIndex with the lowest numeric value "wins". If the situation
+ * changes and it is no longer possible to be confident about the time zone, slotIndexes must have
+ * an empty suggestion submitted in order to "withdraw" their previous suggestion.
*
* <p>Most public methods are marked synchronized to ensure thread safety around internal state.
*/
@@ -91,28 +91,28 @@
private static final String LOG_TAG = "TimeZoneDetectorStrategy";
private static final boolean DBG = false;
- @IntDef({ ORIGIN_PHONE, ORIGIN_MANUAL })
+ @IntDef({ ORIGIN_TELEPHONY, ORIGIN_MANUAL })
@Retention(RetentionPolicy.SOURCE)
public @interface Origin {}
/** Used when a time value originated from a telephony signal. */
@Origin
- private static final int ORIGIN_PHONE = 1;
+ private static final int ORIGIN_TELEPHONY = 1;
/** Used when a time value originated from a user / manual settings. */
@Origin
private static final int ORIGIN_MANUAL = 2;
/**
- * The abstract score for an empty or invalid phone suggestion.
+ * The abstract score for an empty or invalid telephony suggestion.
*
- * Used to score phone suggestions where there is no zone.
+ * Used to score telephony suggestions where there is no zone.
*/
@VisibleForTesting
- public static final int PHONE_SCORE_NONE = 0;
+ public static final int TELEPHONY_SCORE_NONE = 0;
/**
- * The abstract score for a low quality phone suggestion.
+ * The abstract score for a low quality telephony suggestion.
*
* Used to score suggestions where:
* The suggested zone ID is one of several possibilities, and the possibilities have different
@@ -121,10 +121,10 @@
* You would have to be quite desperate to want to use this choice.
*/
@VisibleForTesting
- public static final int PHONE_SCORE_LOW = 1;
+ public static final int TELEPHONY_SCORE_LOW = 1;
/**
- * The abstract score for a medium quality phone suggestion.
+ * The abstract score for a medium quality telephony suggestion.
*
* Used for:
* The suggested zone ID is one of several possibilities but at least the possibilities have the
@@ -132,36 +132,38 @@
* switch to DST at the wrong time and (for example) their calendar events.
*/
@VisibleForTesting
- public static final int PHONE_SCORE_MEDIUM = 2;
+ public static final int TELEPHONY_SCORE_MEDIUM = 2;
/**
- * The abstract score for a high quality phone suggestion.
+ * The abstract score for a high quality telephony suggestion.
*
* Used for:
* The suggestion was for one zone ID and the answer was unambiguous and likely correct given
* the info available.
*/
@VisibleForTesting
- public static final int PHONE_SCORE_HIGH = 3;
+ public static final int TELEPHONY_SCORE_HIGH = 3;
/**
- * The abstract score for a highest quality phone suggestion.
+ * The abstract score for a highest quality telephony suggestion.
*
* Used for:
* Suggestions that must "win" because they constitute test or emulator zone ID.
*/
@VisibleForTesting
- public static final int PHONE_SCORE_HIGHEST = 4;
+ public static final int TELEPHONY_SCORE_HIGHEST = 4;
/**
- * The threshold at which phone suggestions are good enough to use to set the device's time
+ * The threshold at which telephony suggestions are good enough to use to set the device's time
* zone.
*/
@VisibleForTesting
- public static final int PHONE_SCORE_USAGE_THRESHOLD = PHONE_SCORE_MEDIUM;
+ public static final int TELEPHONY_SCORE_USAGE_THRESHOLD = TELEPHONY_SCORE_MEDIUM;
- /** The number of previous phone suggestions to keep for each ID (for use during debugging). */
- private static final int KEEP_PHONE_SUGGESTION_HISTORY_SIZE = 30;
+ /**
+ * The number of previous telephony suggestions to keep for each ID (for use during debugging).
+ */
+ private static final int KEEP_TELEPHONY_SUGGESTION_HISTORY_SIZE = 30;
@NonNull
private final Callback mCallback;
@@ -174,13 +176,14 @@
private final LocalLog mTimeZoneChangesLog = new LocalLog(30, false /* useLocalTimestamps */);
/**
- * A mapping from slotIndex to a phone time zone suggestion. We typically expect one or two
- * mappings: devices will have a small number of telephony devices and slotIndexs are assumed to
- * be stable.
+ * A mapping from slotIndex to a telephony time zone suggestion. We typically expect one or two
+ * mappings: devices will have a small number of telephony devices and slotIndexes are assumed
+ * to be stable.
*/
@GuardedBy("this")
- private ArrayMapWithHistory<Integer, QualifiedPhoneTimeZoneSuggestion> mSuggestionBySlotIndex =
- new ArrayMapWithHistory<>(KEEP_PHONE_SUGGESTION_HISTORY_SIZE);
+ private ArrayMapWithHistory<Integer, QualifiedTelephonyTimeZoneSuggestion>
+ mSuggestionBySlotIndex =
+ new ArrayMapWithHistory<>(KEEP_TELEPHONY_SUGGESTION_HISTORY_SIZE);
/**
* Creates a new instance of {@link TimeZoneDetectorStrategyImpl}.
@@ -205,42 +208,43 @@
}
@Override
- public synchronized void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion suggestion) {
+ public synchronized void suggestTelephonyTimeZone(
+ @NonNull TelephonyTimeZoneSuggestion suggestion) {
if (DBG) {
- Slog.d(LOG_TAG, "Phone suggestion received. newSuggestion=" + suggestion);
+ Slog.d(LOG_TAG, "Telephony suggestion received. newSuggestion=" + suggestion);
}
Objects.requireNonNull(suggestion);
// Score the suggestion.
- int score = scorePhoneSuggestion(suggestion);
- QualifiedPhoneTimeZoneSuggestion scoredSuggestion =
- new QualifiedPhoneTimeZoneSuggestion(suggestion, score);
+ int score = scoreTelephonySuggestion(suggestion);
+ QualifiedTelephonyTimeZoneSuggestion scoredSuggestion =
+ new QualifiedTelephonyTimeZoneSuggestion(suggestion, score);
// Store the suggestion against the correct slotIndex.
mSuggestionBySlotIndex.put(suggestion.getSlotIndex(), scoredSuggestion);
// Now perform auto time zone detection. The new suggestion may be used to modify the time
// zone setting.
- String reason = "New phone time suggested. suggestion=" + suggestion;
+ String reason = "New telephony time suggested. suggestion=" + suggestion;
doAutoTimeZoneDetection(reason);
}
- private static int scorePhoneSuggestion(@NonNull PhoneTimeZoneSuggestion suggestion) {
+ private static int scoreTelephonySuggestion(@NonNull TelephonyTimeZoneSuggestion suggestion) {
int score;
if (suggestion.getZoneId() == null) {
- score = PHONE_SCORE_NONE;
+ score = TELEPHONY_SCORE_NONE;
} else if (suggestion.getMatchType() == MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY
|| suggestion.getMatchType() == MATCH_TYPE_EMULATOR_ZONE_ID) {
// Handle emulator / test cases : These suggestions should always just be used.
- score = PHONE_SCORE_HIGHEST;
+ score = TELEPHONY_SCORE_HIGHEST;
} else if (suggestion.getQuality() == QUALITY_SINGLE_ZONE) {
- score = PHONE_SCORE_HIGH;
+ score = TELEPHONY_SCORE_HIGH;
} else if (suggestion.getQuality() == QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET) {
// The suggestion may be wrong, but at least the offset should be correct.
- score = PHONE_SCORE_MEDIUM;
+ score = TELEPHONY_SCORE_MEDIUM;
} else if (suggestion.getQuality() == QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS) {
// The suggestion has a good chance of being wrong.
- score = PHONE_SCORE_LOW;
+ score = TELEPHONY_SCORE_LOW;
} else {
throw new AssertionError();
}
@@ -248,9 +252,9 @@
}
/**
- * Finds the best available time zone suggestion from all phones. If it is high-enough quality
- * and automatic time zone detection is enabled then it will be set on the device. The outcome
- * can be that this strategy becomes / remains un-opinionated and nothing is set.
+ * Finds the best available time zone suggestion from all slotIndexes. If it is high-enough
+ * quality and automatic time zone detection is enabled then it will be set on the device. The
+ * outcome can be that this strategy becomes / remains un-opinionated and nothing is set.
*/
@GuardedBy("this")
private void doAutoTimeZoneDetection(@NonNull String detectionReason) {
@@ -259,35 +263,37 @@
return;
}
- QualifiedPhoneTimeZoneSuggestion bestPhoneSuggestion = findBestPhoneSuggestion();
+ QualifiedTelephonyTimeZoneSuggestion bestTelephonySuggestion =
+ findBestTelephonySuggestion();
// Work out what to do with the best suggestion.
- if (bestPhoneSuggestion == null) {
- // There is no phone suggestion available at all. Become un-opinionated.
+ if (bestTelephonySuggestion == null) {
+ // There is no telephony suggestion available at all. Become un-opinionated.
if (DBG) {
- Slog.d(LOG_TAG, "Could not determine time zone: No best phone suggestion."
+ Slog.d(LOG_TAG, "Could not determine time zone: No best telephony suggestion."
+ " detectionReason=" + detectionReason);
}
return;
}
// Special case handling for uninitialized devices. This should only happen once.
- String newZoneId = bestPhoneSuggestion.suggestion.getZoneId();
+ String newZoneId = bestTelephonySuggestion.suggestion.getZoneId();
if (newZoneId != null && !mCallback.isDeviceTimeZoneInitialized()) {
String cause = "Device has no time zone set. Attempting to set the device to the best"
+ " available suggestion."
- + " bestPhoneSuggestion=" + bestPhoneSuggestion
+ + " bestTelephonySuggestion=" + bestTelephonySuggestion
+ ", detectionReason=" + detectionReason;
Slog.i(LOG_TAG, cause);
- setDeviceTimeZoneIfRequired(ORIGIN_PHONE, newZoneId, cause);
+ setDeviceTimeZoneIfRequired(ORIGIN_TELEPHONY, newZoneId, cause);
return;
}
- boolean suggestionGoodEnough = bestPhoneSuggestion.score >= PHONE_SCORE_USAGE_THRESHOLD;
+ boolean suggestionGoodEnough =
+ bestTelephonySuggestion.score >= TELEPHONY_SCORE_USAGE_THRESHOLD;
if (!suggestionGoodEnough) {
if (DBG) {
Slog.d(LOG_TAG, "Best suggestion not good enough."
- + " bestPhoneSuggestion=" + bestPhoneSuggestion
+ + " bestTelephonySuggestion=" + bestTelephonySuggestion
+ ", detectionReason=" + detectionReason);
}
return;
@@ -297,16 +303,16 @@
// zone ID.
if (newZoneId == null) {
Slog.w(LOG_TAG, "Empty zone suggestion scored higher than expected. This is an error:"
- + " bestPhoneSuggestion=" + bestPhoneSuggestion
+ + " bestTelephonySuggestion=" + bestTelephonySuggestion
+ " detectionReason=" + detectionReason);
return;
}
- String zoneId = bestPhoneSuggestion.suggestion.getZoneId();
+ String zoneId = bestTelephonySuggestion.suggestion.getZoneId();
String cause = "Found good suggestion."
- + ", bestPhoneSuggestion=" + bestPhoneSuggestion
+ + ", bestTelephonySuggestion=" + bestTelephonySuggestion
+ ", detectionReason=" + detectionReason;
- setDeviceTimeZoneIfRequired(ORIGIN_PHONE, zoneId, cause);
+ setDeviceTimeZoneIfRequired(ORIGIN_TELEPHONY, zoneId, cause);
}
@GuardedBy("this")
@@ -372,15 +378,15 @@
@GuardedBy("this")
@Nullable
- private QualifiedPhoneTimeZoneSuggestion findBestPhoneSuggestion() {
- QualifiedPhoneTimeZoneSuggestion bestSuggestion = null;
+ private QualifiedTelephonyTimeZoneSuggestion findBestTelephonySuggestion() {
+ QualifiedTelephonyTimeZoneSuggestion bestSuggestion = null;
- // Iterate over the latest QualifiedPhoneTimeZoneSuggestion objects received for each phone
- // and find the best. Note that we deliberately do not look at age: the caller can
+ // Iterate over the latest QualifiedTelephonyTimeZoneSuggestion objects received for each
+ // slotIndex and find the best. Note that we deliberately do not look at age: the caller can
// rate-limit so age is not a strong indicator of confidence. Instead, the callers are
// expected to withdraw suggestions they no longer have confidence in.
for (int i = 0; i < mSuggestionBySlotIndex.size(); i++) {
- QualifiedPhoneTimeZoneSuggestion candidateSuggestion =
+ QualifiedTelephonyTimeZoneSuggestion candidateSuggestion =
mSuggestionBySlotIndex.valueAt(i);
if (candidateSuggestion == null) {
// Unexpected
@@ -404,13 +410,13 @@
}
/**
- * Returns the current best phone suggestion. Not intended for general use: it is used during
- * tests to check strategy behavior.
+ * Returns the current best telephony suggestion. Not intended for general use: it is used
+ * during tests to check strategy behavior.
*/
@VisibleForTesting
@Nullable
- public synchronized QualifiedPhoneTimeZoneSuggestion findBestPhoneSuggestionForTests() {
- return findBestPhoneSuggestion();
+ public synchronized QualifiedTelephonyTimeZoneSuggestion findBestTelephonySuggestionForTests() {
+ return findBestTelephonySuggestion();
}
@Override
@@ -447,7 +453,7 @@
mTimeZoneChangesLog.dump(ipw);
ipw.decreaseIndent(); // level 2
- ipw.println("Phone suggestion history:");
+ ipw.println("Telephony suggestion history:");
ipw.increaseIndent(); // level 2
mSuggestionBySlotIndex.dump(ipw);
ipw.decreaseIndent(); // level 2
@@ -459,18 +465,19 @@
* A method used to inspect strategy state during tests. Not intended for general use.
*/
@VisibleForTesting
- public synchronized QualifiedPhoneTimeZoneSuggestion getLatestPhoneSuggestion(int slotIndex) {
+ public synchronized QualifiedTelephonyTimeZoneSuggestion getLatestTelephonySuggestion(
+ int slotIndex) {
return mSuggestionBySlotIndex.get(slotIndex);
}
/**
- * A {@link PhoneTimeZoneSuggestion} with additional qualifying metadata.
+ * A {@link TelephonyTimeZoneSuggestion} with additional qualifying metadata.
*/
@VisibleForTesting
- public static class QualifiedPhoneTimeZoneSuggestion {
+ public static class QualifiedTelephonyTimeZoneSuggestion {
@VisibleForTesting
- public final PhoneTimeZoneSuggestion suggestion;
+ public final TelephonyTimeZoneSuggestion suggestion;
/**
* The score the suggestion has been given. This can be used to rank against other
@@ -480,7 +487,8 @@
public final int score;
@VisibleForTesting
- public QualifiedPhoneTimeZoneSuggestion(PhoneTimeZoneSuggestion suggestion, int score) {
+ public QualifiedTelephonyTimeZoneSuggestion(
+ TelephonyTimeZoneSuggestion suggestion, int score) {
this.suggestion = suggestion;
this.score = score;
}
@@ -493,7 +501,7 @@
if (o == null || getClass() != o.getClass()) {
return false;
}
- QualifiedPhoneTimeZoneSuggestion that = (QualifiedPhoneTimeZoneSuggestion) o;
+ QualifiedTelephonyTimeZoneSuggestion that = (QualifiedTelephonyTimeZoneSuggestion) o;
return score == that.score
&& suggestion.equals(that.suggestion);
}
@@ -505,7 +513,7 @@
@Override
public String toString() {
- return "QualifiedPhoneTimeZoneSuggestion{"
+ return "QualifiedTelephonyTimeZoneSuggestion{"
+ "suggestion=" + suggestion
+ ", score=" + score
+ '}';
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 4f010d5..e3b1152c 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -383,36 +383,38 @@
if (mCurrentUserId == userId) {
return;
}
- UserState userState = mUserStates.get(mCurrentUserId);
- List<SessionState> sessionStatesToRelease = new ArrayList<>();
- for (SessionState sessionState : userState.sessionStateMap.values()) {
- if (sessionState.session != null && !sessionState.isRecordingSession) {
- sessionStatesToRelease.add(sessionState);
- }
- }
- for (SessionState sessionState : sessionStatesToRelease) {
- try {
- sessionState.session.release();
- } catch (RemoteException e) {
- Slog.e(TAG, "error in release", e);
- }
- clearSessionAndNotifyClientLocked(sessionState);
- }
-
- for (Iterator<ComponentName> it = userState.serviceStateMap.keySet().iterator();
- it.hasNext(); ) {
- ComponentName component = it.next();
- ServiceState serviceState = userState.serviceStateMap.get(component);
- if (serviceState != null && serviceState.sessionTokens.isEmpty()) {
- if (serviceState.callback != null) {
- try {
- serviceState.service.unregisterCallback(serviceState.callback);
- } catch (RemoteException e) {
- Slog.e(TAG, "error in unregisterCallback", e);
- }
+ if (mUserStates.contains(mCurrentUserId)) {
+ UserState userState = mUserStates.get(mCurrentUserId);
+ List<SessionState> sessionStatesToRelease = new ArrayList<>();
+ for (SessionState sessionState : userState.sessionStateMap.values()) {
+ if (sessionState.session != null && !sessionState.isRecordingSession) {
+ sessionStatesToRelease.add(sessionState);
}
- mContext.unbindService(serviceState.connection);
- it.remove();
+ }
+ for (SessionState sessionState : sessionStatesToRelease) {
+ try {
+ sessionState.session.release();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in release", e);
+ }
+ clearSessionAndNotifyClientLocked(sessionState);
+ }
+
+ for (Iterator<ComponentName> it = userState.serviceStateMap.keySet().iterator();
+ it.hasNext(); ) {
+ ComponentName component = it.next();
+ ServiceState serviceState = userState.serviceStateMap.get(component);
+ if (serviceState != null && serviceState.sessionTokens.isEmpty()) {
+ if (serviceState.callback != null) {
+ try {
+ serviceState.service.unregisterCallback(serviceState.callback);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in unregisterCallback", e);
+ }
+ }
+ mContext.unbindService(serviceState.connection);
+ it.remove();
+ }
}
}
@@ -490,6 +492,10 @@
userState.mainSessionToken = null;
mUserStates.remove(userId);
+
+ if (userId == mCurrentUserId) {
+ switchUser(UserHandle.USER_SYSTEM);
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 75d87ed..f35ba9e 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -386,6 +386,8 @@
} else {
callingPid = callingUid = -1;
}
+ final int filterCallingUid = ActivityStarter.computeResolveFilterUid(
+ callingUid, realCallingUid, UserHandle.USER_NULL);
final SparseArray<String> startingUidPkgs = new SparseArray<>();
final long origId = Binder.clearCallingIdentity();
try {
@@ -408,9 +410,7 @@
// Collect information about the target of the Intent.
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, resolvedTypes[i],
- 0 /* startFlags */, null /* profilerInfo */, userId,
- ActivityStarter.computeResolveFilterUid(
- callingUid, realCallingUid, UserHandle.USER_NULL));
+ 0 /* startFlags */, null /* profilerInfo */, userId, filterCallingUid);
aInfo = mService.mAmInternal.getActivityInfoForUser(aInfo, userId);
if (aInfo != null) {
@@ -457,6 +457,7 @@
Slog.wtf(TAG, sb.toString());
}
+ final IBinder sourceResultTo = resultTo;
final ActivityRecord[] outActivity = new ActivityRecord[1];
// Lock the loop to ensure the activities launched in a sequence.
synchronized (mService.mGlobalLock) {
@@ -470,7 +471,18 @@
}
return startResult;
}
- resultTo = outActivity[0] != null ? outActivity[0].appToken : null;
+ final ActivityRecord started = outActivity[0];
+ if (started != null && started.getUid() == filterCallingUid) {
+ // Only the started activity which has the same uid as the source caller can
+ // be the caller of next activity.
+ resultTo = started.appToken;
+ } else {
+ resultTo = sourceResultTo;
+ // Different apps not adjacent to the caller are forced to be new task.
+ if (i < starters.length - 1) {
+ starters[i + 1].getIntent().addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ }
+ }
}
}
} finally {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 9e3292b..c7270f2 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2493,7 +2493,6 @@
return this;
}
- @VisibleForTesting
Intent getIntent() {
return mRequest.intent;
}
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
new file mode 100644
index 0000000..94decc7
--- /dev/null
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.ITaskOrganizer;
+import android.view.SurfaceControl;
+
+import java.util.HashMap;
+
+/**
+ * Utility class for collecting and merging transactions from various sources asynchronously.
+ * For example to use to synchronously resize all the children of a window container
+ * 1. Open a new sync set, and pass the listener that will be invoked
+ * int id startSyncSet(TransactionReadyListener)
+ * the returned ID will be eventually passed to the TransactionReadyListener in combination
+ * with the prepared transaction. You also use it to refer to the operation in future steps.
+ * 2. Ask each child to participate:
+ * addToSyncSet(int id, WindowContainer wc)
+ * if the child thinks it will be affected by a configuration change (a.k.a. has a visible
+ * window in its sub hierarchy, then we will increment a counter of expected callbacks
+ * At this point the containers hierarchy will redirect pendingTransaction and sub hierarchy
+ * updates in to the sync engine.
+ * 3. Apply your configuration changes to the window containers.
+ * 4. Tell the engine that the sync set is ready
+ * setReady(int id)
+ * 5. If there were no sub windows anywhere in the hierarchy to wait on, then
+ * transactionReady is immediately invoked, otherwise all the windows are poked
+ * to redraw and to deliver a buffer to WMS#finishDrawing.
+ * Once all this drawing is complete the combined transaction of all the buffers
+ * and pending transaction hierarchy changes will be delivered to the TransactionReadyListener
+ */
+class BLASTSyncEngine {
+ private static final String TAG = "BLASTSyncEngine";
+
+ interface TransactionReadyListener {
+ void transactionReady(int mSyncId, SurfaceControl.Transaction mergedTransaction);
+ };
+
+ // Holds state associated with a single synchronous set of operations.
+ class SyncState implements TransactionReadyListener {
+ int mSyncId;
+ SurfaceControl.Transaction mMergedTransaction;
+ int mRemainingTransactions;
+ TransactionReadyListener mListener;
+ boolean mReady = false;
+
+ private void tryFinish() {
+ if (mRemainingTransactions == 0 && mReady) {
+ mListener.transactionReady(mSyncId, mMergedTransaction);
+ mPendingSyncs.remove(mSyncId);
+ }
+ }
+
+ public void transactionReady(int mSyncId, SurfaceControl.Transaction mergedTransaction) {
+ mRemainingTransactions--;
+ mMergedTransaction.merge(mergedTransaction);
+ tryFinish();
+ }
+
+ void setReady() {
+ mReady = true;
+ tryFinish();
+ }
+
+ boolean addToSync(WindowContainer wc) {
+ if (wc.prepareForSync(this, mSyncId)) {
+ mRemainingTransactions++;
+ return true;
+ }
+ return false;
+ }
+
+ SyncState(TransactionReadyListener l, int id) {
+ mListener = l;
+ mSyncId = id;
+ mMergedTransaction = new SurfaceControl.Transaction();
+ mRemainingTransactions = 0;
+ }
+ };
+
+ int mNextSyncId = 0;
+
+ final HashMap<Integer, SyncState> mPendingSyncs = new HashMap();
+
+ BLASTSyncEngine() {
+ }
+
+ int startSyncSet(TransactionReadyListener listener) {
+ final int id = mNextSyncId++;
+ final SyncState s = new SyncState(listener, id);
+ mPendingSyncs.put(id, s);
+ return id;
+ }
+
+ boolean addToSyncSet(int id, WindowContainer wc) {
+ final SyncState st = mPendingSyncs.get(id);
+ return st.addToSync(wc);
+ }
+
+ // TODO(b/148476626): TIMEOUTS!
+ void setReady(int id) {
+ final SyncState st = mPendingSyncs.get(id);
+ st.setReady();
+ }
+}
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index efe79b3..e71371a 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -526,7 +526,9 @@
mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout);
mIsWaitingForRemoteRotation = false;
mDisplayContent.sendNewConfiguration();
- mService.mAtmService.mTaskOrganizerController.applyContainerTransaction(t);
+ if (t != null) {
+ mService.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null);
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 0733a72..096541f 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -38,6 +38,7 @@
import android.util.Slog;
import android.view.ITaskOrganizer;
import android.view.IWindowContainer;
+import android.view.SurfaceControl;
import android.view.WindowContainerTransaction;
import com.android.internal.util.function.pooled.PooledConsumer;
@@ -53,7 +54,8 @@
* Stores the TaskOrganizers associated with a given windowing mode and
* their associated state.
*/
-class TaskOrganizerController extends ITaskOrganizerController.Stub {
+class TaskOrganizerController extends ITaskOrganizerController.Stub
+ implements BLASTSyncEngine.TransactionReadyListener {
private static final String TAG = "TaskOrganizerController";
/** Flag indicating that an applied transaction may have effected lifecycle */
@@ -164,6 +166,8 @@
private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>();
+ private final BLASTSyncEngine mBLASTSyncEngine = new BLASTSyncEngine();
+
final ActivityTaskManagerService mService;
RunningTaskInfo mTmpTaskInfo;
@@ -223,7 +227,7 @@
}
void onTaskAppeared(ITaskOrganizer organizer, Task task) {
- TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
+ final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
state.addTask(task);
}
@@ -429,15 +433,35 @@
}
@Override
- public void applyContainerTransaction(WindowContainerTransaction t) {
+ public int applyContainerTransaction(WindowContainerTransaction t, ITaskOrganizer organizer) {
enforceStackPermission("applyContainerTransaction()");
+ int syncId = -1;
if (t == null) {
- return;
+ throw new IllegalArgumentException(
+ "Null transaction passed to applyContainerTransaction");
}
long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
int effects = 0;
+
+ /**
+ * If organizer is non-null we are looking to synchronize this transaction
+ * by collecting all the results in to a SurfaceFlinger transaction and
+ * then delivering that to the given organizers transaction ready callback.
+ * See {@link BLASTSyncEngine} for the details of the operation. But at
+ * a high level we create a sync operation with a given ID and an associated
+ * organizer. Then we notify each WindowContainer in this WindowContainer
+ * transaction that it is participating in a sync operation with that
+ * ID. Once everything is notified we tell the BLASTSyncEngine
+ * "setSyncReady" which means that we have added everything
+ * to the set. At any point after this, all the WindowContainers
+ * will eventually finish applying their changes and notify the
+ * BLASTSyncEngine which will deliver the Transaction to the organizer.
+ */
+ if (organizer != null) {
+ syncId = startSyncWithOrganizer(organizer);
+ }
mService.deferWindowLayout();
try {
ArraySet<WindowContainer> haveConfigChanges = new ArraySet<>();
@@ -450,11 +474,15 @@
entry.getKey()).getContainer();
int containerEffect = applyWindowContainerChange(wc, entry.getValue());
effects |= containerEffect;
+
// Lifecycle changes will trigger ensureConfig for everything.
if ((effects & TRANSACT_EFFECTS_LIFECYCLE) == 0
&& (containerEffect & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) {
haveConfigChanges.add(wc);
}
+ if (syncId >= 0) {
+ mBLASTSyncEngine.addToSyncSet(syncId, wc);
+ }
}
if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) {
// Already calls ensureActivityConfig
@@ -475,10 +503,38 @@
}
} finally {
mService.continueWindowLayout();
+ if (syncId >= 0) {
+ setSyncReady(syncId);
+ }
}
}
} finally {
Binder.restoreCallingIdentity(ident);
}
+ return syncId;
+ }
+
+ @Override
+ public void transactionReady(int id, SurfaceControl.Transaction sc) {
+ final ITaskOrganizer organizer = mTaskOrganizersByPendingSyncId.get(id);
+ if (organizer == null) {
+ Slog.e(TAG, "Got transaction complete for unexpected ID");
+ }
+ try {
+ organizer.transactionReady(id, sc);
+ } catch (RemoteException e) {
+ }
+
+ mTaskOrganizersByPendingSyncId.remove(id);
+ }
+
+ int startSyncWithOrganizer(ITaskOrganizer organizer) {
+ int id = mBLASTSyncEngine.startSyncSet(this);
+ mTaskOrganizersByPendingSyncId.put(id, organizer);
+ return id;
+ }
+
+ void setSyncReady(int id) {
+ mBLASTSyncEngine.setReady(id);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 8672315..9acb660 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -94,7 +94,8 @@
* changes are made to this class.
*/
class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
- implements Comparable<WindowContainer>, Animatable {
+ implements Comparable<WindowContainer>, Animatable,
+ BLASTSyncEngine.TransactionReadyListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowContainer" : TAG_WM;
@@ -260,6 +261,12 @@
*/
RemoteToken mRemoteToken = null;
+ BLASTSyncEngine mBLASTSyncEngine = new BLASTSyncEngine();
+ SurfaceControl.Transaction mBLASTSyncTransaction = new SurfaceControl.Transaction();
+ boolean mUsingBLASTSyncTransaction = false;
+ BLASTSyncEngine.TransactionReadyListener mWaitingListener;
+ int mWaitingSyncId;
+
WindowContainer(WindowManagerService wms) {
mWmService = wms;
mPendingTransaction = wms.mTransactionFactory.get();
@@ -1837,6 +1844,10 @@
@Override
public Transaction getPendingTransaction() {
+ if (mUsingBLASTSyncTransaction) {
+ return mBLASTSyncTransaction;
+ }
+
final DisplayContent displayContent = getDisplayContent();
if (displayContent != null && displayContent != this) {
return displayContent.getPendingTransaction();
@@ -2316,4 +2327,38 @@
return sb.toString();
}
}
+
+ @Override
+ public void transactionReady(int mSyncId, SurfaceControl.Transaction mergedTransaction) {
+ mergedTransaction.merge(mBLASTSyncTransaction);
+ mUsingBLASTSyncTransaction = false;
+
+ mWaitingListener.transactionReady(mWaitingSyncId, mergedTransaction);
+
+ mWaitingListener = null;
+ mWaitingSyncId = -1;
+ }
+
+ boolean prepareForSync(BLASTSyncEngine.TransactionReadyListener waitingListener,
+ int waitingId) {
+ boolean willSync = false;
+ if (!isVisible()) {
+ return willSync;
+ }
+ mUsingBLASTSyncTransaction = true;
+
+ int localId = mBLASTSyncEngine.startSyncSet(this);
+ for (int i = 0; i < mChildren.size(); i++) {
+ final WindowContainer child = mChildren.get(i);
+ willSync = mBLASTSyncEngine.addToSyncSet(localId, child) | willSync;
+ }
+
+ // Make sure to set these before we call setReady in case the sync was a no-op
+ mWaitingSyncId = waitingId;
+ mWaitingListener = waitingListener;
+
+ mBLASTSyncEngine.setReady(localId);
+
+ return willSync;
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6e1f46bb..6330985 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2505,7 +2505,7 @@
WindowState win = windowForClientLocked(session, client, false);
ProtoLog.d(WM_DEBUG_ADD_REMOVE, "finishDrawingWindow: %s mDrawState=%s",
win, (win != null ? win.mWinAnimator.drawStateToString() : "null"));
- if (win != null && win.mWinAnimator.finishDrawingLocked(postDrawTransaction)) {
+ if (win != null && win.finishDrawing(postDrawTransaction)) {
if ((win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
win.getDisplayContent().pendingLayoutChanges |=
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
@@ -5687,6 +5687,12 @@
@Override
public void setForceShowSystemBars(boolean show) {
+ boolean isAutomotive = mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_AUTOMOTIVE);
+ if (!isAutomotive) {
+ throw new UnsupportedOperationException("Force showing system bars is only supported"
+ + "for Automotive use cases.");
+ }
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Caller does not hold permission "
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 42e5bbc..b336f8d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -5689,4 +5689,30 @@
SurfaceControl getDeferTransactionBarrier() {
return mWinAnimator.getDeferTransactionBarrier();
}
+
+ @Override
+ boolean prepareForSync(BLASTSyncEngine.TransactionReadyListener waitingListener,
+ int waitingId) {
+ // TODO(b/148871522): Support child window
+ mWaitingListener = waitingListener;
+ mWaitingSyncId = waitingId;
+ mUsingBLASTSyncTransaction = true;
+ return true;
+ }
+
+ boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction) {
+ if (!mUsingBLASTSyncTransaction) {
+ return mWinAnimator.finishDrawingLocked(postDrawTransaction);
+ }
+ if (postDrawTransaction == null) {
+ postDrawTransaction = new SurfaceControl.Transaction();
+ }
+ postDrawTransaction.merge(mBLASTSyncTransaction);
+ mWaitingListener.transactionReady(mWaitingSyncId, postDrawTransaction);
+ mUsingBLASTSyncTransaction = false;
+
+ mWaitingSyncId = 0;
+ mWaitingListener = null;
+ return mWinAnimator.finishDrawingLocked(null);
+ }
}
diff --git a/services/core/java/com/android/server/wm/utils/DisplayRotationUtil.java b/services/core/java/com/android/server/wm/utils/DisplayRotationUtil.java
index 9f307bb..59abaab 100644
--- a/services/core/java/com/android/server/wm/utils/DisplayRotationUtil.java
+++ b/services/core/java/com/android/server/wm/utils/DisplayRotationUtil.java
@@ -59,7 +59,7 @@
}
/**
- * Compute bounds after rotating teh screen.
+ * Compute bounds after rotating the screen.
*
* @param bounds Bounds before the rotation. The array must contain exactly 4 non-null elements.
* @param rotation rotation constant defined in android.view.Surface.
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 390068e..812bc43 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -109,6 +109,7 @@
"libinputservice",
"libprotobuf-cpp-lite",
"libprotoutil",
+ "libstatshidl",
"libstatspull",
"libstatssocket",
"libstatslog",
@@ -155,6 +156,7 @@
"android.hardware.vr@1.0",
"android.frameworks.schedulerservice@1.0",
"android.frameworks.sensorservice@1.0",
+ "android.frameworks.stats@1.0",
"android.system.suspend@1.0",
"service.incremental",
"suspend_control_aidl_interface-cpp",
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index 67254b8..279ea4b 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -29,6 +29,7 @@
#include <schedulerservice/SchedulingPolicyService.h>
#include <sensorservice/SensorService.h>
#include <sensorservicehidl/SensorManager.h>
+#include <stats/StatsHal.h>
#include <bionic/malloc.h>
#include <bionic/reserved_signals.h>
@@ -59,6 +60,8 @@
using ::android::frameworks::schedulerservice::V1_0::implementation::SchedulingPolicyService;
using ::android::frameworks::sensorservice::V1_0::ISensorManager;
using ::android::frameworks::sensorservice::V1_0::implementation::SensorManager;
+ using ::android::frameworks::stats::V1_0::IStats;
+ using ::android::frameworks::stats::V1_0::implementation::StatsHal;
using ::android::hardware::configureRpcThreadpool;
status_t err;
@@ -75,6 +78,10 @@
sp<ISchedulingPolicyService> schedulingService = new SchedulingPolicyService();
err = schedulingService->registerAsService();
ALOGE_IF(err != OK, "Cannot register %s: %d", ISchedulingPolicyService::descriptor, err);
+
+ sp<IStats> statsHal = new StatsHal();
+ err = statsHal->registerAsService();
+ ALOGE_IF(err != OK, "Cannot register %s: %d", IStats::descriptor, err);
}
static void android_server_SystemServer_initZygoteChildHeapProfiling(JNIEnv* /* env */,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 28e44f1..553ec42 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -11598,6 +11598,11 @@
millis, "DevicePolicyManagerService: setTime");
mInjector.binderWithCleanCallingIdentity(
() -> mInjector.getTimeDetector().suggestManualTime(manualTimeSuggestion));
+
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_TIME)
+ .setAdmin(who)
+ .write();
return true;
}
@@ -11614,6 +11619,11 @@
timeZone, "DevicePolicyManagerService: setTimeZone");
mInjector.binderWithCleanCallingIdentity(() ->
mInjector.getTimeZoneDetector().suggestManualTimeZone(manualTimeZoneSuggestion));
+
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_TIME_ZONE)
+ .setAdmin(who)
+ .write();
return true;
}
diff --git a/services/people/java/com/android/server/people/data/CallLogQueryHelper.java b/services/people/java/com/android/server/people/data/CallLogQueryHelper.java
index d825b6b..45e0aac 100644
--- a/services/people/java/com/android/server/people/data/CallLogQueryHelper.java
+++ b/services/people/java/com/android/server/people/data/CallLogQueryHelper.java
@@ -107,7 +107,7 @@
}
@Event.EventType int eventType = CALL_TYPE_TO_EVENT_TYPE.get(callType);
Event event = new Event.Builder(date, eventType)
- .setCallDetails(new Event.CallDetails(durationSeconds))
+ .setDurationSeconds((int) durationSeconds)
.build();
mEventConsumer.accept(phoneNumber, event);
return true;
diff --git a/services/people/java/com/android/server/people/data/ConversationStore.java b/services/people/java/com/android/server/people/data/ConversationStore.java
index f17e1b9..3649921 100644
--- a/services/people/java/com/android/server/people/data/ConversationStore.java
+++ b/services/people/java/com/android/server/people/data/ConversationStore.java
@@ -40,6 +40,9 @@
// Phone Number -> Shortcut ID
private final Map<String, String> mPhoneNumberToShortcutIdMap = new ArrayMap<>();
+ // Notification Channel ID -> Shortcut ID
+ private final Map<String, String> mNotifChannelIdToShortcutIdMap = new ArrayMap<>();
+
void addOrUpdate(@NonNull ConversationInfo conversationInfo) {
mConversationInfoMap.put(conversationInfo.getShortcutId(), conversationInfo);
@@ -57,6 +60,11 @@
if (phoneNumber != null) {
mPhoneNumberToShortcutIdMap.put(phoneNumber, conversationInfo.getShortcutId());
}
+
+ String notifChannelId = conversationInfo.getNotificationChannelId();
+ if (notifChannelId != null) {
+ mNotifChannelIdToShortcutIdMap.put(notifChannelId, conversationInfo.getShortcutId());
+ }
}
void deleteConversation(@NonNull String shortcutId) {
@@ -79,6 +87,11 @@
if (phoneNumber != null) {
mPhoneNumberToShortcutIdMap.remove(phoneNumber);
}
+
+ String notifChannelId = conversationInfo.getNotificationChannelId();
+ if (notifChannelId != null) {
+ mNotifChannelIdToShortcutIdMap.remove(notifChannelId);
+ }
}
void forAllConversations(@NonNull Consumer<ConversationInfo> consumer) {
@@ -106,4 +119,9 @@
ConversationInfo getConversationByPhoneNumber(@NonNull String phoneNumber) {
return getConversation(mPhoneNumberToShortcutIdMap.get(phoneNumber));
}
+
+ @Nullable
+ ConversationInfo getConversationByNotificationChannelId(@NonNull String notifChannelId) {
+ return getConversation(mNotifChannelIdToShortcutIdMap.get(notifChannelId));
+ }
}
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index 79503f7..7fdcf42 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -24,8 +24,6 @@
import android.app.Person;
import android.app.prediction.AppTarget;
import android.app.prediction.AppTargetEvent;
-import android.app.usage.UsageEvents;
-import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -69,6 +67,7 @@
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
+import java.util.function.Function;
/**
* A class manages the lifecycle of the conversations and associated data, and exposes the methods
@@ -96,7 +95,6 @@
private final ContentObserver mMmsSmsContentObserver;
private ShortcutServiceInternal mShortcutServiceInternal;
- private UsageStatsManagerInternal mUsageStatsManagerInternal;
private ShortcutManager mShortcutManager;
private UserManager mUserManager;
@@ -118,7 +116,6 @@
/** Initialization. Called when the system services are up running. */
public void initialize() {
mShortcutServiceInternal = LocalServices.getService(ShortcutServiceInternal.class);
- mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class);
mShortcutManager = mContext.getSystemService(ShortcutManager.class);
mUserManager = mContext.getSystemService(UserManager.class);
@@ -293,13 +290,14 @@
| ShortcutQuery.FLAG_MATCH_PINNED | ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER;
return mShortcutServiceInternal.getShortcuts(
mInjector.getCallingUserId(), /*callingPackage=*/ PLATFORM_PACKAGE_NAME,
- /*changedSince=*/ 0, packageName, shortcutIds, /*componentName=*/ null, queryFlags,
- userId, MY_PID, MY_UID);
+ /*changedSince=*/ 0, packageName, shortcutIds, /*locusIds=*/ null,
+ /*componentName=*/ null, queryFlags, userId, MY_PID, MY_UID);
}
private void forAllUnlockedUsers(Consumer<UserData> consumer) {
for (int i = 0; i < mUserDataArray.size(); i++) {
- UserData userData = mUserDataArray.get(i);
+ int userId = mUserDataArray.keyAt(i);
+ UserData userData = mUserDataArray.get(userId);
if (userData.isUnlocked()) {
consumer.accept(userData);
}
@@ -385,36 +383,6 @@
}
@VisibleForTesting
- @WorkerThread
- void queryUsageStatsService(@UserIdInt int userId, long currentTime, long lastQueryTime) {
- UsageEvents usageEvents = mUsageStatsManagerInternal.queryEventsForUser(
- userId, lastQueryTime, currentTime, false, false);
- if (usageEvents == null) {
- return;
- }
- while (usageEvents.hasNextEvent()) {
- UsageEvents.Event e = new UsageEvents.Event();
- usageEvents.getNextEvent(e);
-
- String packageName = e.getPackageName();
- PackageData packageData = getPackage(packageName, userId);
- if (packageData == null) {
- continue;
- }
- if (e.getEventType() == UsageEvents.Event.SHORTCUT_INVOCATION) {
- String shortcutId = e.getShortcutId();
- if (packageData.getConversationStore().getConversation(shortcutId) != null) {
- EventHistoryImpl eventHistory =
- packageData.getEventStore().getOrCreateShortcutEventHistory(
- shortcutId);
- eventHistory.addEvent(
- new Event(e.getTimeStamp(), Event.TYPE_SHORTCUT_INVOCATION));
- }
- }
- }
- }
-
- @VisibleForTesting
ContentObserver getContactsContentObserverForTesting(@UserIdInt int userId) {
return mContactsContentObservers.get(userId);
}
@@ -611,19 +579,20 @@
*/
private class UsageStatsQueryRunnable implements Runnable {
- private final int mUserId;
- private long mLastQueryTime;
+ private final UsageStatsQueryHelper mUsageStatsQueryHelper;
+ private long mLastEventTimestamp;
private UsageStatsQueryRunnable(int userId) {
- mUserId = userId;
- mLastQueryTime = System.currentTimeMillis() - QUERY_EVENTS_MAX_AGE_MS;
+ mUsageStatsQueryHelper = mInjector.createUsageStatsQueryHelper(userId,
+ (packageName) -> getPackage(packageName, userId));
+ mLastEventTimestamp = System.currentTimeMillis() - QUERY_EVENTS_MAX_AGE_MS;
}
@Override
public void run() {
- long currentTime = System.currentTimeMillis();
- queryUsageStatsService(mUserId, currentTime, mLastQueryTime);
- mLastQueryTime = currentTime;
+ if (mUsageStatsQueryHelper.querySince(mLastEventTimestamp)) {
+ mLastEventTimestamp = mUsageStatsQueryHelper.getLastEventTimestamp();
+ }
}
}
@@ -679,6 +648,11 @@
return new SmsQueryHelper(context, eventConsumer);
}
+ UsageStatsQueryHelper createUsageStatsQueryHelper(@UserIdInt int userId,
+ Function<String, PackageData> packageDataGetter) {
+ return new UsageStatsQueryHelper(userId, packageDataGetter);
+ }
+
int getCallingUserId() {
return Binder.getCallingUserHandle().getIdentifier();
}
diff --git a/services/people/java/com/android/server/people/data/Event.java b/services/people/java/com/android/server/people/data/Event.java
index c2364a2..81411c0 100644
--- a/services/people/java/com/android/server/people/data/Event.java
+++ b/services/people/java/com/android/server/people/data/Event.java
@@ -18,14 +18,12 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.text.format.DateFormat;
import android.util.ArraySet;
-import com.android.internal.util.Preconditions;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
import java.util.Set;
/** An event representing the interaction with a specific conversation or app. */
@@ -55,6 +53,8 @@
public static final int TYPE_CALL_MISSED = 12;
+ public static final int TYPE_IN_APP_CONVERSATION = 13;
+
@IntDef(prefix = { "TYPE_" }, value = {
TYPE_SHORTCUT_INVOCATION,
TYPE_NOTIFICATION_POSTED,
@@ -68,6 +68,7 @@
TYPE_CALL_OUTGOING,
TYPE_CALL_INCOMING,
TYPE_CALL_MISSED,
+ TYPE_IN_APP_CONVERSATION,
})
@Retention(RetentionPolicy.SOURCE)
public @interface EventType {}
@@ -95,6 +96,7 @@
CALL_EVENT_TYPES.add(TYPE_CALL_MISSED);
ALL_EVENT_TYPES.add(TYPE_SHORTCUT_INVOCATION);
+ ALL_EVENT_TYPES.add(TYPE_IN_APP_CONVERSATION);
ALL_EVENT_TYPES.addAll(NOTIFICATION_EVENT_TYPES);
ALL_EVENT_TYPES.addAll(SHARE_EVENT_TYPES);
ALL_EVENT_TYPES.addAll(SMS_EVENT_TYPES);
@@ -105,18 +107,18 @@
private final int mType;
- private final CallDetails mCallDetails;
+ private final int mDurationSeconds;
Event(long timestamp, @EventType int type) {
mTimestamp = timestamp;
mType = type;
- mCallDetails = null;
+ mDurationSeconds = 0;
}
private Event(@NonNull Builder builder) {
mTimestamp = builder.mTimestamp;
mType = builder.mType;
- mCallDetails = builder.mCallDetails;
+ mDurationSeconds = builder.mDurationSeconds;
}
public long getTimestamp() {
@@ -128,12 +130,35 @@
}
/**
- * Gets the {@link CallDetails} of the event. It is only available if the event type is one of
- * {@code CALL_EVENT_TYPES}, otherwise, it's always {@code null}.
+ * Gets the duration of the event in seconds. It is only available for these events:
+ * <ul>
+ * <li>{@link #TYPE_CALL_INCOMING}
+ * <li>{@link #TYPE_CALL_OUTGOING}
+ * <li>{@link #TYPE_IN_APP_CONVERSATION}
+ * </ul>
+ * <p>For the other event types, it always returns {@code 0}.
*/
- @Nullable
- public CallDetails getCallDetails() {
- return mCallDetails;
+ public int getDurationSeconds() {
+ return mDurationSeconds;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof Event)) {
+ return false;
+ }
+ Event other = (Event) obj;
+ return mTimestamp == other.mTimestamp
+ && mType == other.mType
+ && mDurationSeconds == other.mDurationSeconds;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mTimestamp, mType, mDurationSeconds);
}
@Override
@@ -142,32 +167,13 @@
sb.append("Event {");
sb.append("timestamp=").append(DateFormat.format("yyyy-MM-dd HH:mm:ss", mTimestamp));
sb.append(", type=").append(mType);
- if (mCallDetails != null) {
- sb.append(", callDetails=").append(mCallDetails);
+ if (mDurationSeconds > 0) {
+ sb.append(", durationSeconds=").append(mDurationSeconds);
}
sb.append("}");
return sb.toString();
}
- /** Type-specific details of a call event. */
- public static class CallDetails {
-
- private final long mDurationSeconds;
-
- CallDetails(long durationSeconds) {
- mDurationSeconds = durationSeconds;
- }
-
- public long getDurationSeconds() {
- return mDurationSeconds;
- }
-
- @Override
- public String toString() {
- return "CallDetails {durationSeconds=" + mDurationSeconds + "}";
- }
- }
-
/** Builder class for {@link Event} objects. */
static class Builder {
@@ -175,16 +181,15 @@
private final int mType;
- private CallDetails mCallDetails;
+ private int mDurationSeconds;
Builder(long timestamp, @EventType int type) {
mTimestamp = timestamp;
mType = type;
}
- Builder setCallDetails(CallDetails callDetails) {
- Preconditions.checkArgument(CALL_EVENT_TYPES.contains(mType));
- mCallDetails = callDetails;
+ Builder setDurationSeconds(int durationSeconds) {
+ mDurationSeconds = durationSeconds;
return this;
}
diff --git a/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java b/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java
new file mode 100644
index 0000000..4e37f47
--- /dev/null
+++ b/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java
@@ -0,0 +1,158 @@
+/*
+ * 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.people.data;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.app.usage.UsageEvents;
+import android.app.usage.UsageStatsManagerInternal;
+import android.content.ComponentName;
+import android.content.LocusId;
+import android.text.format.DateUtils;
+import android.util.ArrayMap;
+
+import com.android.server.LocalServices;
+
+import java.util.Map;
+import java.util.function.Function;
+
+/** A helper class that queries {@link UsageStatsManagerInternal}. */
+class UsageStatsQueryHelper {
+
+ private final UsageStatsManagerInternal mUsageStatsManagerInternal;
+ private final int mUserId;
+ private final Function<String, PackageData> mPackageDataGetter;
+ // Activity name -> Conversation start event (LOCUS_ID_SET)
+ private final Map<ComponentName, UsageEvents.Event> mConvoStartEvents = new ArrayMap<>();
+ private long mLastEventTimestamp;
+
+ /**
+ * @param userId The user whose events are to be queried.
+ * @param packageDataGetter The function to get {@link PackageData} with a package name.
+ */
+ UsageStatsQueryHelper(@UserIdInt int userId,
+ Function<String, PackageData> packageDataGetter) {
+ mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class);
+ mUserId = userId;
+ mPackageDataGetter = packageDataGetter;
+ }
+
+ /**
+ * Queries {@link UsageStatsManagerInternal} for the recent events occurred since {@code
+ * sinceTime} and adds the derived {@link Event}s into the corresponding package's event store,
+ *
+ * @return true if the query runs successfully and at least one event is found.
+ */
+ boolean querySince(long sinceTime) {
+ UsageEvents usageEvents = mUsageStatsManagerInternal.queryEventsForUser(
+ mUserId, sinceTime, System.currentTimeMillis(), false, false);
+ if (usageEvents == null) {
+ return false;
+ }
+ boolean hasEvents = false;
+ while (usageEvents.hasNextEvent()) {
+ UsageEvents.Event e = new UsageEvents.Event();
+ usageEvents.getNextEvent(e);
+
+ hasEvents = true;
+ mLastEventTimestamp = Math.max(mLastEventTimestamp, e.getTimeStamp());
+ String packageName = e.getPackageName();
+ PackageData packageData = mPackageDataGetter.apply(packageName);
+ if (packageData == null) {
+ continue;
+ }
+ switch (e.getEventType()) {
+ case UsageEvents.Event.SHORTCUT_INVOCATION:
+ addEventByShortcutId(packageData, e.getShortcutId(),
+ new Event(e.getTimeStamp(), Event.TYPE_SHORTCUT_INVOCATION));
+ break;
+ case UsageEvents.Event.NOTIFICATION_INTERRUPTION:
+ addEventByNotificationChannelId(packageData, e.getNotificationChannelId(),
+ new Event(e.getTimeStamp(), Event.TYPE_NOTIFICATION_POSTED));
+ break;
+ case UsageEvents.Event.LOCUS_ID_SET:
+ onInAppConversationEnded(packageData, e);
+ LocusId locusId = e.getLocusId() != null ? new LocusId(e.getLocusId()) : null;
+ if (locusId != null) {
+ if (packageData.getConversationStore().getConversationByLocusId(locusId)
+ != null) {
+ ComponentName activityName =
+ new ComponentName(packageName, e.getClassName());
+ mConvoStartEvents.put(activityName, e);
+ }
+ }
+ break;
+ case UsageEvents.Event.ACTIVITY_PAUSED:
+ case UsageEvents.Event.ACTIVITY_STOPPED:
+ case UsageEvents.Event.ACTIVITY_DESTROYED:
+ onInAppConversationEnded(packageData, e);
+ break;
+ }
+ }
+ return hasEvents;
+ }
+
+ long getLastEventTimestamp() {
+ return mLastEventTimestamp;
+ }
+
+ private void onInAppConversationEnded(@NonNull PackageData packageData,
+ @NonNull UsageEvents.Event endEvent) {
+ ComponentName activityName =
+ new ComponentName(endEvent.getPackageName(), endEvent.getClassName());
+ UsageEvents.Event startEvent = mConvoStartEvents.remove(activityName);
+ if (startEvent == null || startEvent.getTimeStamp() >= endEvent.getTimeStamp()) {
+ return;
+ }
+ long durationMillis = endEvent.getTimeStamp() - startEvent.getTimeStamp();
+ Event event = new Event.Builder(startEvent.getTimeStamp(), Event.TYPE_IN_APP_CONVERSATION)
+ .setDurationSeconds((int) (durationMillis / DateUtils.SECOND_IN_MILLIS))
+ .build();
+ addEventByLocusId(packageData, new LocusId(startEvent.getLocusId()), event);
+ }
+
+ private void addEventByShortcutId(PackageData packageData, String shortcutId, Event event) {
+ if (packageData.getConversationStore().getConversation(shortcutId) == null) {
+ return;
+ }
+ EventHistoryImpl eventHistory = packageData.getEventStore().getOrCreateShortcutEventHistory(
+ shortcutId);
+ eventHistory.addEvent(event);
+ }
+
+ private void addEventByLocusId(PackageData packageData, LocusId locusId, Event event) {
+ if (packageData.getConversationStore().getConversationByLocusId(locusId) == null) {
+ return;
+ }
+ EventHistoryImpl eventHistory = packageData.getEventStore().getOrCreateLocusEventHistory(
+ locusId);
+ eventHistory.addEvent(event);
+ }
+
+ private void addEventByNotificationChannelId(PackageData packageData,
+ String notificationChannelId, Event event) {
+ ConversationInfo conversationInfo =
+ packageData.getConversationStore().getConversationByNotificationChannelId(
+ notificationChannelId);
+ if (conversationInfo == null) {
+ return;
+ }
+ EventHistoryImpl eventHistory = packageData.getEventStore().getOrCreateShortcutEventHistory(
+ conversationInfo.getShortcutId());
+ eventHistory.addEvent(event);
+ }
+}
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 3d9f11f..339ff6b 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -22,6 +22,7 @@
"services.net",
"service-jobscheduler",
"service-permission",
+ "service-blobstore",
"androidx.test.runner",
"mockito-target-extended-minus-junit4",
"platform-test-annotations",
diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml
index 0e24b03..44eb828 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-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" />
<uses-permission android:name="android.permission.HARDWARE_TEST"/>
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
diff --git a/services/tests/servicestests/assets/AppOpsUpgradeTest/appops-unversioned.xml b/services/tests/mockingservicestests/assets/AppOpsUpgradeTest/appops-unversioned.xml
similarity index 100%
rename from services/tests/servicestests/assets/AppOpsUpgradeTest/appops-unversioned.xml
rename to services/tests/mockingservicestests/assets/AppOpsUpgradeTest/appops-unversioned.xml
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 155de3b..2d5fa23 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -101,9 +101,8 @@
private StaticMockitoSession mMockingSession;
private void setupAppOpsService() {
- mAppOpsService = new AppOpsService(mAppOpsFile, mHandler);
+ mAppOpsService = new AppOpsService(mAppOpsFile, mHandler, spy(sContext));
mAppOpsService.mHistoricalRegistry.systemReady(sContext.getContentResolver());
- mAppOpsService.mContext = spy(sContext);
// Always approve all permission checks
doNothing().when(mAppOpsService.mContext).enforcePermission(anyString(), anyInt(),
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
similarity index 85%
rename from services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
rename to services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
index 66d2bab..e48b671 100644
--- a/services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,9 +19,17 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
import android.app.AppOpsManager;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.os.Handler;
import android.os.HandlerThread;
@@ -133,10 +141,24 @@
AppOpsDataParser parser = new AppOpsDataParser(mAppOpsFile);
assertTrue(parser.parse());
assertEquals(AppOpsDataParser.NO_VERSION, parser.mVersion);
- AppOpsService testService = new AppOpsService(mAppOpsFile, mHandler); // trigger upgrade
+
+ // Use mock context and package manager to fake permision package manager calls.
+ Context testContext = spy(mContext);
+
+ // Pretent everybody has all permissions
+ doNothing().when(testContext).enforcePermission(anyString(), anyInt(), anyInt(),
+ nullable(String.class));
+
+ PackageManager testPM = mock(PackageManager.class);
+ when(testContext.getPackageManager()).thenReturn(testPM);
+
+ // Stub out package calls to disable AppOpsService#updatePermissionRevokedCompat
+ when(testPM.getPackagesForUid(anyInt())).thenReturn(null);
+
+ AppOpsService testService = spy(
+ new AppOpsService(mAppOpsFile, mHandler, testContext)); // trigger upgrade
assertSameModes(testService.mUidStates, AppOpsManager.OP_RUN_IN_BACKGROUND,
AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
- testService.mContext = mContext;
mHandler.removeCallbacks(testService.mWriteRunner);
testService.writeState();
assertTrue(parser.parse());
diff --git a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
new file mode 100644
index 0000000..16dde42
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
@@ -0,0 +1,342 @@
+/*
+ * 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.blob;
+
+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.mockitoSession;
+import static com.android.server.blob.BlobStoreConfig.SESSION_EXPIRY_TIMEOUT_MILLIS;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.app.blob.BlobHandle;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
+import android.util.ArrayMap;
+import android.util.LongSparseArray;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.blob.BlobStoreManagerService.Injector;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.io.File;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class BlobStoreManagerServiceTest {
+ private Context mContext;
+ private Handler mHandler;
+ private BlobStoreManagerService mService;
+
+ private MockitoSession mMockitoSession;
+
+ @Mock
+ private File mBlobsDir;
+
+ private LongSparseArray<BlobStoreSession> mUserSessions;
+ private ArrayMap<BlobHandle, BlobMetadata> mUserBlobs;
+
+ private static final String TEST_PKG1 = "com.example1";
+ private static final String TEST_PKG2 = "com.example2";
+ private static final String TEST_PKG3 = "com.example3";
+
+ private static final int TEST_UID1 = 10001;
+ private static final int TEST_UID2 = 10002;
+ private static final int TEST_UID3 = 10003;
+
+ @Before
+ public void setUp() {
+ // Share classloader to allow package private access.
+ System.setProperty("dexmaker.share_classloader", "true");
+
+ mMockitoSession = mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .mockStatic(BlobStoreConfig.class)
+ .startMocking();
+
+ doReturn(mBlobsDir).when(() -> BlobStoreConfig.getBlobsDir());
+ doReturn(true).when(mBlobsDir).exists();
+ doReturn(new File[0]).when(mBlobsDir).listFiles();
+
+ mContext = InstrumentationRegistry.getTargetContext();
+ mHandler = new TestHandler(Looper.getMainLooper());
+ mService = new BlobStoreManagerService(mContext, new TestInjector());
+ mUserSessions = new LongSparseArray<>();
+ mUserBlobs = new ArrayMap<>();
+
+ mService.addUserSessionsForTest(mUserSessions, UserHandle.myUserId());
+ mService.addUserBlobsForTest(mUserBlobs, UserHandle.myUserId());
+ }
+
+ @After
+ public void tearDown() {
+ if (mMockitoSession != null) {
+ mMockitoSession.finishMocking();
+ }
+ }
+
+ @Test
+ public void testHandlePackageRemoved() throws Exception {
+ // Setup sessions
+ final File sessionFile1 = mock(File.class);
+ final long sessionId1 = 11;
+ final BlobStoreSession session1 = createBlobStoreSessionMock(TEST_PKG1, TEST_UID1,
+ sessionId1, sessionFile1);
+ mUserSessions.append(sessionId1, session1);
+
+ final File sessionFile2 = mock(File.class);
+ final long sessionId2 = 25;
+ final BlobStoreSession session2 = createBlobStoreSessionMock(TEST_PKG2, TEST_UID2,
+ sessionId2, sessionFile2);
+ mUserSessions.append(sessionId2, session2);
+
+ final File sessionFile3 = mock(File.class);
+ final long sessionId3 = 37;
+ final BlobStoreSession session3 = createBlobStoreSessionMock(TEST_PKG3, TEST_UID3,
+ sessionId3, sessionFile3);
+ mUserSessions.append(sessionId3, session3);
+
+ final File sessionFile4 = mock(File.class);
+ final long sessionId4 = 48;
+ final BlobStoreSession session4 = createBlobStoreSessionMock(TEST_PKG1, TEST_UID1,
+ sessionId4, sessionFile4);
+ mUserSessions.append(sessionId4, session4);
+
+ // Setup blobs
+ final long blobId1 = 978;
+ final File blobFile1 = mock(File.class);
+ final BlobHandle blobHandle1 = BlobHandle.createWithSha256("digest1".getBytes(),
+ "label1", System.currentTimeMillis(), "tag1");
+ final BlobMetadata blobMetadata1 = createBlobMetadataMock(blobId1, blobFile1, true);
+ mUserBlobs.put(blobHandle1, blobMetadata1);
+
+ final long blobId2 = 347;
+ final File blobFile2 = mock(File.class);
+ final BlobHandle blobHandle2 = BlobHandle.createWithSha256("digest2".getBytes(),
+ "label2", System.currentTimeMillis(), "tag2");
+ final BlobMetadata blobMetadata2 = createBlobMetadataMock(blobId2, blobFile2, false);
+ mUserBlobs.put(blobHandle2, blobMetadata2);
+
+ mService.addKnownIdsForTest(sessionId1, sessionId2, sessionId3, sessionId4,
+ blobId1, blobId2);
+
+ // Invoke test method
+ mService.handlePackageRemoved(TEST_PKG1, TEST_UID1);
+
+ // Verify sessions are removed
+ verify(sessionFile1).delete();
+ verify(sessionFile2, never()).delete();
+ verify(sessionFile3, never()).delete();
+ verify(sessionFile4).delete();
+
+ assertThat(mUserSessions.size()).isEqualTo(2);
+ assertThat(mUserSessions.get(sessionId1)).isNull();
+ assertThat(mUserSessions.get(sessionId2)).isNotNull();
+ assertThat(mUserSessions.get(sessionId3)).isNotNull();
+ assertThat(mUserSessions.get(sessionId4)).isNull();
+
+ // Verify blobs are removed
+ verify(blobMetadata1).removeCommitter(TEST_PKG1, TEST_UID1);
+ verify(blobMetadata1).removeLeasee(TEST_PKG1, TEST_UID1);
+ verify(blobMetadata2).removeCommitter(TEST_PKG1, TEST_UID1);
+ verify(blobMetadata2).removeLeasee(TEST_PKG1, TEST_UID1);
+
+ verify(blobFile1, never()).delete();
+ verify(blobFile2).delete();
+
+ assertThat(mUserBlobs.size()).isEqualTo(1);
+ assertThat(mUserBlobs.get(blobHandle1)).isNotNull();
+ assertThat(mUserBlobs.get(blobHandle2)).isNull();
+
+ assertThat(mService.getKnownIdsForTest()).containsExactly(
+ sessionId2, sessionId3, blobId1);
+ }
+
+ @Test
+ public void testHandleIdleMaintenance_deleteUnknownBlobs() throws Exception {
+ // Setup blob files
+ final long testId1 = 286;
+ final File file1 = mock(File.class);
+ doReturn(String.valueOf(testId1)).when(file1).getName();
+ final long testId2 = 349;
+ final File file2 = mock(File.class);
+ doReturn(String.valueOf(testId2)).when(file2).getName();
+ final long testId3 = 7355;
+ final File file3 = mock(File.class);
+ doReturn(String.valueOf(testId3)).when(file3).getName();
+
+ doReturn(new File[] {file1, file2, file3}).when(mBlobsDir).listFiles();
+ mService.addKnownIdsForTest(testId1, testId3);
+
+ // Invoke test method
+ mService.handleIdleMaintenanceLocked();
+
+ // Verify unknown blobs are delete
+ verify(file1, never()).delete();
+ verify(file2).delete();
+ verify(file3, never()).delete();
+ }
+
+ @Test
+ public void testHandleIdleMaintenance_deleteStaleSessions() throws Exception {
+ // Setup sessions
+ final File sessionFile1 = mock(File.class);
+ doReturn(System.currentTimeMillis() - SESSION_EXPIRY_TIMEOUT_MILLIS + 1000)
+ .when(sessionFile1).lastModified();
+ final long sessionId1 = 342;
+ final BlobHandle blobHandle1 = mock(BlobHandle.class);
+ doReturn(System.currentTimeMillis() - 1000).when(blobHandle1).getExpiryTimeMillis();
+ final BlobStoreSession session1 = createBlobStoreSessionMock(TEST_PKG1, TEST_UID1,
+ sessionId1, sessionFile1, blobHandle1);
+ mUserSessions.append(sessionId1, session1);
+
+ final File sessionFile2 = mock(File.class);
+ doReturn(System.currentTimeMillis() - 20000)
+ .when(sessionFile2).lastModified();
+ final long sessionId2 = 4597;
+ final BlobHandle blobHandle2 = mock(BlobHandle.class);
+ doReturn(System.currentTimeMillis() + 20000).when(blobHandle2).getExpiryTimeMillis();
+ final BlobStoreSession session2 = createBlobStoreSessionMock(TEST_PKG2, TEST_UID2,
+ sessionId2, sessionFile2, blobHandle2);
+ mUserSessions.append(sessionId2, session2);
+
+ final File sessionFile3 = mock(File.class);
+ doReturn(System.currentTimeMillis() - SESSION_EXPIRY_TIMEOUT_MILLIS - 2000)
+ .when(sessionFile3).lastModified();
+ final long sessionId3 = 9484;
+ final BlobHandle blobHandle3 = mock(BlobHandle.class);
+ doReturn(System.currentTimeMillis() + 30000).when(blobHandle3).getExpiryTimeMillis();
+ final BlobStoreSession session3 = createBlobStoreSessionMock(TEST_PKG3, TEST_UID3,
+ sessionId3, sessionFile3, blobHandle3);
+ mUserSessions.append(sessionId3, session3);
+
+ mService.addKnownIdsForTest(sessionId1, sessionId2, sessionId3);
+
+ // Invoke test method
+ mService.handleIdleMaintenanceLocked();
+
+ // Verify stale sessions are removed
+ verify(sessionFile1).delete();
+ verify(sessionFile2, never()).delete();
+ verify(sessionFile3).delete();
+
+ assertThat(mUserSessions.size()).isEqualTo(1);
+ assertThat(mUserSessions.get(sessionId2)).isNotNull();
+
+ assertThat(mService.getKnownIdsForTest()).containsExactly(sessionId2);
+ }
+
+ @Test
+ public void testHandleIdleMaintenance_deleteStaleBlobs() throws Exception {
+ // Setup blobs
+ final long blobId1 = 3489;
+ final File blobFile1 = mock(File.class);
+ final BlobHandle blobHandle1 = BlobHandle.createWithSha256("digest1".getBytes(),
+ "label1", System.currentTimeMillis() - 2000, "tag1");
+ final BlobMetadata blobMetadata1 = createBlobMetadataMock(blobId1, blobFile1, true);
+ mUserBlobs.put(blobHandle1, blobMetadata1);
+
+ final long blobId2 = 78974;
+ final File blobFile2 = mock(File.class);
+ final BlobHandle blobHandle2 = BlobHandle.createWithSha256("digest2".getBytes(),
+ "label2", System.currentTimeMillis() + 30000, "tag2");
+ final BlobMetadata blobMetadata2 = createBlobMetadataMock(blobId2, blobFile2, true);
+ mUserBlobs.put(blobHandle2, blobMetadata2);
+
+ final long blobId3 = 97;
+ final File blobFile3 = mock(File.class);
+ final BlobHandle blobHandle3 = BlobHandle.createWithSha256("digest3".getBytes(),
+ "label3", System.currentTimeMillis() + 4400000, "tag3");
+ final BlobMetadata blobMetadata3 = createBlobMetadataMock(blobId3, blobFile3, false);
+ mUserBlobs.put(blobHandle3, blobMetadata3);
+
+ mService.addKnownIdsForTest(blobId1, blobId2, blobId3);
+
+ // Invoke test method
+ mService.handleIdleMaintenanceLocked();
+
+ // Verify stale blobs are removed
+ verify(blobFile1).delete();
+ verify(blobFile2, never()).delete();
+ verify(blobFile3).delete();
+
+ assertThat(mUserBlobs.size()).isEqualTo(1);
+ assertThat(mUserBlobs.get(blobHandle2)).isNotNull();
+
+ assertThat(mService.getKnownIdsForTest()).containsExactly(blobId2);
+ }
+
+ private BlobStoreSession createBlobStoreSessionMock(String ownerPackageName, int ownerUid,
+ long sessionId, File sessionFile) {
+ return createBlobStoreSessionMock(ownerPackageName, ownerUid, sessionId, sessionFile,
+ mock(BlobHandle.class));
+ }
+ private BlobStoreSession createBlobStoreSessionMock(String ownerPackageName, int ownerUid,
+ long sessionId, File sessionFile, BlobHandle blobHandle) {
+ final BlobStoreSession session = mock(BlobStoreSession.class);
+ doReturn(ownerPackageName).when(session).getOwnerPackageName();
+ doReturn(ownerUid).when(session).getOwnerUid();
+ doReturn(sessionId).when(session).getSessionId();
+ doReturn(sessionFile).when(session).getSessionFile();
+ doReturn(blobHandle).when(session).getBlobHandle();
+ return session;
+ }
+
+ private BlobMetadata createBlobMetadataMock(long blobId, File blobFile, boolean hasLeases) {
+ final BlobMetadata blobMetadata = mock(BlobMetadata.class);
+ doReturn(blobId).when(blobMetadata).getBlobId();
+ doReturn(blobFile).when(blobMetadata).getBlobFile();
+ doReturn(hasLeases).when(blobMetadata).hasLeases();
+ return blobMetadata;
+ }
+
+ private class TestHandler extends Handler {
+ TestHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void dispatchMessage(Message msg) {
+ // Ignore all messages
+ }
+ }
+
+ private class TestInjector extends Injector {
+ @Override
+ public Handler initializeMessageHandler() {
+ return mHandler;
+ }
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/testables/StaticMockFixtureRule.java b/services/tests/mockingservicestests/src/com/android/server/testables/StaticMockFixtureRule.java
index 8e9d7ee..3566aee 100644
--- a/services/tests/mockingservicestests/src/com/android/server/testables/StaticMockFixtureRule.java
+++ b/services/tests/mockingservicestests/src/com/android/server/testables/StaticMockFixtureRule.java
@@ -21,6 +21,7 @@
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
+import org.junit.AssumptionViolatedException;
import org.junit.rules.TestRule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
@@ -100,6 +101,11 @@
}
@Override
+ protected void skipped(AssumptionViolatedException e, Description description) {
+ tearDown(e);
+ }
+
+ @Override
protected void failed(Throwable e, Description description) {
tearDown(e);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/testables/StaticMockFixtureRuleTest.java b/services/tests/mockingservicestests/src/com/android/server/testables/StaticMockFixtureRuleTest.java
index b7e71de..8e0ccf0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/testables/StaticMockFixtureRuleTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/testables/StaticMockFixtureRuleTest.java
@@ -16,8 +16,10 @@
package com.android.server.testables;
+import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
@@ -30,6 +32,7 @@
import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
import org.junit.After;
+import org.junit.AssumptionViolatedException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.Description;
@@ -57,6 +60,8 @@
@Mock private Supplier<StaticMockFixture> mSupplyA;
@Mock private Supplier<StaticMockFixture> mSupplyB;
@Mock private Statement mStatement;
+ @Mock private Statement mSkipStatement;
+ @Mock private Statement mThrowStatement;
@Mock private Description mDescription;
@Before
@@ -91,17 +96,22 @@
when(mB1.setUpMockedClasses(any())).thenAnswer(invocation -> invocation.getArgument(0));
doNothing().when(mB1).setUpMockBehaviors();
doNothing().when(mStatement).evaluate();
+ doThrow(new AssumptionViolatedException("bad assumption, test should be skipped"))
+ .when(mSkipStatement).evaluate();
+ doThrow(new IllegalArgumentException("bad argument, test should be failed"))
+ .when(mThrowStatement).evaluate();
doNothing().when(mA1).tearDown();
doNothing().when(mB1).tearDown();
}
private InOrder mocksInOrder() {
- return inOrder(mSessionBuilder, mSession, mSupplyA, mSupplyB,
- mA1, mA2, mB1, mB2, mStatement, mDescription);
+ return inOrder(mSessionBuilder, mSession, mSupplyA, mSupplyB, mA1, mA2, mB1, mB2,
+ mStatement, mSkipStatement, mThrowStatement, mDescription);
}
private void verifyNoMoreImportantMockInteractions() {
- verifyNoMoreInteractions(mSupplyA, mSupplyB, mA1, mA2, mB1, mB2, mStatement);
+ verifyNoMoreInteractions(mSupplyA, mSupplyB, mA1, mA2, mB1, mB2, mStatement,
+ mSkipStatement, mThrowStatement);
}
@Test
@@ -183,4 +193,66 @@
verifyNoMoreImportantMockInteractions();
}
+
+ @Test
+ public void testTearDownOnSkippedTests() throws Throwable {
+ InOrder inOrder = mocksInOrder();
+
+ StaticMockFixtureRule rule = new StaticMockFixtureRule(mA1, mB1) {
+ @Override public StaticMockitoSessionBuilder getSessionBuilder() {
+ return mSessionBuilder;
+ }
+ };
+ Statement skipStatement = rule.apply(mSkipStatement, mDescription);
+
+ inOrder.verify(mA1).setUpMockedClasses(any(StaticMockitoSessionBuilder.class));
+ inOrder.verify(mB1).setUpMockedClasses(any(StaticMockitoSessionBuilder.class));
+ inOrder.verify(mA1).setUpMockBehaviors();
+ inOrder.verify(mB1).setUpMockBehaviors();
+
+ try {
+ skipStatement.evaluate();
+ fail("AssumptionViolatedException should have been thrown");
+ } catch (AssumptionViolatedException e) {
+ // expected
+ }
+
+ inOrder.verify(mSkipStatement).evaluate();
+ // note: tearDown in reverse order
+ inOrder.verify(mB1).tearDown();
+ inOrder.verify(mA1).tearDown();
+
+ verifyNoMoreImportantMockInteractions();
+ }
+
+ @Test
+ public void testTearDownOnFailedTests() throws Throwable {
+ InOrder inOrder = mocksInOrder();
+
+ StaticMockFixtureRule rule = new StaticMockFixtureRule(mA1, mB1) {
+ @Override public StaticMockitoSessionBuilder getSessionBuilder() {
+ return mSessionBuilder;
+ }
+ };
+ Statement failStatement = rule.apply(mThrowStatement, mDescription);
+
+ inOrder.verify(mA1).setUpMockedClasses(any(StaticMockitoSessionBuilder.class));
+ inOrder.verify(mB1).setUpMockedClasses(any(StaticMockitoSessionBuilder.class));
+ inOrder.verify(mA1).setUpMockBehaviors();
+ inOrder.verify(mB1).setUpMockBehaviors();
+
+ try {
+ failStatement.evaluate();
+ fail("IllegalArgumentException should have been thrown");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ inOrder.verify(mThrowStatement).evaluate();
+ // note: tearDown in reverse order
+ inOrder.verify(mB1).tearDown();
+ inOrder.verify(mA1).tearDown();
+
+ verifyNoMoreImportantMockInteractions();
+ }
}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 8381205..f990810 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -46,7 +46,6 @@
"service-appsearch",
"service-jobscheduler",
"service-permission",
- "service-blobstore",
// TODO: remove once Android migrates to JUnit 4.12,
// which provides assertThrows
"testng",
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index d2ddff3..1212f20 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -65,6 +65,8 @@
<uses-permission android:name="android.permission.WATCH_APPOPS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.SUSPEND_APPS"/>
+ <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.CONTROL_KEYGUARD"/>
<uses-permission android:name="android.permission.MANAGE_BIND_INSTANT_SERVICE"/>
<uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
index cf10559..dfe950e 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
@@ -47,6 +47,7 @@
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -703,14 +704,20 @@
@Test
public void takeScreenshot_returnNull() {
- // no canTakeScreenshot, should return null.
- when(mMockSecurityPolicy.canTakeScreenshotLocked(mServiceConnection)).thenReturn(false);
- assertThat(mServiceConnection.takeScreenshot(Display.DEFAULT_DISPLAY), is(nullValue()));
-
// no checkAccessibilityAccess, should return null.
when(mMockSecurityPolicy.canTakeScreenshotLocked(mServiceConnection)).thenReturn(true);
when(mMockSecurityPolicy.checkAccessibilityAccess(mServiceConnection)).thenReturn(false);
- assertThat(mServiceConnection.takeScreenshot(Display.DEFAULT_DISPLAY), is(nullValue()));
+ mServiceConnection.takeScreenshot(Display.DEFAULT_DISPLAY, new RemoteCallback((result) -> {
+ assertNull(result);
+ }));
+ }
+
+ @Test (expected = SecurityException.class)
+ public void takeScreenshot_throwSecurityException() {
+ // no canTakeScreenshot, should throw security exception.
+ when(mMockSecurityPolicy.canTakeScreenshotLocked(mServiceConnection)).thenReturn(false);
+ mServiceConnection.takeScreenshot(Display.DEFAULT_DISPLAY, new RemoteCallback((result) -> {
+ }));
}
private void updateServiceInfo(AccessibilityServiceInfo serviceInfo, int eventType,
@@ -852,8 +859,5 @@
@Override
public void onFingerprintGesture(int gesture) {}
-
- @Override
- public void takeScreenshotWithCallback(int displayId, RemoteCallback callback) {}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
index d38c80c..6aa9287 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
@@ -24,6 +24,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -32,6 +33,9 @@
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.IBiometricServiceReceiver;
+import android.hardware.face.IFaceService;
+import android.hardware.fingerprint.IFingerprintService;
+import android.hardware.iris.IIrisService;
import android.os.Binder;
import android.os.Bundle;
@@ -61,6 +65,12 @@
AuthService.Injector mInjector;
@Mock
IBiometricService mBiometricService;
+ @Mock
+ IFingerprintService mFingerprintService;
+ @Mock
+ IIrisService mIrisService;
+ @Mock
+ IFaceService mFaceService;
@Before
public void setUp() {
@@ -76,10 +86,28 @@
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mInjector.getBiometricService()).thenReturn(mBiometricService);
when(mInjector.getConfiguration(any())).thenReturn(config);
- when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
- .thenReturn(true);
- when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IRIS)).thenReturn(true);
- when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
+ when(mInjector.getFingerprintService()).thenReturn(mFingerprintService);
+ when(mInjector.getFaceService()).thenReturn(mFaceService);
+ when(mInjector.getIrisService()).thenReturn(mIrisService);
+ }
+
+ @Test
+ public void testRegisterNullService_doesNotRegister() throws Exception {
+
+ // Config contains Fingerprint, Iris, Face, but services are all null
+
+ when(mInjector.getFingerprintService()).thenReturn(null);
+ when(mInjector.getFaceService()).thenReturn(null);
+ when(mInjector.getIrisService()).thenReturn(null);
+
+ mAuthService = new AuthService(mContext, mInjector);
+ mAuthService.onStart();
+
+ verify(mBiometricService, never()).registerAuthenticator(
+ anyInt(),
+ anyInt(),
+ anyInt(),
+ any());
}
diff --git a/services/tests/servicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
deleted file mode 100644
index ff728e7..0000000
--- a/services/tests/servicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * 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.blob;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.blob.BlobHandle;
-import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.UserHandle;
-import android.platform.test.annotations.Presubmit;
-import android.util.ArrayMap;
-import android.util.LongSparseArray;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.blob.BlobStoreManagerService.Injector;
-import com.android.server.blob.BlobStoreManagerService.SessionStateChangeListener;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.File;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-@Presubmit
-public class BlobStoreManagerServiceTest {
- private Context mContext;
- private Handler mHandler;
- private BlobStoreManagerService mService;
-
- private LongSparseArray<BlobStoreSession> mUserSessions;
- private ArrayMap<BlobHandle, BlobMetadata> mUserBlobs;
-
- private SessionStateChangeListener mStateChangeListener;
-
- private static final String TEST_PKG1 = "com.example1";
- private static final String TEST_PKG2 = "com.example2";
- private static final String TEST_PKG3 = "com.example3";
-
- private static final int TEST_UID1 = 10001;
- private static final int TEST_UID2 = 10002;
- private static final int TEST_UID3 = 10003;
-
- @Before
- public void setUp() {
- // Share classloader to allow package private access.
- System.setProperty("dexmaker.share_classloader", "true");
-
- mContext = InstrumentationRegistry.getTargetContext();
- mHandler = new TestHandler(Looper.getMainLooper());
- mService = new BlobStoreManagerService(mContext, new TestInjector());
- mUserSessions = new LongSparseArray<>();
- mUserBlobs = new ArrayMap<>();
-
- mService.addUserSessionsForTest(mUserSessions, UserHandle.myUserId());
- mService.addUserBlobsForTest(mUserBlobs, UserHandle.myUserId());
-
- mStateChangeListener = mService.new SessionStateChangeListener();
- }
-
- @Test
- public void testHandlePackageRemoved() throws Exception {
- // Setup sessions
- final File sessionFile1 = mock(File.class);
- final long sessionId1 = 11;
- final BlobStoreSession session1 = createBlobStoreSessionMock(TEST_PKG1, TEST_UID1,
- sessionId1, sessionFile1);
- mUserSessions.append(sessionId1, session1);
-
- final File sessionFile2 = mock(File.class);
- final long sessionId2 = 25;
- final BlobStoreSession session2 = createBlobStoreSessionMock(TEST_PKG2, TEST_UID2,
- sessionId2, sessionFile2);
- mUserSessions.append(sessionId2, session2);
-
- final File sessionFile3 = mock(File.class);
- final long sessionId3 = 37;
- final BlobStoreSession session3 = createBlobStoreSessionMock(TEST_PKG3, TEST_UID3,
- sessionId3, sessionFile3);
- mUserSessions.append(sessionId3, session3);
-
- final File sessionFile4 = mock(File.class);
- final long sessionId4 = 48;
- final BlobStoreSession session4 = createBlobStoreSessionMock(TEST_PKG1, TEST_UID1,
- sessionId4, sessionFile4);
- mUserSessions.append(sessionId4, session4);
-
- // Setup blobs
- final File blobFile1 = mock(File.class);
- final BlobHandle blobHandle1 = BlobHandle.createWithSha256("digest1".getBytes(),
- "label1", System.currentTimeMillis(), "tag1");
- final BlobMetadata blobMetadata1 = createBlobMetadataMock(blobFile1, true);
- mUserBlobs.put(blobHandle1, blobMetadata1);
-
- final File blobFile2 = mock(File.class);
- final BlobHandle blobHandle2 = BlobHandle.createWithSha256("digest2".getBytes(),
- "label2", System.currentTimeMillis(), "tag2");
- final BlobMetadata blobMetadata2 = createBlobMetadataMock(blobFile2, false);
- mUserBlobs.put(blobHandle2, blobMetadata2);
-
- // Invoke test method
- mService.handlePackageRemoved(TEST_PKG1, TEST_UID1);
-
- // Verify sessions are removed
- verify(sessionFile1).delete();
- verify(sessionFile2, never()).delete();
- verify(sessionFile3, never()).delete();
- verify(sessionFile4).delete();
-
- assertThat(mUserSessions.size()).isEqualTo(2);
- assertThat(mUserSessions.get(sessionId1)).isNull();
- assertThat(mUserSessions.get(sessionId2)).isNotNull();
- assertThat(mUserSessions.get(sessionId3)).isNotNull();
- assertThat(mUserSessions.get(sessionId4)).isNull();
-
- // Verify blobs are removed
- verify(blobMetadata1).removeCommitter(TEST_PKG1, TEST_UID1);
- verify(blobMetadata1).removeLeasee(TEST_PKG1, TEST_UID1);
- verify(blobMetadata2).removeCommitter(TEST_PKG1, TEST_UID1);
- verify(blobMetadata2).removeLeasee(TEST_PKG1, TEST_UID1);
-
- verify(blobFile1, never()).delete();
- verify(blobFile2).delete();
-
- assertThat(mUserBlobs.size()).isEqualTo(1);
- assertThat(mUserBlobs.get(blobHandle1)).isNotNull();
- assertThat(mUserBlobs.get(blobHandle2)).isNull();
- }
-
- private BlobStoreSession createBlobStoreSessionMock(String ownerPackageName, int ownerUid,
- long sessionId, File sessionFile) {
- final BlobStoreSession session = mock(BlobStoreSession.class);
- when(session.getOwnerPackageName()).thenReturn(ownerPackageName);
- when(session.getOwnerUid()).thenReturn(ownerUid);
- when(session.getSessionId()).thenReturn(sessionId);
- when(session.getSessionFile()).thenReturn(sessionFile);
- return session;
- }
-
- private BlobMetadata createBlobMetadataMock(File blobFile, boolean hasLeases) {
- final BlobMetadata blobMetadata = mock(BlobMetadata.class);
- when(blobMetadata.getBlobFile()).thenReturn(blobFile);
- when(blobMetadata.hasLeases()).thenReturn(hasLeases);
- return blobMetadata;
- }
-
- private class TestHandler extends Handler {
- TestHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void dispatchMessage(Message msg) {
- // Ignore all messages
- }
- }
-
- private class TestInjector extends Injector {
- @Override
- public Handler initializeMessageHandler() {
- return mHandler;
- }
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
index 4a7636a..c9ec874 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -423,7 +423,8 @@
PackageInfo packageInfo =
mRealContext
.getPackageManager()
- .getPackageInfo(TEST_FRAMEWORK_PACKAGE, PackageManager.GET_SIGNATURES);
+ .getPackageInfo(TEST_FRAMEWORK_PACKAGE,
+ PackageManager.GET_SIGNING_CERTIFICATES);
doReturn(packageInfo).when(mSpyPackageManager).getPackageInfo(eq(INSTALLER), anyInt());
doReturn(1).when(mSpyPackageManager).getPackageUid(eq(INSTALLER), anyInt());
return makeVerificationIntent(INSTALLER);
diff --git a/services/tests/servicestests/src/com/android/server/people/data/CallLogQueryHelperTest.java b/services/tests/servicestests/src/com/android/server/people/data/CallLogQueryHelperTest.java
index 7a16d17..a545010 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/CallLogQueryHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/CallLogQueryHelperTest.java
@@ -92,7 +92,7 @@
assertEquals(1, events.size());
assertEquals(Event.TYPE_CALL_INCOMING, events.get(0).getType());
assertEquals(100L, events.get(0).getTimestamp());
- assertEquals(30L, events.get(0).getCallDetails().getDurationSeconds());
+ assertEquals(30L, events.get(0).getDurationSeconds());
}
@Test
@@ -108,7 +108,7 @@
assertEquals(1, events.size());
assertEquals(Event.TYPE_CALL_OUTGOING, events.get(0).getType());
assertEquals(100L, events.get(0).getTimestamp());
- assertEquals(40L, events.get(0).getCallDetails().getDurationSeconds());
+ assertEquals(40L, events.get(0).getDurationSeconds());
}
@Test
@@ -124,7 +124,7 @@
assertEquals(1, events.size());
assertEquals(Event.TYPE_CALL_MISSED, events.get(0).getType());
assertEquals(100L, events.get(0).getTimestamp());
- assertEquals(0L, events.get(0).getCallDetails().getDurationSeconds());
+ assertEquals(0L, events.get(0).getDurationSeconds());
}
@Test
@@ -145,7 +145,7 @@
assertEquals(100L, events.get(0).getTimestamp());
assertEquals(Event.TYPE_CALL_OUTGOING, events.get(1).getType());
assertEquals(110L, events.get(1).getTimestamp());
- assertEquals(40L, events.get(1).getCallDetails().getDurationSeconds());
+ assertEquals(40L, events.get(1).getDurationSeconds());
}
private class EventConsumer implements BiConsumer<String, Event> {
diff --git a/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java b/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
index a40c6ab..bbcb54e 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
@@ -37,6 +37,7 @@
public final class ConversationStoreTest {
private static final String SHORTCUT_ID = "abc";
+ private static final String NOTIFICATION_CHANNEL_ID = "test : abc";
private static final LocusId LOCUS_ID = new LocusId("def");
private static final Uri CONTACT_URI = Uri.parse("tel:+1234567890");
private static final String PHONE_NUMBER = "+1234567890";
@@ -59,16 +60,19 @@
@Test
public void testUpdateConversation() {
- ConversationInfo original =
- buildConversationInfo(SHORTCUT_ID, LOCUS_ID, CONTACT_URI, PHONE_NUMBER);
+ ConversationInfo original = buildConversationInfo(SHORTCUT_ID, LOCUS_ID, CONTACT_URI,
+ PHONE_NUMBER, null);
mConversationStore.addOrUpdate(original);
assertEquals(LOCUS_ID, mConversationStore.getConversation(SHORTCUT_ID).getLocusId());
+ assertNull(mConversationStore.getConversation(SHORTCUT_ID).getNotificationChannelId());
LocusId newLocusId = new LocusId("ghi");
ConversationInfo update = buildConversationInfo(
- SHORTCUT_ID, newLocusId, CONTACT_URI, PHONE_NUMBER);
+ SHORTCUT_ID, newLocusId, CONTACT_URI, PHONE_NUMBER, NOTIFICATION_CHANNEL_ID);
mConversationStore.addOrUpdate(update);
- assertEquals(newLocusId, mConversationStore.getConversation(SHORTCUT_ID).getLocusId());
+ ConversationInfo updated = mConversationStore.getConversation(SHORTCUT_ID);
+ assertEquals(newLocusId, updated.getLocusId());
+ assertEquals(NOTIFICATION_CHANNEL_ID, updated.getNotificationChannelId());
}
@Test
@@ -97,8 +101,8 @@
@Test
public void testGetConversationByLocusId() {
- ConversationInfo in =
- buildConversationInfo(SHORTCUT_ID, LOCUS_ID, CONTACT_URI, PHONE_NUMBER);
+ ConversationInfo in = buildConversationInfo(SHORTCUT_ID, LOCUS_ID, CONTACT_URI,
+ PHONE_NUMBER, NOTIFICATION_CHANNEL_ID);
mConversationStore.addOrUpdate(in);
ConversationInfo out = mConversationStore.getConversationByLocusId(LOCUS_ID);
assertNotNull(out);
@@ -110,8 +114,8 @@
@Test
public void testGetConversationByContactUri() {
- ConversationInfo in =
- buildConversationInfo(SHORTCUT_ID, LOCUS_ID, CONTACT_URI, PHONE_NUMBER);
+ ConversationInfo in = buildConversationInfo(SHORTCUT_ID, LOCUS_ID, CONTACT_URI,
+ PHONE_NUMBER, NOTIFICATION_CHANNEL_ID);
mConversationStore.addOrUpdate(in);
ConversationInfo out = mConversationStore.getConversationByContactUri(CONTACT_URI);
assertNotNull(out);
@@ -123,8 +127,8 @@
@Test
public void testGetConversationByPhoneNumber() {
- ConversationInfo in =
- buildConversationInfo(SHORTCUT_ID, LOCUS_ID, CONTACT_URI, PHONE_NUMBER);
+ ConversationInfo in = buildConversationInfo(SHORTCUT_ID, LOCUS_ID, CONTACT_URI,
+ PHONE_NUMBER, NOTIFICATION_CHANNEL_ID);
mConversationStore.addOrUpdate(in);
ConversationInfo out = mConversationStore.getConversationByPhoneNumber(PHONE_NUMBER);
assertNotNull(out);
@@ -134,17 +138,34 @@
assertNull(mConversationStore.getConversationByPhoneNumber(PHONE_NUMBER));
}
+ @Test
+ public void testGetConversationByNotificationChannelId() {
+ ConversationInfo in = buildConversationInfo(SHORTCUT_ID, LOCUS_ID, CONTACT_URI,
+ PHONE_NUMBER, NOTIFICATION_CHANNEL_ID);
+ mConversationStore.addOrUpdate(in);
+ ConversationInfo out = mConversationStore.getConversationByNotificationChannelId(
+ NOTIFICATION_CHANNEL_ID);
+ assertNotNull(out);
+ assertEquals(SHORTCUT_ID, out.getShortcutId());
+
+ mConversationStore.deleteConversation(SHORTCUT_ID);
+ assertNull(
+ mConversationStore.getConversationByNotificationChannelId(NOTIFICATION_CHANNEL_ID));
+ }
+
private static ConversationInfo buildConversationInfo(String shortcutId) {
- return buildConversationInfo(shortcutId, null, null, null);
+ return buildConversationInfo(shortcutId, null, null, null, null);
}
private static ConversationInfo buildConversationInfo(
- String shortcutId, LocusId locusId, Uri contactUri, String phoneNumber) {
+ String shortcutId, LocusId locusId, Uri contactUri, String phoneNumber,
+ String notificationChannelId) {
return new ConversationInfo.Builder()
.setShortcutId(shortcutId)
.setLocusId(locusId)
.setContactUri(contactUri)
.setContactPhoneNumber(phoneNumber)
+ .setNotificationChannelId(notificationChannelId)
.setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED)
.setVip(true)
.setBubbled(true)
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index 62ea425..ad5c57d 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -16,15 +16,12 @@
package com.android.server.people.data;
-import static android.app.usage.UsageEvents.Event.SHORTCUT_INVOCATION;
-
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
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;
@@ -40,7 +37,6 @@
import android.app.prediction.AppTarget;
import android.app.prediction.AppTargetEvent;
import android.app.prediction.AppTargetId;
-import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ContentResolver;
import android.content.Context;
@@ -232,7 +228,7 @@
mDataManager.getShortcut(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID);
verify(mShortcutServiceInternal).getShortcuts(anyInt(), anyString(), anyLong(),
eq(TEST_PKG_NAME), eq(Collections.singletonList(TEST_SHORTCUT_ID)),
- eq(null), anyInt(), eq(USER_ID_PRIMARY), anyInt(), anyInt());
+ eq(null), eq(null), anyInt(), eq(USER_ID_PRIMARY), anyInt(), anyInt());
}
@Test
@@ -263,6 +259,7 @@
@Test
public void testContactsChanged() {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+ mDataManager.onUserUnlocked(USER_ID_SECONDARY);
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
buildPerson());
@@ -289,6 +286,7 @@
@Test
public void testNotificationListener() {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+ mDataManager.onUserUnlocked(USER_ID_SECONDARY);
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
buildPerson());
@@ -310,37 +308,9 @@
}
@Test
- public void testQueryUsageStatsService() {
- UsageEvents.Event e = new UsageEvents.Event(SHORTCUT_INVOCATION,
- System.currentTimeMillis());
- e.mPackage = TEST_PKG_NAME;
- e.mShortcutId = TEST_SHORTCUT_ID;
- List<UsageEvents.Event> events = new ArrayList<>();
- events.add(e);
- UsageEvents usageEvents = new UsageEvents(events, new String[]{});
- when(mUsageStatsManagerInternal.queryEventsForUser(anyInt(), anyLong(), anyLong(),
- anyBoolean(), anyBoolean())).thenReturn(usageEvents);
-
- mDataManager.onUserUnlocked(USER_ID_PRIMARY);
-
- ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
- buildPerson());
- mDataManager.onShortcutAddedOrUpdated(shortcut);
-
- mDataManager.queryUsageStatsService(USER_ID_PRIMARY, 0L, Long.MAX_VALUE);
-
- List<Range<Long>> activeShortcutInvocationTimeSlots = new ArrayList<>();
- mDataManager.forAllPackages(packageData ->
- activeShortcutInvocationTimeSlots.addAll(
- packageData.getEventHistory(TEST_SHORTCUT_ID)
- .getEventIndex(Event.TYPE_SHORTCUT_INVOCATION)
- .getActiveTimeSlots()));
- assertEquals(1, activeShortcutInvocationTimeSlots.size());
- }
-
- @Test
public void testCallLogContentObserver() {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+ mDataManager.onUserUnlocked(USER_ID_SECONDARY);
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
buildPerson());
@@ -368,6 +338,7 @@
@Test
public void testMmsSmsContentObserver() {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+ mDataManager.onUserUnlocked(USER_ID_SECONDARY);
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
buildPerson());
diff --git a/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java b/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
new file mode 100644
index 0000000..e4248a0
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
@@ -0,0 +1,295 @@
+/*
+ * 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.people.data;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.usage.UsageEvents;
+import android.app.usage.UsageStatsManagerInternal;
+import android.content.LocusId;
+
+import com.android.server.LocalServices;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Predicate;
+
+@RunWith(JUnit4.class)
+public final class UsageStatsQueryHelperTest {
+
+ private static final int USER_ID_PRIMARY = 0;
+ private static final String PKG_NAME = "pkg";
+ private static final String ACTIVITY_NAME = "TestActivity";
+ private static final String SHORTCUT_ID = "abc";
+ private static final String NOTIFICATION_CHANNEL_ID = "test : abc";
+ private static final LocusId LOCUS_ID_1 = new LocusId("locus_1");
+ private static final LocusId LOCUS_ID_2 = new LocusId("locus_2");
+
+ @Mock private UsageStatsManagerInternal mUsageStatsManagerInternal;
+
+ private TestPackageData mPackageData;
+ private UsageStatsQueryHelper mHelper;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ addLocalServiceMock(UsageStatsManagerInternal.class, mUsageStatsManagerInternal);
+
+ mPackageData = new TestPackageData(PKG_NAME, USER_ID_PRIMARY, pkg -> false, pkg -> false);
+ mPackageData.mConversationStore.mConversationInfo = new ConversationInfo.Builder()
+ .setShortcutId(SHORTCUT_ID)
+ .setNotificationChannelId(NOTIFICATION_CHANNEL_ID)
+ .setLocusId(LOCUS_ID_1)
+ .build();
+
+ mHelper = new UsageStatsQueryHelper(USER_ID_PRIMARY, pkg -> mPackageData);
+ }
+
+ @After
+ public void tearDown() {
+ LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
+ }
+
+ @Test
+ public void testQueryNoEvents() {
+ assertFalse(mHelper.querySince(50L));
+ }
+
+ @Test
+ public void testQueryShortcutInvocationEvent() {
+ addUsageEvents(createShortcutInvocationEvent(100L));
+
+ assertTrue(mHelper.querySince(50L));
+ assertEquals(100L, mHelper.getLastEventTimestamp());
+ Event expectedEvent = new Event(100L, Event.TYPE_SHORTCUT_INVOCATION);
+ List<Event> events = mPackageData.mEventStore.mShortcutEventHistory.queryEvents(
+ Event.ALL_EVENT_TYPES, 0L, Long.MAX_VALUE);
+ assertEquals(1, events.size());
+ assertEquals(expectedEvent, events.get(0));
+ }
+
+ @Test
+ public void testQueryNotificationInterruptionEvent() {
+ addUsageEvents(createNotificationInterruptionEvent(100L));
+
+ assertTrue(mHelper.querySince(50L));
+ assertEquals(100L, mHelper.getLastEventTimestamp());
+ Event expectedEvent = new Event(100L, Event.TYPE_NOTIFICATION_POSTED);
+ List<Event> events = mPackageData.mEventStore.mShortcutEventHistory.queryEvents(
+ Event.ALL_EVENT_TYPES, 0L, Long.MAX_VALUE);
+ assertEquals(1, events.size());
+ assertEquals(expectedEvent, events.get(0));
+ }
+
+ @Test
+ public void testInAppConversationSwitch() {
+ addUsageEvents(
+ createLocusIdSetEvent(100_000L, LOCUS_ID_1.getId()),
+ createLocusIdSetEvent(110_000L, LOCUS_ID_2.getId()));
+
+ assertTrue(mHelper.querySince(50_000L));
+ assertEquals(110_000L, mHelper.getLastEventTimestamp());
+ List<Event> events = mPackageData.mEventStore.mLocusEventHistory.queryEvents(
+ Event.ALL_EVENT_TYPES, 0L, Long.MAX_VALUE);
+ assertEquals(1, events.size());
+ assertEquals(createInAppConversationEvent(100_000L, 10), events.get(0));
+ }
+
+ @Test
+ public void testInAppConversationExplicitlyEnd() {
+ addUsageEvents(
+ createLocusIdSetEvent(100_000L, LOCUS_ID_1.getId()),
+ createLocusIdSetEvent(110_000L, null));
+
+ assertTrue(mHelper.querySince(50_000L));
+ assertEquals(110_000L, mHelper.getLastEventTimestamp());
+ List<Event> events = mPackageData.mEventStore.mLocusEventHistory.queryEvents(
+ Event.ALL_EVENT_TYPES, 0L, Long.MAX_VALUE);
+ assertEquals(1, events.size());
+ assertEquals(createInAppConversationEvent(100_000L, 10), events.get(0));
+ }
+
+ @Test
+ public void testInAppConversationImplicitlyEnd() {
+ addUsageEvents(
+ createLocusIdSetEvent(100_000L, LOCUS_ID_1.getId()),
+ createActivityStoppedEvent(110_000L));
+
+ assertTrue(mHelper.querySince(50_000L));
+ assertEquals(110_000L, mHelper.getLastEventTimestamp());
+ List<Event> events = mPackageData.mEventStore.mLocusEventHistory.queryEvents(
+ Event.ALL_EVENT_TYPES, 0L, Long.MAX_VALUE);
+ assertEquals(1, events.size());
+ assertEquals(createInAppConversationEvent(100_000L, 10), events.get(0));
+ }
+
+ @Test
+ public void testMultipleInAppConversations() {
+ addUsageEvents(
+ createLocusIdSetEvent(100_000L, LOCUS_ID_1.getId()),
+ createLocusIdSetEvent(110_000L, LOCUS_ID_2.getId()),
+ createLocusIdSetEvent(130_000L, LOCUS_ID_1.getId()),
+ createActivityStoppedEvent(160_000L));
+
+ assertTrue(mHelper.querySince(50_000L));
+ assertEquals(160_000L, mHelper.getLastEventTimestamp());
+ List<Event> events = mPackageData.mEventStore.mLocusEventHistory.queryEvents(
+ Event.ALL_EVENT_TYPES, 0L, Long.MAX_VALUE);
+ assertEquals(3, events.size());
+ assertEquals(createInAppConversationEvent(100_000L, 10), events.get(0));
+ assertEquals(createInAppConversationEvent(110_000L, 20), events.get(1));
+ assertEquals(createInAppConversationEvent(130_000L, 30), events.get(2));
+ }
+
+ private void addUsageEvents(UsageEvents.Event ... events) {
+ UsageEvents usageEvents = new UsageEvents(Arrays.asList(events), new String[]{});
+ when(mUsageStatsManagerInternal.queryEventsForUser(anyInt(), anyLong(), anyLong(),
+ anyBoolean(), anyBoolean())).thenReturn(usageEvents);
+ }
+
+ private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
+ LocalServices.removeServiceForTest(clazz);
+ LocalServices.addService(clazz, mock);
+ }
+
+ private static UsageEvents.Event createShortcutInvocationEvent(long timestamp) {
+ UsageEvents.Event e = createUsageEvent(UsageEvents.Event.SHORTCUT_INVOCATION, timestamp);
+ e.mShortcutId = SHORTCUT_ID;
+ return e;
+ }
+
+ private static UsageEvents.Event createNotificationInterruptionEvent(long timestamp) {
+ UsageEvents.Event e = createUsageEvent(UsageEvents.Event.NOTIFICATION_INTERRUPTION,
+ timestamp);
+ e.mNotificationChannelId = NOTIFICATION_CHANNEL_ID;
+ return e;
+ }
+
+ private static UsageEvents.Event createLocusIdSetEvent(long timestamp, String locusId) {
+ UsageEvents.Event e = createUsageEvent(UsageEvents.Event.LOCUS_ID_SET, timestamp);
+ e.mClass = ACTIVITY_NAME;
+ e.mLocusId = locusId;
+ return e;
+ }
+
+ private static UsageEvents.Event createActivityStoppedEvent(long timestamp) {
+ UsageEvents.Event e = createUsageEvent(UsageEvents.Event.ACTIVITY_STOPPED, timestamp);
+ e.mClass = ACTIVITY_NAME;
+ return e;
+ }
+
+ private static UsageEvents.Event createUsageEvent(int eventType, long timestamp) {
+ UsageEvents.Event e = new UsageEvents.Event(eventType, timestamp);
+ e.mPackage = PKG_NAME;
+ return e;
+ }
+
+ private static Event createInAppConversationEvent(long timestamp, int durationSeconds) {
+ return new Event.Builder(timestamp, Event.TYPE_IN_APP_CONVERSATION)
+ .setDurationSeconds(durationSeconds)
+ .build();
+ }
+
+ private static class TestConversationStore extends ConversationStore {
+
+ private ConversationInfo mConversationInfo;
+
+ @Override
+ @Nullable
+ ConversationInfo getConversation(@Nullable String shortcutId) {
+ return mConversationInfo;
+ }
+ }
+
+ private static class TestPackageData extends PackageData {
+
+ private final TestConversationStore mConversationStore = new TestConversationStore();
+ private final TestEventStore mEventStore = new TestEventStore();
+
+ TestPackageData(@NonNull String packageName, @UserIdInt int userId,
+ @NonNull Predicate<String> isDefaultDialerPredicate,
+ @NonNull Predicate<String> isDefaultSmsAppPredicate) {
+ super(packageName, userId, isDefaultDialerPredicate, isDefaultSmsAppPredicate);
+ }
+
+ @Override
+ @NonNull
+ ConversationStore getConversationStore() {
+ return mConversationStore;
+ }
+
+ @Override
+ @NonNull
+ EventStore getEventStore() {
+ return mEventStore;
+ }
+ }
+
+ private static class TestEventStore extends EventStore {
+
+ private final EventHistoryImpl mShortcutEventHistory = new TestEventHistoryImpl();
+ private final EventHistoryImpl mLocusEventHistory = new TestEventHistoryImpl();
+
+ @Override
+ @NonNull
+ EventHistoryImpl getOrCreateShortcutEventHistory(String shortcutId) {
+ return mShortcutEventHistory;
+ }
+
+ @Override
+ @NonNull
+ EventHistoryImpl getOrCreateLocusEventHistory(LocusId locusId) {
+ return mLocusEventHistory;
+ }
+ }
+
+ private static class TestEventHistoryImpl extends EventHistoryImpl {
+
+ private final List<Event> mEvents = new ArrayList<>();
+
+ @Override
+ @NonNull
+ public List<Event> queryEvents(Set<Integer> eventTypes, long startTime, long endTime) {
+ return mEvents;
+ }
+
+ @Override
+ void addEvent(Event event) {
+ mEvents.add(event);
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 41416f1..3d190be 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -52,6 +52,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
+import android.content.LocusId;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ILauncherApps;
@@ -1600,6 +1601,22 @@
}
/**
+ * Make a shortcut with an ID and a locus ID.
+ */
+ protected ShortcutInfo makeShortcutWithLocusId(String id, LocusId locusId) {
+ final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mClientContext, id)
+ .setActivity(new ComponentName(mClientContext.getPackageName(), "main"))
+ .setShortLabel("title-" + id)
+ .setIntent(makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class))
+ .setLocusId(locusId);
+ final ShortcutInfo s = b.build();
+
+ s.setTimestamp(mInjectedCurrentTimeMillis); // HACK
+
+ return s;
+ }
+
+ /**
* Make an intent.
*/
protected Intent makeIntent(String action, Class<?> clazz, Object... bundleKeysAndValues) {
@@ -1618,6 +1635,13 @@
}
/**
+ * Make a LocusId.
+ */
+ protected LocusId makeLocusId(String id) {
+ return new LocusId(id);
+ }
+
+ /**
* Make an component name, with the client context.
*/
@NonNull
@@ -1955,16 +1979,17 @@
protected static ShortcutQuery buildQuery(long changedSince,
String packageName, ComponentName componentName,
/* @ShortcutQuery.QueryFlags */ int flags) {
- return buildQuery(changedSince, packageName, null, componentName, flags);
+ return buildQuery(changedSince, packageName, null, null, componentName, flags);
}
protected static ShortcutQuery buildQuery(long changedSince,
- String packageName, List<String> shortcutIds, ComponentName componentName,
- /* @ShortcutQuery.QueryFlags */ int flags) {
+ String packageName, List<String> shortcutIds, List<LocusId> locusIds,
+ ComponentName componentName, /* @ShortcutQuery.QueryFlags */ int flags) {
final ShortcutQuery q = new ShortcutQuery();
q.setChangedSince(changedSince);
q.setPackage(packageName);
q.setShortcutIds(shortcutIds);
+ q.setLocusIds(locusIds);
q.setActivity(componentName);
q.setQueryFlags(flags);
return q;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
index bfe0c15..d4edab4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
@@ -24,6 +24,7 @@
import static org.xmlpull.v1.XmlPullParser.START_TAG;
import android.content.pm.PackageInstaller;
+import android.platform.test.annotations.Presubmit;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.Xml;
@@ -57,6 +58,7 @@
import java.util.List;
@RunWith(AndroidJUnit4.class)
+@Presubmit
public class PackageInstallerSessionTest {
@Rule
public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 798420e..63da5fb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -1372,7 +1372,7 @@
setCaller(CALLING_PACKAGE_1);
final ShortcutInfo s1_1 = makeShortcut("s1");
- final ShortcutInfo s1_2 = makeShortcut("s2");
+ final ShortcutInfo s1_2 = makeShortcutWithLocusId("s2", makeLocusId("l1"));
assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
@@ -1394,7 +1394,7 @@
getCallerShortcut("s4").setTimestamp(500);
setCaller(CALLING_PACKAGE_3);
- final ShortcutInfo s3_2 = makeShortcut("s3");
+ final ShortcutInfo s3_2 = makeShortcutWithLocusId("s3", makeLocusId("l2"));
assertTrue(mManager.setDynamicShortcuts(list(s3_2)));
getCallerShortcut("s3").setTimestamp(START_TIME + 5000);
@@ -1446,7 +1446,7 @@
// With ID.
assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
- /* time =*/ 1000, CALLING_PACKAGE_2, list("s3"),
+ /* time =*/ 1000, CALLING_PACKAGE_2, list("s3"), /* locusIds =*/ null,
/* activity =*/ null,
ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
getCallingUser())),
@@ -1454,20 +1454,51 @@
assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
/* time =*/ 1000, CALLING_PACKAGE_2, list("s3", "s2", "ss"),
- /* activity =*/ null,
+ /* locusIds =*/ null, /* activity =*/ null,
ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
getCallingUser())),
"s2", "s3"))));
assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
/* time =*/ 1000, CALLING_PACKAGE_2, list("s3x", "s2x"),
- /* activity =*/ null,
+ /* locusIds =*/ null, /* activity =*/ null,
ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
getCallingUser()))
/* empty */))));
assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
- /* time =*/ 1000, CALLING_PACKAGE_2, list(),
+ /* time =*/ 1000, CALLING_PACKAGE_2, list(), /* locusIds =*/ null,
+ /* activity =*/ null,
+ ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
+ getCallingUser()))
+ /* empty */))));
+
+ // With locus ID.
+ assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
+ assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
+ /* time =*/ 1000, CALLING_PACKAGE_3, /* shortcutIds =*/ null,
+ list(makeLocusId("l2")), /* activity =*/ null,
+ ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
+ getCallingUser())),
+ "s3"))));
+ assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
+ assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
+ /* time =*/ 1000, CALLING_PACKAGE_1, /* shortcutIds =*/ null,
+ list(makeLocusId("l1"), makeLocusId("l2"), makeLocusId("l3")),
+ /* activity =*/ null,
+ ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
+ getCallingUser())),
+ "s2"))));
+ assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
+ assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
+ /* time =*/ 1000, CALLING_PACKAGE_1, /* shortcutIds =*/ null,
+ list(makeLocusId("lx1"), makeLocusId("lx2")), /* activity =*/ null,
+ ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
+ getCallingUser()))
+ /* empty */))));
+ assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
+ assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
+ /* time =*/ 1000, CALLING_PACKAGE_3, /* shortcutIds =*/ null, list(),
/* activity =*/ null,
ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
getCallingUser()))
@@ -1498,7 +1529,7 @@
assertExpectException(
IllegalArgumentException.class, "package name must also be set", () -> {
mLauncherApps.getShortcuts(buildQuery(
- /* time =*/ 0, /* package= */ null, list("id"),
+ /* time =*/ 0, /* package= */ null, list("id"), /* locusIds =*/ null,
/* activity =*/ null, /* flags */ 0), getCallingUser());
});
@@ -1537,7 +1568,7 @@
assertExpectException(
IllegalArgumentException.class, "package name must also be set", () -> {
mLauncherApps.getShortcuts(buildQuery(
- /* time =*/ 0, /* package= */ null, list("id"),
+ /* time =*/ 0, /* package= */ null, list("id"), /* locusIds= */ null,
/* activity =*/ null, /* flags */ 0), getCallingUser());
});
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index 218f43c..2eeeb3e 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -30,7 +30,7 @@
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
-import android.app.timedetector.PhoneTimeSuggestion;
+import android.app.timedetector.TelephonyTimeSuggestion;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.HandlerThread;
@@ -80,35 +80,35 @@
}
@Test(expected = SecurityException.class)
- public void testSuggestPhoneTime_withoutPermission() {
+ public void testSuggestTelephonyTime_withoutPermission() {
doThrow(new SecurityException("Mock"))
.when(mMockContext).enforceCallingPermission(anyString(), any());
- PhoneTimeSuggestion phoneTimeSuggestion = createPhoneTimeSuggestion();
+ TelephonyTimeSuggestion timeSuggestion = createTelephonyTimeSuggestion();
try {
- mTimeDetectorService.suggestPhoneTime(phoneTimeSuggestion);
+ mTimeDetectorService.suggestTelephonyTime(timeSuggestion);
fail();
} finally {
verify(mMockContext).enforceCallingPermission(
- eq(android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE),
+ eq(android.Manifest.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE),
anyString());
}
}
@Test
- public void testSuggestPhoneTime() throws Exception {
+ public void testSuggestTelephonyTime() throws Exception {
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
- PhoneTimeSuggestion phoneTimeSuggestion = createPhoneTimeSuggestion();
- mTimeDetectorService.suggestPhoneTime(phoneTimeSuggestion);
+ TelephonyTimeSuggestion timeSuggestion = createTelephonyTimeSuggestion();
+ mTimeDetectorService.suggestTelephonyTime(timeSuggestion);
mTestHandler.assertTotalMessagesEnqueued(1);
verify(mMockContext).enforceCallingPermission(
- eq(android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE),
+ eq(android.Manifest.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE),
anyString());
mTestHandler.waitForMessagesToBeProcessed();
- mStubbedTimeDetectorStrategy.verifySuggestPhoneTimeCalled(phoneTimeSuggestion);
+ mStubbedTimeDetectorStrategy.verifySuggestTelephonyTimeCalled(timeSuggestion);
}
@Test(expected = SecurityException.class)
@@ -199,10 +199,10 @@
mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionChangedCalled();
}
- private static PhoneTimeSuggestion createPhoneTimeSuggestion() {
+ private static TelephonyTimeSuggestion createTelephonyTimeSuggestion() {
int slotIndex = 1234;
TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
- return new PhoneTimeSuggestion.Builder(slotIndex)
+ return new TelephonyTimeSuggestion.Builder(slotIndex)
.setUtcTime(timeValue)
.build();
}
@@ -220,7 +220,7 @@
private static class StubbedTimeDetectorStrategy implements TimeDetectorStrategy {
// Call tracking.
- private PhoneTimeSuggestion mLastPhoneSuggestion;
+ private TelephonyTimeSuggestion mLastTelephonySuggestion;
private ManualTimeSuggestion mLastManualSuggestion;
private NetworkTimeSuggestion mLastNetworkSuggestion;
private boolean mHandleAutoTimeDetectionChangedCalled;
@@ -231,8 +231,8 @@
}
@Override
- public void suggestPhoneTime(PhoneTimeSuggestion timeSuggestion) {
- mLastPhoneSuggestion = timeSuggestion;
+ public void suggestTelephonyTime(TelephonyTimeSuggestion timeSuggestion) {
+ mLastTelephonySuggestion = timeSuggestion;
}
@Override
@@ -256,15 +256,15 @@
}
void resetCallTracking() {
- mLastPhoneSuggestion = null;
+ mLastTelephonySuggestion = null;
mLastManualSuggestion = null;
mLastNetworkSuggestion = null;
mHandleAutoTimeDetectionChangedCalled = false;
mDumpCalled = false;
}
- void verifySuggestPhoneTimeCalled(PhoneTimeSuggestion expectedSuggestion) {
- assertEquals(expectedSuggestion, mLastPhoneSuggestion);
+ void verifySuggestTelephonyTimeCalled(TelephonyTimeSuggestion expectedSuggestion) {
+ assertEquals(expectedSuggestion, mLastTelephonySuggestion);
}
public void verifySuggestManualTimeCalled(ManualTimeSuggestion expectedSuggestion) {
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index d940a6a..803b245 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -24,7 +24,7 @@
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
-import android.app.timedetector.PhoneTimeSuggestion;
+import android.app.timedetector.TelephonyTimeSuggestion;
import android.icu.util.Calendar;
import android.icu.util.GregorianCalendar;
import android.icu.util.TimeZone;
@@ -52,7 +52,7 @@
*/
private static final long ARBITRARY_TEST_TIME_MILLIS = createUtcTime(2018, 1, 1, 12, 0, 0);
- private static final int ARBITRARY_PHONE_ID = 123456;
+ private static final int ARBITRARY_SLOT_INDEX = 123456;
private Script mScript;
@@ -62,51 +62,51 @@
}
@Test
- public void testSuggestPhoneTime_autoTimeEnabled() {
+ public void testSuggestTelephonyTime_autoTimeEnabled() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeAutoTimeDetectionEnabled(true);
- int phoneId = ARBITRARY_PHONE_ID;
+ int slotIndex = ARBITRARY_SLOT_INDEX;
long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
- PhoneTimeSuggestion timeSuggestion =
- mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis);
+ TelephonyTimeSuggestion timeSuggestion =
+ mScript.generateTelephonyTimeSuggestion(slotIndex, testTimeMillis);
mScript.simulateTimePassing()
- .simulatePhoneTimeSuggestion(timeSuggestion);
+ .simulateTelephonyTimeSuggestion(timeSuggestion);
long expectedSystemClockMillis =
mScript.calculateTimeInMillisForNow(timeSuggestion.getUtcTime());
mScript.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis)
- .assertLatestPhoneSuggestion(phoneId, timeSuggestion);
+ .assertLatestTelephonySuggestion(slotIndex, timeSuggestion);
}
@Test
- public void testSuggestPhoneTime_emptySuggestionIgnored() {
+ public void testSuggestTelephonyTime_emptySuggestionIgnored() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeAutoTimeDetectionEnabled(true);
- int phoneId = ARBITRARY_PHONE_ID;
- PhoneTimeSuggestion timeSuggestion =
- mScript.generatePhoneTimeSuggestion(phoneId, null);
- mScript.simulatePhoneTimeSuggestion(timeSuggestion)
+ int slotIndex = ARBITRARY_SLOT_INDEX;
+ TelephonyTimeSuggestion timeSuggestion =
+ mScript.generateTelephonyTimeSuggestion(slotIndex, null);
+ mScript.simulateTelephonyTimeSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking()
- .assertLatestPhoneSuggestion(phoneId, null);
+ .assertLatestTelephonySuggestion(slotIndex, null);
}
@Test
- public void testSuggestPhoneTime_systemClockThreshold() {
+ public void testSuggestTelephonyTime_systemClockThreshold() {
final int systemClockUpdateThresholdMillis = 1000;
final int clockIncrementMillis = 100;
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeThresholds(systemClockUpdateThresholdMillis)
.pokeAutoTimeDetectionEnabled(true);
- int phoneId = ARBITRARY_PHONE_ID;
+ int slotIndex = ARBITRARY_SLOT_INDEX;
// Send the first time signal. It should be used.
{
- PhoneTimeSuggestion timeSuggestion1 =
- mScript.generatePhoneTimeSuggestion(phoneId, ARBITRARY_TEST_TIME_MILLIS);
+ TelephonyTimeSuggestion timeSuggestion1 =
+ mScript.generateTelephonyTimeSuggestion(slotIndex, ARBITRARY_TEST_TIME_MILLIS);
// Increment the the device clocks to simulate the passage of time.
mScript.simulateTimePassing(clockIncrementMillis);
@@ -114,151 +114,151 @@
long expectedSystemClockMillis1 =
mScript.calculateTimeInMillisForNow(timeSuggestion1.getUtcTime());
- mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
+ mScript.simulateTelephonyTimeSuggestion(timeSuggestion1)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1)
- .assertLatestPhoneSuggestion(phoneId, timeSuggestion1);
+ .assertLatestTelephonySuggestion(slotIndex, timeSuggestion1);
}
// Now send another time signal, but one that is too similar to the last one and should be
// stored, but not used to set the system clock.
{
int underThresholdMillis = systemClockUpdateThresholdMillis - 1;
- PhoneTimeSuggestion timeSuggestion2 = mScript.generatePhoneTimeSuggestion(
- phoneId, mScript.peekSystemClockMillis() + underThresholdMillis);
+ TelephonyTimeSuggestion timeSuggestion2 = mScript.generateTelephonyTimeSuggestion(
+ slotIndex, mScript.peekSystemClockMillis() + underThresholdMillis);
mScript.simulateTimePassing(clockIncrementMillis)
- .simulatePhoneTimeSuggestion(timeSuggestion2)
+ .simulateTelephonyTimeSuggestion(timeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking()
- .assertLatestPhoneSuggestion(phoneId, timeSuggestion2);
+ .assertLatestTelephonySuggestion(slotIndex, timeSuggestion2);
}
// Now send another time signal, but one that is on the threshold and so should be used.
{
- PhoneTimeSuggestion timeSuggestion3 = mScript.generatePhoneTimeSuggestion(
- phoneId,
+ TelephonyTimeSuggestion timeSuggestion3 = mScript.generateTelephonyTimeSuggestion(
+ slotIndex,
mScript.peekSystemClockMillis() + systemClockUpdateThresholdMillis);
mScript.simulateTimePassing(clockIncrementMillis);
long expectedSystemClockMillis3 =
mScript.calculateTimeInMillisForNow(timeSuggestion3.getUtcTime());
- mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
+ mScript.simulateTelephonyTimeSuggestion(timeSuggestion3)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis3)
- .assertLatestPhoneSuggestion(phoneId, timeSuggestion3);
+ .assertLatestTelephonySuggestion(slotIndex, timeSuggestion3);
}
}
@Test
- public void testSuggestPhoneTime_multiplePhoneIdsAndBucketing() {
+ public void testSuggestTelephonyTime_multipleSlotIndexsAndBucketing() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeAutoTimeDetectionEnabled(true);
- // There are 2 phones in this test. Phone 2 has a different idea of the current time.
- // phone1Id < phone2Id (which is important because the strategy uses the lowest ID when
- // multiple phone suggestions are available.
- int phone1Id = ARBITRARY_PHONE_ID;
- int phone2Id = ARBITRARY_PHONE_ID + 1;
- long phone1TimeMillis = ARBITRARY_TEST_TIME_MILLIS;
- long phone2TimeMillis = ARBITRARY_TEST_TIME_MILLIS + Duration.ofDays(1).toMillis();
+ // There are 2 slotIndexes in this test. slotIndex1 and slotIndex2 have different opinions
+ // about the current time. slotIndex1 < slotIndex2 (which is important because the strategy
+ // uses the lowest slotIndex when multiple telephony suggestions are available.
+ int slotIndex1 = ARBITRARY_SLOT_INDEX;
+ int slotIndex2 = ARBITRARY_SLOT_INDEX + 1;
+ long slotIndex1TimeMillis = ARBITRARY_TEST_TIME_MILLIS;
+ long slotIndex2TimeMillis = ARBITRARY_TEST_TIME_MILLIS + Duration.ofDays(1).toMillis();
- // Make a suggestion with phone2Id.
+ // Make a suggestion with slotIndex2.
{
- PhoneTimeSuggestion phone2TimeSuggestion =
- mScript.generatePhoneTimeSuggestion(phone2Id, phone2TimeMillis);
+ TelephonyTimeSuggestion slotIndex2TimeSuggestion =
+ mScript.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2TimeMillis);
mScript.simulateTimePassing();
long expectedSystemClockMillis =
- mScript.calculateTimeInMillisForNow(phone2TimeSuggestion.getUtcTime());
+ mScript.calculateTimeInMillisForNow(slotIndex2TimeSuggestion.getUtcTime());
- mScript.simulatePhoneTimeSuggestion(phone2TimeSuggestion)
+ mScript.simulateTelephonyTimeSuggestion(slotIndex2TimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis)
- .assertLatestPhoneSuggestion(phone1Id, null)
- .assertLatestPhoneSuggestion(phone2Id, phone2TimeSuggestion);
+ .assertLatestTelephonySuggestion(slotIndex1, null)
+ .assertLatestTelephonySuggestion(slotIndex2, slotIndex2TimeSuggestion);
}
mScript.simulateTimePassing();
- // Now make a different suggestion with phone1Id.
+ // Now make a different suggestion with slotIndex1.
{
- PhoneTimeSuggestion phone1TimeSuggestion =
- mScript.generatePhoneTimeSuggestion(phone1Id, phone1TimeMillis);
+ TelephonyTimeSuggestion slotIndex1TimeSuggestion =
+ mScript.generateTelephonyTimeSuggestion(slotIndex1, slotIndex1TimeMillis);
mScript.simulateTimePassing();
long expectedSystemClockMillis =
- mScript.calculateTimeInMillisForNow(phone1TimeSuggestion.getUtcTime());
+ mScript.calculateTimeInMillisForNow(slotIndex1TimeSuggestion.getUtcTime());
- mScript.simulatePhoneTimeSuggestion(phone1TimeSuggestion)
+ mScript.simulateTelephonyTimeSuggestion(slotIndex1TimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis)
- .assertLatestPhoneSuggestion(phone1Id, phone1TimeSuggestion);
+ .assertLatestTelephonySuggestion(slotIndex1, slotIndex1TimeSuggestion);
}
mScript.simulateTimePassing();
- // Make another suggestion with phone2Id. It should be stored but not used because the
- // phone1Id suggestion will still "win".
+ // Make another suggestion with slotIndex2. It should be stored but not used because the
+ // slotIndex1 suggestion will still "win".
{
- PhoneTimeSuggestion phone2TimeSuggestion =
- mScript.generatePhoneTimeSuggestion(phone2Id, phone2TimeMillis);
+ TelephonyTimeSuggestion slotIndex2TimeSuggestion =
+ mScript.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2TimeMillis);
mScript.simulateTimePassing();
- mScript.simulatePhoneTimeSuggestion(phone2TimeSuggestion)
+ mScript.simulateTelephonyTimeSuggestion(slotIndex2TimeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking()
- .assertLatestPhoneSuggestion(phone2Id, phone2TimeSuggestion);
+ .assertLatestTelephonySuggestion(slotIndex2, slotIndex2TimeSuggestion);
}
- // Let enough time pass that phone1Id's suggestion should now be too old.
- mScript.simulateTimePassing(TimeDetectorStrategyImpl.PHONE_BUCKET_SIZE_MILLIS);
+ // Let enough time pass that slotIndex1's suggestion should now be too old.
+ mScript.simulateTimePassing(TimeDetectorStrategyImpl.TELEPHONY_BUCKET_SIZE_MILLIS);
- // Make another suggestion with phone2Id. It should be used because the phoneId1
+ // Make another suggestion with slotIndex2. It should be used because the slotIndex1
// is in an older "bucket".
{
- PhoneTimeSuggestion phone2TimeSuggestion =
- mScript.generatePhoneTimeSuggestion(phone2Id, phone2TimeMillis);
+ TelephonyTimeSuggestion slotIndex2TimeSuggestion =
+ mScript.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2TimeMillis);
mScript.simulateTimePassing();
long expectedSystemClockMillis =
- mScript.calculateTimeInMillisForNow(phone2TimeSuggestion.getUtcTime());
+ mScript.calculateTimeInMillisForNow(slotIndex2TimeSuggestion.getUtcTime());
- mScript.simulatePhoneTimeSuggestion(phone2TimeSuggestion)
+ mScript.simulateTelephonyTimeSuggestion(slotIndex2TimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis)
- .assertLatestPhoneSuggestion(phone2Id, phone2TimeSuggestion);
+ .assertLatestTelephonySuggestion(slotIndex2, slotIndex2TimeSuggestion);
}
}
@Test
- public void testSuggestPhoneTime_autoTimeDisabled() {
+ public void testSuggestTelephonyTime_autoTimeDisabled() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeAutoTimeDetectionEnabled(false);
- int phoneId = ARBITRARY_PHONE_ID;
- PhoneTimeSuggestion timeSuggestion =
- mScript.generatePhoneTimeSuggestion(phoneId, ARBITRARY_TEST_TIME_MILLIS);
+ int slotIndex = ARBITRARY_SLOT_INDEX;
+ TelephonyTimeSuggestion timeSuggestion =
+ mScript.generateTelephonyTimeSuggestion(slotIndex, ARBITRARY_TEST_TIME_MILLIS);
mScript.simulateTimePassing()
- .simulatePhoneTimeSuggestion(timeSuggestion)
+ .simulateTelephonyTimeSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking()
- .assertLatestPhoneSuggestion(phoneId, timeSuggestion);
+ .assertLatestTelephonySuggestion(slotIndex, timeSuggestion);
}
@Test
- public void testSuggestPhoneTime_invalidNitzReferenceTimesIgnored() {
+ public void testSuggestTelephonyTime_invalidNitzReferenceTimesIgnored() {
final int systemClockUpdateThreshold = 2000;
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeThresholds(systemClockUpdateThreshold)
.pokeAutoTimeDetectionEnabled(true);
long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
- int phoneId = ARBITRARY_PHONE_ID;
+ int slotIndex = ARBITRARY_SLOT_INDEX;
- PhoneTimeSuggestion timeSuggestion1 =
- mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis);
+ TelephonyTimeSuggestion timeSuggestion1 =
+ mScript.generateTelephonyTimeSuggestion(slotIndex, testTimeMillis);
TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
- // Initialize the strategy / device with a time set from a phone suggestion.
+ // Initialize the strategy / device with a time set from a telephony suggestion.
mScript.simulateTimePassing();
long expectedSystemClockMillis1 = mScript.calculateTimeInMillisForNow(utcTime1);
- mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
+ mScript.simulateTelephonyTimeSuggestion(timeSuggestion1)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1)
- .assertLatestPhoneSuggestion(phoneId, timeSuggestion1);
+ .assertLatestTelephonySuggestion(slotIndex, timeSuggestion1);
// The UTC time increment should be larger than the system clock update threshold so we
// know it shouldn't be ignored for other reasons.
@@ -269,11 +269,11 @@
long referenceTimeBeforeLastSignalMillis = utcTime1.getReferenceTimeMillis() - 1;
TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
referenceTimeBeforeLastSignalMillis, validUtcTimeMillis);
- PhoneTimeSuggestion timeSuggestion2 =
- createPhoneTimeSuggestion(phoneId, utcTime2);
- mScript.simulatePhoneTimeSuggestion(timeSuggestion2)
+ TelephonyTimeSuggestion timeSuggestion2 =
+ createTelephonyTimeSuggestion(slotIndex, utcTime2);
+ mScript.simulateTelephonyTimeSuggestion(timeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking()
- .assertLatestPhoneSuggestion(phoneId, timeSuggestion1);
+ .assertLatestTelephonySuggestion(slotIndex, timeSuggestion1);
// Now supply a new signal that has an obviously bogus reference time : substantially in the
// future.
@@ -281,36 +281,36 @@
utcTime1.getReferenceTimeMillis() + Integer.MAX_VALUE + 1;
TimestampedValue<Long> utcTime3 = new TimestampedValue<>(
referenceTimeInFutureMillis, validUtcTimeMillis);
- PhoneTimeSuggestion timeSuggestion3 =
- createPhoneTimeSuggestion(phoneId, utcTime3);
- mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
+ TelephonyTimeSuggestion timeSuggestion3 =
+ createTelephonyTimeSuggestion(slotIndex, utcTime3);
+ mScript.simulateTelephonyTimeSuggestion(timeSuggestion3)
.verifySystemClockWasNotSetAndResetCallTracking()
- .assertLatestPhoneSuggestion(phoneId, timeSuggestion1);
+ .assertLatestTelephonySuggestion(slotIndex, timeSuggestion1);
// Just to prove validUtcTimeMillis is valid.
long validReferenceTimeMillis = utcTime1.getReferenceTimeMillis() + 100;
TimestampedValue<Long> utcTime4 = new TimestampedValue<>(
validReferenceTimeMillis, validUtcTimeMillis);
long expectedSystemClockMillis4 = mScript.calculateTimeInMillisForNow(utcTime4);
- PhoneTimeSuggestion timeSuggestion4 =
- createPhoneTimeSuggestion(phoneId, utcTime4);
- mScript.simulatePhoneTimeSuggestion(timeSuggestion4)
+ TelephonyTimeSuggestion timeSuggestion4 =
+ createTelephonyTimeSuggestion(slotIndex, utcTime4);
+ mScript.simulateTelephonyTimeSuggestion(timeSuggestion4)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis4)
- .assertLatestPhoneSuggestion(phoneId, timeSuggestion4);
+ .assertLatestTelephonySuggestion(slotIndex, timeSuggestion4);
}
@Test
- public void testSuggestPhoneTime_timeDetectionToggled() {
+ public void testSuggestTelephonyTime_timeDetectionToggled() {
final int clockIncrementMillis = 100;
final int systemClockUpdateThreshold = 2000;
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeThresholds(systemClockUpdateThreshold)
.pokeAutoTimeDetectionEnabled(false);
- int phoneId = ARBITRARY_PHONE_ID;
+ int slotIndex = ARBITRARY_SLOT_INDEX;
long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
- PhoneTimeSuggestion timeSuggestion1 =
- mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis);
+ TelephonyTimeSuggestion timeSuggestion1 =
+ mScript.generateTelephonyTimeSuggestion(slotIndex, testTimeMillis);
TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
// Simulate time passing.
@@ -318,9 +318,9 @@
// Simulate the time signal being received. It should not be used because auto time
// detection is off but it should be recorded.
- mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
+ mScript.simulateTelephonyTimeSuggestion(timeSuggestion1)
.verifySystemClockWasNotSetAndResetCallTracking()
- .assertLatestPhoneSuggestion(phoneId, timeSuggestion1);
+ .assertLatestTelephonySuggestion(slotIndex, timeSuggestion1);
// Simulate more time passing.
mScript.simulateTimePassing(clockIncrementMillis);
@@ -330,17 +330,17 @@
// Turn on auto time detection.
mScript.simulateAutoTimeDetectionToggle()
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1)
- .assertLatestPhoneSuggestion(phoneId, timeSuggestion1);
+ .assertLatestTelephonySuggestion(slotIndex, timeSuggestion1);
// Turn off auto time detection.
mScript.simulateAutoTimeDetectionToggle()
.verifySystemClockWasNotSetAndResetCallTracking()
- .assertLatestPhoneSuggestion(phoneId, timeSuggestion1);
+ .assertLatestTelephonySuggestion(slotIndex, timeSuggestion1);
// Receive another valid time signal.
// It should be on the threshold and accounting for the clock increments.
- PhoneTimeSuggestion timeSuggestion2 = mScript.generatePhoneTimeSuggestion(
- phoneId, mScript.peekSystemClockMillis() + systemClockUpdateThreshold);
+ TelephonyTimeSuggestion timeSuggestion2 = mScript.generateTelephonyTimeSuggestion(
+ slotIndex, mScript.peekSystemClockMillis() + systemClockUpdateThreshold);
// Simulate more time passing.
mScript.simulateTimePassing(clockIncrementMillis);
@@ -350,45 +350,45 @@
// The new time, though valid, should not be set in the system clock because auto time is
// disabled.
- mScript.simulatePhoneTimeSuggestion(timeSuggestion2)
+ mScript.simulateTelephonyTimeSuggestion(timeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking()
- .assertLatestPhoneSuggestion(phoneId, timeSuggestion2);
+ .assertLatestTelephonySuggestion(slotIndex, timeSuggestion2);
// Turn on auto time detection.
mScript.simulateAutoTimeDetectionToggle()
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis2)
- .assertLatestPhoneSuggestion(phoneId, timeSuggestion2);
+ .assertLatestTelephonySuggestion(slotIndex, timeSuggestion2);
}
@Test
- public void testSuggestPhoneTime_maxSuggestionAge() {
+ public void testSuggestTelephonyTime_maxSuggestionAge() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeAutoTimeDetectionEnabled(true);
- int phoneId = ARBITRARY_PHONE_ID;
+ int slotIndex = ARBITRARY_SLOT_INDEX;
long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
- PhoneTimeSuggestion phoneSuggestion =
- mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis);
+ TelephonyTimeSuggestion telephonySuggestion =
+ mScript.generateTelephonyTimeSuggestion(slotIndex, testTimeMillis);
mScript.simulateTimePassing();
long expectedSystemClockMillis =
- mScript.calculateTimeInMillisForNow(phoneSuggestion.getUtcTime());
- mScript.simulatePhoneTimeSuggestion(phoneSuggestion)
+ mScript.calculateTimeInMillisForNow(telephonySuggestion.getUtcTime());
+ mScript.simulateTelephonyTimeSuggestion(telephonySuggestion)
.verifySystemClockWasSetAndResetCallTracking(
expectedSystemClockMillis /* expectedNetworkBroadcast */)
- .assertLatestPhoneSuggestion(phoneId, phoneSuggestion);
+ .assertLatestTelephonySuggestion(slotIndex, telephonySuggestion);
- // Look inside and check what the strategy considers the current best phone suggestion.
- assertEquals(phoneSuggestion, mScript.peekBestPhoneSuggestion());
+ // Look inside and check what the strategy considers the current best telephony suggestion.
+ assertEquals(telephonySuggestion, mScript.peekBestTelephonySuggestion());
- // Simulate time passing, long enough that phoneSuggestion is now too old.
+ // Simulate time passing, long enough that telephonySuggestion is now too old.
mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_UTC_TIME_AGE_MILLIS);
- // Look inside and check what the strategy considers the current best phone suggestion. It
- // should still be the, it's just no longer used.
- assertNull(mScript.peekBestPhoneSuggestion());
- mScript.assertLatestPhoneSuggestion(phoneId, phoneSuggestion);
+ // Look inside and check what the strategy considers the current best telephony suggestion.
+ // It should still be the, it's just no longer used.
+ assertNull(mScript.peekBestTelephonySuggestion());
+ mScript.assertLatestTelephonySuggestion(slotIndex, telephonySuggestion);
}
@Test
@@ -413,21 +413,21 @@
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeAutoTimeDetectionEnabled(true);
- int phoneId = ARBITRARY_PHONE_ID;
+ int slotIndex = ARBITRARY_SLOT_INDEX;
- // Simulate a phone suggestion.
+ // Simulate a telephony suggestion.
long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
- PhoneTimeSuggestion phoneTimeSuggestion =
- mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis);
+ TelephonyTimeSuggestion telephonyTimeSuggestion =
+ mScript.generateTelephonyTimeSuggestion(slotIndex, testTimeMillis);
// Simulate the passage of time.
mScript.simulateTimePassing();
long expectedAutoClockMillis =
- mScript.calculateTimeInMillisForNow(phoneTimeSuggestion.getUtcTime());
- mScript.simulatePhoneTimeSuggestion(phoneTimeSuggestion)
+ mScript.calculateTimeInMillisForNow(telephonyTimeSuggestion.getUtcTime());
+ mScript.simulateTelephonyTimeSuggestion(telephonyTimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(expectedAutoClockMillis)
- .assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion);
+ .assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion);
// Simulate the passage of time.
mScript.simulateTimePassing();
@@ -435,7 +435,7 @@
// Switch to manual.
mScript.simulateAutoTimeDetectionToggle()
.verifySystemClockWasNotSetAndResetCallTracking()
- .assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion);
+ .assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion);
// Simulate the passage of time.
mScript.simulateTimePassing();
@@ -450,7 +450,7 @@
mScript.calculateTimeInMillisForNow(manualTimeSuggestion.getUtcTime());
mScript.simulateManualTimeSuggestion(manualTimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(expectedManualClockMillis)
- .assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion);
+ .assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion);
// Simulate the passage of time.
mScript.simulateTimePassing();
@@ -459,14 +459,14 @@
mScript.simulateAutoTimeDetectionToggle();
expectedAutoClockMillis =
- mScript.calculateTimeInMillisForNow(phoneTimeSuggestion.getUtcTime());
+ mScript.calculateTimeInMillisForNow(telephonyTimeSuggestion.getUtcTime());
mScript.verifySystemClockWasSetAndResetCallTracking(expectedAutoClockMillis)
- .assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion);
+ .assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion);
// Switch back to manual - nothing should happen to the clock.
mScript.simulateAutoTimeDetectionToggle()
.verifySystemClockWasNotSetAndResetCallTracking()
- .assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion);
+ .assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion);
}
/**
@@ -515,19 +515,19 @@
}
@Test
- public void testSuggestNetworkTime_phoneSuggestionsBeatNetworkSuggestions() {
+ public void testSuggestNetworkTime_telephonySuggestionsBeatNetworkSuggestions() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeAutoTimeDetectionEnabled(true);
// Three obviously different times that could not be mistaken for each other.
long networkTimeMillis1 = ARBITRARY_TEST_TIME_MILLIS;
long networkTimeMillis2 = ARBITRARY_TEST_TIME_MILLIS + Duration.ofDays(30).toMillis();
- long phoneTimeMillis = ARBITRARY_TEST_TIME_MILLIS + Duration.ofDays(60).toMillis();
+ long telephonyTimeMillis = ARBITRARY_TEST_TIME_MILLIS + Duration.ofDays(60).toMillis();
// A small increment used to simulate the passage of time, but not enough to interfere with
// macro-level time changes associated with suggestion age.
final long smallTimeIncrementMillis = 101;
- // A network suggestion is made. It should be used because there is no phone suggestion.
+ // A network suggestion is made. It should be used because there is no telephony suggestion.
NetworkTimeSuggestion networkTimeSuggestion1 =
mScript.generateNetworkTimeSuggestion(networkTimeMillis1);
mScript.simulateTimePassing(smallTimeIncrementMillis)
@@ -536,37 +536,37 @@
mScript.calculateTimeInMillisForNow(networkTimeSuggestion1.getUtcTime()));
// Check internal state.
- mScript.assertLatestPhoneSuggestion(ARBITRARY_PHONE_ID, null)
+ mScript.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, null)
.assertLatestNetworkSuggestion(networkTimeSuggestion1);
assertEquals(networkTimeSuggestion1, mScript.peekLatestValidNetworkSuggestion());
- assertNull(mScript.peekBestPhoneSuggestion());
+ assertNull(mScript.peekBestTelephonySuggestion());
// Simulate a little time passing.
mScript.simulateTimePassing(smallTimeIncrementMillis)
.verifySystemClockWasNotSetAndResetCallTracking();
- // Now a phone suggestion is made. Phone suggestions are prioritized over network
+ // Now a telephony suggestion is made. Telephony suggestions are prioritized over network
// suggestions so it should "win".
- PhoneTimeSuggestion phoneTimeSuggestion =
- mScript.generatePhoneTimeSuggestion(ARBITRARY_PHONE_ID, phoneTimeMillis);
+ TelephonyTimeSuggestion telephonyTimeSuggestion =
+ mScript.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeMillis);
mScript.simulateTimePassing(smallTimeIncrementMillis)
- .simulatePhoneTimeSuggestion(phoneTimeSuggestion)
+ .simulateTelephonyTimeSuggestion(telephonyTimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(
- mScript.calculateTimeInMillisForNow(phoneTimeSuggestion.getUtcTime()));
+ mScript.calculateTimeInMillisForNow(telephonyTimeSuggestion.getUtcTime()));
// Check internal state.
- mScript.assertLatestPhoneSuggestion(ARBITRARY_PHONE_ID, phoneTimeSuggestion)
+ mScript.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
.assertLatestNetworkSuggestion(networkTimeSuggestion1);
assertEquals(networkTimeSuggestion1, mScript.peekLatestValidNetworkSuggestion());
- assertEquals(phoneTimeSuggestion, mScript.peekBestPhoneSuggestion());
+ assertEquals(telephonyTimeSuggestion, mScript.peekBestTelephonySuggestion());
// Simulate some significant time passing: half the time allowed before a time signal
// becomes "too old to use".
mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_UTC_TIME_AGE_MILLIS / 2)
.verifySystemClockWasNotSetAndResetCallTracking();
- // Now another network suggestion is made. Phone suggestions are prioritized over network
- // suggestions so the latest phone suggestion should still "win".
+ // Now another network suggestion is made. Telephony suggestions are prioritized over
+ // network suggestions so the latest telephony suggestion should still "win".
NetworkTimeSuggestion networkTimeSuggestion2 =
mScript.generateNetworkTimeSuggestion(networkTimeMillis2);
mScript.simulateTimePassing(smallTimeIncrementMillis)
@@ -574,14 +574,14 @@
.verifySystemClockWasNotSetAndResetCallTracking();
// Check internal state.
- mScript.assertLatestPhoneSuggestion(ARBITRARY_PHONE_ID, phoneTimeSuggestion)
+ mScript.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
.assertLatestNetworkSuggestion(networkTimeSuggestion2);
assertEquals(networkTimeSuggestion2, mScript.peekLatestValidNetworkSuggestion());
- assertEquals(phoneTimeSuggestion, mScript.peekBestPhoneSuggestion());
+ assertEquals(telephonyTimeSuggestion, mScript.peekBestTelephonySuggestion());
// Simulate some significant time passing: half the time allowed before a time signal
- // becomes "too old to use". This should mean that phoneTimeSuggestion is now too old to be
- // used but networkTimeSuggestion2 is not.
+ // becomes "too old to use". This should mean that telephonyTimeSuggestion is now too old to
+ // be used but networkTimeSuggestion2 is not.
mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_UTC_TIME_AGE_MILLIS / 2);
// NOTE: The TimeDetectorStrategyImpl doesn't set an alarm for the point when the last
@@ -591,10 +591,10 @@
mScript.verifySystemClockWasNotSetAndResetCallTracking();
// Check internal state.
- mScript.assertLatestPhoneSuggestion(ARBITRARY_PHONE_ID, phoneTimeSuggestion)
+ mScript.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
.assertLatestNetworkSuggestion(networkTimeSuggestion2);
assertEquals(networkTimeSuggestion2, mScript.peekLatestValidNetworkSuggestion());
- assertNull(mScript.peekBestPhoneSuggestion());
+ assertNull(mScript.peekBestTelephonySuggestion());
// Toggle auto-time off and on to force the detection logic to run.
mScript.simulateAutoTimeDetectionToggle()
@@ -606,10 +606,10 @@
mScript.calculateTimeInMillisForNow(networkTimeSuggestion2.getUtcTime()));
// Check internal state.
- mScript.assertLatestPhoneSuggestion(ARBITRARY_PHONE_ID, phoneTimeSuggestion)
+ mScript.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
.assertLatestNetworkSuggestion(networkTimeSuggestion2);
assertEquals(networkTimeSuggestion2, mScript.peekLatestValidNetworkSuggestion());
- assertNull(mScript.peekBestPhoneSuggestion());
+ assertNull(mScript.peekBestTelephonySuggestion());
}
/**
@@ -760,8 +760,8 @@
return mFakeCallback.peekSystemClockMillis();
}
- Script simulatePhoneTimeSuggestion(PhoneTimeSuggestion timeSuggestion) {
- mTimeDetectorStrategy.suggestPhoneTime(timeSuggestion);
+ Script simulateTelephonyTimeSuggestion(TelephonyTimeSuggestion timeSuggestion) {
+ mTimeDetectorStrategy.suggestTelephonyTime(timeSuggestion);
return this;
}
@@ -806,10 +806,10 @@
}
/**
- * White box test info: Asserts the latest suggestion for the phone ID is as expected.
+ * White box test info: Asserts the latest suggestion for the slotIndex is as expected.
*/
- Script assertLatestPhoneSuggestion(int phoneId, PhoneTimeSuggestion expected) {
- assertEquals(expected, mTimeDetectorStrategy.getLatestPhoneSuggestion(phoneId));
+ Script assertLatestTelephonySuggestion(int slotIndex, TelephonyTimeSuggestion expected) {
+ assertEquals(expected, mTimeDetectorStrategy.getLatestTelephonySuggestion(slotIndex));
return this;
}
@@ -822,11 +822,11 @@
}
/**
- * White box test info: Returns the phone suggestion that would be used, if any, given the
- * current elapsed real time clock and regardless of origin prioritization.
+ * White box test info: Returns the telephony suggestion that would be used, if any, given
+ * the current elapsed real time clock and regardless of origin prioritization.
*/
- PhoneTimeSuggestion peekBestPhoneSuggestion() {
- return mTimeDetectorStrategy.findBestPhoneSuggestionForTests();
+ TelephonyTimeSuggestion peekBestTelephonySuggestion() {
+ return mTimeDetectorStrategy.findBestTelephonySuggestionForTests();
}
/**
@@ -848,15 +848,15 @@
}
/**
- * Generates a PhoneTimeSuggestion using the current elapsed realtime clock for the
- * reference time.
+ * Generates a {@link TelephonyTimeSuggestion} using the current elapsed realtime clock for
+ * the reference time.
*/
- PhoneTimeSuggestion generatePhoneTimeSuggestion(int phoneId, Long timeMillis) {
+ TelephonyTimeSuggestion generateTelephonyTimeSuggestion(int slotIndex, Long timeMillis) {
TimestampedValue<Long> time = null;
if (timeMillis != null) {
time = new TimestampedValue<>(peekElapsedRealtimeMillis(), timeMillis);
}
- return createPhoneTimeSuggestion(phoneId, time);
+ return createTelephonyTimeSuggestion(slotIndex, time);
}
/**
@@ -878,9 +878,9 @@
}
}
- private static PhoneTimeSuggestion createPhoneTimeSuggestion(int phoneId,
+ private static TelephonyTimeSuggestion createTelephonyTimeSuggestion(int slotIndex,
TimestampedValue<Long> utcTime) {
- return new PhoneTimeSuggestion.Builder(phoneId)
+ return new TelephonyTimeSuggestion.Builder(slotIndex)
.setUtcTime(utcTime)
.build();
}
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 3e7d40a..039c2b4 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
@@ -29,7 +29,7 @@
import static org.mockito.Mockito.when;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
-import android.app.timezonedetector.PhoneTimeZoneSuggestion;
+import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.HandlerThread;
@@ -76,35 +76,35 @@
}
@Test(expected = SecurityException.class)
- public void testSuggestPhoneTime_withoutPermission() {
+ public void testSuggestTelephonyTime_withoutPermission() {
doThrow(new SecurityException("Mock"))
.when(mMockContext).enforceCallingPermission(anyString(), any());
- PhoneTimeZoneSuggestion timeZoneSuggestion = createPhoneTimeZoneSuggestion();
+ TelephonyTimeZoneSuggestion timeZoneSuggestion = createTelephonyTimeZoneSuggestion();
try {
- mTimeZoneDetectorService.suggestPhoneTimeZone(timeZoneSuggestion);
+ mTimeZoneDetectorService.suggestTelephonyTimeZone(timeZoneSuggestion);
fail();
} finally {
verify(mMockContext).enforceCallingPermission(
- eq(android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE),
+ eq(android.Manifest.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE),
anyString());
}
}
@Test
- public void testSuggestPhoneTimeZone() throws Exception {
+ public void testSuggestTelephonyTimeZone() throws Exception {
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
- PhoneTimeZoneSuggestion timeZoneSuggestion = createPhoneTimeZoneSuggestion();
- mTimeZoneDetectorService.suggestPhoneTimeZone(timeZoneSuggestion);
+ TelephonyTimeZoneSuggestion timeZoneSuggestion = createTelephonyTimeZoneSuggestion();
+ mTimeZoneDetectorService.suggestTelephonyTimeZone(timeZoneSuggestion);
mTestHandler.assertTotalMessagesEnqueued(1);
verify(mMockContext).enforceCallingPermission(
- eq(android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE),
+ eq(android.Manifest.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE),
anyString());
mTestHandler.waitForMessagesToBeProcessed();
- mStubbedTimeZoneDetectorStrategy.verifySuggestPhoneTimeZoneCalled(timeZoneSuggestion);
+ mStubbedTimeZoneDetectorStrategy.verifySuggestTelephonyTimeZoneCalled(timeZoneSuggestion);
}
@Test(expected = SecurityException.class)
@@ -165,12 +165,12 @@
mStubbedTimeZoneDetectorStrategy.verifyHandleAutoTimeZoneDetectionChangedCalled();
}
- private static PhoneTimeZoneSuggestion createPhoneTimeZoneSuggestion() {
+ private static TelephonyTimeZoneSuggestion createTelephonyTimeZoneSuggestion() {
int slotIndex = 1234;
- return new PhoneTimeZoneSuggestion.Builder(slotIndex)
+ return new TelephonyTimeZoneSuggestion.Builder(slotIndex)
.setZoneId("TestZoneId")
- .setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET)
- .setQuality(PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE)
+ .setMatchType(TelephonyTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET)
+ .setQuality(TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE)
.build();
}
@@ -181,14 +181,14 @@
private static class StubbedTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
// Call tracking.
- private PhoneTimeZoneSuggestion mLastPhoneSuggestion;
+ private TelephonyTimeZoneSuggestion mLastTelephonySuggestion;
private ManualTimeZoneSuggestion mLastManualSuggestion;
private boolean mHandleAutoTimeZoneDetectionChangedCalled;
private boolean mDumpCalled;
@Override
- public void suggestPhoneTimeZone(PhoneTimeZoneSuggestion timeZoneSuggestion) {
- mLastPhoneSuggestion = timeZoneSuggestion;
+ public void suggestTelephonyTimeZone(TelephonyTimeZoneSuggestion timeZoneSuggestion) {
+ mLastTelephonySuggestion = timeZoneSuggestion;
}
@Override
@@ -207,14 +207,14 @@
}
void resetCallTracking() {
- mLastPhoneSuggestion = null;
+ mLastTelephonySuggestion = null;
mLastManualSuggestion = null;
mHandleAutoTimeZoneDetectionChangedCalled = false;
mDumpCalled = false;
}
- void verifySuggestPhoneTimeZoneCalled(PhoneTimeZoneSuggestion expectedSuggestion) {
- assertEquals(expectedSuggestion, mLastPhoneSuggestion);
+ void verifySuggestTelephonyTimeZoneCalled(TelephonyTimeZoneSuggestion expectedSuggestion) {
+ assertEquals(expectedSuggestion, mLastTelephonySuggestion);
}
public void verifySuggestManualTimeZoneCalled(ManualTimeZoneSuggestion expectedSuggestion) {
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
index 1e38711..ba30967 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
@@ -16,20 +16,20 @@
package com.android.server.timezonedetector;
-import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID;
-import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET;
-import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY;
-import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY;
-import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
-import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
-import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID;
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET;
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY;
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY;
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
-import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.PHONE_SCORE_HIGH;
-import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.PHONE_SCORE_HIGHEST;
-import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.PHONE_SCORE_LOW;
-import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.PHONE_SCORE_MEDIUM;
-import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.PHONE_SCORE_NONE;
-import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.PHONE_SCORE_USAGE_THRESHOLD;
+import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.TELEPHONY_SCORE_HIGH;
+import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.TELEPHONY_SCORE_HIGHEST;
+import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.TELEPHONY_SCORE_LOW;
+import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.TELEPHONY_SCORE_MEDIUM;
+import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.TELEPHONY_SCORE_NONE;
+import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.TELEPHONY_SCORE_USAGE_THRESHOLD;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -37,11 +37,11 @@
import static org.junit.Assert.assertTrue;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
-import android.app.timezonedetector.PhoneTimeZoneSuggestion;
-import android.app.timezonedetector.PhoneTimeZoneSuggestion.MatchType;
-import android.app.timezonedetector.PhoneTimeZoneSuggestion.Quality;
+import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
+import android.app.timezonedetector.TelephonyTimeZoneSuggestion.MatchType;
+import android.app.timezonedetector.TelephonyTimeZoneSuggestion.Quality;
-import com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.QualifiedPhoneTimeZoneSuggestion;
+import com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.QualifiedTelephonyTimeZoneSuggestion;
import org.junit.Before;
import org.junit.Test;
@@ -58,24 +58,24 @@
/** A time zone used for initialization that does not occur elsewhere in tests. */
private static final String ARBITRARY_TIME_ZONE_ID = "Etc/UTC";
- private static final int PHONE1_ID = 10000;
- private static final int PHONE2_ID = 20000;
+ private static final int SLOT_INDEX1 = 10000;
+ private static final int SLOT_INDEX2 = 20000;
// Suggestion test cases are ordered so that each successive one is of the same or higher score
// than the previous.
private static final SuggestionTestCase[] TEST_CASES = new SuggestionTestCase[] {
newTestCase(MATCH_TYPE_NETWORK_COUNTRY_ONLY,
- QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS, PHONE_SCORE_LOW),
+ QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS, TELEPHONY_SCORE_LOW),
newTestCase(MATCH_TYPE_NETWORK_COUNTRY_ONLY, QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET,
- PHONE_SCORE_MEDIUM),
+ TELEPHONY_SCORE_MEDIUM),
newTestCase(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET,
- QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET, PHONE_SCORE_MEDIUM),
- newTestCase(MATCH_TYPE_NETWORK_COUNTRY_ONLY, QUALITY_SINGLE_ZONE, PHONE_SCORE_HIGH),
+ QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET, TELEPHONY_SCORE_MEDIUM),
+ newTestCase(MATCH_TYPE_NETWORK_COUNTRY_ONLY, QUALITY_SINGLE_ZONE, TELEPHONY_SCORE_HIGH),
newTestCase(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, QUALITY_SINGLE_ZONE,
- PHONE_SCORE_HIGH),
+ TELEPHONY_SCORE_HIGH),
newTestCase(MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY,
- QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET, PHONE_SCORE_HIGHEST),
- newTestCase(MATCH_TYPE_EMULATOR_ZONE_ID, QUALITY_SINGLE_ZONE, PHONE_SCORE_HIGHEST),
+ QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET, TELEPHONY_SCORE_HIGHEST),
+ newTestCase(MATCH_TYPE_EMULATOR_ZONE_ID, QUALITY_SINGLE_ZONE, TELEPHONY_SCORE_HIGHEST),
};
private TimeZoneDetectorStrategyImpl mTimeZoneDetectorStrategy;
@@ -89,76 +89,82 @@
}
@Test
- public void testEmptyPhoneSuggestions() {
- PhoneTimeZoneSuggestion phone1TimeZoneSuggestion = createEmptyPhone1Suggestion();
- PhoneTimeZoneSuggestion phone2TimeZoneSuggestion = createEmptyPhone2Suggestion();
+ public void testEmptyTelephonySuggestions() {
+ TelephonyTimeZoneSuggestion slotIndex1TimeZoneSuggestion =
+ createEmptySlotIndex1Suggestion();
+ TelephonyTimeZoneSuggestion slotIndex2TimeZoneSuggestion =
+ createEmptySlotIndex2Suggestion();
Script script = new Script()
.initializeAutoTimeZoneDetection(true)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
- script.suggestPhoneTimeZone(phone1TimeZoneSuggestion)
+ script.suggestTelephonyTimeZone(slotIndex1TimeZoneSuggestion)
.verifyTimeZoneNotSet();
// Assert internal service state.
- QualifiedPhoneTimeZoneSuggestion expectedPhone1ScoredSuggestion =
- new QualifiedPhoneTimeZoneSuggestion(phone1TimeZoneSuggestion, PHONE_SCORE_NONE);
- assertEquals(expectedPhone1ScoredSuggestion,
- mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
- assertNull(mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE2_ID));
- assertEquals(expectedPhone1ScoredSuggestion,
- mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+ QualifiedTelephonyTimeZoneSuggestion expectedSlotIndex1ScoredSuggestion =
+ new QualifiedTelephonyTimeZoneSuggestion(slotIndex1TimeZoneSuggestion,
+ TELEPHONY_SCORE_NONE);
+ assertEquals(expectedSlotIndex1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
+ assertNull(mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX2));
+ assertEquals(expectedSlotIndex1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
- script.suggestPhoneTimeZone(phone2TimeZoneSuggestion)
+ script.suggestTelephonyTimeZone(slotIndex2TimeZoneSuggestion)
.verifyTimeZoneNotSet();
// Assert internal service state.
- QualifiedPhoneTimeZoneSuggestion expectedPhone2ScoredSuggestion =
- new QualifiedPhoneTimeZoneSuggestion(phone2TimeZoneSuggestion, PHONE_SCORE_NONE);
- assertEquals(expectedPhone1ScoredSuggestion,
- mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
- assertEquals(expectedPhone2ScoredSuggestion,
- mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE2_ID));
- // Phone 1 should always beat phone 2, all other things being equal.
- assertEquals(expectedPhone1ScoredSuggestion,
- mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+ QualifiedTelephonyTimeZoneSuggestion expectedSlotIndex2ScoredSuggestion =
+ new QualifiedTelephonyTimeZoneSuggestion(slotIndex2TimeZoneSuggestion,
+ TELEPHONY_SCORE_NONE);
+ assertEquals(expectedSlotIndex1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
+ assertEquals(expectedSlotIndex2ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX2));
+ // SlotIndex1 should always beat slotIndex2, all other things being equal.
+ assertEquals(expectedSlotIndex1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
}
@Test
- public void testFirstPlausiblePhoneSuggestionAcceptedWhenTimeZoneUninitialized() {
+ public void testFirstPlausibleTelephonySuggestionAcceptedWhenTimeZoneUninitialized() {
SuggestionTestCase testCase = newTestCase(MATCH_TYPE_NETWORK_COUNTRY_ONLY,
- QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS, PHONE_SCORE_LOW);
- PhoneTimeZoneSuggestion lowQualitySuggestion =
- testCase.createSuggestion(PHONE1_ID, "America/New_York");
+ QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS, TELEPHONY_SCORE_LOW);
+ TelephonyTimeZoneSuggestion lowQualitySuggestion =
+ testCase.createSuggestion(SLOT_INDEX1, "America/New_York");
// The device time zone setting is left uninitialized.
Script script = new Script()
.initializeAutoTimeZoneDetection(true);
// The very first suggestion will be taken.
- script.suggestPhoneTimeZone(lowQualitySuggestion)
+ script.suggestTelephonyTimeZone(lowQualitySuggestion)
.verifyTimeZoneSetAndReset(lowQualitySuggestion);
// Assert internal service state.
- QualifiedPhoneTimeZoneSuggestion expectedScoredSuggestion =
- new QualifiedPhoneTimeZoneSuggestion(lowQualitySuggestion, testCase.expectedScore);
+ QualifiedTelephonyTimeZoneSuggestion expectedScoredSuggestion =
+ new QualifiedTelephonyTimeZoneSuggestion(
+ lowQualitySuggestion, testCase.expectedScore);
assertEquals(expectedScoredSuggestion,
- mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+ mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
assertEquals(expectedScoredSuggestion,
- mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+ mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
// Another low quality suggestion will be ignored now that the setting is initialized.
- PhoneTimeZoneSuggestion lowQualitySuggestion2 =
- testCase.createSuggestion(PHONE1_ID, "America/Los_Angeles");
- script.suggestPhoneTimeZone(lowQualitySuggestion2)
+ TelephonyTimeZoneSuggestion lowQualitySuggestion2 =
+ testCase.createSuggestion(SLOT_INDEX1, "America/Los_Angeles");
+ script.suggestTelephonyTimeZone(lowQualitySuggestion2)
.verifyTimeZoneNotSet();
// Assert internal service state.
- QualifiedPhoneTimeZoneSuggestion expectedScoredSuggestion2 =
- new QualifiedPhoneTimeZoneSuggestion(lowQualitySuggestion2, testCase.expectedScore);
+ QualifiedTelephonyTimeZoneSuggestion expectedScoredSuggestion2 =
+ new QualifiedTelephonyTimeZoneSuggestion(
+ lowQualitySuggestion2, testCase.expectedScore);
assertEquals(expectedScoredSuggestion2,
- mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+ mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
assertEquals(expectedScoredSuggestion2,
- mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+ mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
}
/**
@@ -174,28 +180,28 @@
script.initializeAutoTimeZoneDetection(false)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
- PhoneTimeZoneSuggestion suggestion =
- testCase.createSuggestion(PHONE1_ID, "Europe/London");
- script.suggestPhoneTimeZone(suggestion);
+ TelephonyTimeZoneSuggestion suggestion =
+ testCase.createSuggestion(SLOT_INDEX1, "Europe/London");
+ script.suggestTelephonyTimeZone(suggestion);
// When time zone detection is not enabled, the time zone suggestion will not be set
// regardless of the score.
script.verifyTimeZoneNotSet();
// Assert internal service state.
- QualifiedPhoneTimeZoneSuggestion expectedScoredSuggestion =
- new QualifiedPhoneTimeZoneSuggestion(suggestion, testCase.expectedScore);
+ QualifiedTelephonyTimeZoneSuggestion expectedScoredSuggestion =
+ new QualifiedTelephonyTimeZoneSuggestion(suggestion, testCase.expectedScore);
assertEquals(expectedScoredSuggestion,
- mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+ mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
assertEquals(expectedScoredSuggestion,
- mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+ mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
// Toggling the time zone setting on should cause the device setting to be set.
script.autoTimeZoneDetectionEnabled(true);
// When time zone detection is already enabled the suggestion (if it scores highly
// enough) should be set immediately.
- if (testCase.expectedScore >= PHONE_SCORE_USAGE_THRESHOLD) {
+ if (testCase.expectedScore >= TELEPHONY_SCORE_USAGE_THRESHOLD) {
script.verifyTimeZoneSetAndReset(suggestion);
} else {
script.verifyTimeZoneNotSet();
@@ -203,9 +209,9 @@
// Assert internal service state.
assertEquals(expectedScoredSuggestion,
- mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+ mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
assertEquals(expectedScoredSuggestion,
- mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+ mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
// Toggling the time zone setting should off should do nothing.
script.autoTimeZoneDetectionEnabled(false)
@@ -213,20 +219,20 @@
// Assert internal service state.
assertEquals(expectedScoredSuggestion,
- mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+ mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
assertEquals(expectedScoredSuggestion,
- mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+ mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
}
}
@Test
- public void testPhoneSuggestionsSinglePhone() {
+ public void testTelephonySuggestionsSingleSlotId() {
Script script = new Script()
.initializeAutoTimeZoneDetection(true)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
for (SuggestionTestCase testCase : TEST_CASES) {
- makePhone1SuggestionAndCheckState(script, testCase);
+ makeSlotIndex1SuggestionAndCheckState(script, testCase);
}
/*
@@ -241,125 +247,128 @@
Collections.reverse(descendingCasesByScore);
for (SuggestionTestCase testCase : descendingCasesByScore) {
- makePhone1SuggestionAndCheckState(script, testCase);
+ makeSlotIndex1SuggestionAndCheckState(script, testCase);
}
}
- private void makePhone1SuggestionAndCheckState(Script script, SuggestionTestCase testCase) {
+ private void makeSlotIndex1SuggestionAndCheckState(Script script, SuggestionTestCase testCase) {
// Give the next suggestion a different zone from the currently set device time zone;
String currentZoneId = mFakeTimeZoneDetectorStrategyCallback.getDeviceTimeZone();
String suggestionZoneId =
"Europe/London".equals(currentZoneId) ? "Europe/Paris" : "Europe/London";
- PhoneTimeZoneSuggestion zonePhone1Suggestion =
- testCase.createSuggestion(PHONE1_ID, suggestionZoneId);
- QualifiedPhoneTimeZoneSuggestion expectedZonePhone1ScoredSuggestion =
- new QualifiedPhoneTimeZoneSuggestion(zonePhone1Suggestion, testCase.expectedScore);
+ TelephonyTimeZoneSuggestion zoneSlotIndex1Suggestion =
+ testCase.createSuggestion(SLOT_INDEX1, suggestionZoneId);
+ QualifiedTelephonyTimeZoneSuggestion expectedZoneSlotIndex1ScoredSuggestion =
+ new QualifiedTelephonyTimeZoneSuggestion(
+ zoneSlotIndex1Suggestion, testCase.expectedScore);
- script.suggestPhoneTimeZone(zonePhone1Suggestion);
- if (testCase.expectedScore >= PHONE_SCORE_USAGE_THRESHOLD) {
- script.verifyTimeZoneSetAndReset(zonePhone1Suggestion);
+ script.suggestTelephonyTimeZone(zoneSlotIndex1Suggestion);
+ if (testCase.expectedScore >= TELEPHONY_SCORE_USAGE_THRESHOLD) {
+ script.verifyTimeZoneSetAndReset(zoneSlotIndex1Suggestion);
} else {
script.verifyTimeZoneNotSet();
}
// Assert internal service state.
- assertEquals(expectedZonePhone1ScoredSuggestion,
- mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
- assertEquals(expectedZonePhone1ScoredSuggestion,
- mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+ assertEquals(expectedZoneSlotIndex1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
+ assertEquals(expectedZoneSlotIndex1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
}
/**
- * Tries a set of test cases to see if the phone with the lowest ID is given preference. This
- * test also confirms that the time zone setting would only be set if a suggestion is of
- * sufficient quality.
+ * Tries a set of test cases to see if the slotIndex with the lowest numeric value is given
+ * preference. This test also confirms that the time zone setting would only be set if a
+ * suggestion is of sufficient quality.
*/
@Test
- public void testMultiplePhoneSuggestionScoringAndPhoneIdBias() {
+ public void testMultipleSlotIndexSuggestionScoringAndSlotIndexBias() {
String[] zoneIds = { "Europe/London", "Europe/Paris" };
- PhoneTimeZoneSuggestion emptyPhone1Suggestion = createEmptyPhone1Suggestion();
- PhoneTimeZoneSuggestion emptyPhone2Suggestion = createEmptyPhone2Suggestion();
- QualifiedPhoneTimeZoneSuggestion expectedEmptyPhone1ScoredSuggestion =
- new QualifiedPhoneTimeZoneSuggestion(emptyPhone1Suggestion, PHONE_SCORE_NONE);
- QualifiedPhoneTimeZoneSuggestion expectedEmptyPhone2ScoredSuggestion =
- new QualifiedPhoneTimeZoneSuggestion(emptyPhone2Suggestion, PHONE_SCORE_NONE);
+ TelephonyTimeZoneSuggestion emptySlotIndex1Suggestion = createEmptySlotIndex1Suggestion();
+ TelephonyTimeZoneSuggestion emptySlotIndex2Suggestion = createEmptySlotIndex2Suggestion();
+ QualifiedTelephonyTimeZoneSuggestion expectedEmptySlotIndex1ScoredSuggestion =
+ new QualifiedTelephonyTimeZoneSuggestion(emptySlotIndex1Suggestion,
+ TELEPHONY_SCORE_NONE);
+ QualifiedTelephonyTimeZoneSuggestion expectedEmptySlotIndex2ScoredSuggestion =
+ new QualifiedTelephonyTimeZoneSuggestion(emptySlotIndex2Suggestion,
+ TELEPHONY_SCORE_NONE);
Script script = new Script()
.initializeAutoTimeZoneDetection(true)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
// Initialize the latest suggestions as empty so we don't need to worry about nulls
// below for the first loop.
- .suggestPhoneTimeZone(emptyPhone1Suggestion)
- .suggestPhoneTimeZone(emptyPhone2Suggestion)
+ .suggestTelephonyTimeZone(emptySlotIndex1Suggestion)
+ .suggestTelephonyTimeZone(emptySlotIndex2Suggestion)
.resetState();
for (SuggestionTestCase testCase : TEST_CASES) {
- PhoneTimeZoneSuggestion zonePhone1Suggestion =
- testCase.createSuggestion(PHONE1_ID, zoneIds[0]);
- PhoneTimeZoneSuggestion zonePhone2Suggestion =
- testCase.createSuggestion(PHONE2_ID, zoneIds[1]);
- QualifiedPhoneTimeZoneSuggestion expectedZonePhone1ScoredSuggestion =
- new QualifiedPhoneTimeZoneSuggestion(zonePhone1Suggestion,
+ TelephonyTimeZoneSuggestion zoneSlotIndex1Suggestion =
+ testCase.createSuggestion(SLOT_INDEX1, zoneIds[0]);
+ TelephonyTimeZoneSuggestion zoneSlotIndex2Suggestion =
+ testCase.createSuggestion(SLOT_INDEX2, zoneIds[1]);
+ QualifiedTelephonyTimeZoneSuggestion expectedZoneSlotIndex1ScoredSuggestion =
+ new QualifiedTelephonyTimeZoneSuggestion(zoneSlotIndex1Suggestion,
testCase.expectedScore);
- QualifiedPhoneTimeZoneSuggestion expectedZonePhone2ScoredSuggestion =
- new QualifiedPhoneTimeZoneSuggestion(zonePhone2Suggestion,
+ QualifiedTelephonyTimeZoneSuggestion expectedZoneSlotIndex2ScoredSuggestion =
+ new QualifiedTelephonyTimeZoneSuggestion(zoneSlotIndex2Suggestion,
testCase.expectedScore);
- // Start the test by making a suggestion for phone 1.
- script.suggestPhoneTimeZone(zonePhone1Suggestion);
- if (testCase.expectedScore >= PHONE_SCORE_USAGE_THRESHOLD) {
- script.verifyTimeZoneSetAndReset(zonePhone1Suggestion);
+ // Start the test by making a suggestion for slotIndex1.
+ script.suggestTelephonyTimeZone(zoneSlotIndex1Suggestion);
+ if (testCase.expectedScore >= TELEPHONY_SCORE_USAGE_THRESHOLD) {
+ script.verifyTimeZoneSetAndReset(zoneSlotIndex1Suggestion);
} else {
script.verifyTimeZoneNotSet();
}
// Assert internal service state.
- assertEquals(expectedZonePhone1ScoredSuggestion,
- mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
- assertEquals(expectedEmptyPhone2ScoredSuggestion,
- mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE2_ID));
- assertEquals(expectedZonePhone1ScoredSuggestion,
- mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+ assertEquals(expectedZoneSlotIndex1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
+ assertEquals(expectedEmptySlotIndex2ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX2));
+ assertEquals(expectedZoneSlotIndex1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
- // Phone 2 then makes an alternative suggestion with an identical score. Phone 1's
+ // SlotIndex2 then makes an alternative suggestion with an identical score. SlotIndex1's
// suggestion should still "win" if it is above the required threshold.
- script.suggestPhoneTimeZone(zonePhone2Suggestion);
+ script.suggestTelephonyTimeZone(zoneSlotIndex2Suggestion);
script.verifyTimeZoneNotSet();
// Assert internal service state.
- assertEquals(expectedZonePhone1ScoredSuggestion,
- mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
- assertEquals(expectedZonePhone2ScoredSuggestion,
- mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE2_ID));
- // Phone 1 should always beat phone 2, all other things being equal.
- assertEquals(expectedZonePhone1ScoredSuggestion,
- mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+ assertEquals(expectedZoneSlotIndex1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
+ assertEquals(expectedZoneSlotIndex2ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX2));
+ // SlotIndex1 should always beat slotIndex2, all other things being equal.
+ assertEquals(expectedZoneSlotIndex1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
- // Withdrawing phone 1's suggestion should leave phone 2 as the new winner. Since the
- // zoneId is different, the time zone setting should be updated if the score is high
+ // Withdrawing slotIndex1's suggestion should leave slotIndex2 as the new winner. Since
+ // the zoneId is different, the time zone setting should be updated if the score is high
// enough.
- script.suggestPhoneTimeZone(emptyPhone1Suggestion);
- if (testCase.expectedScore >= PHONE_SCORE_USAGE_THRESHOLD) {
- script.verifyTimeZoneSetAndReset(zonePhone2Suggestion);
+ script.suggestTelephonyTimeZone(emptySlotIndex1Suggestion);
+ if (testCase.expectedScore >= TELEPHONY_SCORE_USAGE_THRESHOLD) {
+ script.verifyTimeZoneSetAndReset(zoneSlotIndex2Suggestion);
} else {
script.verifyTimeZoneNotSet();
}
// Assert internal service state.
- assertEquals(expectedEmptyPhone1ScoredSuggestion,
- mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
- assertEquals(expectedZonePhone2ScoredSuggestion,
- mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE2_ID));
- assertEquals(expectedZonePhone2ScoredSuggestion,
- mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+ assertEquals(expectedEmptySlotIndex1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
+ assertEquals(expectedZoneSlotIndex2ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX2));
+ assertEquals(expectedZoneSlotIndex2ScoredSuggestion,
+ mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
// Reset the state for the next loop.
- script.suggestPhoneTimeZone(emptyPhone2Suggestion)
+ script.suggestTelephonyTimeZone(emptySlotIndex2Suggestion)
.verifyTimeZoneNotSet();
- assertEquals(expectedEmptyPhone1ScoredSuggestion,
- mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
- assertEquals(expectedEmptyPhone2ScoredSuggestion,
- mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE2_ID));
+ assertEquals(expectedEmptySlotIndex1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1));
+ assertEquals(expectedEmptySlotIndex2ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX2));
}
}
@@ -375,21 +384,21 @@
SuggestionTestCase testCase =
newTestCase(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, QUALITY_SINGLE_ZONE,
- PHONE_SCORE_HIGH);
- PhoneTimeZoneSuggestion losAngelesSuggestion =
- testCase.createSuggestion(PHONE1_ID, "America/Los_Angeles");
- PhoneTimeZoneSuggestion newYorkSuggestion =
- testCase.createSuggestion(PHONE1_ID, "America/New_York");
+ TELEPHONY_SCORE_HIGH);
+ TelephonyTimeZoneSuggestion losAngelesSuggestion =
+ testCase.createSuggestion(SLOT_INDEX1, "America/Los_Angeles");
+ TelephonyTimeZoneSuggestion newYorkSuggestion =
+ testCase.createSuggestion(SLOT_INDEX1, "America/New_York");
// Initialization.
- script.suggestPhoneTimeZone(losAngelesSuggestion)
+ script.suggestTelephonyTimeZone(losAngelesSuggestion)
.verifyTimeZoneSetAndReset(losAngelesSuggestion);
// Suggest it again - it should not be set because it is already set.
- script.suggestPhoneTimeZone(losAngelesSuggestion)
+ script.suggestTelephonyTimeZone(losAngelesSuggestion)
.verifyTimeZoneNotSet();
// Toggling time zone detection should set the device time zone only if the current setting
- // value is different from the most recent phone suggestion.
+ // value is different from the most recent telephony suggestion.
script.autoTimeZoneDetectionEnabled(false)
.verifyTimeZoneNotSet()
.autoTimeZoneDetectionEnabled(true)
@@ -398,7 +407,7 @@
// Simulate a user turning auto detection off, a new suggestion being made while auto
// detection is off, and the user turning it on again.
script.autoTimeZoneDetectionEnabled(false)
- .suggestPhoneTimeZone(newYorkSuggestion)
+ .suggestTelephonyTimeZone(newYorkSuggestion)
.verifyTimeZoneNotSet();
// Latest suggestion should be used.
script.autoTimeZoneDetectionEnabled(true)
@@ -433,12 +442,12 @@
return new ManualTimeZoneSuggestion(zoneId);
}
- private static PhoneTimeZoneSuggestion createEmptyPhone1Suggestion() {
- return new PhoneTimeZoneSuggestion.Builder(PHONE1_ID).build();
+ private static TelephonyTimeZoneSuggestion createEmptySlotIndex1Suggestion() {
+ return new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX1).build();
}
- private static PhoneTimeZoneSuggestion createEmptyPhone2Suggestion() {
- return new PhoneTimeZoneSuggestion.Builder(PHONE2_ID).build();
+ private static TelephonyTimeZoneSuggestion createEmptySlotIndex2Suggestion() {
+ return new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX2).build();
}
static class FakeTimeZoneDetectorStrategyCallback
@@ -565,9 +574,11 @@
return this;
}
- /** Simulates the time zone detection strategy receiving a phone-originated suggestion. */
- Script suggestPhoneTimeZone(PhoneTimeZoneSuggestion phoneTimeZoneSuggestion) {
- mTimeZoneDetectorStrategy.suggestPhoneTimeZone(phoneTimeZoneSuggestion);
+ /**
+ * Simulates the time zone detection strategy receiving a telephony-originated suggestion.
+ */
+ Script suggestTelephonyTimeZone(TelephonyTimeZoneSuggestion timeZoneSuggestion) {
+ mTimeZoneDetectorStrategy.suggestTelephonyTimeZone(timeZoneSuggestion);
return this;
}
@@ -582,7 +593,7 @@
return this;
}
- Script verifyTimeZoneSetAndReset(PhoneTimeZoneSuggestion suggestion) {
+ Script verifyTimeZoneSetAndReset(TelephonyTimeZoneSuggestion suggestion) {
mFakeTimeZoneDetectorStrategyCallback.assertTimeZoneSet(suggestion.getZoneId());
mFakeTimeZoneDetectorStrategyCallback.commitAllChanges();
return this;
@@ -611,8 +622,8 @@
this.expectedScore = expectedScore;
}
- private PhoneTimeZoneSuggestion createSuggestion(int phoneId, String zoneId) {
- return new PhoneTimeZoneSuggestion.Builder(phoneId)
+ private TelephonyTimeZoneSuggestion createSuggestion(int slotIndex, String zoneId) {
+ return new TelephonyTimeZoneSuggestion.Builder(slotIndex)
.setZoneId(zoneId)
.setMatchType(matchType)
.setQuality(quality)
diff --git a/services/tests/uiservicestests/AndroidManifest.xml b/services/tests/uiservicestests/AndroidManifest.xml
index 180deb5..dab0a5f 100644
--- a/services/tests/uiservicestests/AndroidManifest.xml
+++ b/services/tests/uiservicestests/AndroidManifest.xml
@@ -28,6 +28,8 @@
<uses-permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE" />
<uses-permission android:name="android.permission.DEVICE_POWER" />
<uses-permission android:name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY" />
+ <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.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS" />
<uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT"/>
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 8c454424..123bb07 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -37,6 +37,7 @@
<uses-permission android:name="android.permission.WAKE_LOCK" />
<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" />
<!-- 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/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
index a9a20f6..7172a1b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -26,16 +26,19 @@
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.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
@@ -207,7 +210,7 @@
WindowContainerTransaction t = new WindowContainerTransaction();
Rect newBounds = new Rect(10, 10, 100, 100);
t.setBounds(task.mRemoteToken, new Rect(10, 10, 100, 100));
- mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t);
+ mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null);
assertEquals(newBounds, task.getBounds());
}
@@ -222,7 +225,7 @@
assertEquals(stack.mRemoteToken, info.stackToken);
Rect newBounds = new Rect(10, 10, 100, 100);
t.setBounds(info.stackToken, new Rect(10, 10, 100, 100));
- mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t);
+ mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null);
assertEquals(newBounds, stack.getBounds());
}
@@ -235,7 +238,7 @@
WindowContainerTransaction t = new WindowContainerTransaction();
assertTrue(task.isFocusable());
t.setFocusable(stack.mRemoteToken, false);
- mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t);
+ mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null);
assertFalse(task.isFocusable());
}
@@ -364,4 +367,46 @@
}
return out;
}
+
+ @Test
+ public void testTrivialBLASTCallback() throws RemoteException {
+ final ActivityStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
+ final Task task = createTaskInStack(stackController1, 0 /* userId */);
+ final ITaskOrganizer organizer = registerMockOrganizer();
+
+ BLASTSyncEngine bse = new BLASTSyncEngine();
+
+ BLASTSyncEngine.TransactionReadyListener transactionListener =
+ mock(BLASTSyncEngine.TransactionReadyListener.class);
+
+ int id = bse.startSyncSet(transactionListener);
+ bse.addToSyncSet(id, task);
+ bse.setReady(id);
+ // Since this task has no windows the sync is trivial and completes immediately.
+ verify(transactionListener)
+ .transactionReady(anyInt(), any());
+ }
+
+ @Test
+ public void testBLASTCallbackWithWindow() {
+ final ActivityStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
+ final Task task = createTaskInStack(stackController1, 0 /* userId */);
+ final ITaskOrganizer organizer = registerMockOrganizer();
+ final WindowState w = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window");
+
+ BLASTSyncEngine bse = new BLASTSyncEngine();
+
+ BLASTSyncEngine.TransactionReadyListener transactionListener =
+ mock(BLASTSyncEngine.TransactionReadyListener.class);
+
+ int id = bse.startSyncSet(transactionListener);
+ bse.addToSyncSet(id, task);
+ bse.setReady(id);
+ // Since we have a window we have to wait for it to draw to finish sync.
+ verify(transactionListener, never())
+ .transactionReady(anyInt(), any());
+ w.finishDrawing(null);
+ verify(transactionListener)
+ .transactionReady(anyInt(), any());
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
new file mode 100644
index 0000000..35723ab
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.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.wm;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import android.content.pm.PackageManager;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class WindowManagerServiceTests extends WindowTestsBase {
+ @Rule
+ public ExpectedException mExpectedException = ExpectedException.none();
+
+ @Test
+ public void testForceShowSystemBarsThrowsExceptionForNonAutomotive() {
+ if (!isAutomotive()) {
+ mExpectedException.expect(UnsupportedOperationException.class);
+
+ mWm.setForceShowSystemBars(true);
+ }
+ }
+
+ @Test
+ public void testForceShowSystemBarsDoesNotThrowExceptionForAutomotiveWithStatusBarPermission() {
+ if (isAutomotive()) {
+ mExpectedException.none();
+
+ mWm.setForceShowSystemBars(true);
+ }
+ }
+
+ private boolean isAutomotive() {
+ return getInstrumentation().getTargetContext().getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_AUTOMOTIVE);
+ }
+}
diff --git a/telephony/common/com/google/android/mms/pdu/CharacterSets.java b/telephony/common/com/google/android/mms/pdu/CharacterSets.java
index 5172b7b..a3894d6 100644
--- a/telephony/common/com/google/android/mms/pdu/CharacterSets.java
+++ b/telephony/common/com/google/android/mms/pdu/CharacterSets.java
@@ -48,6 +48,51 @@
public static final int UTF_16 = 0x03F7;
/**
+ * Extend charsets.
+ *
+ * From http://www.iana.org/assignments/character-sets/
+ */
+ public static final int BIG5_HKSCS = 0x0835; //2101
+ public static final int BOCU_1 = 0x03FC; //1020
+ public static final int CESU_8 = 0x03F8; //1016
+ public static final int CP864 = 0x0803; //2051
+ public static final int EUC_JP = 0x12; //18
+ public static final int EUC_KR = 0x26; //38
+ public static final int GB18030 = 0x72; //114
+ public static final int GBK = 0x71; //113
+ public static final int HZ_GB_2312 = 0x0825; //2085
+ public static final int GB_2312 = 0x07E9; //2025
+ public static final int ISO_2022_CN = 0x68; //104
+ public static final int ISO_2022_CN_EXT = 0x69; //105
+ public static final int ISO_2022_JP = 0x27; //39
+ public static final int ISO_2022_KR = 0x25; //37
+ public static final int ISO_8859_10 = 0x0D; //13
+ public static final int ISO_8859_13 = 0x6D; //109
+ public static final int ISO_8859_14 = 0x6E; //110
+ public static final int ISO_8859_15 = 0x6F; //111
+ public static final int ISO_8859_16 = 0x70; //112
+ public static final int KOI8_R = 0x0824; //2084
+ public static final int KOI8_U = 0x0828; //2088
+ public static final int MACINTOSH = 0x07EB; //2027
+ public static final int SCSU = 0x03F3; //1011
+ public static final int TIS_620 = 0x08D3; //2259
+ public static final int UTF_16BE = 0x03F5; //1013
+ public static final int UTF_16LE = 0x03F6; //1014
+ public static final int UTF_32 = 0x03F9; //1017
+ public static final int UTF_32BE = 0x03FA; //1018
+ public static final int UTF_32LE = 0x03FB; //1019
+ public static final int UTF_7 = 0x03F4; //1012
+ public static final int WINDOWS_1250 = 0x08CA; //2250
+ public static final int WINDOWS_1251 = 0x08CB; //2251
+ public static final int WINDOWS_1252 = 0x08CC; //2252
+ public static final int WINDOWS_1253 = 0x08CD; //2253
+ public static final int WINDOWS_1254 = 0x08CE; //2254
+ public static final int WINDOWS_1255 = 0x08CF; //2255
+ public static final int WINDOWS_1256 = 0x08D0; //2256
+ public static final int WINDOWS_1257 = 0x08D1; //2257
+ public static final int WINDOWS_1258 = 0x08D2; //2258
+
+ /**
* If the encoding of given data is unsupported, use UTF_8 to decode it.
*/
public static final int DEFAULT_CHARSET = UTF_8;
@@ -72,6 +117,45 @@
BIG5,
UCS2,
UTF_16,
+ BIG5_HKSCS,
+ BOCU_1,
+ CESU_8,
+ CP864,
+ EUC_JP,
+ EUC_KR,
+ GB18030,
+ GBK,
+ HZ_GB_2312,
+ GB_2312,
+ ISO_2022_CN,
+ ISO_2022_CN_EXT,
+ ISO_2022_JP,
+ ISO_2022_KR,
+ ISO_8859_10,
+ ISO_8859_13,
+ ISO_8859_14,
+ ISO_8859_15,
+ ISO_8859_16,
+ KOI8_R,
+ KOI8_U,
+ MACINTOSH,
+ SCSU,
+ TIS_620,
+ UTF_16BE,
+ UTF_16LE,
+ UTF_32,
+ UTF_32BE,
+ UTF_32LE,
+ UTF_7,
+ WINDOWS_1250,
+ WINDOWS_1251,
+ WINDOWS_1252,
+ WINDOWS_1253,
+ WINDOWS_1254,
+ WINDOWS_1255,
+ WINDOWS_1256,
+ WINDOWS_1257,
+ WINDOWS_1258,
};
/**
@@ -94,6 +178,51 @@
public static final String MIMENAME_UCS2 = "iso-10646-ucs-2";
public static final String MIMENAME_UTF_16 = "utf-16";
+ /**
+ * Extend charsets.
+ *
+ * From http://www.iana.org/assignments/character-sets/
+ */
+ public static final String MIMENAME_BIG5_HKSCS = "Big5-HKSCS";
+ public static final String MIMENAME_BOCU_1 = "BOCU-1";
+ public static final String MIMENAME_CESU_8 = "CESU-8";
+ public static final String MIMENAME_CP864 = "cp864";
+ public static final String MIMENAME_EUC_JP = "EUC-JP";
+ public static final String MIMENAME_EUC_KR = "EUC-KR";
+ public static final String MIMENAME_GB18030 = "GB18030";
+ public static final String MIMENAME_GBK = "GBK";
+ public static final String MIMENAME_HZ_GB_2312 = "HZ-GB-2312";
+ public static final String MIMENAME_GB_2312 = "GB2312";
+ public static final String MIMENAME_ISO_2022_CN = "ISO-2022-CN";
+ public static final String MIMENAME_ISO_2022_CN_EXT = "ISO-2022-CN-EXT";
+ public static final String MIMENAME_ISO_2022_JP = "ISO-2022-JP";
+ public static final String MIMENAME_ISO_2022_KR = "ISO-2022-KR";
+ public static final String MIMENAME_ISO_8859_10 = "ISO-8859-10";
+ public static final String MIMENAME_ISO_8859_13 = "ISO-8859-13";
+ public static final String MIMENAME_ISO_8859_14 = "ISO-8859-14";
+ public static final String MIMENAME_ISO_8859_15 = "ISO-8859-15";
+ public static final String MIMENAME_ISO_8859_16 = "ISO-8859-16";
+ public static final String MIMENAME_KOI8_R = "KOI8-R";
+ public static final String MIMENAME_KOI8_U = "KOI8-U";
+ public static final String MIMENAME_MACINTOSH = "macintosh";
+ public static final String MIMENAME_SCSU = "SCSU";
+ public static final String MIMENAME_TIS_620 = "TIS-620";
+ public static final String MIMENAME_UTF_16BE = "UTF-16BE";
+ public static final String MIMENAME_UTF_16LE = "UTF-16LE";
+ public static final String MIMENAME_UTF_32 = "UTF-32";
+ public static final String MIMENAME_UTF_32BE = "UTF-32BE";
+ public static final String MIMENAME_UTF_32LE = "UTF-32LE";
+ public static final String MIMENAME_UTF_7 = "UTF-7";
+ public static final String MIMENAME_WINDOWS_1250 = "windows-1250";
+ public static final String MIMENAME_WINDOWS_1251 = "windows-1251";
+ public static final String MIMENAME_WINDOWS_1252 = "windows-1252";
+ public static final String MIMENAME_WINDOWS_1253 = "windows-1253";
+ public static final String MIMENAME_WINDOWS_1254 = "windows-1254";
+ public static final String MIMENAME_WINDOWS_1255 = "windows-1255";
+ public static final String MIMENAME_WINDOWS_1256 = "windows-1256";
+ public static final String MIMENAME_WINDOWS_1257 = "windows-1257";
+ public static final String MIMENAME_WINDOWS_1258 = "windows-1258";
+
public static final String DEFAULT_CHARSET_NAME = MIMENAME_UTF_8;
/**
@@ -116,6 +245,45 @@
MIMENAME_BIG5,
MIMENAME_UCS2,
MIMENAME_UTF_16,
+ MIMENAME_BIG5_HKSCS,
+ MIMENAME_BOCU_1,
+ MIMENAME_CESU_8,
+ MIMENAME_CP864,
+ MIMENAME_EUC_JP,
+ MIMENAME_EUC_KR,
+ MIMENAME_GB18030,
+ MIMENAME_GBK,
+ MIMENAME_HZ_GB_2312,
+ MIMENAME_GB_2312,
+ MIMENAME_ISO_2022_CN,
+ MIMENAME_ISO_2022_CN_EXT,
+ MIMENAME_ISO_2022_JP,
+ MIMENAME_ISO_2022_KR,
+ MIMENAME_ISO_8859_10,
+ MIMENAME_ISO_8859_13,
+ MIMENAME_ISO_8859_14,
+ MIMENAME_ISO_8859_15,
+ MIMENAME_ISO_8859_16,
+ MIMENAME_KOI8_R,
+ MIMENAME_KOI8_U,
+ MIMENAME_MACINTOSH,
+ MIMENAME_SCSU,
+ MIMENAME_TIS_620,
+ MIMENAME_UTF_16BE,
+ MIMENAME_UTF_16LE,
+ MIMENAME_UTF_32,
+ MIMENAME_UTF_32BE,
+ MIMENAME_UTF_32LE,
+ MIMENAME_UTF_7,
+ MIMENAME_WINDOWS_1250,
+ MIMENAME_WINDOWS_1251,
+ MIMENAME_WINDOWS_1252,
+ MIMENAME_WINDOWS_1253,
+ MIMENAME_WINDOWS_1254,
+ MIMENAME_WINDOWS_1255,
+ MIMENAME_WINDOWS_1256,
+ MIMENAME_WINDOWS_1257,
+ MIMENAME_WINDOWS_1258,
};
private static final HashMap<Integer, String> MIBENUM_TO_NAME_MAP;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 6723522..e520a02 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -7761,9 +7761,8 @@
*
* @hide
*/
- @SystemApi
public static final int DEFAULT_PREFERRED_NETWORK_MODE =
- RILConstants.DEFAULT_PREFERRED_NETWORK_MODE;
+ RILConstants.PREFERRED_NETWORK_MODE;
/**
* Get the preferred network type.
@@ -11290,14 +11289,6 @@
*/
public static final int INDICATION_UPDATE_MODE_IGNORE_SCREEN_OFF = 2;
- /** @hide */
- @IntDef(prefix = { "INDICATION_UPDATE_MODE_" }, value = {
- INDICATION_UPDATE_MODE_NORMAL,
- INDICATION_UPDATE_MODE_IGNORE_SCREEN_OFF
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface IndicationUpdateMode{}
-
/**
* The indication for signal strength update.
* @hide
@@ -11328,51 +11319,6 @@
*/
public static final int INDICATION_FILTER_PHYSICAL_CHANNEL_CONFIG = 0x10;
- /** @hide */
- @IntDef(flag = true, prefix = { "INDICATION_FILTER_" }, value = {
- INDICATION_FILTER_SIGNAL_STRENGTH,
- INDICATION_FILTER_FULL_NETWORK_STATE,
- INDICATION_FILTER_DATA_CALL_DORMANCY_CHANGED,
- INDICATION_FILTER_LINK_CAPACITY_ESTIMATE,
- INDICATION_FILTER_PHYSICAL_CHANNEL_CONFIG
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface IndicationFilters{}
-
- /**
- * Sets radio indication update mode. This can be used to control the behavior of indication
- * update from modem to Android frameworks. For example, by default several indication updates
- * are turned off when screen is off, but in some special cases (e.g. carkit is connected but
- * screen is off) we want to turn on those indications even when the screen is off.
- *
- * <p>Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- *
- * @param filters Indication filters. Should be a bitmask of INDICATION_FILTER_XXX.
- * @see #INDICATION_FILTER_SIGNAL_STRENGTH
- * @see #INDICATION_FILTER_FULL_NETWORK_STATE
- * @see #INDICATION_FILTER_DATA_CALL_DORMANCY_CHANGED
- * @param updateMode The voice activation state
- * @see #INDICATION_UPDATE_MODE_NORMAL
- * @see #INDICATION_UPDATE_MODE_IGNORE_SCREEN_OFF
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void setRadioIndicationUpdateMode(@IndicationFilters int filters,
- @IndicationUpdateMode int updateMode) {
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null) {
- telephony.setRadioIndicationUpdateMode(getSubId(), filters, updateMode);
- }
- } catch (RemoteException ex) {
- // This could happen if binder process crashes.
- if (!isSystemProcess()) {
- ex.rethrowAsRuntimeException();
- }
- }
- }
-
/**
* A test API to override carrier information including mccmnc, imsi, iccid, gid1, gid2,
* plmn and spn. This would be handy for, eg, forcing a particular carrier id, carrier's config
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index beb3c8c..168c8b6 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1827,14 +1827,6 @@
boolean switchSlots(in int[] physicalSlots);
/**
- * Sets radio indication update mode. This can be used to control the behavior of indication
- * update from modem to Android frameworks. For example, by default several indication updates
- * are turned off when screen is off, but in some special cases (e.g. carkit is connected but
- * screen is off) we want to turn on those indications even when the screen is off.
- */
- void setRadioIndicationUpdateMode(int subId, int filters, int mode);
-
- /**
* Returns whether mobile data roaming is enabled on the subscription with id {@code subId}.
*
* @param subId the subscription id
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 9ac8cb1..c40573b 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -233,14 +233,11 @@
/** NR 5G, LTE, TD-SCDMA, CDMA, EVDO, GSM and WCDMA */
int NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 33;
- /** Default preferred network mode */
- int DEFAULT_PREFERRED_NETWORK_MODE = NETWORK_MODE_WCDMA_PREF;
-
@UnsupportedAppUsage
int PREFERRED_NETWORK_MODE = Optional.of(TelephonyProperties.default_network())
.filter(list -> !list.isEmpty())
.map(list -> list.get(0))
- .orElse(DEFAULT_PREFERRED_NETWORK_MODE);
+ .orElse(NETWORK_MODE_WCDMA_PREF);
int BAND_MODE_UNSPECIFIED = 0; //"unspecified" (selected by baseband automatically)
int BAND_MODE_EURO = 1; //"EURO band" (GSM-900 / DCS-1800 / WCDMA-IMT-2000)
diff --git a/tests/BlobStoreTestUtils/Android.bp b/tests/BlobStoreTestUtils/Android.bp
new file mode 100644
index 0000000..edd2b43
--- /dev/null
+++ b/tests/BlobStoreTestUtils/Android.bp
@@ -0,0 +1,20 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_library {
+ name: "BlobStoreTestUtils",
+ srcs: ["src/**/*.java"],
+ static_libs: ["truth-prebuilt"],
+ platform_apis: true
+}
\ No newline at end of file
diff --git a/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java b/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java
new file mode 100644
index 0000000..f96766a
--- /dev/null
+++ b/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java
@@ -0,0 +1,227 @@
+/*
+ * 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.utils.blob;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.blob.BlobHandle;
+import android.app.blob.BlobStoreManager;
+import android.content.Context;
+import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.nio.file.Files;
+import java.security.MessageDigest;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+
+public class DummyBlobData {
+ private static final long DEFAULT_SIZE_BYTES = 10 * 1024L * 1024L;
+ private static final int BUFFER_SIZE_BYTES = 16 * 1024;
+
+ private final Context mContext;
+ private final Random mRandom;
+ private final File mFile;
+ private final long mFileSize;
+ private final String mLabel;
+
+ byte[] mFileDigest;
+ long mExpiryTimeMs;
+
+ public DummyBlobData(Context context) {
+ this(context, new Random(0), "blob_" + System.nanoTime());
+ }
+
+ public DummyBlobData(Context context, long fileSize) {
+ this(context, fileSize, new Random(0), "blob_" + System.nanoTime(), "Test label");
+ }
+
+ public DummyBlobData(Context context, Random random, String fileName) {
+ this(context, DEFAULT_SIZE_BYTES, random, fileName, "Test label");
+ }
+
+ public DummyBlobData(Context context, Random random, String fileName, String label) {
+ this(context, DEFAULT_SIZE_BYTES, random, fileName, label);
+ }
+
+ public DummyBlobData(Context context, long fileSize, Random random, String fileName,
+ String label) {
+ mContext = context;
+ mRandom = random;
+ mFile = new File(mContext.getFilesDir(), fileName);
+ mFileSize = fileSize;
+ mLabel = label;
+ }
+
+ public void prepare() throws Exception {
+ try (RandomAccessFile file = new RandomAccessFile(mFile, "rw")) {
+ writeRandomData(file, mFileSize);
+ }
+ mFileDigest = FileUtils.digest(mFile, "SHA-256");
+ mExpiryTimeMs = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1);
+ }
+
+ public BlobHandle getBlobHandle() throws Exception {
+ return BlobHandle.createWithSha256(createSha256Digest(mFile), mLabel,
+ mExpiryTimeMs, "test_tag");
+ }
+
+ public long getFileSize() throws Exception {
+ return mFileSize;
+ }
+
+ public long getExpiryTimeMillis() {
+ return mExpiryTimeMs;
+ }
+
+ public void delete() {
+ mFile.delete();
+ }
+
+ public void writeToSession(BlobStoreManager.Session session) throws Exception {
+ writeToSession(session, 0, mFileSize);
+ }
+
+ public void writeToSession(BlobStoreManager.Session session,
+ long offsetBytes, long lengthBytes) throws Exception {
+ try (FileInputStream in = new FileInputStream(mFile)) {
+ in.getChannel().position(offsetBytes);
+ try (FileOutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(
+ session.openWrite(offsetBytes, lengthBytes))) {
+ copy(in, out, lengthBytes);
+ }
+ }
+ }
+
+ public void writeToFd(FileDescriptor fd, long offsetBytes, long lengthBytes) throws Exception {
+ try (FileInputStream in = new FileInputStream(mFile)) {
+ in.getChannel().position(offsetBytes);
+ try (FileOutputStream out = new FileOutputStream(fd)) {
+ copy(in, out, lengthBytes);
+ }
+ }
+ }
+
+ private void copy(InputStream in, OutputStream out, long lengthBytes) throws Exception {
+ final byte[] buffer = new byte[BUFFER_SIZE_BYTES];
+ long bytesWrittern = 0;
+ while (bytesWrittern < lengthBytes) {
+ final int toWrite = (bytesWrittern + buffer.length <= lengthBytes)
+ ? buffer.length : (int) (lengthBytes - bytesWrittern);
+ in.read(buffer, 0, toWrite);
+ out.write(buffer, 0, toWrite);
+ bytesWrittern += toWrite;
+ }
+ }
+
+ public void readFromSessionAndVerifyBytes(BlobStoreManager.Session session,
+ long offsetBytes, int lengthBytes) throws Exception {
+ final byte[] expectedBytes = new byte[lengthBytes];
+ try (FileInputStream in = new FileInputStream(mFile)) {
+ read(in, expectedBytes, offsetBytes, lengthBytes);
+ }
+
+ final byte[] actualBytes = new byte[lengthBytes];
+ try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(
+ session.openWrite(0L, 0L))) {
+ read(in, actualBytes, offsetBytes, lengthBytes);
+ }
+
+ assertThat(actualBytes).isEqualTo(expectedBytes);
+
+ }
+
+ private void read(FileInputStream in, byte[] buffer,
+ long offsetBytes, int lengthBytes) throws Exception {
+ in.getChannel().position(offsetBytes);
+ in.read(buffer, 0, lengthBytes);
+ }
+
+ public void readFromSessionAndVerifyDigest(BlobStoreManager.Session session)
+ throws Exception {
+ readFromSessionAndVerifyDigest(session, 0, mFile.length());
+ }
+
+ public void readFromSessionAndVerifyDigest(BlobStoreManager.Session session,
+ long offsetBytes, long lengthBytes) throws Exception {
+ final byte[] actualDigest;
+ try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(
+ session.openWrite(0L, 0L))) {
+ actualDigest = createSha256Digest(in, offsetBytes, lengthBytes);
+ }
+
+ assertThat(actualDigest).isEqualTo(mFileDigest);
+ }
+
+ public void verifyBlob(ParcelFileDescriptor pfd) throws Exception {
+ final byte[] actualDigest;
+ try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
+ actualDigest = FileUtils.digest(in, "SHA-256");
+ }
+ assertThat(actualDigest).isEqualTo(mFileDigest);
+ }
+
+ private byte[] createSha256Digest(FileInputStream in, long offsetBytes, long lengthBytes)
+ throws Exception {
+ final MessageDigest digest = MessageDigest.getInstance("SHA-256");
+ in.getChannel().position(offsetBytes);
+ final byte[] buffer = new byte[BUFFER_SIZE_BYTES];
+ long bytesRead = 0;
+ while (bytesRead < lengthBytes) {
+ int toRead = (bytesRead + buffer.length <= lengthBytes)
+ ? buffer.length : (int) (lengthBytes - bytesRead);
+ toRead = in.read(buffer, 0, toRead);
+ digest.update(buffer, 0, toRead);
+ bytesRead += toRead;
+ }
+ return digest.digest();
+ }
+
+ private byte[] createSha256Digest(File file) throws Exception {
+ final MessageDigest digest = MessageDigest.getInstance("SHA-256");
+ try (BufferedInputStream in = new BufferedInputStream(
+ Files.newInputStream(file.toPath()))) {
+ final byte[] buffer = new byte[BUFFER_SIZE_BYTES];
+ int bytesRead;
+ while ((bytesRead = in.read(buffer)) > 0) {
+ digest.update(buffer, 0, bytesRead);
+ }
+ }
+ return digest.digest();
+ }
+
+ private void writeRandomData(RandomAccessFile file, long fileSize)
+ throws Exception {
+ long bytesWritten = 0;
+ final byte[] buffer = new byte[BUFFER_SIZE_BYTES];
+ while (bytesWritten < fileSize) {
+ mRandom.nextBytes(buffer);
+ final int toWrite = (bytesWritten + buffer.length <= fileSize)
+ ? buffer.length : (int) (fileSize - bytesWritten);
+ file.seek(bytesWritten);
+ file.write(buffer, 0, toWrite);
+ bytesWritten += toWrite;
+ }
+ }
+}
diff --git a/tests/PlatformCompatGating/Android.bp b/tests/PlatformCompatGating/Android.bp
index 5e9ef8e..74dfde8 100644
--- a/tests/PlatformCompatGating/Android.bp
+++ b/tests/PlatformCompatGating/Android.bp
@@ -18,14 +18,11 @@
name: "PlatformCompatGating",
// Only compile source java files in this apk.
srcs: ["src/**/*.java"],
- certificate: "platform",
- libs: [
- "android.test.runner",
- "android.test.base",
- ],
static_libs: [
"junit",
- "android-support-test",
+ "androidx.test.runner",
+ "androidx.test.core",
+ "androidx.test.ext.junit",
"mockito-target-minus-junit4",
"truth-prebuilt",
"platform-compat-test-rules"
diff --git a/tests/PlatformCompatGating/AndroidManifest.xml b/tests/PlatformCompatGating/AndroidManifest.xml
index 7f14b83..c24dc31 100644
--- a/tests/PlatformCompatGating/AndroidManifest.xml
+++ b/tests/PlatformCompatGating/AndroidManifest.xml
@@ -6,6 +6,6 @@
<uses-library android:name="android.test.runner" />
</application>
- <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.tests.gating"/>
</manifest>
diff --git a/tests/PlatformCompatGating/AndroidTest.xml b/tests/PlatformCompatGating/AndroidTest.xml
index c626848..0c7485b 100644
--- a/tests/PlatformCompatGating/AndroidTest.xml
+++ b/tests/PlatformCompatGating/AndroidTest.xml
@@ -24,7 +24,6 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.tests.gating"/>
- <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
<option name="hidden-api-checks" value="false"/>
</test>
</configuration>
diff --git a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatGatingTest.java b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatGatingTest.java
index dc317f19..c1ce0e9 100644
--- a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatGatingTest.java
+++ b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatGatingTest.java
@@ -18,8 +18,9 @@
import static com.google.common.truth.Truth.assertThat;
import android.compat.testing.PlatformCompatChangeRule;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compat.testing.DummyApi;
@@ -81,14 +82,14 @@
@Test
@EnableCompatChanges({DummyApi.CHANGE_SYSTEM_SERVER})
public void testDummyGatingPositiveSystemServer() {
- assertThat(
- DummyApi.dummySystemServer(InstrumentationRegistry.getTargetContext())).isTrue();
+ assertThat(DummyApi.dummySystemServer(
+ InstrumentationRegistry.getInstrumentation().getTargetContext())).isTrue();
}
@Test
@DisableCompatChanges({DummyApi.CHANGE_SYSTEM_SERVER})
public void testDummyGatingNegativeSystemServer() {
- assertThat(
- DummyApi.dummySystemServer(InstrumentationRegistry.getTargetContext())).isFalse();
+ assertThat(DummyApi.dummySystemServer(
+ InstrumentationRegistry.getInstrumentation().getTargetContext())).isFalse();
}
}
diff --git a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatPermissionsTest.java b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatPermissionsTest.java
new file mode 100644
index 0000000..9b9e581
--- /dev/null
+++ b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatPermissionsTest.java
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.gating;
+
+import static android.Manifest.permission.LOG_COMPAT_CHANGE;
+import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG;
+import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG;
+
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.compat.Compatibility.ChangeConfig;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Process;
+import android.os.ServiceManager;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.internal.compat.CompatibilityChangeConfig;
+import com.android.internal.compat.IPlatformCompat;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.HashSet;
+import java.util.Set;
+
+@RunWith(JUnit4.class)
+public final class PlatformCompatPermissionsTest {
+
+ // private Context mContext;
+ private IPlatformCompat mPlatformCompat;
+
+ @Rule
+ public final ExpectedException thrown = ExpectedException.none();
+ private Context mContext;
+ private UiAutomation mUiAutomation;
+ private PackageManager mPackageManager;
+
+ @Before
+ public void setUp() {
+ // mContext;
+ mPlatformCompat = IPlatformCompat.Stub
+ .asInterface(ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+ Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ mUiAutomation = instrumentation.getUiAutomation();
+ mContext = instrumentation.getTargetContext();
+
+ mPackageManager = mContext.getPackageManager();
+ }
+
+ @After
+ public void tearDown() {
+
+ mUiAutomation.dropShellPermissionIdentity();
+ }
+
+ @Test
+ public void reportChange_noLogCompatChangePermission_throwsSecurityException()
+ throws Throwable {
+ thrown.expect(SecurityException.class);
+ final String packageName = mContext.getPackageName();
+
+ mPlatformCompat.reportChange(1, mPackageManager.getApplicationInfo(packageName, 0));
+ }
+
+ @Test
+ public void reportChange_logCompatChangePermission_noThrow()
+ throws Throwable {
+ mUiAutomation.adoptShellPermissionIdentity(LOG_COMPAT_CHANGE);
+ final String packageName = mContext.getPackageName();
+
+ mPlatformCompat.reportChange(1, mPackageManager.getApplicationInfo(packageName, 0));
+ }
+
+ @Test
+ public void reportChangeByPackageName_noLogCompatChangePermission_throwsSecurityException()
+ throws Throwable {
+ thrown.expect(SecurityException.class);
+ final String packageName = mContext.getPackageName();
+
+ mPlatformCompat.reportChangeByPackageName(1, packageName, 0);
+ }
+
+ @Test
+ public void reportChangeByPackageName_logCompatChangePermission_noThrow()
+ throws Throwable {
+ mUiAutomation.adoptShellPermissionIdentity(LOG_COMPAT_CHANGE);
+ final String packageName = mContext.getPackageName();
+
+ mPlatformCompat.reportChangeByPackageName(1, packageName, 0);
+ }
+
+ @Test
+ public void reportChangeByUid_noLogCompatChangePermission_throwsSecurityException()
+ throws Throwable {
+ thrown.expect(SecurityException.class);
+
+ mPlatformCompat.reportChangeByUid(1, Process.myUid());
+ }
+
+ @Test
+ public void reportChangeByUid_logCompatChangePermission_noThrow()
+ throws Throwable {
+ mUiAutomation.adoptShellPermissionIdentity(LOG_COMPAT_CHANGE);
+
+ mPlatformCompat.reportChangeByUid(1, Process.myUid());
+ }
+
+ @Test
+ public void isChangeEnabled_noReadCompatConfigPermission_throwsSecurityException()
+ throws Throwable {
+ thrown.expect(SecurityException.class);
+ final String packageName = mContext.getPackageName();
+
+ mPlatformCompat.isChangeEnabled(1, mPackageManager.getApplicationInfo(packageName, 0));
+ }
+
+ @Test
+ public void isChangeEnabled_noLogCompatChangeConfigPermission_throwsSecurityException()
+ throws Throwable {
+ thrown.expect(SecurityException.class);
+ mUiAutomation.adoptShellPermissionIdentity(READ_COMPAT_CHANGE_CONFIG);
+ final String packageName = mContext.getPackageName();
+
+ mPlatformCompat.isChangeEnabled(1, mPackageManager.getApplicationInfo(packageName, 0));
+ }
+
+ @Test
+ public void isChangeEnabled_readAndLogCompatChangeConfigPermission_noThrow()
+ throws Throwable {
+ mUiAutomation.adoptShellPermissionIdentity(READ_COMPAT_CHANGE_CONFIG, LOG_COMPAT_CHANGE);
+ final String packageName = mContext.getPackageName();
+
+ mPlatformCompat.isChangeEnabled(1, mPackageManager.getApplicationInfo(packageName, 0));
+ }
+
+ @Test
+ public void isChangeEnabledByPackageName_noReadCompatConfigPermission_throwsSecurityException()
+ throws Throwable {
+ thrown.expect(SecurityException.class);
+ final String packageName = mContext.getPackageName();
+
+ mPlatformCompat.isChangeEnabledByPackageName(1, packageName, 0);
+ }
+
+ @Test
+ public void isChangeEnabledByPackageName_noLogompatConfigPermission_throwsSecurityException()
+ throws Throwable {
+ thrown.expect(SecurityException.class);
+ mUiAutomation.adoptShellPermissionIdentity(READ_COMPAT_CHANGE_CONFIG);
+ final String packageName = mContext.getPackageName();
+
+ mPlatformCompat.isChangeEnabledByPackageName(1, packageName, 0);
+ }
+
+ @Test
+ public void isChangeEnabledByPackageName_readAndLogCompatChangeConfigPermission_noThrow()
+ throws Throwable {
+ mUiAutomation.adoptShellPermissionIdentity(READ_COMPAT_CHANGE_CONFIG, LOG_COMPAT_CHANGE);
+ final String packageName = mContext.getPackageName();
+
+ mPlatformCompat.isChangeEnabledByPackageName(1, packageName, 0);
+ }
+
+ @Test
+ public void isChangeEnabledByUid_noReadCompatConfigPermission_throwsSecurityException()
+ throws Throwable {
+ thrown.expect(SecurityException.class);
+
+ mPlatformCompat.isChangeEnabledByUid(1, Process.myUid());
+ }
+
+ @Test
+ public void isChangeEnabledByUid_noLogCompatChangePermission_throwsSecurityException()
+ throws Throwable {
+ thrown.expect(SecurityException.class);
+ mUiAutomation.adoptShellPermissionIdentity(READ_COMPAT_CHANGE_CONFIG);
+
+ mPlatformCompat.isChangeEnabledByUid(1, Process.myUid());
+ }
+
+ @Test
+ public void isChangeEnabledByUid_readAndLogCompatChangeConfigPermission_noThrow()
+ throws Throwable {
+ mUiAutomation.adoptShellPermissionIdentity(READ_COMPAT_CHANGE_CONFIG, LOG_COMPAT_CHANGE);
+
+ mPlatformCompat.isChangeEnabledByUid(1, Process.myUid());
+ }
+
+ @Test
+ public void setOverrides_noOverridesPermission_throwsSecurityException()
+ throws Throwable {
+ thrown.expect(SecurityException.class);
+ Set<Long> enabled = new HashSet<>();
+ Set<Long> disabled = new HashSet<>();
+ ChangeConfig changeConfig = new ChangeConfig(enabled, disabled);
+ CompatibilityChangeConfig compatibilityChangeConfig =
+ new CompatibilityChangeConfig(changeConfig);
+
+ mPlatformCompat.setOverrides(compatibilityChangeConfig, "foo.bar");
+ }
+ @Test
+ public void setOverrides_overridesPermission_noThrow()
+ throws Throwable {
+ mUiAutomation.adoptShellPermissionIdentity(OVERRIDE_COMPAT_CHANGE_CONFIG);
+ Set<Long> enabled = new HashSet<>();
+ Set<Long> disabled = new HashSet<>();
+ ChangeConfig changeConfig = new ChangeConfig(enabled, disabled);
+ CompatibilityChangeConfig compatibilityChangeConfig =
+ new CompatibilityChangeConfig(changeConfig);
+
+ mPlatformCompat.setOverrides(compatibilityChangeConfig, "foo.bar");
+ }
+
+ @Test
+ public void setOverridesForTest_noOverridesPermission_throwsSecurityException()
+ throws Throwable {
+ thrown.expect(SecurityException.class);
+ Set<Long> enabled = new HashSet<>();
+ Set<Long> disabled = new HashSet<>();
+ ChangeConfig changeConfig = new ChangeConfig(enabled, disabled);
+ CompatibilityChangeConfig compatibilityChangeConfig =
+ new CompatibilityChangeConfig(changeConfig);
+
+ mPlatformCompat.setOverridesForTest(compatibilityChangeConfig, "foo.bar");
+ }
+ @Test
+ public void setOverridesForTest_overridesPermission_noThrow()
+ throws Throwable {
+ mUiAutomation.adoptShellPermissionIdentity(OVERRIDE_COMPAT_CHANGE_CONFIG);
+ Set<Long> enabled = new HashSet<>();
+ Set<Long> disabled = new HashSet<>();
+ ChangeConfig changeConfig = new ChangeConfig(enabled, disabled);
+ CompatibilityChangeConfig compatibilityChangeConfig =
+ new CompatibilityChangeConfig(changeConfig);
+
+ mPlatformCompat.setOverridesForTest(compatibilityChangeConfig, "foo.bar");
+ }
+
+ @Test
+ public void clearOverrides_noOverridesPermission_throwsSecurityException()
+ throws Throwable {
+ thrown.expect(SecurityException.class);
+
+ mPlatformCompat.clearOverrides("foo.bar");
+ }
+ @Test
+ public void clearOverrides_overridesPermission_noThrow()
+ throws Throwable {
+ mUiAutomation.adoptShellPermissionIdentity(OVERRIDE_COMPAT_CHANGE_CONFIG);
+
+ mPlatformCompat.clearOverrides("foo.bar");
+ }
+
+ @Test
+ public void clearOverridesForTest_noOverridesPermission_throwsSecurityException()
+ throws Throwable {
+ thrown.expect(SecurityException.class);
+
+ mPlatformCompat.clearOverridesForTest("foo.bar");
+ }
+ @Test
+ public void clearOverridesForTest_overridesPermission_noThrow()
+ throws Throwable {
+ mUiAutomation.adoptShellPermissionIdentity(OVERRIDE_COMPAT_CHANGE_CONFIG);
+
+ mPlatformCompat.clearOverridesForTest("foo.bar");
+ }
+
+ @Test
+ public void clearOverride_noOverridesPermission_throwsSecurityException()
+ throws Throwable {
+ thrown.expect(SecurityException.class);
+
+ mPlatformCompat.clearOverride(1, "foo.bar");
+ }
+ @Test
+ public void clearOverride_overridesPermission_noThrow()
+ throws Throwable {
+ mUiAutomation.adoptShellPermissionIdentity(OVERRIDE_COMPAT_CHANGE_CONFIG);
+
+ mPlatformCompat.clearOverride(1, "foo.bar");
+ }
+
+ @Test
+ public void listAllChanges_noReadCompatConfigPermission_throwsSecurityException()
+ throws Throwable {
+ thrown.expect(SecurityException.class);
+
+ mPlatformCompat.listAllChanges();
+ }
+ @Test
+ public void listAllChanges_readCompatConfigPermission_noThrow()
+ throws Throwable {
+ mUiAutomation.adoptShellPermissionIdentity(READ_COMPAT_CHANGE_CONFIG);
+
+ mPlatformCompat.listAllChanges();
+ }
+}
diff --git a/tests/PlatformCompatGating/test-rules/Android.bp b/tests/PlatformCompatGating/test-rules/Android.bp
index 8211ef5..10fa2dc 100644
--- a/tests/PlatformCompatGating/test-rules/Android.bp
+++ b/tests/PlatformCompatGating/test-rules/Android.bp
@@ -19,7 +19,7 @@
srcs: ["src/**/*.java"],
static_libs: [
"junit",
- "android-support-test",
+ "androidx.test.core",
"truth-prebuilt",
"core-compat-test-rules"
],
diff --git a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
index 932ec64..d6846fa 100644
--- a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
+++ b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
@@ -16,13 +16,17 @@
package android.compat.testing;
+import android.Manifest;
import android.app.Instrumentation;
+import android.app.UiAutomation;
import android.compat.Compatibility;
import android.compat.Compatibility.ChangeConfig;
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.support.test.InstrumentationRegistry;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
import com.android.internal.compat.CompatibilityChangeConfig;
import com.android.internal.compat.IPlatformCompat;
@@ -83,12 +87,17 @@
@Override
public void evaluate() throws Throwable {
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ UiAutomation uiAutomation = instrumentation.getUiAutomation();
String packageName = instrumentation.getTargetContext().getPackageName();
IPlatformCompat platformCompat = IPlatformCompat.Stub
.asInterface(ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
if (platformCompat == null) {
throw new IllegalStateException("Could not get IPlatformCompat service!");
}
+ uiAutomation.adoptShellPermissionIdentity(
+ Manifest.permission.LOG_COMPAT_CHANGE,
+ Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG,
+ Manifest.permission.READ_COMPAT_CHANGE_CONFIG);
Compatibility.setOverrides(mConfig);
try {
platformCompat.setOverridesForTest(new CompatibilityChangeConfig(mConfig),
@@ -101,6 +110,7 @@
} catch (RemoteException e) {
throw new RuntimeException("Could not call IPlatformCompat binder method!", e);
} finally {
+ uiAutomation.dropShellPermissionIdentity();
Compatibility.clearOverrides();
}
}
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 82a524b..032f182 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -23,6 +23,8 @@
import static org.testng.Assert.assertThrows;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.device.LogcatReceiver;
+import com.android.tradefed.result.InputStreamSource;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
@@ -31,11 +33,18 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* Runs the staged rollback tests.
+ *
+ * TODO(gavincorkery): Support the verification of logging parents in Watchdog metrics.
*/
@RunWith(DeviceJUnit4ClassRunner.class)
public class StagedRollbackTest extends BaseHostJUnit4Test {
@@ -54,6 +63,7 @@
}
private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
+ private static final String TESTAPP_A = "com.android.cts.install.lib.testapp.A";
private static final String TEST_SUBDIR = "/subdir/";
@@ -66,8 +76,19 @@
private static final String TEST_FILENAME_4 = "one_more.test";
private static final String TEST_STRING_4 = "once more unto the test";
+ private static final String REASON_APP_CRASH = "REASON_APP_CRASH";
+ private static final String REASON_NATIVE_CRASH = "REASON_NATIVE_CRASH";
+ private static final String REASON_EXPLICIT_HEALTH_CHECK = "REASON_EXPLICIT_HEALTH_CHECK";
+
+ private static final String ROLLBACK_INITIATE = "ROLLBACK_INITIATE";
+ private static final String ROLLBACK_BOOT_TRIGGERED = "ROLLBACK_BOOT_TRIGGERED";
+
+ private LogcatReceiver mReceiver;
+
@Before
public void setUp() throws Exception {
+ mReceiver = new LogcatReceiver(getDevice(), "logcat -s WatchdogRollbackLogger",
+ getDevice().getOptions().getMaxLogcatDataSize(), 0);
if (!getDevice().isAdbRoot()) {
getDevice().enableAdbRoot();
}
@@ -77,10 +98,13 @@
+ "/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex");
getDevice().reboot();
runPhase("testCleanUp");
+ mReceiver.start();
}
@After
public void tearDown() throws Exception {
+ mReceiver.stop();
+ mReceiver.clear();
runPhase("testCleanUp");
if (!getDevice().isAdbRoot()) {
@@ -110,6 +134,16 @@
getDevice().waitForDeviceAvailable();
runPhase("testBadApkOnly_Phase4");
+ InputStreamSource logcatStream = mReceiver.getLogcatData();
+ try {
+ List<String> watchdogEvents = getWatchdogLoggingEvents(logcatStream);
+ assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
+ REASON_APP_CRASH, TESTAPP_A));
+ assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
+ null, null));
+ } finally {
+ logcatStream.close();
+ }
}
@Test
@@ -137,6 +171,16 @@
// verify rollback committed
runPhase("testNativeWatchdogTriggersRollback_Phase3");
+ InputStreamSource logcatStream = mReceiver.getLogcatData();
+ try {
+ List<String> watchdogEvents = getWatchdogLoggingEvents(logcatStream);
+ assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
+ REASON_NATIVE_CRASH, null));
+ assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
+ null, null));
+ } finally {
+ logcatStream.close();
+ }
}
@Test
@@ -171,6 +215,16 @@
// verify all available rollbacks have been committed
runPhase("testNativeWatchdogTriggersRollbackForAll_Phase4");
+ InputStreamSource logcatStream = mReceiver.getLogcatData();
+ try {
+ List<String> watchdogEvents = getWatchdogLoggingEvents(logcatStream);
+ assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
+ REASON_NATIVE_CRASH, null));
+ assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
+ null, null));
+ } finally {
+ logcatStream.close();
+ }
}
/**
@@ -194,6 +248,16 @@
getDevice().waitForDeviceAvailable();
// Verify rollback was executed after health check deadline
runPhase("testNetworkFailedRollback_Phase4");
+ InputStreamSource logcatStream = mReceiver.getLogcatData();
+ try {
+ List<String> watchdogEvents = getWatchdogLoggingEvents(logcatStream);
+ assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
+ REASON_EXPLICIT_HEALTH_CHECK, null));
+ assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
+ null, null));
+ } finally {
+ logcatStream.close();
+ }
} finally {
// Reconnect internet again so we won't break tests which assume internet available
getDevice().executeShellCommand("svc wifi enable");
@@ -223,6 +287,15 @@
// Verify rollback was not executed after health check deadline
runPhase("testNetworkPassedDoesNotRollback_Phase3");
+ InputStreamSource logcatStream = mReceiver.getLogcatData();
+ try {
+ List<String> watchdogEvents = getWatchdogLoggingEvents(logcatStream);
+ assertEquals(watchdogEventOccurred(watchdogEvents, null, null,
+ REASON_EXPLICIT_HEALTH_CHECK, null), false);
+ } finally {
+ logcatStream.close();
+ }
+
}
/**
@@ -288,6 +361,16 @@
getDevice().waitForDeviceAvailable();
// Verify rollback occurred due to crash of apk-in-apex
runPhase("testRollbackApexWithApkCrashing_Phase3");
+ InputStreamSource logcatStream = mReceiver.getLogcatData();
+ try {
+ List<String> watchdogEvents = getWatchdogLoggingEvents(logcatStream);
+ assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
+ REASON_APP_CRASH, TESTAPP_A));
+ assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
+ null, null));
+ } finally {
+ logcatStream.close();
+ }
}
/**
@@ -457,4 +540,57 @@
return false;
}
}
+
+ /**
+ * Returns a list of all Watchdog logging events which have occurred.
+ */
+ private List<String> getWatchdogLoggingEvents(InputStreamSource inputStreamSource)
+ throws Exception {
+ List<String> watchdogEvents = new ArrayList<>();
+ InputStream inputStream = inputStreamSource.createInputStream();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ if (line.contains("Watchdog event occurred")) {
+ watchdogEvents.add(line);
+ }
+ }
+ return watchdogEvents;
+ }
+
+ /**
+ * Returns whether a Watchdog event has occurred that matches the given criteria.
+ *
+ * Check the value of all non-null parameters against the list of Watchdog events that have
+ * occurred, and return {@code true} if an event exists which matches all criteria.
+ */
+ private boolean watchdogEventOccurred(List<String> loggingEvents,
+ String type, String logPackage,
+ String rollbackReason, String failedPackageName) throws Exception {
+ List<String> eventCriteria = new ArrayList<>();
+ if (type != null) {
+ eventCriteria.add("type: " + type);
+ }
+ if (logPackage != null) {
+ eventCriteria.add("logPackage: " + logPackage);
+ }
+ if (rollbackReason != null) {
+ eventCriteria.add("rollbackReason: " + rollbackReason);
+ }
+ if (failedPackageName != null) {
+ eventCriteria.add("failedPackageName: " + failedPackageName);
+ }
+ for (String loggingEvent: loggingEvents) {
+ boolean matchesCriteria = true;
+ for (String criterion: eventCriteria) {
+ if (!loggingEvent.contains(criterion)) {
+ matchesCriteria = false;
+ }
+ }
+ if (matchesCriteria) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
index 8f3cb34..bdfaaa8 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
@@ -45,7 +45,7 @@
final WindowContainerTransaction wct = new WindowContainerTransaction();
wct.scheduleFinishEnterPip(ti.token, new Rect(0, 0, PIP_WIDTH, PIP_HEIGHT));
try {
- ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct);
+ ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct, null);
} catch (Exception e) {
}
}
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 3e4f3d8..efea91a 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -272,10 +272,24 @@
netCap.setOwnerUid(123);
assertParcelingIsLossless(netCap);
netCap.setSSID(TEST_SSID);
- assertParcelSane(netCap, 13);
+ assertParcelSane(netCap, 15);
}
@Test
+ public void testParcelNetworkCapabilitiesWithRequestorUidAndPackageName() {
+ final NetworkCapabilities netCap = new NetworkCapabilities()
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .setRequestorUid(9304)
+ .setRequestorPackageName("com.android.test")
+ .addCapability(NET_CAPABILITY_EIMS)
+ .addCapability(NET_CAPABILITY_NOT_METERED);
+ assertParcelingIsLossless(netCap);
+ netCap.setSSID(TEST_SSID);
+ assertParcelSane(netCap, 15);
+ }
+
+
+ @Test
public void testOemPaid() {
NetworkCapabilities nc = new NetworkCapabilities();
// By default OEM_PAID is neither in the unwanted or required lists and the network is not
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index 7ede144..d6bf334 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -212,7 +212,8 @@
ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
// register callback
- when(mService.requestNetwork(any(), captor.capture(), anyInt(), any(), anyInt()))
+ when(mService.requestNetwork(
+ any(), captor.capture(), anyInt(), any(), anyInt(), any()))
.thenReturn(request);
manager.requestNetwork(request, callback, handler);
@@ -240,7 +241,8 @@
ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
// register callback
- when(mService.requestNetwork(any(), captor.capture(), anyInt(), any(), anyInt()))
+ when(mService.requestNetwork(
+ any(), captor.capture(), anyInt(), any(), anyInt(), any()))
.thenReturn(req1);
manager.requestNetwork(req1, callback, handler);
@@ -258,7 +260,8 @@
verify(callback, timeout(100).times(0)).onLosing(any(), anyInt());
// callback can be registered again
- when(mService.requestNetwork(any(), captor.capture(), anyInt(), any(), anyInt()))
+ when(mService.requestNetwork(
+ any(), captor.capture(), anyInt(), any(), anyInt(), any()))
.thenReturn(req2);
manager.requestNetwork(req2, callback, handler);
@@ -282,7 +285,8 @@
info.targetSdkVersion = VERSION_CODES.N_MR1 + 1;
when(mCtx.getApplicationInfo()).thenReturn(info);
- when(mService.requestNetwork(any(), any(), anyInt(), any(), anyInt())).thenReturn(request);
+ when(mService.requestNetwork(any(), any(), anyInt(), any(), anyInt(), any()))
+ .thenReturn(request);
Handler handler = new Handler(Looper.getMainLooper());
manager.requestNetwork(request, callback, handler);
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index b4f32e7..968f552 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -107,6 +107,7 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -305,6 +306,7 @@
private static final String MOBILE_IFNAME = "test_rmnet_data0";
private static final String WIFI_IFNAME = "test_wlan0";
private static final String WIFI_WOL_IFNAME = "test_wlan_wol";
+ private static final String TEST_PACKAGE_NAME = "com.android.test.package";
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private MockContext mServiceContext;
@@ -654,7 +656,7 @@
if (mNmValidationRedirectUrl != null) {
mNmCallbacks.showProvisioningNotification(
- "test_provisioning_notif_action", "com.android.test.package");
+ "test_provisioning_notif_action", TEST_PACKAGE_NAME);
mNmProvNotificationRequested = true;
}
}
@@ -2972,7 +2974,7 @@
networkCapabilities.addTransportType(TRANSPORT_WIFI)
.setNetworkSpecifier(new MatchAllNetworkSpecifier());
mService.requestNetwork(networkCapabilities, null, 0, null,
- ConnectivityManager.TYPE_WIFI);
+ ConnectivityManager.TYPE_WIFI, TEST_PACKAGE_NAME);
});
class NonParcelableSpecifier extends NetworkSpecifier {
@@ -3011,31 +3013,12 @@
}
@Test
- public void testNetworkSpecifierUidSpoofSecurityException() throws Exception {
- class UidAwareNetworkSpecifier extends NetworkSpecifier implements Parcelable {
- @Override
- public boolean satisfiedBy(NetworkSpecifier other) {
- return true;
- }
-
- @Override
- public void assertValidFromUid(int requestorUid) {
- throw new SecurityException("failure");
- }
-
- @Override
- public int describeContents() { return 0; }
- @Override
- public void writeToParcel(Parcel dest, int flags) {}
- }
-
+ public void testNetworkRequestUidSpoofSecurityException() throws Exception {
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
-
- UidAwareNetworkSpecifier networkSpecifier = new UidAwareNetworkSpecifier();
- NetworkRequest networkRequest = newWifiRequestBuilder().setNetworkSpecifier(
- networkSpecifier).build();
+ NetworkRequest networkRequest = newWifiRequestBuilder().build();
TestNetworkCallback networkCallback = new TestNetworkCallback();
+ doThrow(new SecurityException()).when(mAppOpsManager).checkPackage(anyInt(), anyString());
assertThrows(SecurityException.class, () -> {
mCm.requestNetwork(networkRequest, networkCallback);
});
@@ -6446,14 +6429,16 @@
public void testRegisterUnregisterConnectivityDiagnosticsCallback() throws Exception {
final NetworkRequest wifiRequest =
new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI).build();
-
when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
mService.registerConnectivityDiagnosticsCallback(
mConnectivityDiagnosticsCallback, wifiRequest, mContext.getPackageName());
- verify(mIBinder, timeout(TIMEOUT_MS))
- .linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
+ // Block until all other events are done processing.
+ HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
+
+ verify(mIBinder).linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
+ verify(mConnectivityDiagnosticsCallback).asBinder();
assertTrue(
mService.mConnectivityDiagnosticsCallbacks.containsKey(
mConnectivityDiagnosticsCallback));
@@ -6476,8 +6461,10 @@
mService.registerConnectivityDiagnosticsCallback(
mConnectivityDiagnosticsCallback, wifiRequest, mContext.getPackageName());
- verify(mIBinder, timeout(TIMEOUT_MS))
- .linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
+ // Block until all other events are done processing.
+ HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
+
+ verify(mIBinder).linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
verify(mConnectivityDiagnosticsCallback).asBinder();
assertTrue(
mService.mConnectivityDiagnosticsCallbacks.containsKey(
@@ -6635,8 +6622,11 @@
public void testConnectivityDiagnosticsCallbackOnConnectivityReport() throws Exception {
setUpConnectivityDiagnosticsCallback();
- // Wait for onConnectivityReport to fire
- verify(mConnectivityDiagnosticsCallback, timeout(TIMEOUT_MS))
+ // Block until all other events are done processing.
+ HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
+
+ // Verify onConnectivityReport fired
+ verify(mConnectivityDiagnosticsCallback)
.onConnectivityReport(any(ConnectivityReport.class));
}
@@ -6648,9 +6638,11 @@
// cellular network agent
mCellNetworkAgent.notifyDataStallSuspected();
- // Wait for onDataStallSuspected to fire
- verify(mConnectivityDiagnosticsCallback, timeout(TIMEOUT_MS))
- .onDataStallSuspected(any(DataStallReport.class));
+ // Block until all other events are done processing.
+ HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
+
+ // Verify onDataStallSuspected fired
+ verify(mConnectivityDiagnosticsCallback).onDataStallSuspected(any(DataStallReport.class));
}
@Test
@@ -6661,15 +6653,21 @@
final boolean hasConnectivity = true;
mService.reportNetworkConnectivity(n, hasConnectivity);
- // Wait for onNetworkConnectivityReported to fire
- verify(mConnectivityDiagnosticsCallback, timeout(TIMEOUT_MS))
+ // Block until all other events are done processing.
+ HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
+
+ // Verify onNetworkConnectivityReported fired
+ verify(mConnectivityDiagnosticsCallback)
.onNetworkConnectivityReported(eq(n), eq(hasConnectivity));
final boolean noConnectivity = false;
mService.reportNetworkConnectivity(n, noConnectivity);
+ // Block until all other events are done processing.
+ HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
+
// Wait for onNetworkConnectivityReported to fire
- verify(mConnectivityDiagnosticsCallback, timeout(TIMEOUT_MS))
+ verify(mConnectivityDiagnosticsCallback)
.onNetworkConnectivityReported(eq(n), eq(noConnectivity));
}
}
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index d3958a6..a251c05 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -30,7 +30,7 @@
"utils.cpp",
],
cflags: [
- "-DSTATS_SCHEMA_LEGACY",
+ //"-DSTATS_SCHEMA_LEGACY",
"-Wall",
"-Werror",
],
diff --git a/tools/stats_log_api_gen/java_writer_q.cpp b/tools/stats_log_api_gen/java_writer_q.cpp
index a68c3a2..12c050d 100644
--- a/tools/stats_log_api_gen/java_writer_q.cpp
+++ b/tools/stats_log_api_gen/java_writer_q.cpp
@@ -175,9 +175,7 @@
indent.c_str());
fprintf(out,
"%s android.util.SparseArray<Float> floatMap = null;\n", indent.c_str());
- fprintf(out,
- "%s int keyValuePairSize = LIST_TYPE_OVERHEAD * 5;\n",
- indent.c_str());
+ fprintf(out, "%s int keyValuePairSize = LIST_TYPE_OVERHEAD;\n", indent.c_str());
fprintf(out,
"%s for (int i = 0; i < count; i++) {\n", indent.c_str());
fprintf(out,
@@ -360,8 +358,9 @@
requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT;
requiredHelpers |= JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS;
fprintf(out,
- "%s writeKeyValuePairs(buff, pos, intMap, longMap, stringMap, "
- "floatMap);\n", indent.c_str());
+ "%s writeKeyValuePairs(buff, pos, (byte) count, intMap, longMap, "
+ "stringMap, floatMap);\n",
+ indent.c_str());
fprintf(out, "%s pos += keyValuePairSize;\n", indent.c_str());
break;
default:
@@ -472,7 +471,8 @@
}
if (requiredHelpers & JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS) {
- fprintf(out, "%sprivate static void writeKeyValuePairs(byte[] buff, int pos,\n",
+ fprintf(out,
+ "%sprivate static void writeKeyValuePairs(byte[] buff, int pos, byte numPairs,\n",
indent.c_str());
fprintf(out, "%s final android.util.SparseIntArray intMap,\n", indent.c_str());
fprintf(out, "%s final android.util.SparseLongArray longMap,\n", indent.c_str());
@@ -483,15 +483,12 @@
// Start list of lists.
fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
- fprintf(out, "%s buff[pos + 1] = (byte) 4;\n", indent.c_str());
+ fprintf(out, "%s buff[pos + 1] = (byte) numPairs;\n", indent.c_str());
fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
// Write integers.
fprintf(out, "%s final int intMapSize = null == intMap ? 0 : intMap.size();\n",
indent.c_str());
- fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
- fprintf(out, "%s buff[pos + 1] = (byte) intMapSize;\n", indent.c_str());
- fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
fprintf(out, "%s for (int i = 0; i < intMapSize; i++) {\n", indent.c_str());
fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
fprintf(out, "%s buff[pos + 1] = (byte) 2;\n", indent.c_str());
@@ -509,9 +506,6 @@
// Write longs.
fprintf(out, "%s final int longMapSize = null == longMap ? 0 : longMap.size();\n",
indent.c_str());
- fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
- fprintf(out, "%s buff[pos + 1] = (byte) longMapSize;\n", indent.c_str());
- fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
fprintf(out, "%s for (int i = 0; i < longMapSize; i++) {\n", indent.c_str());
fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
fprintf(out, "%s buff[pos + 1] = (byte) 2;\n", indent.c_str());
@@ -529,9 +523,6 @@
// Write Strings.
fprintf(out, "%s final int stringMapSize = null == stringMap ? 0 : stringMap.size();\n",
indent.c_str());
- fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
- fprintf(out, "%s buff[pos + 1] = (byte) stringMapSize;\n", indent.c_str());
- fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
fprintf(out, "%s for (int i = 0; i < stringMapSize; i++) {\n", indent.c_str());
fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
fprintf(out, "%s buff[pos + 1] = (byte) 2;\n", indent.c_str());
@@ -556,9 +547,6 @@
// Write floats.
fprintf(out, "%s final int floatMapSize = null == floatMap ? 0 : floatMap.size();\n",
indent.c_str());
- fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
- fprintf(out, "%s buff[pos + 1] = (byte) floatMapSize;\n", indent.c_str());
- fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
fprintf(out, "%s for (int i = 0; i < floatMapSize; i++) {\n", indent.c_str());
fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
fprintf(out, "%s buff[pos + 1] = (byte) 2;\n", indent.c_str());
diff --git a/tools/streaming_proto/cpp/main.cpp b/tools/streaming_proto/cpp/main.cpp
index d6b9d81..fe9a438 100644
--- a/tools/streaming_proto/cpp/main.cpp
+++ b/tools/streaming_proto/cpp/main.cpp
@@ -33,13 +33,13 @@
if (GENERATE_MAPPING) {
string name = make_constant_name(enu.name());
string prefix = name + "_";
- text << indent << "const int _ENUM_" << name << "_COUNT = " << N << ";" << endl;
- text << indent << "const char* _ENUM_" << name << "_NAMES[" << N << "] = {" << endl;
+ text << indent << "static const int _ENUM_" << name << "_COUNT = " << N << ";" << endl;
+ text << indent << "static const char* _ENUM_" << name << "_NAMES[" << N << "] = {" << endl;
for (int i=0; i<N; i++) {
text << indent << INDENT << "\"" << stripPrefix(enu.value(i).name(), prefix) << "\"," << endl;
}
text << indent << "};" << endl;
- text << indent << "const int _ENUM_" << name << "_VALUES[" << N << "] = {" << endl;
+ text << indent << "static const int _ENUM_" << name << "_VALUES[" << N << "] = {" << endl;
for (int i=0; i<N; i++) {
text << indent << INDENT << make_constant_name(enu.value(i).name()) << "," << endl;
}
@@ -102,13 +102,13 @@
if (GENERATE_MAPPING) {
N = message.field_size();
- text << indented << "const int _FIELD_COUNT = " << N << ";" << endl;
- text << indented << "const char* _FIELD_NAMES[" << N << "] = {" << endl;
+ text << indented << "static const int _FIELD_COUNT = " << N << ";" << endl;
+ text << indented << "static const char* _FIELD_NAMES[" << N << "] = {" << endl;
for (int i=0; i<N; i++) {
text << indented << INDENT << "\"" << message.field(i).name() << "\"," << endl;
}
text << indented << "};" << endl;
- text << indented << "const uint64_t _FIELD_IDS[" << N << "] = {" << endl;
+ text << indented << "static const uint64_t _FIELD_IDS[" << N << "] = {" << endl;
for (int i=0; i<N; i++) {
text << indented << INDENT << make_constant_name(message.field(i).name()) << "," << endl;
}
@@ -152,7 +152,7 @@
write_message(text, file_descriptor.message_type(i), "");
}
- for (vector<string>::iterator it = namespaces.begin(); it != namespaces.end(); it++) {
+ for (vector<string>::reverse_iterator it = namespaces.rbegin(); it != namespaces.rend(); it++) {
text << "} // " << *it << endl;
}
diff --git a/wifi/Android.bp b/wifi/Android.bp
index dae04c6..6a29b1c 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -63,7 +63,6 @@
"//frameworks/base/wifi/tests",
"//frameworks/opt/net/wifi/tests/wifitests:__subpackages__",
- "//frameworks/opt/net/wifi/libs/WifiTrackerLib/tests",
"//external/robolectric-shadows:__subpackages__",
"//frameworks/base/packages/SettingsLib/tests/integ",
"//external/sl4a:__subpackages__",
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 62d6067..7c3d0b9 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -1301,10 +1301,34 @@
public static final int DISABLED_BY_WRONG_PASSWORD = 8;
/** This network is disabled because service is not subscribed. */
public static final int DISABLED_AUTHENTICATION_NO_SUBSCRIPTION = 9;
- /** All other disable reasons should be strictly less than this value. */
+ /**
+ * All other disable reasons should be strictly less than this value.
+ * @hide
+ */
public static final int NETWORK_SELECTION_DISABLED_MAX = 10;
/**
+ * Get an integer that is equal to the maximum integer value of all the
+ * DISABLED_* reasons
+ * e.g. {@link #DISABLED_NONE}, {@link #DISABLED_ASSOCIATION_REJECTION}, etc.
+ *
+ * All DISABLED_* constants will be contiguous in the range
+ * 0, 1, 2, 3, ..., getMaxNetworkSelectionDisableReasons()
+ *
+ * <br />
+ * For example, this can be used to iterate through all the network selection
+ * disable reasons like so:
+ * <pre>{@code
+ * for (int reason = 0; reason <= getMaxNetworkSelectionDisableReasons(); reason++) {
+ * ...
+ * }
+ * }</pre>
+ */
+ public static int getMaxNetworkSelectionDisableReason() {
+ return NETWORK_SELECTION_DISABLED_MAX - 1;
+ }
+
+ /**
* Contains info about disable reasons.
* @hide
*/
@@ -1706,7 +1730,10 @@
return mStatus;
}
- /** True if the current network is enabled to join network selection, false otherwise. */
+ /**
+ * True if the current network is enabled to join network selection, false otherwise.
+ * @hide
+ */
public boolean isNetworkEnabled() {
return mStatus == NETWORK_SELECTION_ENABLED;
}
@@ -1719,7 +1746,10 @@
return mStatus == NETWORK_SELECTION_TEMPORARY_DISABLED;
}
- /** True if the current network is permanently disabled, false otherwise. */
+ /**
+ * True if the current network is permanently disabled, false otherwise.
+ * @hide
+ */
public boolean isNetworkPermanentlyDisabled() {
return mStatus == NETWORK_SELECTION_PERMANENTLY_DISABLED;
}
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 7c031ea..24b2a8e 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -449,9 +449,8 @@
* <p>
* If the SSID can be decoded as UTF-8, it will be returned surrounded by double
* quotation marks. Otherwise, it is returned as a string of hex digits.
- * The SSID may be
- * <lt><unknown ssid>, if there is no network currently connected or if the caller has
- * insufficient permissions to access the SSID.<lt>
+ * The SSID may be {@link WifiManager#UNKNOWN_SSID}, if there is no network currently connected
+ * or if the caller has insufficient permissions to access the SSID.
* </p>
* <p>
* Prior to {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 1dc4a06..a3cce7c 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2625,8 +2625,8 @@
public void getWifiActivityEnergyInfoAsync(
@NonNull @CallbackExecutor Executor executor,
@NonNull OnWifiActivityEnergyInfoListener listener) {
- if (executor == null) throw new IllegalArgumentException("executor cannot be null");
- if (listener == null) throw new IllegalArgumentException("listener cannot be null");
+ Objects.requireNonNull(executor, "executor cannot be null");
+ Objects.requireNonNull(listener, "listener cannot be null");
try {
mService.getWifiActivityEnergyInfoAsync(
new OnWifiActivityEnergyInfoProxy(executor, listener));
diff --git a/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java
index 04d2e1a..6632c16 100644
--- a/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java
+++ b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java
@@ -27,7 +27,6 @@
import android.net.NetworkSpecifier;
import android.os.Parcel;
import android.os.Parcelable;
-import android.text.TextUtils;
import java.util.Objects;
@@ -41,33 +40,10 @@
*/
private final WifiConfiguration mWifiConfiguration;
- /**
- * The UID of the app that requested a specific wifi network using {@link WifiNetworkSpecifier}.
- *
- * Will only be filled when the device connects to a wifi network as a result of a
- * {@link NetworkRequest} with {@link WifiNetworkSpecifier}. Will be set to -1 if the device
- * auto-connected to a wifi network.
- */
- private final int mOriginalRequestorUid;
-
- /**
- * The package name of the app that requested a specific wifi network using
- * {@link WifiNetworkSpecifier}.
- *
- * Will only be filled when the device connects to a wifi network as a result of a
- * {@link NetworkRequest} with {@link WifiNetworkSpecifier}. Will be set to null if the device
- * auto-connected to a wifi network.
- */
- private final String mOriginalRequestorPackageName;
-
- public WifiNetworkAgentSpecifier(@NonNull WifiConfiguration wifiConfiguration,
- int originalRequestorUid,
- @Nullable String originalRequestorPackageName) {
+ public WifiNetworkAgentSpecifier(@NonNull WifiConfiguration wifiConfiguration) {
checkNotNull(wifiConfiguration);
mWifiConfiguration = wifiConfiguration;
- mOriginalRequestorUid = originalRequestorUid;
- mOriginalRequestorPackageName = originalRequestorPackageName;
}
/**
@@ -78,10 +54,7 @@
@Override
public WifiNetworkAgentSpecifier createFromParcel(@NonNull Parcel in) {
WifiConfiguration wifiConfiguration = in.readParcelable(null);
- int originalRequestorUid = in.readInt();
- String originalRequestorPackageName = in.readString();
- return new WifiNetworkAgentSpecifier(
- wifiConfiguration, originalRequestorUid, originalRequestorPackageName);
+ return new WifiNetworkAgentSpecifier(wifiConfiguration);
}
@Override
@@ -98,8 +71,6 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeParcelable(mWifiConfiguration, flags);
- dest.writeInt(mOriginalRequestorUid);
- dest.writeString(mOriginalRequestorPackageName);
}
@Override
@@ -149,12 +120,6 @@
this.mWifiConfiguration.allowedKeyManagement)) {
return false;
}
- if (ns.requestorUid != this.mOriginalRequestorUid) {
- return false;
- }
- if (!TextUtils.equals(ns.requestorPackageName, this.mOriginalRequestorPackageName)) {
- return false;
- }
return true;
}
@@ -163,9 +128,7 @@
return Objects.hash(
mWifiConfiguration.SSID,
mWifiConfiguration.BSSID,
- mWifiConfiguration.allowedKeyManagement,
- mOriginalRequestorUid,
- mOriginalRequestorPackageName);
+ mWifiConfiguration.allowedKeyManagement);
}
@Override
@@ -180,10 +143,7 @@
return Objects.equals(this.mWifiConfiguration.SSID, lhs.mWifiConfiguration.SSID)
&& Objects.equals(this.mWifiConfiguration.BSSID, lhs.mWifiConfiguration.BSSID)
&& Objects.equals(this.mWifiConfiguration.allowedKeyManagement,
- lhs.mWifiConfiguration.allowedKeyManagement)
- && mOriginalRequestorUid == lhs.mOriginalRequestorUid
- && TextUtils.equals(mOriginalRequestorPackageName,
- lhs.mOriginalRequestorPackageName);
+ lhs.mWifiConfiguration.allowedKeyManagement);
}
@Override
@@ -192,19 +152,11 @@
sb.append("WifiConfiguration=")
.append(", SSID=").append(mWifiConfiguration.SSID)
.append(", BSSID=").append(mWifiConfiguration.BSSID)
- .append(", mOriginalRequestorUid=").append(mOriginalRequestorUid)
- .append(", mOriginalRequestorPackageName=").append(mOriginalRequestorPackageName)
.append("]");
return sb.toString();
}
@Override
- public void assertValidFromUid(int requestorUid) {
- throw new IllegalStateException("WifiNetworkAgentSpecifier should never be used "
- + "for requests.");
- }
-
- @Override
public NetworkSpecifier redact() {
return null;
}
diff --git a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
index 444e1ef..3d946c9 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
@@ -20,7 +20,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.Application;
import android.net.MacAddress;
import android.net.MatchAllNetworkSpecifier;
import android.net.NetworkRequest;
@@ -28,13 +27,9 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PatternMatcher;
-import android.os.Process;
import android.text.TextUtils;
-import android.util.Log;
import android.util.Pair;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
@@ -438,24 +433,7 @@
return new WifiNetworkSpecifier(
mSsidPatternMatcher,
mBssidPatternMatcher,
- buildWifiConfiguration(),
- Process.myUid(),
- getCurrentApplicationReflectively().getApplicationContext().getOpPackageName());
- }
-
- // TODO(b/144102365): Remove once refactor is complete
- private static Application getCurrentApplicationReflectively() {
- try {
- // reflection for static method android.app.ActivityThread#currentApplication()
- Class<?> klass = Class.forName("android.app.ActivityThread");
- Method currentApplicationMethod = klass.getDeclaredMethod("currentApplication");
- Object result = currentApplicationMethod.invoke(null);
- return (Application) result;
- } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException
- | InvocationTargetException e) {
- Log.e(TAG, "Failed to call ActivityThread#currentApplication() reflectively!", e);
- throw new RuntimeException(e);
- }
+ buildWifiConfiguration());
}
}
@@ -483,20 +461,6 @@
*/
public final WifiConfiguration wifiConfiguration;
- /**
- * The UID of the process initializing this network specifier. Validated by receiver using
- * checkUidIfNecessary() and is used by satisfiedBy() to determine whether the specifier
- * matches the offered network.
- * @hide
- */
- public final int requestorUid;
-
- /**
- * The package name of the app initializing this network specifier.
- * @hide
- */
- public final String requestorPackageName;
-
/** @hide */
public WifiNetworkSpecifier() throws IllegalAccessException {
throw new IllegalAccessException("Use the builder to create an instance");
@@ -505,18 +469,14 @@
/** @hide */
public WifiNetworkSpecifier(@NonNull PatternMatcher ssidPatternMatcher,
@NonNull Pair<MacAddress, MacAddress> bssidPatternMatcher,
- @NonNull WifiConfiguration wifiConfiguration,
- int requestorUid, @NonNull String requestorPackageName) {
+ @NonNull WifiConfiguration wifiConfiguration) {
checkNotNull(ssidPatternMatcher);
checkNotNull(bssidPatternMatcher);
checkNotNull(wifiConfiguration);
- checkNotNull(requestorPackageName);
this.ssidPatternMatcher = ssidPatternMatcher;
this.bssidPatternMatcher = bssidPatternMatcher;
this.wifiConfiguration = wifiConfiguration;
- this.requestorUid = requestorUid;
- this.requestorPackageName = requestorPackageName;
}
public static final @NonNull Creator<WifiNetworkSpecifier> CREATOR =
@@ -529,10 +489,8 @@
Pair<MacAddress, MacAddress> bssidPatternMatcher =
Pair.create(baseAddress, mask);
WifiConfiguration wifiConfiguration = in.readParcelable(null);
- int requestorUid = in.readInt();
- String requestorPackageName = in.readString();
return new WifiNetworkSpecifier(ssidPatternMatcher, bssidPatternMatcher,
- wifiConfiguration, requestorUid, requestorPackageName);
+ wifiConfiguration);
}
@Override
@@ -552,18 +510,13 @@
dest.writeParcelable(bssidPatternMatcher.first, flags);
dest.writeParcelable(bssidPatternMatcher.second, flags);
dest.writeParcelable(wifiConfiguration, flags);
- dest.writeInt(requestorUid);
- dest.writeString(requestorPackageName);
}
@Override
public int hashCode() {
return Objects.hash(
- ssidPatternMatcher.getPath(),
- ssidPatternMatcher.getType(),
- bssidPatternMatcher,
- wifiConfiguration.allowedKeyManagement,
- requestorUid, requestorPackageName);
+ ssidPatternMatcher.getPath(), ssidPatternMatcher.getType(), bssidPatternMatcher,
+ wifiConfiguration.allowedKeyManagement);
}
@Override
@@ -582,9 +535,7 @@
&& Objects.equals(this.bssidPatternMatcher,
lhs.bssidPatternMatcher)
&& Objects.equals(this.wifiConfiguration.allowedKeyManagement,
- lhs.wifiConfiguration.allowedKeyManagement)
- && requestorUid == lhs.requestorUid
- && TextUtils.equals(requestorPackageName, lhs.requestorPackageName);
+ lhs.wifiConfiguration.allowedKeyManagement);
}
@Override
@@ -595,8 +546,6 @@
.append(", BSSID Match pattern=").append(bssidPatternMatcher)
.append(", SSID=").append(wifiConfiguration.SSID)
.append(", BSSID=").append(wifiConfiguration.BSSID)
- .append(", requestorUid=").append(requestorUid)
- .append(", requestorPackageName=").append(requestorPackageName)
.append("]")
.toString();
}
@@ -618,12 +567,4 @@
// not make much sense!
return equals(other);
}
-
- /** @hide */
- @Override
- public void assertValidFromUid(int requestorUid) {
- if (this.requestorUid != requestorUid) {
- throw new SecurityException("mismatched UIDs");
- }
- }
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java
index c667334..a4b3e86 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java
@@ -143,12 +143,6 @@
}
@Override
- public void assertValidFromUid(int requestorUid) {
- throw new SecurityException(
- "WifiAwareAgentNetworkSpecifier should not be used in network requests");
- }
-
- @Override
public NetworkSpecifier redact() {
return null;
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 81bf81e..2ebaa18 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -34,7 +34,6 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
@@ -447,8 +446,7 @@
pmk,
passphrase,
0, // no port info for deprecated IB APIs
- -1, // no transport info for deprecated IB APIs
- Process.myUid());
+ -1); // no transport info for deprecated IB APIs
}
/** @hide */
@@ -488,8 +486,7 @@
pmk,
passphrase,
0, // no port info for OOB APIs
- -1, // no transport protocol info for OOB APIs
- Process.myUid());
+ -1); // no transport protocol info for OOB APIs
}
private static class WifiAwareEventCallbackProxy extends IWifiAwareEventCallback.Stub {
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
index 5a4ed3c..65ac1ab 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
@@ -23,7 +23,6 @@
import android.net.NetworkSpecifier;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.Process;
import android.text.TextUtils;
import java.util.Arrays;
@@ -144,19 +143,9 @@
*/
public final int transportProtocol;
- /**
- * The UID of the process initializing this network specifier. Validated by receiver using
- * checkUidIfNecessary() and is used by satisfiedBy() to determine whether matches the
- * offered network.
- *
- * @hide
- */
- public final int requestorUid;
-
/** @hide */
public WifiAwareNetworkSpecifier(int type, int role, int clientId, int sessionId, int peerId,
- byte[] peerMac, byte[] pmk, String passphrase, int port, int transportProtocol,
- int requestorUid) {
+ byte[] peerMac, byte[] pmk, String passphrase, int port, int transportProtocol) {
this.type = type;
this.role = role;
this.clientId = clientId;
@@ -167,7 +156,6 @@
this.passphrase = passphrase;
this.port = port;
this.transportProtocol = transportProtocol;
- this.requestorUid = requestorUid;
}
public static final @android.annotation.NonNull Creator<WifiAwareNetworkSpecifier> CREATOR =
@@ -184,8 +172,7 @@
in.createByteArray(), // pmk
in.readString(), // passphrase
in.readInt(), // port
- in.readInt(), // transportProtocol
- in.readInt()); // requestorUid
+ in.readInt()); // transportProtocol
}
@Override
@@ -221,7 +208,6 @@
dest.writeString(passphrase);
dest.writeInt(port);
dest.writeInt(transportProtocol);
- dest.writeInt(requestorUid);
}
/** @hide */
@@ -238,7 +224,7 @@
@Override
public int hashCode() {
return Objects.hash(type, role, clientId, sessionId, peerId, Arrays.hashCode(peerMac),
- Arrays.hashCode(pmk), passphrase, port, transportProtocol, requestorUid);
+ Arrays.hashCode(pmk), passphrase, port, transportProtocol);
}
/** @hide */
@@ -263,8 +249,7 @@
&& Arrays.equals(pmk, lhs.pmk)
&& Objects.equals(passphrase, lhs.passphrase)
&& port == lhs.port
- && transportProtocol == lhs.transportProtocol
- && requestorUid == lhs.requestorUid;
+ && transportProtocol == lhs.transportProtocol;
}
/** @hide */
@@ -283,19 +268,11 @@
// masking PII
.append(", passphrase=").append((passphrase == null) ? "<null>" : "<non-null>")
.append(", port=").append(port).append(", transportProtocol=")
- .append(transportProtocol).append(", requestorUid=").append(requestorUid)
+ .append(transportProtocol)
.append("]");
return sb.toString();
}
- /** @hide */
- @Override
- public void assertValidFromUid(int requestorUid) {
- if (this.requestorUid != requestorUid) {
- throw new SecurityException("mismatched UIDs");
- }
- }
-
/**
* A builder class for a Wi-Fi Aware network specifier to set up an Aware connection with a
* peer.
@@ -463,7 +440,7 @@
return new WifiAwareNetworkSpecifier(
WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB, role,
mDiscoverySession.mClientId, mDiscoverySession.mSessionId, mPeerHandle.peerId,
- null, mPmk, mPskPassphrase, mPort, mTransportProtocol, Process.myUid());
+ null, mPmk, mPskPassphrase, mPort, mTransportProtocol);
}
}
}
diff --git a/wifi/java/android/net/wifi/wificond/NativeScanResult.java b/wifi/java/android/net/wifi/wificond/NativeScanResult.java
index 85251e8b..7cc617d 100644
--- a/wifi/java/android/net/wifi/wificond/NativeScanResult.java
+++ b/wifi/java/android/net/wifi/wificond/NativeScanResult.java
@@ -24,7 +24,6 @@
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
-import java.util.BitSet;
import java.util.List;
/**
@@ -34,8 +33,6 @@
*/
@SystemApi
public final class NativeScanResult implements Parcelable {
- private static final int CAPABILITY_SIZE = 16;
-
/** @hide */
@VisibleForTesting
public byte[] ssid;
@@ -56,7 +53,7 @@
public long tsf;
/** @hide */
@VisibleForTesting
- public BitSet capability;
+ public int capability;
/** @hide */
@VisibleForTesting
public boolean associated;
@@ -134,7 +131,7 @@
* Returns the capabilities of the AP repseresented by this scan result as advertised in the
* received probe response or beacon.
*
- * This is a bit mask describing the capabilities of a BSS. See IEEE Std 802.11: 8.4.1.4:
+ * This is a bit mask describing the capabilities of a BSS. See IEEE Std 802.11: 9.4.1.4:
* Bit 0 - ESS
* Bit 1 - IBSS
* Bit 2 - CF Pollable
@@ -143,7 +140,7 @@
* Bit 5 - Short Preamble
* Bit 6 - PBCC
* Bit 7 - Channel Agility
- * Bit 8 - Spectrum Mgmt
+ * Bit 8 - Spectrum Management
* Bit 9 - QoS
* Bit 10 - Short Slot Time
* Bit 11 - APSD
@@ -154,7 +151,7 @@
*
* @return a bit mask of capabilities.
*/
- @NonNull public BitSet getCapabilities() {
+ @NonNull public int getCapabilities() {
return capability;
}
@@ -188,13 +185,7 @@
out.writeInt(frequency);
out.writeInt(signalMbm);
out.writeLong(tsf);
- int capabilityInt = 0;
- for (int i = 0; i < CAPABILITY_SIZE; i++) {
- if (capability.get(i)) {
- capabilityInt |= 1 << i;
- }
- }
- out.writeInt(capabilityInt);
+ out.writeInt(capability);
out.writeInt(associated ? 1 : 0);
out.writeTypedList(radioChainInfos);
}
@@ -220,13 +211,7 @@
result.frequency = in.readInt();
result.signalMbm = in.readInt();
result.tsf = in.readLong();
- int capabilityInt = in.readInt();
- result.capability = new BitSet(CAPABILITY_SIZE);
- for (int i = 0; i < CAPABILITY_SIZE; i++) {
- if ((capabilityInt & (1 << i)) != 0) {
- result.capability.set(i);
- }
- }
+ result.capability = in.readInt();
result.associated = (in.readInt() != 0);
result.radioChainInfos = new ArrayList<>();
in.readTypedList(result.radioChainInfos, RadioChainInfo.CREATOR);
diff --git a/wifi/java/android/net/wifi/wificond/PnoSettings.java b/wifi/java/android/net/wifi/wificond/PnoSettings.java
index 57c9ca5..533d37d 100644
--- a/wifi/java/android/net/wifi/wificond/PnoSettings.java
+++ b/wifi/java/android/net/wifi/wificond/PnoSettings.java
@@ -16,6 +16,7 @@
package android.net.wifi.wificond;
+import android.annotation.DurationMillisLong;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
@@ -33,7 +34,7 @@
*/
@SystemApi
public final class PnoSettings implements Parcelable {
- private int mIntervalMs;
+ private long mIntervalMs;
private int mMin2gRssi;
private int mMin5gRssi;
private int mMin6gRssi;
@@ -47,17 +48,17 @@
*
* @return An interval in milliseconds.
*/
- public int getIntervalMillis() {
+ public @DurationMillisLong long getIntervalMillis() {
return mIntervalMs;
}
/**
* Set the requested PNO scan interval in milliseconds.
*
- * @param intervalMs An interval in milliseconds.
+ * @param intervalMillis An interval in milliseconds.
*/
- public void setIntervalMillis(int intervalMs) {
- this.mIntervalMs = intervalMs;
+ public void setIntervalMillis(@DurationMillisLong long intervalMillis) {
+ this.mIntervalMs = intervalMillis;
}
/**
@@ -176,7 +177,7 @@
**/
@Override
public void writeToParcel(@NonNull Parcel out, int flags) {
- out.writeInt(mIntervalMs);
+ out.writeLong(mIntervalMs);
out.writeInt(mMin2gRssi);
out.writeInt(mMin5gRssi);
out.writeInt(mMin6gRssi);
@@ -189,7 +190,7 @@
@Override
public PnoSettings createFromParcel(Parcel in) {
PnoSettings result = new PnoSettings();
- result.mIntervalMs = in.readInt();
+ result.mIntervalMs = in.readLong();
result.mMin2gRssi = in.readInt();
result.mMin5gRssi = in.readInt();
result.mMin6gRssi = in.readInt();
diff --git a/wifi/java/android/net/wifi/wificond/WifiCondManager.java b/wifi/java/android/net/wifi/wificond/WifiCondManager.java
index 43aa1b6..7a31a5a 100644
--- a/wifi/java/android/net/wifi/wificond/WifiCondManager.java
+++ b/wifi/java/android/net/wifi/wificond/WifiCondManager.java
@@ -496,22 +496,17 @@
}
/**
- * Initializes WifiCondManager & registers a death notification for the WifiCondManager which
- * acts as a proxy for the wificond daemon (i.e. the death listener will be called when and if
- * the wificond daemon dies).
- *
- * Note: This method clears any existing state in wificond daemon.
+ * Register a death notification for the WifiCondManager which acts as a proxy for the
+ * wificond daemon (i.e. the death listener will be called when and if the wificond daemon
+ * dies).
*
* @param deathEventHandler A {@link Runnable} to be called whenever the wificond daemon dies.
- * @return Returns true on success.
*/
- public boolean initialize(@NonNull Runnable deathEventHandler) {
+ public void setOnServiceDeadCallback(@NonNull Runnable deathEventHandler) {
if (mDeathEventHandler != null) {
Log.e(TAG, "Death handler already present");
}
mDeathEventHandler = deathEventHandler;
- tearDownInterfaces();
- return true;
}
/**
@@ -603,11 +598,12 @@
}
/**
- * Tear down a specific client (STA) interface, initially configured using
+ * Tear down a specific client (STA) interface configured using
* {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}.
*
* @param ifaceName Name of the interface to tear down.
- * @return Returns true on success.
+ * @return Returns true on success, false on failure (e.g. when called before an interface was
+ * set up).
*/
public boolean tearDownClientInterface(@NonNull String ifaceName) {
if (getClientInterface(ifaceName) == null) {
@@ -681,11 +677,12 @@
}
/**
- * Tear down a Soft AP interface initially configured using
+ * Tear down a Soft AP interface configured using
* {@link #setupInterfaceForSoftApMode(String)}.
*
* @param ifaceName Name of the interface to tear down.
- * @return Returns true on success.
+ * @return Returns true on success, false on failure (e.g. when called before an interface was
+ * set up).
*/
public boolean tearDownSoftApInterface(@NonNull String ifaceName) {
if (getApInterface(ifaceName) == null) {
@@ -750,9 +747,13 @@
/**
* Request signal polling.
*
- * @param ifaceName Name of the interface on which to poll.
+ * @param ifaceName Name of the interface on which to poll. The interface must have been
+ * already set up using
+ *{@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
+ * or {@link #setupInterfaceForSoftApMode(String)}.
+ *
* @return A {@link SignalPollResult} object containing interface statistics, or a null on
- * error.
+ * error (e.g. the interface hasn't been set up yet).
*/
@Nullable public SignalPollResult signalPoll(@NonNull String ifaceName) {
IClientInterface iface = getClientInterface(ifaceName);
@@ -776,10 +777,14 @@
}
/**
- * Get current transmit (Tx) packet counters of the specified interface.
+ * Get current transmit (Tx) packet counters of the specified interface. The interface must
+ * have been already set up using
+ * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
+ * or {@link #setupInterfaceForSoftApMode(String)}.
*
* @param ifaceName Name of the interface.
- * @return {@link TxPacketCounters} of the current interface or null on error.
+ * @return {@link TxPacketCounters} of the current interface or null on error (e.g. when
+ * called before the interface has been set up).
*/
@Nullable public TxPacketCounters getTxPacketCounters(@NonNull String ifaceName) {
IClientInterface iface = getClientInterface(ifaceName);
@@ -813,10 +818,15 @@
* be done using {@link #startScan(String, int, Set, List)} or
* {@link #startPnoScan(String, PnoSettings, Executor, PnoScanRequestCallback)}.
*
+ * Note: The interface must have been already set up using
+ * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
+ * or {@link #setupInterfaceForSoftApMode(String)}.
+ *
* @param ifaceName Name of the interface.
* @param scanType The type of scan result to be returned, can be
* {@link #SCAN_TYPE_SINGLE_SCAN} or {@link #SCAN_TYPE_PNO_SCAN}.
- * @return Returns an array of {@link NativeScanResult} or an empty array on failure.
+ * @return Returns an array of {@link NativeScanResult} or an empty array on failure (e.g. when
+ * called before the interface has been set up).
*/
@NonNull public List<NativeScanResult> getScanResults(@NonNull String ifaceName,
@ScanResultType int scanType) {
@@ -869,13 +879,19 @@
* The latest scans can be obtained using {@link #getScanResults(String, int)} and using a
* {@link #SCAN_TYPE_SINGLE_SCAN} for the {@code scanType}.
*
+ * Note: The interface must have been already set up using
+ * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
+ * or {@link #setupInterfaceForSoftApMode(String)}.
+ *
* @param ifaceName Name of the interface on which to initiate the scan.
* @param scanType Type of scan to perform, can be any of
* {@link WifiScanner#SCAN_TYPE_HIGH_ACCURACY}, {@link WifiScanner#SCAN_TYPE_LOW_POWER}, or
* {@link WifiScanner#SCAN_TYPE_LOW_LATENCY}.
* @param freqs list of frequencies to scan for, if null scan all supported channels.
- * @param hiddenNetworkSSIDs List of hidden networks to be scanned for.
- * @return Returns true on success.
+ * @param hiddenNetworkSSIDs List of hidden networks to be scanned for, a null indicates that
+ * no hidden frequencies will be scanned for.
+ * @return Returns true on success, false on failure (e.g. when called before the interface
+ * has been set up).
*/
public boolean startScan(@NonNull String ifaceName, @WifiAnnotations.ScanType int scanType,
@Nullable Set<Integer> freqs, @Nullable List<byte[]> hiddenNetworkSSIDs) {
@@ -931,11 +947,16 @@
* The latest PNO scans can be obtained using {@link #getScanResults(String, int)} with the
* {@code scanType} set to {@link #SCAN_TYPE_PNO_SCAN}.
*
+ * Note: The interface must have been already set up using
+ * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
+ * or {@link #setupInterfaceForSoftApMode(String)}.
+ *
* @param ifaceName Name of the interface on which to request a PNO.
* @param pnoSettings PNO scan configuration.
* @param executor The Executor on which to execute the callback.
* @param callback Callback for the results of the offload request.
- * @return true on success.
+ * @return true on success, false on failure (e.g. when called before the interface has been set
+ * up).
*/
public boolean startPnoScan(@NonNull String ifaceName, @NonNull PnoSettings pnoSettings,
@NonNull @CallbackExecutor Executor executor,
@@ -969,8 +990,13 @@
* Stop PNO scan configured with
* {@link #startPnoScan(String, PnoSettings, Executor, PnoScanRequestCallback)}.
*
+ * Note: The interface must have been already set up using
+ * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
+ * or {@link #setupInterfaceForSoftApMode(String)}.
+ *
* @param ifaceName Name of the interface on which the PNO scan was configured.
- * @return true on success.
+ * @return true on success, false on failure (e.g. when called before the interface has been
+ * set up).
*/
public boolean stopPnoScan(@NonNull String ifaceName) {
IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
@@ -987,7 +1013,13 @@
}
/**
- * Abort ongoing single scan started with {@link #startScan(String, int, Set, List)}.
+ * Abort ongoing single scan started with {@link #startScan(String, int, Set, List)}. No failure
+ * callback, e.g. {@link ScanEventCallback#onScanFailed()}, is triggered by this operation.
+ *
+ * Note: The interface must have been already set up using
+ * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
+ * or {@link #setupInterfaceForSoftApMode(String)}. If the interface has not been set up then
+ * this method has no impact.
*
* @param ifaceName Name of the interface on which the scan was started.
*/
@@ -1055,7 +1087,14 @@
}
/**
- * Get the device phy capabilities for a given interface
+ * Get the device phy capabilities for a given interface.
+ *
+ * Note: The interface must have been already set up using
+ * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
+ * or {@link #setupInterfaceForSoftApMode(String)}.
+ *
+ * @return DeviceWiphyCapabilities or null on error (e.g. when called on an interface which has
+ * not been set up).
*/
@Nullable public DeviceWiphyCapabilities getDeviceWiphyCapabilities(@NonNull String ifaceName) {
if (mWificond == null) {
@@ -1071,13 +1110,19 @@
}
/**
- * Register the provided callback handler for SoftAp events. Note that the Soft AP itself is
- * configured using {@link #setupInterfaceForSoftApMode(String)}.
+ * Register the provided callback handler for SoftAp events. The interface must first be created
+ * using {@link #setupInterfaceForSoftApMode(String)}. The callback registration is valid until
+ * the interface is deleted using {@link #tearDownSoftApInterface(String)} (no deregistration
+ * method is provided).
+ * <p>
+ * Note that only one callback can be registered at a time - any registration overrides previous
+ * registrations.
*
* @param ifaceName Name of the interface on which to register the callback.
* @param executor The Executor on which to execute the callbacks.
* @param callback Callback for AP events.
- * @return true on success, false otherwise.
+ * @return true on success, false on failure (e.g. when called on an interface which has not
+ * been set up).
*/
public boolean registerApCallback(@NonNull String ifaceName,
@NonNull @CallbackExecutor Executor executor,
@@ -1113,6 +1158,10 @@
* Send a management frame on the specified interface at the specified rate. Useful for probing
* the link with arbitrary frames.
*
+ * Note: The interface must have been already set up using
+ * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
+ * or {@link #setupInterfaceForSoftApMode(String)}.
+ *
* @param ifaceName The interface on which to send the frame.
* @param frame The raw byte array of the management frame to tramit.
* @param mcs The MCS (modulation and coding scheme), i.e. rate, at which to transmit the
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
deleted file mode 100644
index 060c85c..0000000
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ /dev/null
@@ -1,641 +0,0 @@
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License") {
- * throw new UnsupportedOperationException();
- }
- * 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.wifi;
-
-import android.content.pm.ParceledListSlice;
-import android.net.DhcpInfo;
-import android.net.Network;
-import android.net.wifi.IActionListener;
-import android.net.wifi.IDppCallback;
-import android.net.wifi.ILocalOnlyHotspotCallback;
-import android.net.wifi.INetworkRequestMatchCallback;
-import android.net.wifi.IOnWifiActivityEnergyInfoListener;
-import android.net.wifi.IOnWifiUsabilityStatsListener;
-import android.net.wifi.IScanResultsCallback;
-import android.net.wifi.ISoftApCallback;
-import android.net.wifi.ISuggestionConnectionStatusListener;
-import android.net.wifi.ITrafficStateCallback;
-import android.net.wifi.ITxPacketCountListener;
-import android.net.wifi.IWifiConnectedNetworkScorer;
-import android.net.wifi.IWifiManager;
-import android.net.wifi.ScanResult;
-import android.net.wifi.SoftApConfiguration;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.net.wifi.WifiNetworkSuggestion;
-import android.net.wifi.hotspot2.IProvisioningCallback;
-import android.net.wifi.hotspot2.OsuProvider;
-import android.net.wifi.hotspot2.PasspointConfiguration;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.os.WorkSource;
-import android.os.connectivity.WifiActivityEnergyInfo;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * Empty concrete class implementing IWifiManager with stub methods throwing runtime exceptions.
- *
- * This class is meant to be extended by real implementations of IWifiManager in order to facilitate
- * cross-repo changes to WiFi internal APIs, including the introduction of new APIs, the removal of
- * deprecated APIs, or the migration of existing API signatures.
- *
- * When an existing API is scheduled for removal, it can be removed from IWifiManager.aidl
- * immediately and marked as @Deprecated first in this class. Children inheriting this class are
- * then given a short grace period to update themselves before the @Deprecated stub is removed for
- * good. If the API scheduled for removal has a replacement or an overload (signature change),
- * these should be introduced before the stub is removed to allow children to migrate.
- *
- * When a new API is added to IWifiManager.aidl, a stub should be added in BaseWifiService as
- * well otherwise compilation will fail.
- */
-public class BaseWifiService extends IWifiManager.Stub {
-
- private static final String TAG = BaseWifiService.class.getSimpleName();
-
- @Override
- public long getSupportedFeatures() {
- throw new UnsupportedOperationException();
- }
-
- /** @deprecated use {@link #getWifiActivityEnergyInfoAsync} instead */
- @Deprecated
- public WifiActivityEnergyInfo reportActivityInfo() {
- throw new UnsupportedOperationException();
- }
-
- /** @deprecated use {@link #getWifiActivityEnergyInfoAsync} instead */
- @Deprecated
- public void requestActivityInfo(ResultReceiver result) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void getWifiActivityEnergyInfoAsync(IOnWifiActivityEnergyInfoListener listener) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public ParceledListSlice getConfiguredNetworks(String packageName, String featureId) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public ParceledListSlice getPrivilegedConfiguredNetworks(String packageName, String featureId) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Map<String, Map<Integer, List<ScanResult>>> getAllMatchingFqdnsForScanResults(
- List<ScanResult> scanResults) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
- List<ScanResult> scanResults) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(
- List<OsuProvider> osuProviders) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int addOrUpdateNetwork(WifiConfiguration config, String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean addOrUpdatePasspointConfiguration(
- PasspointConfiguration config, String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean removePasspointConfiguration(String fqdn, String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public List<PasspointConfiguration> getPasspointConfigurations(String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public List<WifiConfiguration> getWifiConfigsForPasspointProfiles(List<String> fqdnList) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void queryPasspointIcon(long bssid, String fileName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int matchProviderWithCurrentNetwork(String fqdn) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void deauthenticateNetwork(long holdoff, boolean ess) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean removeNetwork(int netId, String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean enableNetwork(int netId, boolean disableOthers, String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean disableNetwork(int netId, String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void allowAutojoinGlobal(boolean choice) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void allowAutojoin(int netId, boolean choice) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void allowAutojoinPasspoint(String fqdn, boolean enableAutoJoin) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setMacRandomizationSettingPasspointEnabled(String fqdn, boolean enable) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setMeteredOverridePasspoint(String fqdn, int meteredOverride) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean startScan(String packageName, String featureId) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public List<ScanResult> getScanResults(String callingPackage, String callingFeatureId) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean disconnect(String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean reconnect(String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean reassociate(String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public WifiInfo getConnectionInfo(String callingPackage, String callingFeatureId) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean setWifiEnabled(String packageName, boolean enable) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int getWifiEnabledState() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getCountryCode() {
- throw new UnsupportedOperationException();
- }
-
- /** @deprecated use {@link #is5GHzBandSupported} instead */
- @Deprecated
- public boolean isDualBandSupported() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean is5GHzBandSupported() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean is6GHzBandSupported() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isWifiStandardSupported(int standard) {
- throw new UnsupportedOperationException();
- }
-
- /** @deprecated use {@link WifiManager#isStaApConcurrencySupported()} */
- @Deprecated
- public boolean needs5GHzToAnyApBandConversion() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public DhcpInfo getDhcpInfo() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isScanAlwaysAvailable() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean acquireWifiLock(IBinder lock, int lockType, String tag, WorkSource ws) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean releaseWifiLock(IBinder lock) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void initializeMulticastFiltering() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isMulticastEnabled() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void acquireMulticastLock(IBinder binder, String tag) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void releaseMulticastLock(String tag) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void updateInterfaceIpState(String ifaceName, int mode) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean startSoftAp(WifiConfiguration wifiConfig) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean startTetheredHotspot(SoftApConfiguration softApConfig) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean stopSoftAp() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int startLocalOnlyHotspot(ILocalOnlyHotspotCallback callback, String packageName,
- String featureId, SoftApConfiguration customConfig) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void stopLocalOnlyHotspot() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void startWatchLocalOnlyHotspot(ILocalOnlyHotspotCallback callback) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void stopWatchLocalOnlyHotspot() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int getWifiApEnabledState() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public WifiConfiguration getWifiApConfiguration() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public SoftApConfiguration getSoftApConfiguration() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean setWifiApConfiguration(WifiConfiguration wifiConfig, String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean setSoftApConfiguration(SoftApConfiguration softApConfig, String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void notifyUserOfApBandConversion(String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void enableTdls(String remoteIPAddress, boolean enable) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getCurrentNetworkWpsNfcConfigurationToken() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void enableVerboseLogging(int verbose) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int getVerboseLoggingLevel() {
- throw new UnsupportedOperationException();
- }
-
- /** @deprecated use {@link #allowAutojoinGlobal(boolean)} instead */
- @Deprecated
- public void enableWifiConnectivityManager(boolean enabled) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void disableEphemeralNetwork(String SSID, String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void factoryReset(String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Network getCurrentNetwork() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public byte[] retrieveBackupData() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void restoreBackupData(byte[] data) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public byte[] retrieveSoftApBackupData() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public SoftApConfiguration restoreSoftApBackupData(byte[] data) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void startSubscriptionProvisioning(
- OsuProvider provider, IProvisioningCallback callback) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void registerSoftApCallback(
- IBinder binder, ISoftApCallback callback, int callbackIdentifier) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void unregisterSoftApCallback(int callbackIdentifier) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void registerTrafficStateCallback(
- IBinder binder, ITrafficStateCallback callback, int callbackIdentifier) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void unregisterTrafficStateCallback(int callbackIdentifier) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void registerNetworkRequestMatchCallback(
- IBinder binder, INetworkRequestMatchCallback callback, int callbackIdentifier) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void unregisterNetworkRequestMatchCallback(int callbackIdentifier) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int addNetworkSuggestions(
- List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName,
- String callingFeatureId) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int removeNetworkSuggestions(
- List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public List<WifiNetworkSuggestion> getNetworkSuggestions(String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String[] getFactoryMacAddresses() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setDeviceMobilityState(int state) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void startDppAsConfiguratorInitiator(IBinder binder, String enrolleeUri,
- int selectedNetworkId, int netRole, IDppCallback callback) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void startDppAsEnrolleeInitiator(IBinder binder, String configuratorUri,
- IDppCallback callback) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void stopDppSession() throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void addOnWifiUsabilityStatsListener(
- IBinder binder, IOnWifiUsabilityStatsListener listener, int listenerIdentifier) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void removeOnWifiUsabilityStatsListener(int listenerIdentifier) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void connect(WifiConfiguration config, int netId, IBinder binder,
- IActionListener callback, int callbackIdentifier) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void save(WifiConfiguration config, IBinder binder, IActionListener callback,
- int callbackIdentifier) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void forget(int netId, IBinder binder, IActionListener callback,
- int callbackIdentifier) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void getTxPacketCount(String packageName, IBinder binder,
- ITxPacketCountListener callback, int callbackIdentifier) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void registerScanResultsCallback(IScanResultsCallback callback) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void unregisterScanResultsCallback(IScanResultsCallback callback) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void registerSuggestionConnectionStatusListener(IBinder binder,
- ISuggestionConnectionStatusListener listener,
- int listenerIdentifier, String packageName, String featureId) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void unregisterSuggestionConnectionStatusListener(int listenerIdentifier,
- String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int calculateSignalLevel(int rssi) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public List<WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(
- List<ScanResult> scanResults) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean setWifiConnectedNetworkScorer(IBinder binder,
- IWifiConnectedNetworkScorer scorer) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void clearWifiConnectedNetworkScorer() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Map<WifiNetworkSuggestion, List<ScanResult>> getMatchingScanResults(
- List<WifiNetworkSuggestion> networkSuggestions,
- List<ScanResult> scanResults,
- String callingPackage, String callingFeatureId) {
- throw new UnsupportedOperationException();
- }
-}
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 8023160..05a3dce 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -336,6 +336,20 @@
}
/**
+ * Ensure that {@link NetworkSelectionStatus#getMaxNetworkSelectionDisableReason()} returns
+ * the maximum disable reason.
+ */
+ @Test
+ public void testNetworkSelectionGetMaxNetworkSelectionDisableReason() {
+ int maxReason = Integer.MIN_VALUE;
+ for (int i = 0; i < NetworkSelectionStatus.DISABLE_REASON_INFOS.size(); i++) {
+ int reason = NetworkSelectionStatus.DISABLE_REASON_INFOS.keyAt(i);
+ maxReason = Math.max(maxReason, reason);
+ }
+ assertEquals(maxReason, NetworkSelectionStatus.getMaxNetworkSelectionDisableReason());
+ }
+
+ /**
* Ensure that {@link WifiConfiguration#setSecurityParams(int)} sets up the
* {@link WifiConfiguration} object correctly for SAE security type.
* @throws Exception
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index a189d50..6320f85 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -1867,7 +1867,7 @@
* Tests that passing a null Executor to {@link WifiManager#getWifiActivityEnergyInfoAsync}
* throws an exception.
*/
- @Test(expected = IllegalArgumentException.class)
+ @Test(expected = NullPointerException.class)
public void testGetWifiActivityInfoNullExecutor() throws Exception {
mWifiManager.getWifiActivityEnergyInfoAsync(null, mOnWifiActivityEnergyInfoListener);
}
@@ -1876,7 +1876,7 @@
* Tests that passing a null listener to {@link WifiManager#getWifiActivityEnergyInfoAsync}
* throws an exception.
*/
- @Test(expected = IllegalArgumentException.class)
+ @Test(expected = NullPointerException.class)
public void testGetWifiActivityInfoNullListener() throws Exception {
mWifiManager.getWifiActivityEnergyInfoAsync(mExecutor, null);
}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
index adc41f0..0233ee2 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
@@ -22,7 +22,6 @@
import android.net.MacAddress;
import android.net.MatchAllNetworkSpecifier;
-import android.net.NetworkRequest;
import android.os.Parcel;
import android.os.PatternMatcher;
import android.util.Pair;
@@ -36,10 +35,6 @@
*/
@SmallTest
public class WifiNetworkAgentSpecifierTest {
- private static final int TEST_UID = 5;
- private static final int TEST_UID_1 = 8;
- private static final String TEST_PACKAGE = "com.test";
- private static final String TEST_PACKAGE_1 = "com.test.1";
private static final String TEST_SSID = "Test123";
private static final String TEST_SSID_PATTERN = "Test";
private static final String TEST_SSID_1 = "456test";
@@ -71,16 +66,6 @@
}
/**
- * Validate that the NetworkAgentSpecifier cannot be used in a {@link NetworkRequest} by apps.
- */
- @Test(expected = IllegalStateException.class)
- public void testWifiNetworkAgentSpecifierNotUsedInNetworkRequest() {
- WifiNetworkAgentSpecifier specifier = createDefaultNetworkAgentSpecifier();
-
- specifier.assertValidFromUid(TEST_UID);
- }
-
- /**
* Validate NetworkAgentSpecifier equals with itself.
* a) Create network agent specifier 1 for WPA_PSK network
* b) Create network agent specifier 2 with the same params as specifier 1.
@@ -105,15 +90,13 @@
WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration();
WifiNetworkAgentSpecifier specifier1 =
new WifiNetworkAgentSpecifier(
- wifiConfiguration1,
- TEST_UID, TEST_PACKAGE);
+ wifiConfiguration1);
WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
wifiConfiguration2.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkAgentSpecifier specifier2 =
new WifiNetworkAgentSpecifier(
- wifiConfiguration2,
- TEST_UID, TEST_PACKAGE);
+ wifiConfiguration2);
assertFalse(specifier2.equals(specifier1));
}
@@ -129,15 +112,13 @@
WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration();
WifiNetworkAgentSpecifier specifier1 =
new WifiNetworkAgentSpecifier(
- wifiConfiguration1,
- TEST_UID, TEST_PACKAGE);
+ wifiConfiguration1);
WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
wifiConfiguration2.SSID = TEST_SSID_1;
WifiNetworkAgentSpecifier specifier2 =
new WifiNetworkAgentSpecifier(
- wifiConfiguration2,
- TEST_UID, TEST_PACKAGE);
+ wifiConfiguration2);
assertFalse(specifier2.equals(specifier1));
}
@@ -153,15 +134,13 @@
WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration();
WifiNetworkAgentSpecifier specifier1 =
new WifiNetworkAgentSpecifier(
- wifiConfiguration1,
- TEST_UID, TEST_PACKAGE);
+ wifiConfiguration1);
WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
wifiConfiguration2.BSSID = TEST_BSSID_1;
WifiNetworkAgentSpecifier specifier2 =
new WifiNetworkAgentSpecifier(
- wifiConfiguration2,
- TEST_UID, TEST_PACKAGE);
+ wifiConfiguration2);
assertFalse(specifier2.equals(specifier1));
}
@@ -215,8 +194,7 @@
WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
ssidPattern,
bssidPattern,
- wificonfigurationNetworkSpecifier,
- TEST_UID, TEST_PACKAGE);
+ wificonfigurationNetworkSpecifier);
assertTrue(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
assertTrue(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
@@ -244,8 +222,7 @@
WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
ssidPattern,
bssidPattern,
- wificonfigurationNetworkSpecifier,
- TEST_UID, TEST_PACKAGE);
+ wificonfigurationNetworkSpecifier);
assertTrue(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
assertTrue(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
@@ -273,8 +250,7 @@
WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
ssidPattern,
bssidPattern,
- wificonfigurationNetworkSpecifier,
- TEST_UID, TEST_PACKAGE);
+ wificonfigurationNetworkSpecifier);
assertTrue(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
assertTrue(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
@@ -293,8 +269,7 @@
wifiConfigurationNetworkAgent.SSID = "\"" + TEST_SSID_1 + "\"";
WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
new WifiNetworkAgentSpecifier(
- wifiConfigurationNetworkAgent,
- TEST_UID, TEST_PACKAGE);
+ wifiConfigurationNetworkAgent);
PatternMatcher ssidPattern =
new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
@@ -306,8 +281,7 @@
WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
ssidPattern,
bssidPattern,
- wificonfigurationNetworkSpecifier,
- TEST_UID, TEST_PACKAGE);
+ wificonfigurationNetworkSpecifier);
assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
@@ -326,8 +300,7 @@
wifiConfigurationNetworkAgent.BSSID = TEST_BSSID_1;
WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
new WifiNetworkAgentSpecifier(
- wifiConfigurationNetworkAgent,
- TEST_UID, TEST_PACKAGE);
+ wifiConfigurationNetworkAgent);
PatternMatcher ssidPattern =
new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB);
@@ -340,8 +313,7 @@
WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
ssidPattern,
bssidPattern,
- wificonfigurationNetworkSpecifier,
- TEST_UID, TEST_PACKAGE);
+ wificonfigurationNetworkSpecifier);
assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
@@ -360,8 +332,7 @@
wifiConfigurationNetworkAgent.BSSID = TEST_BSSID_1;
WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
new WifiNetworkAgentSpecifier(
- wifiConfigurationNetworkAgent,
- TEST_UID, TEST_PACKAGE);
+ wifiConfigurationNetworkAgent);
PatternMatcher ssidPattern =
new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
@@ -374,8 +345,7 @@
WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
ssidPattern,
bssidPattern,
- wificonfigurationNetworkSpecifier,
- TEST_UID, TEST_PACKAGE);
+ wificonfigurationNetworkSpecifier);
assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
@@ -402,41 +372,12 @@
WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
ssidPattern,
bssidPattern,
- wificonfigurationNetworkSpecifier,
- TEST_UID, TEST_PACKAGE);
+ wificonfigurationNetworkSpecifier);
assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
}
- /**
- * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
- * a) Create network agent specifier for WPA_PSK network
- * b) Create network specifier with matching SSID and BSSID pattern, but different UID.
- * c) Ensure that the agent specifier is not satisfied by specifier.
- */
- @Test
- public void
- testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithDifferentUid() {
- WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
-
- PatternMatcher ssidPattern =
- new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
- Pair<MacAddress, MacAddress> bssidPattern =
- Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
- MacAddress.fromString(TEST_BSSID_OUI_MASK));
- WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
- wificonfigurationNetworkSpecifier.allowedKeyManagement
- .set(WifiConfiguration.KeyMgmt.WPA_PSK);
- WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
- ssidPattern,
- bssidPattern,
- wificonfigurationNetworkSpecifier,
- TEST_UID_1, TEST_PACKAGE_1);
-
- assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
- assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
- }
private WifiConfiguration createDefaultWifiConfiguration() {
WifiConfiguration wifiConfiguration = new WifiConfiguration();
@@ -448,8 +389,7 @@
}
private WifiNetworkAgentSpecifier createDefaultNetworkAgentSpecifier() {
- return new WifiNetworkAgentSpecifier(createDefaultWifiConfiguration(), TEST_UID,
- TEST_PACKAGE);
+ return new WifiNetworkAgentSpecifier(createDefaultWifiConfiguration());
}
}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
index 1619744..3b67236 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
@@ -29,7 +29,6 @@
import android.net.NetworkSpecifier;
import android.os.Parcel;
import android.os.PatternMatcher;
-import android.os.Process;
import android.util.Pair;
import androidx.test.filters.SmallTest;
@@ -41,8 +40,6 @@
*/
@SmallTest
public class WifiNetworkSpecifierTest {
- private static final int TEST_UID = 5;
- private static final String TEST_PACKAGE_NAME = "com.test";
private static final String TEST_SSID = "Test123";
private static final String TEST_BSSID_OUI_BASE_ADDRESS = "12:12:12:00:00:00";
private static final String TEST_BSSID_OUI_MASK = "ff:ff:ff:00:00:00";
@@ -62,7 +59,6 @@
assertTrue(specifier instanceof WifiNetworkSpecifier);
WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier;
- assertEquals(Process.myUid(), wifiNetworkSpecifier.requestorUid);
assertEquals(TEST_SSID, wifiNetworkSpecifier.ssidPatternMatcher.getPath());
assertEquals(PATTERN_PREFIX, wifiNetworkSpecifier.ssidPatternMatcher.getType());
assertEquals(WifiManager.ALL_ZEROS_MAC_ADDRESS,
@@ -367,8 +363,7 @@
new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration,
- TEST_UID, TEST_PACKAGE_NAME);
+ wifiConfiguration);
Parcel parcelW = Parcel.obtain();
specifier.writeToParcel(parcelW, 0);
@@ -399,8 +394,7 @@
new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration,
- TEST_UID, TEST_PACKAGE_NAME);
+ wifiConfiguration);
assertTrue(specifier.satisfiedBy(null));
assertTrue(specifier.satisfiedBy(new MatchAllNetworkSpecifier()));
@@ -422,15 +416,13 @@
new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration,
- TEST_UID, TEST_PACKAGE_NAME);
+ wifiConfiguration);
WifiNetworkSpecifier specifier2 =
new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration,
- TEST_UID, TEST_PACKAGE_NAME);
+ wifiConfiguration);
assertTrue(specifier2.satisfiedBy(specifier1));
}
@@ -451,8 +443,7 @@
new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration1,
- TEST_UID, TEST_PACKAGE_NAME);
+ wifiConfiguration1);
WifiConfiguration wifiConfiguration2 = new WifiConfiguration();
wifiConfiguration2.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
@@ -460,8 +451,7 @@
new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration2,
- TEST_UID, TEST_PACKAGE_NAME);
+ wifiConfiguration2);
assertFalse(specifier2.satisfiedBy(specifier1));
}
@@ -482,15 +472,13 @@
new WifiNetworkSpecifier(new PatternMatcher("", PATTERN_LITERAL),
Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration,
- TEST_UID, TEST_PACKAGE_NAME);
+ wifiConfiguration);
WifiNetworkSpecifier specifier2 =
new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration,
- TEST_UID, TEST_PACKAGE_NAME);
+ wifiConfiguration);
assertFalse(specifier2.satisfiedBy(specifier1));
}
@@ -511,44 +499,13 @@
new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration,
- TEST_UID, TEST_PACKAGE_NAME);
+ wifiConfiguration);
WifiNetworkSpecifier specifier2 =
new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
Pair.create(WifiManager.ALL_ZEROS_MAC_ADDRESS,
WifiManager.ALL_ZEROS_MAC_ADDRESS),
- wifiConfiguration,
- TEST_UID, TEST_PACKAGE_NAME);
-
- assertFalse(specifier2.satisfiedBy(specifier1));
- }
-
- /**
- * Validate NetworkSpecifier matching.
- * a) Create network specifier 1 for WPA_PSK network
- * b) Create network specifier 2 with different package name .
- * c) Ensure that the specifier 2 is not satisfied by specifier 1.
- */
- @Test
- public void testWifiNetworkSpecifierDoesNotSatisfyWhenPackageNameDifferent() {
- WifiConfiguration wifiConfiguration = new WifiConfiguration();
- wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
- wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
-
- WifiNetworkSpecifier specifier1 =
- new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
- Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
- MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration,
- TEST_UID, TEST_PACKAGE_NAME);
-
- WifiNetworkSpecifier specifier2 =
- new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
- Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
- MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration,
- TEST_UID, TEST_PACKAGE_NAME + "blah");
+ wifiConfiguration);
assertFalse(specifier2.satisfiedBy(specifier1));
}
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java
index c3b6285..81b02fa 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java
@@ -162,17 +162,6 @@
collector.checkThat("Match unexpected", oldNs.satisfiedBy(newNs), equalTo(false));
}
- /**
- * Validate that agent network specifier cannot be used as in network requests - i.e. that
- * throws an exception when queried for UID validity.
- */
- @Test(expected = SecurityException.class)
- public void testNoUsageInRequest() {
- WifiAwareAgentNetworkSpecifier dut = new WifiAwareAgentNetworkSpecifier();
-
- dut.assertValidFromUid(0);
- }
-
// utilities
/**
@@ -182,6 +171,6 @@
WifiAwareNetworkSpecifier getDummyNetworkSpecifier(int clientId) {
return new WifiAwareNetworkSpecifier(WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_OOB,
WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, clientId, 0, 0, new byte[6],
- null, null, 10, 5, 0);
+ null, null, 10, 5);
}
}
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 65fbf5b..c5f9804 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -1564,7 +1564,7 @@
WifiAwareNetworkSpecifier ns = new WifiAwareNetworkSpecifier(NETWORK_SPECIFIER_TYPE_IB,
WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER, 5, 568, 334,
HexEncoding.decode("000102030405".toCharArray(), false),
- "01234567890123456789012345678901".getBytes(), "blah blah", 666, 4, 10001);
+ "01234567890123456789012345678901".getBytes(), "blah blah", 666, 4);
Parcel parcelW = Parcel.obtain();
ns.writeToParcel(parcelW, 0);
diff --git a/wifi/tests/src/android/net/wifi/wificond/NativeScanResultTest.java b/wifi/tests/src/android/net/wifi/wificond/NativeScanResultTest.java
index 06f12f7..0df170f 100644
--- a/wifi/tests/src/android/net/wifi/wificond/NativeScanResultTest.java
+++ b/wifi/tests/src/android/net/wifi/wificond/NativeScanResultTest.java
@@ -28,7 +28,6 @@
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.BitSet;
/**
* Unit tests for {@link android.net.wifi.wificond.NativeScanResult}.
@@ -46,7 +45,7 @@
private static final int TEST_FREQUENCY = 2456;
private static final int TEST_SIGNAL_MBM = -45;
private static final long TEST_TSF = 34455441;
- private static final BitSet TEST_CAPABILITY = new BitSet(16) {{ set(2); set(5); }};
+ private static final int TEST_CAPABILITY = (0x1 << 2) | (0x1 << 5);
private static final boolean TEST_ASSOCIATED = true;
private static final int[] RADIO_CHAIN_IDS = { 0, 1 };
private static final int[] RADIO_CHAIN_LEVELS = { -56, -65 };
diff --git a/wifi/tests/src/android/net/wifi/wificond/WifiCondManagerTest.java b/wifi/tests/src/android/net/wifi/wificond/WifiCondManagerTest.java
index 5ba02a7..32105be 100644
--- a/wifi/tests/src/android/net/wifi/wificond/WifiCondManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/wificond/WifiCondManagerTest.java
@@ -720,8 +720,7 @@
@Test
public void testRegisterDeathHandler() throws Exception {
Runnable deathHandler = mock(Runnable.class);
- assertTrue(mWificondControl.initialize(deathHandler));
- verify(mWificond).tearDownInterfaces();
+ mWificondControl.setOnServiceDeadCallback(deathHandler);
mWificondControl.binderDied();
mLooper.dispatchAll();
verify(deathHandler).run();
@@ -734,7 +733,7 @@
@Test
public void testDeathHandling() throws Exception {
Runnable deathHandler = mock(Runnable.class);
- assertTrue(mWificondControl.initialize(deathHandler));
+ mWificondControl.setOnServiceDeadCallback(deathHandler);
testSetupInterfaceForClientMode();