Merge "Moves car_audio_configuration.xml out of CarService package"
diff --git a/EncryptionRunner/Android.bp b/EncryptionRunner/Android.bp
new file mode 100644
index 0000000..b02e6de
--- /dev/null
+++ b/EncryptionRunner/Android.bp
@@ -0,0 +1,49 @@
+// 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.
+
+android_library {
+ name: "EncryptionRunner",
+ min_sdk_version: "23",
+ product_variables: {
+ pdk: {
+ enabled: false,
+ },
+ },
+ srcs: [
+ "src/**/*.java",
+ ],
+}
+
+android_test {
+ name: "EncryptionRunnerTest",
+ min_sdk_version: "23",
+ srcs: [
+ "test/**/*.java",
+ ],
+ product_variables: {
+ pdk: {
+ enabled: false,
+ },
+ },
+ libs: [
+ "android.test.base",
+ "android.test.runner",
+ ],
+ static_libs: [
+ "androidx.test.rules",
+ "EncryptionRunner",
+ "junit",
+ "truth-prebuilt",
+ ],
+}
diff --git a/EncryptionRunner/AndroidManifest.xml b/EncryptionRunner/AndroidManifest.xml
new file mode 100644
index 0000000..8d7643e
--- /dev/null
+++ b/EncryptionRunner/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ package="android.car.encryptionrunner" >
+ <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="23" />
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.car.encryptionrunner"
+ android:label="Encryption Runner Tests" />
+</manifest>
diff --git a/EncryptionRunner/AndroidTest.xml b/EncryptionRunner/AndroidTest.xml
new file mode 100644
index 0000000..b6cbbfa
--- /dev/null
+++ b/EncryptionRunner/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+<configuration description="Runs Tests for EncryptionRunner.">
+ <option name="test-tag" value="EncryptionRunnerTest" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="EncryptionRunnerTest.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.car.encryptionrunner" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
diff --git a/EncryptionRunner/src/android/car/encryptionrunner/DummyEncryptionRunner.java b/EncryptionRunner/src/android/car/encryptionrunner/DummyEncryptionRunner.java
new file mode 100644
index 0000000..b08c985
--- /dev/null
+++ b/EncryptionRunner/src/android/car/encryptionrunner/DummyEncryptionRunner.java
@@ -0,0 +1,138 @@
+/*
+ * 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.car.encryptionrunner;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * An ecnryption runnner that doesn't actually do encryption. Useful for debugging. Do not use in
+ * production environments.
+ */
+class DummyEncryptionRunner implements EncryptionRunner {
+
+ private static final String KEY = "key";
+ private static final String INIT = "init";
+ private static final String INIT_RESPONSE = "initResponse";
+ private static final String CLIENT_RESPONSE = "clientResponse";
+ public static final String PIN = "1234";
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({Mode.UNKNOWN, Mode.CLIENT, Mode.SERVER})
+ private @interface Mode {
+
+ int UNKNOWN = 0;
+ int CLIENT = 1;
+ int SERVER = 2;
+ }
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({State.UNKNOWN, State.WAITING_FOR_RESPONSE, State.FINISHED})
+ private @interface State {
+
+ int UNKNOWN = 0;
+ int WAITING_FOR_RESPONSE = 1;
+ int FINISHED = 2;
+ }
+
+ @Mode
+ private int mMode;
+ @State
+ private int mState;
+
+ @Override
+ public HandshakeMessage initHandshake() {
+ mMode = Mode.CLIENT;
+ mState = State.WAITING_FOR_RESPONSE;
+ return HandshakeMessage.newBuilder()
+ .setNextMessage(INIT.getBytes())
+ .build();
+ }
+
+ @Override
+ public HandshakeMessage respondToInitRequest(byte[] initializationRequest)
+ throws HandshakeException {
+ mMode = Mode.SERVER;
+ if (!new String(initializationRequest).equals(INIT)) {
+ throw new HandshakeException("Unexpected initialization request");
+ }
+ mState = State.WAITING_FOR_RESPONSE;
+ return HandshakeMessage.newBuilder()
+ .setNextMessage(INIT_RESPONSE.getBytes())
+ .build();
+ }
+
+ @Override
+ public HandshakeMessage continueHandshake(byte[] response) throws HandshakeException {
+ if (mState != State.WAITING_FOR_RESPONSE) {
+ throw new HandshakeException("not waiting for response but got one");
+ }
+ switch(mMode) {
+ case Mode.SERVER:
+ if (!CLIENT_RESPONSE.equals(new String(response))) {
+ throw new HandshakeException("unexpected response: " + new String(response));
+ }
+ mState = State.FINISHED;
+ return HandshakeMessage.newBuilder()
+ .setHandshakeComplete(true)
+ .setKey(new DummyKey())
+ .build();
+ case Mode.CLIENT:
+ if (!INIT_RESPONSE.equals(new String(response))) {
+ throw new HandshakeException("unexpected response: " + new String(response));
+ }
+ mState = State.FINISHED;
+ return HandshakeMessage.newBuilder()
+ .setHandshakeComplete(true)
+ .setKey(new DummyKey())
+ .setNextMessage(CLIENT_RESPONSE.getBytes())
+ .build();
+ default:
+ throw new IllegalStateException();
+ }
+ }
+
+ @Override
+ public Key keyOf(byte[] serialized) {
+ return new DummyKey();
+ }
+
+ @Override
+ public String getPin() {
+ return PIN;
+ }
+
+ @Override
+ public byte[] encryptData(Key key, byte[] data) {
+ return data;
+ }
+
+ @Override
+ public byte[] decryptData(Key key, byte[] encryptedData) {
+ return encryptedData;
+ }
+
+ private class DummyKey implements Key {
+
+ @Override
+ public byte[] asBytes() {
+ return KEY.getBytes();
+ }
+ }
+}
diff --git a/EncryptionRunner/src/android/car/encryptionrunner/EncryptionRunner.java b/EncryptionRunner/src/android/car/encryptionrunner/EncryptionRunner.java
new file mode 100644
index 0000000..7e7bd3e
--- /dev/null
+++ b/EncryptionRunner/src/android/car/encryptionrunner/EncryptionRunner.java
@@ -0,0 +1,87 @@
+/*
+ * 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.car.encryptionrunner;
+
+import android.annotation.NonNull;
+
+/**
+ * A generalized interface that allows for generating shared secrets as well as encrypting
+ * messages.
+ */
+public interface EncryptionRunner {
+
+ /**
+ * Starts an encryption handshake.
+ *
+ * @return A handshake message with information about the handshake that is started.
+ */
+ HandshakeMessage initHandshake();
+
+ /**
+ * Starts an encryption handshake where the device that is being communicated with already
+ * initiated the request.
+ *
+ * @param initializationRequest the bytes that the other device sent over.
+ * @return a handshake message with information about the handshake.
+ * @throws HandshakeException if initialization request is invalid.
+ */
+ HandshakeMessage respondToInitRequest(@NonNull byte[] initializationRequest)
+ throws HandshakeException;
+
+ /**
+ * Continues a handshake after receiving another response from the connected device.
+ *
+ * @param response the response from the other device.
+ * @return a message that can be used to continue the handshake.
+ * @throws HandshakeException if unexpected bytes in response.
+ */
+ HandshakeMessage continueHandshake(@NonNull byte[] response) throws HandshakeException;
+
+ /**
+ * De seriliazes a previously serilized key generated by an instance of this encryption runner.
+ *
+ * @param serialized the serialized bytes of the key.
+ * @return the Key object used for encryption.
+ */
+ Key keyOf(@NonNull byte[] serialized);
+
+ /**
+ * A user visible shared pin. This pin can be used to verify that both devices that are
+ * communicating have agreed to the same key and will be shown to a user.
+ *
+ * @return the user visible pin.
+ */
+ String getPin();
+
+ /**
+ * Encrypts data using an encryption key.
+ *
+ * @param key the key used to encrypt the data.
+ * @param data the data to be encrypted
+ * @return the encrypted data.
+ */
+ byte[] encryptData(@NonNull Key key, @NonNull byte[] data);
+
+ /**
+ * Decrypts data using a specified key.
+ *
+ * @param key The key used to decrypt the data.
+ * @param encryptedData The encrypted data.
+ * @return decrypted data.
+ */
+ byte[] decryptData(@NonNull Key key, @NonNull byte[] encryptedData);
+}
diff --git a/EncryptionRunner/src/android/car/encryptionrunner/EncryptionRunnerFactory.java b/EncryptionRunner/src/android/car/encryptionrunner/EncryptionRunnerFactory.java
new file mode 100644
index 0000000..d975835
--- /dev/null
+++ b/EncryptionRunner/src/android/car/encryptionrunner/EncryptionRunnerFactory.java
@@ -0,0 +1,31 @@
+/*
+ * 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.car.encryptionrunner;
+
+/**
+ * Factory that creates encryption runner.
+ */
+public class EncryptionRunnerFactory {
+
+ /**
+ * Creates a new {@link EncryptionRunner} one that doesn't actually do encryption but is useful
+ * for testing.
+ */
+ static EncryptionRunner newDummyRunner() {
+ return new DummyEncryptionRunner();
+ }
+}
diff --git a/EncryptionRunner/src/android/car/encryptionrunner/HandshakeException.java b/EncryptionRunner/src/android/car/encryptionrunner/HandshakeException.java
new file mode 100644
index 0000000..02c873c
--- /dev/null
+++ b/EncryptionRunner/src/android/car/encryptionrunner/HandshakeException.java
@@ -0,0 +1,27 @@
+/*
+ * 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.car.encryptionrunner;
+
+/**
+ * Exception indicating an error during a Handshake of EncryptionRunner.
+ */
+public class HandshakeException extends Exception {
+
+ public HandshakeException(String message) {
+ super(message);
+ }
+}
diff --git a/EncryptionRunner/src/android/car/encryptionrunner/HandshakeMessage.java b/EncryptionRunner/src/android/car/encryptionrunner/HandshakeMessage.java
new file mode 100644
index 0000000..5286770
--- /dev/null
+++ b/EncryptionRunner/src/android/car/encryptionrunner/HandshakeMessage.java
@@ -0,0 +1,97 @@
+/*
+ * 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.car.encryptionrunner;
+
+import android.annotation.Nullable;
+
+/**
+ * During an {@link EncryptionRunner} handshake process, these are the messages returned as part
+ * of each step.
+ */
+public class HandshakeMessage {
+
+ private final boolean mHandShakeComplete;
+ private final Key mKey;
+ private final byte[] mNextMessage;
+
+ /**
+ * @return Returns a builder for {@link HandshakeMessage}.
+ */
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ /**
+ * Use the builder;
+ */
+ private HandshakeMessage(
+ boolean handShakeComplete,
+ @Nullable Key key,
+ @Nullable byte[] nextMessage) {
+ mHandShakeComplete = handShakeComplete;
+ mKey = key;
+ mNextMessage = nextMessage;
+ }
+
+ /**
+ * Returns the next message to send in a handshake.
+ */
+ @Nullable
+ public byte[] getNextMessage() {
+ return mNextMessage == null ? null : mNextMessage.clone();
+ }
+
+ /**
+ * Returns true if the handshake is complete.
+ */
+ public boolean isHandShakeComplete() {
+ return mHandShakeComplete;
+ }
+
+ /**
+ * Returns the encryption key that can be used to encrypt data.
+ */
+ @Nullable
+ public Key getKey() {
+ return mKey;
+ }
+
+ static class Builder {
+ boolean mHandshakeComplete;
+ Key mKey;
+ byte[] mNextMessage;
+
+ Builder setHandshakeComplete(boolean handshakeComplete) {
+ mHandshakeComplete = handshakeComplete;
+ return this;
+ }
+
+ Builder setKey(Key key) {
+ mKey = key;
+ return this;
+ }
+
+ Builder setNextMessage(byte[] nextMessage) {
+ mNextMessage = nextMessage == null ? null : nextMessage.clone();
+ return this;
+ }
+
+ HandshakeMessage build() {
+ return new HandshakeMessage(mHandshakeComplete, mKey, mNextMessage);
+ }
+ }
+}
diff --git a/EncryptionRunner/src/android/car/encryptionrunner/Key.java b/EncryptionRunner/src/android/car/encryptionrunner/Key.java
new file mode 100644
index 0000000..97dd362
--- /dev/null
+++ b/EncryptionRunner/src/android/car/encryptionrunner/Key.java
@@ -0,0 +1,29 @@
+/*
+ * 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.car.encryptionrunner;
+
+import android.annotation.NonNull;
+
+/**
+ * Represents a serializable encryption key.
+ */
+public interface Key {
+ /**
+ * Returns a serialized encryption key.
+ */
+ @NonNull byte[] asBytes();
+}
diff --git a/EncryptionRunner/test/android/car/encryptionrunner/EncryptionRunnerTest.java b/EncryptionRunner/test/android/car/encryptionrunner/EncryptionRunnerTest.java
new file mode 100644
index 0000000..d08b37a
--- /dev/null
+++ b/EncryptionRunner/test/android/car/encryptionrunner/EncryptionRunnerTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.encryptionrunner;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class EncryptionRunnerTest {
+
+ private static final byte[] sTestData = "test data".getBytes();
+
+ @Test
+ public void happyFlow() throws Exception {
+ // This performs a handshake and then sends an "encrypted" message back and forth.
+ // Any encryption runner should be able to do this.
+ // Right now just using the dummy runner, when we have a real runner we can extract this
+ // method or just have the factory create a real runner.
+ EncryptionRunner clientRunner = EncryptionRunnerFactory.newDummyRunner();
+ EncryptionRunner serverRunner = EncryptionRunnerFactory.newDummyRunner();
+ HandshakeMessage initialClientMessage = clientRunner.initHandshake();
+
+ assertThat(initialClientMessage.isHandShakeComplete()).isFalse();
+ assertThat(initialClientMessage.getKey()).isNull();
+ assertThat(initialClientMessage.getNextMessage()).isNotNull();
+
+ HandshakeMessage initialServerMessage =
+ serverRunner.respondToInitRequest(initialClientMessage.getNextMessage());
+
+ assertThat(initialServerMessage.isHandShakeComplete()).isFalse();
+ assertThat(initialServerMessage.getKey()).isNull();
+ assertThat(initialServerMessage.getNextMessage()).isNotNull();
+
+ HandshakeMessage clientMessage =
+ clientRunner.continueHandshake(initialServerMessage.getNextMessage());
+
+ assertThat(clientMessage.isHandShakeComplete()).isTrue();
+ assertThat(clientMessage.getKey()).isNotNull();
+ assertThat(clientMessage.getNextMessage()).isNotNull();
+
+ HandshakeMessage serverMessage =
+ serverRunner.continueHandshake(clientMessage.getNextMessage());
+
+ assertThat(serverMessage.isHandShakeComplete()).isTrue();
+ assertThat(serverMessage.getKey()).isNotNull();
+ assertThat(serverMessage.getNextMessage()).isNull();
+
+ assertThat(serverRunner.decryptData(
+ serverMessage.getKey(),
+ clientRunner.encryptData(clientMessage.getKey(), sTestData))).isEqualTo(sTestData);
+ assertThat(clientRunner.decryptData(
+ clientMessage.getKey(),
+ serverRunner.encryptData(serverMessage.getKey(), sTestData))).isEqualTo(sTestData);
+ }
+
+}
diff --git a/car-cluster-logging-renderer/res/values-en-rXC/strings.xml b/car-cluster-logging-renderer/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..04b729a
--- /dev/null
+++ b/car-cluster-logging-renderer/res/values-en-rXC/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="8762201061451645291">"LOGGING_INSTRUMENT_CLUSTER_RENDERER"</string>
+</resources>
diff --git a/car-default-input-service/res/values-en-rXC/strings.xml b/car-default-input-service/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..7a58b83
--- /dev/null
+++ b/car-default-input-service/res/values-en-rXC/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="2732799531977169961">"Car Default Input Service"</string>
+</resources>
diff --git a/car-lib/Android.bp b/car-lib/Android.bp
index c037284..1d887fa 100644
--- a/car-lib/Android.bp
+++ b/car-lib/Android.bp
@@ -71,7 +71,7 @@
installable: true,
}
-doc_defaults {
+stubs_defaults {
name: "android.car-docs-default",
srcs: [
"src/**/*.java",
@@ -80,7 +80,6 @@
libs: [
"android.car",
],
- custom_template: "droiddoc-templates-sdk",
product_variables: {
pdk: {
enabled: false,
@@ -121,13 +120,13 @@
],
}
-droiddoc {
+droidstubs {
name: "android.car-stubs-docs",
defaults: ["android.car-docs-default"],
api_tag_name: "ANDROID_CAR",
api_filename: "api.txt",
removed_api_filename: "removed.txt",
- args: "-hide 113 -hide 110 -nodocs -stubpackages android.car* ",
+ args: "--hide UnavailableSymbol --no-docs --stub-packages android.car* ",
installable: false,
check_api: {
last_released: {
@@ -147,14 +146,14 @@
},
}
-droiddoc {
+droidstubs {
name: "android.car-system-stubs-docs",
defaults: ["android.car-docs-default"],
api_tag_name: "ANDROID_CAR_SYSTEM",
api_filename: "api.txt",
removed_api_filename: "removed.txt",
- args: "-hide 113 -hide 110 -nodocs -stubpackages android.car* " +
- "-showAnnotation android.annotation.SystemApi ",
+ args: "--hide UnavailableSymbol --no-docs --stub-packages android.car* " +
+ "--show-annotation android.annotation.SystemApi ",
installable: false,
check_api: {
last_released: {
@@ -174,14 +173,14 @@
},
}
-droiddoc {
+droidstubs {
name: "android.car-test-stubs-docs",
defaults: ["android.car-docs-default"],
api_tag_name: "ANDROID_CAR_SYSTEM",
api_filename: "api.txt",
removed_api_filename: "removed.txt",
- args: "-hide 113 -hide 110 -nodocs -stubpackages android.car* " +
- "-showAnnotation android.annotation.TestApi ",
+ args: "--hide UnavailableSymbol --no-docs --stub-packages android.car* " +
+ "--show-annotation android.annotation.TestApi ",
installable: false,
check_api: {
current: {
@@ -194,7 +193,7 @@
},
}
-droiddoc {
+droidstubs {
name: "android.car-stub-docs",
srcs: [
"src/**/*.java",
@@ -204,8 +203,7 @@
],
api_tag_name: "ANDROID_CAR_STUB",
api_filename: "api.txt",
- custom_template: "droiddoc-templates-sdk",
- args: "-nodocs -stubpackages android.car* ",
+ args: "--hide UnavailableSymbol --no-docs --stub-packages android.car* ",
installable: false,
product_variables: {
pdk: {
diff --git a/car-lib/api/baseline.txt b/car-lib/api/baseline.txt
new file mode 100644
index 0000000..16e4b7b
--- /dev/null
+++ b/car-lib/api/baseline.txt
@@ -0,0 +1,41 @@
+// Baseline format: 1.0
+HiddenTypeParameter: android.car.hardware.CarSensorManager#getPropertyList():
+ Method android.car.hardware.CarSensorManager.getPropertyList() references hidden type class android.car.hardware.CarPropertyConfig.
+HiddenTypeParameter: android.car.navigation.CarNavigationStatusManager#getInstrumentClusterInfo():
+ Method android.car.navigation.CarNavigationStatusManager.getInstrumentClusterInfo() references hidden type android.car.navigation.CarNavigationInstrumentCluster.
+
+
+HiddenTypedefConstant: android.car.CarInfoManager#getEvConnectorTypes():
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.EvConnectorType#UNKNOWN
+HiddenTypedefConstant: android.car.CarInfoManager#getFuelTypes():
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.FuelType#UNKNOWN
+HiddenTypedefConstant: android.car.hardware.CarSensorManager#getLatestSensorEvent(int) parameter #0:
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
+HiddenTypedefConstant: android.car.hardware.CarSensorManager#isSensorSupported(int) parameter #0:
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
+HiddenTypedefConstant: android.car.hardware.CarSensorManager#isSensorSupported(int[], int) parameter #1:
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
+HiddenTypedefConstant: android.car.hardware.CarSensorManager#registerListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int, int) parameter #1:
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
+HiddenTypedefConstant: android.car.hardware.CarSensorManager#unregisterListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int) parameter #1:
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
+
+
+ReferencesHidden: android.car.hardware.CarSensorManager#getPropertyList():
+ Class android.car.hardware.CarPropertyConfig is hidden but was referenced (as return type parameter) from public method android.car.hardware.CarSensorManager.getPropertyList()
+ReferencesHidden: android.car.navigation.CarNavigationStatusManager#getInstrumentClusterInfo():
+ Class android.car.navigation.CarNavigationInstrumentCluster is hidden but was referenced (as return type) from public method android.car.navigation.CarNavigationStatusManager.getInstrumentClusterInfo()
+
+
+RequiresPermission: android.car.hardware.CarSensorManager#registerListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int, int):
+ Method 'registerListener' documentation mentions permissions already declared by @RequiresPermission
+
+
+SdkConstant: android.car.Car#CAR_INTENT_ACTION_MEDIA_TEMPLATE:
+ Field 'CAR_INTENT_ACTION_MEDIA_TEMPLATE' is missing @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+
+
+Todo: android.car.CarInfoManager#getVehicleId():
+ Documentation mentions 'TODO'
+
+
diff --git a/car-lib/api/system-baseline.txt b/car-lib/api/system-baseline.txt
new file mode 100644
index 0000000..3d4f02d
--- /dev/null
+++ b/car-lib/api/system-baseline.txt
@@ -0,0 +1,59 @@
+// Baseline format: 1.0
+HiddenTypeParameter: android.car.vms.VmsAvailableLayers#VmsAvailableLayers(java.util.Set<android.car.vms.VmsAssociatedLayer>, int) parameter #0:
+ Parameter associatedLayers references hidden type class android.car.vms.VmsAssociatedLayer.
+HiddenTypeParameter: android.car.vms.VmsAvailableLayers#getAssociatedLayers():
+ Method android.car.vms.VmsAvailableLayers.getAssociatedLayers() references hidden type class android.car.vms.VmsAssociatedLayer.
+HiddenTypeParameter: android.car.vms.VmsOperationRecorder#VmsOperationRecorder(android.car.vms.VmsOperationRecorder.Writer) parameter #0:
+ Parameter writer references hidden type android.car.vms.VmsOperationRecorder.Writer.
+HiddenTypeParameter: android.car.vms.VmsPublisherClientService#getSubscriptions():
+ Method android.car.vms.VmsPublisherClientService.getSubscriptions() references hidden type android.car.vms.VmsSubscriptionState.
+HiddenTypeParameter: android.car.vms.VmsPublisherClientService#onVmsSubscriptionChange(android.car.vms.VmsSubscriptionState) parameter #0:
+ Parameter subscriptionState references hidden type android.car.vms.VmsSubscriptionState.
+
+
+HiddenTypedefConstant: android.car.CarInfoManager#getEvConnectorTypes():
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.EvConnectorType#UNKNOWN
+HiddenTypedefConstant: android.car.CarInfoManager#getFuelTypes():
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.FuelType#UNKNOWN
+HiddenTypedefConstant: android.car.hardware.CarPropertyValue#getStatus():
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarPropertyValue#STATUS_AVAILABLE
+HiddenTypedefConstant: android.car.hardware.CarSensorManager#getLatestSensorEvent(int) parameter #0:
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
+HiddenTypedefConstant: android.car.hardware.CarSensorManager#isSensorSupported(int) parameter #0:
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
+HiddenTypedefConstant: android.car.hardware.CarSensorManager#isSensorSupported(int[], int) parameter #1:
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
+HiddenTypedefConstant: android.car.hardware.CarSensorManager#registerListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int, int) parameter #1:
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
+HiddenTypedefConstant: android.car.hardware.CarSensorManager#unregisterListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int) parameter #1:
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
+
+
+ReferencesHidden: android.car.vms.VmsAvailableLayers#VmsAvailableLayers(java.util.Set<android.car.vms.VmsAssociatedLayer>, int) parameter #0:
+ Class android.car.vms.VmsAssociatedLayer is hidden but was referenced (as parameter type) from public parameter associatedLayers in android.car.vms.VmsAvailableLayers(java.util.Set<android.car.vms.VmsAssociatedLayer> associatedLayers, int sequence)
+ReferencesHidden: android.car.vms.VmsAvailableLayers#getAssociatedLayers():
+ Class android.car.vms.VmsAssociatedLayer is hidden but was referenced (as return type parameter) from public method android.car.vms.VmsAvailableLayers.getAssociatedLayers()
+ReferencesHidden: android.car.vms.VmsOperationRecorder#VmsOperationRecorder(android.car.vms.VmsOperationRecorder.Writer) parameter #0:
+ Class android.car.vms.VmsOperationRecorder.Writer is hidden but was referenced (as parameter type) from public parameter writer in android.car.vms.VmsOperationRecorder(android.car.vms.VmsOperationRecorder.Writer writer)
+ReferencesHidden: android.car.vms.VmsPublisherClientService#getSubscriptions():
+ Class android.car.vms.VmsSubscriptionState is hidden but was referenced (as return type) from public method android.car.vms.VmsPublisherClientService.getSubscriptions()
+ReferencesHidden: android.car.vms.VmsPublisherClientService#onVmsSubscriptionChange(android.car.vms.VmsSubscriptionState) parameter #0:
+ Class android.car.vms.VmsSubscriptionState is hidden but was referenced (as parameter type) from public parameter subscriptionState in android.car.vms.VmsPublisherClientService.onVmsSubscriptionChange(android.car.vms.VmsSubscriptionState subscriptionState)
+
+
+RequiresPermission: android.car.hardware.CarSensorManager#registerListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int, int):
+ Method 'registerListener' documentation mentions permissions already declared by @RequiresPermission
+
+
+SdkConstant: android.car.Car#CAR_INTENT_ACTION_MEDIA_TEMPLATE:
+ Field 'CAR_INTENT_ACTION_MEDIA_TEMPLATE' is missing @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+
+
+Todo: android.car.CarInfoManager#getVehicleId():
+ Documentation mentions 'TODO'
+Todo: android.car.cluster.renderer.InstrumentClusterRenderer:
+ Documentation mentions 'TODO'
+Todo: android.car.drivingstate.CarDrivingStateEvent#DRIVING_STATE_IDLING:
+ Documentation mentions 'TODO'
+
+
diff --git a/car-lib/api/system-current.txt b/car-lib/api/system-current.txt
index a0046eb..a5965e9 100644
--- a/car-lib/api/system-current.txt
+++ b/car-lib/api/system-current.txt
@@ -3,6 +3,7 @@
public final class Car {
field public static final java.lang.String CABIN_SERVICE = "cabin";
field public static final java.lang.String CAR_DRIVING_STATE_SERVICE = "drivingstate";
+ field public static final java.lang.String CAR_TRUST_AGENT_ENROLLMENT_SERVICE = "trust_enroll";
field public static final java.lang.String DIAGNOSTIC_SERVICE = "diagnostic";
field public static final java.lang.String HVAC_SERVICE = "hvac";
field public static final java.lang.String PERMISSION_CAR_DIAGNOSTIC_CLEAR = "android.car.permission.CLEAR_CAR_DIAGNOSTICS";
@@ -10,6 +11,7 @@
field public static final java.lang.String PERMISSION_CAR_DRIVING_STATE = "android.car.permission.CAR_DRIVING_STATE";
field public static final java.lang.String PERMISSION_CAR_DYNAMICS_STATE = "android.car.permission.CAR_DYNAMICS_STATE";
field public static final java.lang.String PERMISSION_CAR_ENGINE_DETAILED = "android.car.permission.CAR_ENGINE_DETAILED";
+ field public static final java.lang.String PERMISSION_CAR_ENROLL_TRUST = "android.car.permission.CAR_ENROLL_TRUST";
field public static final java.lang.String PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL = "android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL";
field public static final java.lang.String PERMISSION_CAR_POWER = "android.car.permission.CAR_POWER";
field public static final java.lang.String PERMISSION_CAR_PROJECTION = "android.car.permission.CAR_PROJECTION";
@@ -891,6 +893,38 @@
}
+package android.car.trust {
+
+ public final class CarTrustAgentEnrollmentManager {
+ method public void activateToken(long) throws android.car.CarNotConnectedException;
+ method public void enrollmentHandshakeAccepted() throws android.car.CarNotConnectedException;
+ method public java.util.List<java.lang.Integer> getEnrollmentHandlesForUser(int) throws android.car.CarNotConnectedException;
+ method public void initiateEnrollmentHandshake(android.bluetooth.BluetoothDevice) throws android.car.CarNotConnectedException;
+ method public void revokeTrust(long) throws android.car.CarNotConnectedException;
+ method public void setBleCallback(android.car.trust.CarTrustAgentEnrollmentManager.CarTrustAgentBleCallback) throws android.car.CarNotConnectedException;
+ method public void setEnrollmentCallback(android.car.trust.CarTrustAgentEnrollmentManager.CarTrustAgentEnrollmentCallback) throws android.car.CarNotConnectedException;
+ method public void startEnrollmentAdvertising() throws android.car.CarNotConnectedException;
+ method public void stopEnrollmentAdvertising() throws android.car.CarNotConnectedException;
+ method public void terminateEnrollmentHandshake() throws android.car.CarNotConnectedException;
+ }
+
+ public static abstract interface CarTrustAgentEnrollmentManager.CarTrustAgentBleCallback {
+ method public abstract void onBleEnrollmentDeviceConnected(android.bluetooth.BluetoothDevice);
+ method public abstract void onBleEnrollmentDeviceDisconnected(android.bluetooth.BluetoothDevice);
+ method public abstract void onEnrollmentAdvertisingFailed(int);
+ method public abstract void onEnrollmentAdvertisingStarted();
+ }
+
+ public static abstract interface CarTrustAgentEnrollmentManager.CarTrustAgentEnrollmentCallback {
+ method public abstract void onAuthStringAvailable(android.bluetooth.BluetoothDevice, java.lang.String);
+ method public abstract void onEnrollmentHandshakeFailure(android.bluetooth.BluetoothDevice, int);
+ method public abstract void onEscrowTokenActiveStateChanged(long, boolean);
+ method public abstract void onEscrowTokenAdded(long);
+ method public abstract void onTrustRevoked(long, boolean);
+ }
+
+}
+
package android.car.vms {
public final class VmsAvailableLayers implements android.os.Parcelable {
diff --git a/car-lib/api/test-baseline.txt b/car-lib/api/test-baseline.txt
new file mode 100644
index 0000000..d71a9e5
--- /dev/null
+++ b/car-lib/api/test-baseline.txt
@@ -0,0 +1,55 @@
+// Baseline format: 1.0
+HiddenTypeParameter: android.car.drivingstate.CarUxRestrictionsManager#getConfig():
+ Method android.car.drivingstate.CarUxRestrictionsManager.getConfig() references hidden type android.car.drivingstate.CarUxRestrictionsConfiguration.
+HiddenTypeParameter: android.car.drivingstate.CarUxRestrictionsManager#getStagedConfig():
+ Method android.car.drivingstate.CarUxRestrictionsManager.getStagedConfig() references hidden type android.car.drivingstate.CarUxRestrictionsConfiguration.
+HiddenTypeParameter: android.car.hardware.CarSensorManager#getPropertyList():
+ Method android.car.hardware.CarSensorManager.getPropertyList() references hidden type class android.car.hardware.CarPropertyConfig.
+HiddenTypeParameter: android.car.navigation.CarNavigationStatusManager#getInstrumentClusterInfo():
+ Method android.car.navigation.CarNavigationStatusManager.getInstrumentClusterInfo() references hidden type android.car.navigation.CarNavigationInstrumentCluster.
+
+
+HiddenTypedefConstant: android.car.CarInfoManager#getEvConnectorTypes():
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.EvConnectorType#UNKNOWN
+HiddenTypedefConstant: android.car.CarInfoManager#getFuelTypes():
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.FuelType#UNKNOWN
+HiddenTypedefConstant: android.car.hardware.CarSensorManager#getLatestSensorEvent(int) parameter #0:
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
+HiddenTypedefConstant: android.car.hardware.CarSensorManager#isSensorSupported(int) parameter #0:
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
+HiddenTypedefConstant: android.car.hardware.CarSensorManager#isSensorSupported(int[], int) parameter #1:
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
+HiddenTypedefConstant: android.car.hardware.CarSensorManager#registerListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int, int) parameter #1:
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
+HiddenTypedefConstant: android.car.hardware.CarSensorManager#unregisterListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int) parameter #1:
+ Typedef references constant which isn't part of the API, skipping in documentation: android.car.hardware.CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL
+
+
+MissingPermission: android.car.drivingstate.CarUxRestrictionsManager#getConfig():
+ Permission Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION required by method android.car.drivingstate.CarUxRestrictionsManager.getConfig() is hidden or removed
+MissingPermission: android.car.drivingstate.CarUxRestrictionsManager#getStagedConfig():
+ Permission Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION required by method android.car.drivingstate.CarUxRestrictionsManager.getStagedConfig() is hidden or removed
+
+
+ReferencesHidden: android.car.drivingstate.CarUxRestrictionsManager#getConfig():
+ Class android.car.drivingstate.CarUxRestrictionsConfiguration is hidden but was referenced (as return type) from public method android.car.drivingstate.CarUxRestrictionsManager.getConfig()
+ReferencesHidden: android.car.drivingstate.CarUxRestrictionsManager#getStagedConfig():
+ Class android.car.drivingstate.CarUxRestrictionsConfiguration is hidden but was referenced (as return type) from public method android.car.drivingstate.CarUxRestrictionsManager.getStagedConfig()
+ReferencesHidden: android.car.hardware.CarSensorManager#getPropertyList():
+ Class android.car.hardware.CarPropertyConfig is hidden but was referenced (as return type parameter) from public method android.car.hardware.CarSensorManager.getPropertyList()
+ReferencesHidden: android.car.navigation.CarNavigationStatusManager#getInstrumentClusterInfo():
+ Class android.car.navigation.CarNavigationInstrumentCluster is hidden but was referenced (as return type) from public method android.car.navigation.CarNavigationStatusManager.getInstrumentClusterInfo()
+
+
+RequiresPermission: android.car.hardware.CarSensorManager#registerListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int, int):
+ Method 'registerListener' documentation mentions permissions already declared by @RequiresPermission
+
+
+SdkConstant: android.car.Car#CAR_INTENT_ACTION_MEDIA_TEMPLATE:
+ Field 'CAR_INTENT_ACTION_MEDIA_TEMPLATE' is missing @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+
+
+Todo: android.car.CarInfoManager#getVehicleId():
+ Documentation mentions 'TODO'
+
+
diff --git a/car-lib/api/test-current.txt b/car-lib/api/test-current.txt
index ca87f9a..02cbd6c 100644
--- a/car-lib/api/test-current.txt
+++ b/car-lib/api/test-current.txt
@@ -6,6 +6,15 @@
}
+package android.car.drivingstate {
+
+ public final class CarUxRestrictionsManager {
+ method public synchronized android.car.drivingstate.CarUxRestrictionsConfiguration getConfig() throws android.car.CarNotConnectedException;
+ method public synchronized android.car.drivingstate.CarUxRestrictionsConfiguration getStagedConfig() throws android.car.CarNotConnectedException;
+ }
+
+}
+
package android.car.media {
public final class CarAudioManager {
diff --git a/car-lib/src/android/car/Car.java b/car-lib/src/android/car/Car.java
index b4c4509..85f0ca5 100644
--- a/car-lib/src/android/car/Car.java
+++ b/car-lib/src/android/car/Car.java
@@ -35,6 +35,7 @@
import android.car.settings.CarConfigurationManager;
import android.car.storagemonitoring.CarStorageMonitoringManager;
import android.car.test.CarTestManagerBinderWrapper;
+import android.car.trust.CarTrustAgentEnrollmentManager;
import android.car.vms.VmsSubscriberManager;
import android.content.ComponentName;
import android.content.Context;
@@ -171,6 +172,13 @@
public static final String STORAGE_MONITORING_SERVICE = "storage_monitoring";
/**
+ * Service name for {@link android.car.trust.CarTrustAgentEnrollmentManager}
+ * @hide
+ */
+ @SystemApi
+ public static final String CAR_TRUST_AGENT_ENROLLMENT_SERVICE = "trust_enroll";
+
+ /**
* Service for testing. This is system app only feature.
* Service name for {@link CarTestManager}, to be used in {@link #getCarManager(String)}.
* @hide
@@ -426,6 +434,15 @@
public static final String PERMISSION_STORAGE_MONITORING =
"android.car.permission.STORAGE_MONITORING";
+ /**
+ * Permission necessary to enroll a device as a trusted authenticator device.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String PERMISSION_CAR_ENROLL_TRUST =
+ "android.car.permission.CAR_ENROLL_TRUST";
+
/** Type of car connection: platform runs directly in car. */
public static final int CONNECTION_TYPE_EMBEDDED = 5;
@@ -711,6 +728,7 @@
* @return Matching service manager or null if there is no such service.
* @throws CarNotConnectedException if the connection to the car service has been lost.
*/
+ @Nullable
public Object getCarManager(String serviceName) throws CarNotConnectedException {
CarManagerBase manager;
ICar service = getICarOrThrow();
@@ -779,6 +797,7 @@
}
}
+ @Nullable
private CarManagerBase createCarManager(String serviceName, IBinder binder)
throws CarNotConnectedException {
CarManagerBase manager = null;
@@ -849,6 +868,9 @@
case CAR_CONFIGURATION_SERVICE:
manager = new CarConfigurationManager(binder);
break;
+ case CAR_TRUST_AGENT_ENROLLMENT_SERVICE:
+ manager = new CarTrustAgentEnrollmentManager(binder, mContext, mEventHandler);
+ break;
default:
break;
}
diff --git a/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java b/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java
index b93b9e3..7b60538 100644
--- a/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java
+++ b/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.TestApi;
import android.car.Car;
import android.car.CarManagerBase;
import android.car.CarNotConnectedException;
@@ -178,6 +179,49 @@
}
/**
+ * Get the current staged configuration, staged config file will only be accessible after
+ * the boot up completed or user has been switched.
+ * This methods is only for test purpose, please do not use in production.
+ *
+ * @return current staged configuration, {@code null} if it's not available
+ *
+ * @hide
+ *
+ */
+ @TestApi
+ @Nullable
+ @RequiresPermission(value = Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION)
+ public synchronized CarUxRestrictionsConfiguration getStagedConfig()
+ throws CarNotConnectedException {
+ try {
+ return mUxRService.getStagedConfig();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not get staged UX restrictions staged configuration " + e);
+ throw new CarNotConnectedException(e);
+ }
+ }
+
+ /**
+ * Get the current prod configuration
+ *
+ * @return current prod configuration that is in effect.
+ *
+ * @hide
+ *
+ */
+ @TestApi
+ @RequiresPermission(value = Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION)
+ public synchronized CarUxRestrictionsConfiguration getConfig()
+ throws CarNotConnectedException {
+ try {
+ return mUxRService.getConfig();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not get production UX restrictions prod configuration" + e);
+ throw new CarNotConnectedException(e);
+ }
+ }
+
+ /**
* Class that implements the listener interface and gets called back from the
* {@link com.android.car.CarDrivingStateService} across the binder interface.
*/
diff --git a/car-lib/src/android/car/drivingstate/ICarUxRestrictionsManager.aidl b/car-lib/src/android/car/drivingstate/ICarUxRestrictionsManager.aidl
index 270c74e..8f48c5e 100644
--- a/car-lib/src/android/car/drivingstate/ICarUxRestrictionsManager.aidl
+++ b/car-lib/src/android/car/drivingstate/ICarUxRestrictionsManager.aidl
@@ -32,4 +32,6 @@
void unregisterUxRestrictionsChangeListener(in ICarUxRestrictionsChangeListener listener) = 1;
CarUxRestrictions getCurrentUxRestrictions() = 2;
boolean saveUxRestrictionsConfigurationForNextBoot(in CarUxRestrictionsConfiguration config) = 3;
+ CarUxRestrictionsConfiguration getStagedConfig() = 4;
+ CarUxRestrictionsConfiguration getConfig() = 5;
}
diff --git a/car-lib/src/android/car/trust/CarTrustAgentEnrollmentManager.java b/car-lib/src/android/car/trust/CarTrustAgentEnrollmentManager.java
new file mode 100644
index 0000000..48ee384
--- /dev/null
+++ b/car-lib/src/android/car/trust/CarTrustAgentEnrollmentManager.java
@@ -0,0 +1,437 @@
+/*
+ * 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.car.trust;
+
+import static android.car.Car.PERMISSION_CAR_ENROLL_TRUST;
+
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.bluetooth.BluetoothDevice;
+import android.car.CarManagerBase;
+import android.car.CarNotConnectedException;
+import android.content.Context;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.lang.ref.WeakReference;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+
+/**
+ * APIs to help enroll a remote device as a trusted device that can be used to authenticate a user
+ * in the head unit.
+ * <p>
+ * The call sequence to add a new trusted device from the client should be as follows:
+ * <ol>
+ * <li> setEnrollmentCallback()
+ * <li> setBleCallback(bleCallback)
+ * <li> startEnrollmentAdvertising()
+ * <li> wait for onEnrollmentAdvertisingStarted() or
+ * <li> wait for onBleEnrollmentDeviceConnected() and check if the device connected is the right
+ * one.
+ * <li> initiateEnrollmentHandhake()
+ * <li> wait for onAuthStringAvailable() to get the pairing code to display to the user
+ * <li> enrollmentHandshakeAccepted() after user confirms the pairing code
+ * <li> wait for onEscrowTokenAdded()
+ * <li> Authenticate user's credentials by showing the lock screen
+ * <li> activateToken()
+ * <li> wait for onEscrowTokenActiveStateChanged() to add the device as a trusted device and show
+ * in the list
+ * </ol>
+ *
+ * @hide
+ */
+@SystemApi
+public final class CarTrustAgentEnrollmentManager implements CarManagerBase {
+ private static final String TAG = "CarTrustEnrollMgr";
+ private final Context mContext;
+ private final ICarTrustAgentEnrollment mEnrollmentService;
+ private Object mListenerLock = new Object();
+ @GuardedBy("mListenerLock")
+ private CarTrustAgentEnrollmentCallback mEnrollmentCallback;
+ @GuardedBy("mListenerLock")
+ private CarTrustAgentBleCallback mBleCallback;
+ @GuardedBy("mListenerLock")
+ private final ListenerToEnrollmentService mListenerToEnrollmentService =
+ new ListenerToEnrollmentService(this);
+ private final ListenerToBleService mListenerToBleService = new ListenerToBleService(this);
+
+
+ /** @hide */
+ public CarTrustAgentEnrollmentManager(IBinder service, Context context, Handler handler) {
+ mContext = context;
+ mEnrollmentService = ICarTrustAgentEnrollment.Stub.asInterface(service);
+ }
+
+ /** @hide */
+ @Override
+ public synchronized void onCarDisconnected() {
+ }
+
+ /**
+ * Starts broadcasting enrollment UUID on BLE.
+ * Phones can scan and connect for the enrollment process to begin.
+ */
+ @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
+ public void startEnrollmentAdvertising() throws CarNotConnectedException {
+ try {
+ mEnrollmentService.startEnrollmentAdvertising();
+ } catch (RemoteException e) {
+ throw new CarNotConnectedException(e);
+ }
+ }
+
+ /**
+ * Stops Enrollment advertising.
+ */
+ @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
+ public void stopEnrollmentAdvertising() throws CarNotConnectedException {
+ try {
+ mEnrollmentService.stopEnrollmentAdvertising();
+ } catch (RemoteException e) {
+ throw new CarNotConnectedException(e);
+ }
+ }
+
+ /**
+ * Initiates the handshake with the phone for enrollment. This should be called after the
+ * user has confirmed the phone that is requesting enrollment.
+ *
+ * @param device the remote Bluetooth device that is trying to enroll.
+ */
+ @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
+ public void initiateEnrollmentHandshake(BluetoothDevice device)
+ throws CarNotConnectedException {
+ try {
+ mEnrollmentService.initiateEnrollmentHandshake(device);
+ } catch (RemoteException e) {
+ throw new CarNotConnectedException(e);
+ }
+ }
+
+ /**
+ * Confirms that the enrollment handshake has been accepted by the user. This should be called
+ * after the user has confirmed the verification code displayed on the UI.
+ */
+ @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
+ public void enrollmentHandshakeAccepted() throws CarNotConnectedException {
+ try {
+ mEnrollmentService.enrollmentHandshakeAccepted();
+ } catch (RemoteException e) {
+ throw new CarNotConnectedException(e);
+ }
+ }
+
+ /**
+ * Provides an option to quit enrollment if the pairing code doesn't match for example.
+ */
+ @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
+ public void terminateEnrollmentHandshake() throws CarNotConnectedException {
+ try {
+ mEnrollmentService.terminateEnrollmentHandshake();
+ } catch (RemoteException e) {
+ throw new CarNotConnectedException(e);
+ }
+ }
+
+ /**
+ * Activate the newly added escrow token.
+ *
+ * @param handle the handle corresponding to the escrow token
+ */
+ @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
+ public void activateToken(long handle) throws CarNotConnectedException {
+ try {
+ mEnrollmentService.activateToken(handle);
+ } catch (RemoteException e) {
+ throw new CarNotConnectedException(e);
+ }
+ }
+
+ /**
+ * Revoke trust for the remote device denoted by the handle.
+ *
+ * @param handle the handle associated with the escrow token
+ */
+ @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
+ public void revokeTrust(long handle) throws CarNotConnectedException {
+ try {
+ mEnrollmentService.revokeTrust(handle);
+ } catch (RemoteException e) {
+ throw new CarNotConnectedException(e);
+ }
+ }
+
+ /**
+ * Register for enrollment event callbacks.
+ *
+ * @param callback The callback methods to call, null to unregister
+ */
+ @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
+ public void setEnrollmentCallback(@Nullable CarTrustAgentEnrollmentCallback callback)
+ throws CarNotConnectedException {
+ if (callback == null) {
+ unregisterEnrollmentCallback();
+ } else {
+ registerEnrollmentCallback(callback);
+ }
+ }
+
+ private void registerEnrollmentCallback(CarTrustAgentEnrollmentCallback callback)
+ throws CarNotConnectedException {
+ synchronized (mListenerLock) {
+ if (callback != null && mEnrollmentCallback == null) {
+ try {
+ mEnrollmentService.registerEnrollmentCallback(mListenerToEnrollmentService);
+ mEnrollmentCallback = callback;
+ } catch (RemoteException e) {
+ throw new CarNotConnectedException(e);
+ }
+ }
+ }
+ }
+
+ private void unregisterEnrollmentCallback() throws CarNotConnectedException {
+ synchronized (mListenerLock) {
+ if (mEnrollmentCallback != null) {
+ try {
+ mEnrollmentService.unregisterEnrollmentCallback(mListenerToEnrollmentService);
+ } catch (RemoteException e) {
+ throw new CarNotConnectedException(e);
+ }
+ mEnrollmentCallback = null;
+ }
+ }
+ }
+
+ /**
+ * Register for general BLE callbacks
+ *
+ * @param callback The callback methods to call, null to unregister
+ */
+ @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
+ public void setBleCallback(@Nullable CarTrustAgentBleCallback callback)
+ throws CarNotConnectedException {
+ if (callback == null) {
+ unregisterBleCallback();
+ } else {
+ registerBleCallback(callback);
+ }
+ }
+
+ private void registerBleCallback(CarTrustAgentBleCallback callback)
+ throws CarNotConnectedException {
+ synchronized (mListenerLock) {
+ if (callback != null && mBleCallback == null) {
+ try {
+ mEnrollmentService.registerBleCallback(mListenerToBleService);
+ mBleCallback = callback;
+ } catch (RemoteException e) {
+ throw new CarNotConnectedException(e);
+ }
+ }
+ }
+ }
+
+ private void unregisterBleCallback() throws CarNotConnectedException {
+ synchronized (mListenerLock) {
+ if (mBleCallback != null) {
+ try {
+ mEnrollmentService.unregisterBleCallback(mListenerToBleService);
+ } catch (RemoteException e) {
+ throw new CarNotConnectedException(e);
+ }
+ mBleCallback = null;
+ }
+ }
+ }
+
+ /**
+ * Provides a list of enrollment handles for the given user id.
+ * Each enrollment handle corresponds to a trusted device for the given user.
+ *
+ * @param uid user id.
+ * @return list of the Enrollment handles for the user id.
+ */
+ @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
+ public List<Integer> getEnrollmentHandlesForUser(int uid) throws CarNotConnectedException {
+ try {
+ return Arrays.stream(
+ mEnrollmentService.getEnrollmentHandlesForUser(uid)).boxed().collect(
+ Collectors.toList());
+ } catch (RemoteException e) {
+ throw new CarNotConnectedException(e);
+ }
+ }
+
+ /**
+ * Callback interface for Trusted device enrollment applications to implement. The applications
+ * get notified on various enrollment state change events.
+ */
+ public interface CarTrustAgentEnrollmentCallback {
+ /**
+ * Communicate about failure/timeouts in the handshake process.
+ *
+ * @param device the remote device trying to enroll
+ * @param errorCode information on what failed.
+ */
+ void onEnrollmentHandshakeFailure(BluetoothDevice device, int errorCode);
+
+ /**
+ * Present the pairing/authentication string to the user.
+ *
+ * @param device the remote device trying to enroll
+ * @param authString the authentication string to show to the user to confirm across
+ * both devices
+ */
+ void onAuthStringAvailable(BluetoothDevice device, String authString);
+
+ /**
+ * Escrow token was received and the Trust Agent framework has generated a corresponding
+ * handle.
+ *
+ * @param handle the handle associated with the escrow token.
+ */
+ void onEscrowTokenAdded(long handle);
+
+ /**
+ * Escrow token corresponding to the given handle has been removed.
+ *
+ * @param handle the handle associated with the escrow token.
+ * @param success status of the revoke operation.
+ */
+ void onTrustRevoked(long handle, boolean success);
+
+ /**
+ * Escrow token's active state changed.
+ *
+ * @param handle the handle associated with the escrow token
+ * @param active True if token has been activated, false if not.
+ */
+ void onEscrowTokenActiveStateChanged(long handle, boolean active);
+
+ }
+
+ /**
+ * Callback interface for Trusted device enrollment applications to implement. The applications
+ * get notified on various BLE state change events that happen during trusted device enrollment.
+ */
+ public interface CarTrustAgentBleCallback {
+ /**
+ * Indicates a remote device connected on BLE.
+ */
+ void onBleEnrollmentDeviceConnected(BluetoothDevice device);
+
+ /**
+ * Indicates a remote device disconnected on BLE.
+ */
+ void onBleEnrollmentDeviceDisconnected(BluetoothDevice device);
+
+ /**
+ * Indicates that the device is broadcasting for trusted device enrollment on BLE.
+ */
+ void onEnrollmentAdvertisingStarted();
+
+ /**
+ * Indicates a failure in BLE broadcasting for enrollment.
+ */
+ void onEnrollmentAdvertisingFailed(int errorCode);
+ }
+
+ // TODO(ramperry) - call the client callbacks from the methods of this listener to the service
+ // callbacks.
+ private class ListenerToEnrollmentService extends ICarTrustAgentEnrollmentCallback.Stub {
+ private final WeakReference<CarTrustAgentEnrollmentManager> mMgr;
+
+ ListenerToEnrollmentService(CarTrustAgentEnrollmentManager mgr) {
+ mMgr = new WeakReference<>(mgr);
+ }
+
+ /**
+ * Communicate about failure/timeouts in the handshake process.
+ */
+ public void onEnrollmentHandshakeFailure(BluetoothDevice device, int errorCode) {
+ }
+
+ /**
+ * Present the pairing/authentication string to the user.
+ */
+ public void onAuthStringAvailable(BluetoothDevice device, byte[] authString) {
+ }
+
+ /**
+ * Escrow token was received and the Trust Agent framework has generated a corresponding
+ * handle.
+ */
+ public void onEscrowTokenAdded(long handle) {
+ }
+
+ /**
+ * Escrow token corresponding to the given handle has been removed.
+ */
+ public void onTrustRevoked(long handle, boolean success) {
+ }
+
+ /**
+ * Escrow token's active state changed.
+ */
+ public void onEscrowTokenActiveStateChanged(long handle, boolean active) {
+ }
+ }
+
+ // TODO(ramperry) - call the client callbacks from the methods of this listener to the service
+ // callbacks.
+ private class ListenerToBleService extends ICarTrustAgentBleCallback.Stub {
+ private final WeakReference<CarTrustAgentEnrollmentManager> mMgr;
+
+ ListenerToBleService(CarTrustAgentEnrollmentManager mgr) {
+ mMgr = new WeakReference<>(mgr);
+ }
+
+ /**
+ * Called when the GATT server is started and BLE is successfully advertising for
+ * enrollment.
+ */
+ public void onEnrollmentAdvertisingStarted() {
+ }
+
+ /**
+ * Called when the BLE enrollment advertisement fails to start.
+ * see AdvertiseCallback#ADVERTISE_FAILED_* for possible error codes.
+ */
+ public void onEnrollmentAdvertisingFailed(int errorCode) {
+ }
+
+ /**
+ * Called when a remote device is connected on BLE.
+ */
+ public void onBleEnrollmentDeviceConnected(BluetoothDevice device) {
+ }
+
+ /**
+ * Called when a remote device is disconnected on BLE.
+ */
+ public void onBleEnrollmentDeviceDisconnected(BluetoothDevice device) {
+ }
+ }
+}
diff --git a/car-lib/src/android/car/trust/ICarTrustAgentBleCallback.aidl b/car-lib/src/android/car/trust/ICarTrustAgentBleCallback.aidl
new file mode 100644
index 0000000..e2a972d
--- /dev/null
+++ b/car-lib/src/android/car/trust/ICarTrustAgentBleCallback.aidl
@@ -0,0 +1,47 @@
+/*
+ * 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.car.trust;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * Callback interface for BLE connection state changes during trusted device enrollment.
+ *
+ * @hide
+ */
+oneway interface ICarTrustAgentBleCallback {
+ /**
+ * Called when the GATT server is started and BLE is successfully advertising for enrollment.
+ */
+ void onEnrollmentAdvertisingStarted();
+
+ /**
+ * Called when the BLE enrollment advertisement fails to start.
+ * see AdvertiseCallback#ADVERTISE_FAILED_* for possible error codes.
+ */
+ void onEnrollmentAdvertisingFailed(int errorCode);
+
+ /**
+ * Called when a remote device is connected on BLE.
+ */
+ void onBleEnrollmentDeviceConnected(in BluetoothDevice device);
+
+ /**
+ * Called when a remote device is disconnected on BLE.
+ */
+ void onBleEnrollmentDeviceDisconnected(in BluetoothDevice device);
+}
diff --git a/car-lib/src/android/car/trust/ICarTrustAgentEnrollment.aidl b/car-lib/src/android/car/trust/ICarTrustAgentEnrollment.aidl
new file mode 100644
index 0000000..0476f70
--- /dev/null
+++ b/car-lib/src/android/car/trust/ICarTrustAgentEnrollment.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.car.trust;
+
+import android.bluetooth.BluetoothDevice;
+import android.car.trust.ICarTrustAgentBleCallback;
+import android.car.trust.ICarTrustAgentEnrollmentCallback;
+
+/**
+ * Binder interface for CarTrustAgentEnrollmentService. The service implements the functionality
+ * to communicate with the remote device securely to enroll the remote device as a trusted device.
+ *
+ * @hide
+ */
+interface ICarTrustAgentEnrollment {
+ void startEnrollmentAdvertising();
+ void stopEnrollmentAdvertising();
+ void initiateEnrollmentHandshake(in BluetoothDevice device);
+ void enrollmentHandshakeAccepted();
+ void terminateEnrollmentHandshake();
+ void activateToken(in long handle);
+ void revokeTrust(in long handle);
+ int[] getEnrollmentHandlesForUser(in int uid);
+ void registerEnrollmentCallback(in ICarTrustAgentEnrollmentCallback callback);
+ void unregisterEnrollmentCallback(in ICarTrustAgentEnrollmentCallback callback);
+ void registerBleCallback(in ICarTrustAgentBleCallback callback);
+ void unregisterBleCallback(in ICarTrustAgentBleCallback callback);
+}
diff --git a/car-lib/src/android/car/trust/ICarTrustAgentEnrollmentCallback.aidl b/car-lib/src/android/car/trust/ICarTrustAgentEnrollmentCallback.aidl
new file mode 100644
index 0000000..9457fec
--- /dev/null
+++ b/car-lib/src/android/car/trust/ICarTrustAgentEnrollmentCallback.aidl
@@ -0,0 +1,52 @@
+/*
+ * 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.car.trust;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * Callback interface for state changes during Trusted device enrollment.
+ *
+ * @hide
+ */
+oneway interface ICarTrustAgentEnrollmentCallback {
+ /**
+ * Communicate about failure/timeouts in the handshake process.
+ */
+ void onEnrollmentHandshakeFailure(in BluetoothDevice device, in int errorCode);
+
+ /**
+ * Present the pairing/authentication string to the user.
+ */
+ void onAuthStringAvailable(in BluetoothDevice device, in byte[] authString);
+
+ /**
+ * Escrow token was received and the Trust Agent framework has generated a corresponding handle.
+ */
+ void onEscrowTokenAdded(in long handle);
+
+ /*
+ * Escrow token corresponding to the given handle has been removed.
+ */
+ void onTrustRevoked(in long handle, in boolean success);
+
+ /**
+ * Escrow token's active state changed.
+ */
+ void onEscrowTokenActiveStateChanged(in long handle, in boolean active);
+
+}
diff --git a/car-maps-placeholder/res/values-en-rXC/strings.xml b/car-maps-placeholder/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..4e862cd
--- /dev/null
+++ b/car-maps-placeholder/res/values-en-rXC/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="6575346965016311017">"Maps"</string>
+ <string name="error_text" msgid="5575174711944349180">"No maps application installed. Please contact your car manufacturer."</string>
+</resources>
diff --git a/car-usb-handler/res/values-en-rXC/strings.xml b/car-usb-handler/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..1a5589e
--- /dev/null
+++ b/car-usb-handler/res/values-en-rXC/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="6963366455471441257">"USB Handler"</string>
+ <string name="usb_saved_devices" msgid="2829442070749964872">"Saved devices"</string>
+ <string name="usb_pref_delete_title" msgid="3885061814853467483">"Remove handling app for USB device"</string>
+ <string name="usb_pref_delete_message" msgid="5849493572520646218">"Are you sure you wan to delete dafault handling app for %1$s?"</string>
+ <string name="usb_pref_delete_yes" msgid="7803356145103146036">"Yes"</string>
+ <string name="usb_pref_delete_cancel" msgid="5999791462730255929">"Cancel"</string>
+ <string name="usb_resolving_handlers" msgid="1943100136172948686">"Getting supported handlers"</string>
+ <string name="usb_unknown_device" msgid="4211439272338937095">"Unknown USB device"</string>
+</resources>
diff --git a/car-usb-handler/res/values/strings.xml b/car-usb-handler/res/values/strings.xml
index cb59e27..e73a03a 100644
--- a/car-usb-handler/res/values/strings.xml
+++ b/car-usb-handler/res/values/strings.xml
@@ -24,4 +24,11 @@
<string name="usb_pref_delete_cancel">Cancel</string>
<string name="usb_resolving_handlers">Getting supported handlers</string>
<string name="usb_unknown_device">Unknown USB device</string>
+
+ <!-- VID:PID pairs (in hexadecimal and separated by a colon, e.g. 18d1:4e11)
+ of Android devices known to be incompatible with AOAP. Devices in this
+ list will not be probed by UsbHostManagementActivity for AOAP support. -->
+ <string-array name="config_AoapIncompatibleDeviceIds">
+ <item>18d1:9302</item>
+ </string-array>
</resources>
diff --git a/car-usb-handler/src/android/car/usb/handler/AoapInterface.java b/car-usb-handler/src/android/car/usb/handler/AoapInterface.java
index e4d843f..35b570a 100644
--- a/car-usb-handler/src/android/car/usb/handler/AoapInterface.java
+++ b/car-usb-handler/src/android/car/usb/handler/AoapInterface.java
@@ -13,11 +13,16 @@
*/
package android.car.usb.handler;
+import android.content.Context;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.util.Log;
+import android.util.Pair;
+
import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
final class AoapInterface {
/**
@@ -94,6 +99,12 @@
*/
public static final int AOAP_TIMEOUT_MS = 2000;
+ /**
+ * Set of VID:PID pairs blacklisted through config_AoapIncompatibleDeviceIds. Only
+ * isDeviceBlacklisted() should ever access this variable.
+ */
+ private static Set<Pair<Integer, Integer>> sBlacklistedVidPidPairs;
+
private static final String TAG = AoapInterface.class.getSimpleName();
public static int getProtocol(UsbDeviceConnection conn) {
@@ -107,8 +118,8 @@
return (buffer[1] << 8) | buffer[0];
}
- public static boolean isSupported(UsbDeviceConnection conn) {
- return getProtocol(conn) >= 1;
+ public static boolean isSupported(Context context, UsbDevice device, UsbDeviceConnection conn) {
+ return !isDeviceBlacklisted(context, device) && getProtocol(conn) >= 1;
}
public static void sendString(UsbDeviceConnection conn, int index, String string)
@@ -134,6 +145,33 @@
}
}
+ public static synchronized boolean isDeviceBlacklisted(Context context, UsbDevice device) {
+ if (sBlacklistedVidPidPairs == null) {
+ sBlacklistedVidPidPairs = new HashSet<>();
+ String[] idPairs =
+ context.getResources().getStringArray(R.array.config_AoapIncompatibleDeviceIds);
+ for (String idPair : idPairs) {
+ boolean success = false;
+ String[] tokens = idPair.split(":");
+ if (tokens.length == 2) {
+ try {
+ sBlacklistedVidPidPairs.add(Pair.create(Integer.parseInt(tokens[0], 16),
+ Integer.parseInt(tokens[1], 16)));
+ success = true;
+ } catch (NumberFormatException e) {
+ }
+ }
+ if (!success) {
+ Log.e(TAG, "config_AoapIncompatibleDeviceIds contains malformed value: "
+ + idPair);
+ }
+ }
+ }
+
+ return sBlacklistedVidPidPairs.contains(Pair.create(device.getVendorId(),
+ device.getProductId()));
+ }
+
public static boolean isDeviceInAoapMode(UsbDevice device) {
if (device == null) {
return false;
diff --git a/car-usb-handler/src/android/car/usb/handler/BootUsbScanner.java b/car-usb-handler/src/android/car/usb/handler/BootUsbScanner.java
index 18dabdc..9658a37 100644
--- a/car-usb-handler/src/android/car/usb/handler/BootUsbScanner.java
+++ b/car-usb-handler/src/android/car/usb/handler/BootUsbScanner.java
@@ -20,7 +20,8 @@
} else {
UsbDeviceConnection connection = UsbUtil.openConnection(manager, device);
try {
- if (connection != null && AoapInterface.isSupported(connection)) {
+ if (connection != null
+ && AoapInterface.isSupported(context, device, connection)) {
handle(context, device);
}
} finally {
diff --git a/car-usb-handler/src/android/car/usb/handler/UsbDeviceHandlerResolver.java b/car-usb-handler/src/android/car/usb/handler/UsbDeviceHandlerResolver.java
index 51c2838..b5abc58 100644
--- a/car-usb-handler/src/android/car/usb/handler/UsbDeviceHandlerResolver.java
+++ b/car-usb-handler/src/android/car/usb/handler/UsbDeviceHandlerResolver.java
@@ -489,7 +489,7 @@
DeviceContext deviceContext =
new DeviceContext(device, UsbDeviceSettings.constructSettings(device), settings);
if (deviceContext.connection != null
- && AoapInterface.isSupported(deviceContext.connection)) {
+ && AoapInterface.isSupported(mContext, device, deviceContext.connection)) {
deviceContext.mActiveDeviceOptions.addAll(getDeviceMatches(device, intent, true));
queryNextAoapHandler(deviceContext);
} else {
diff --git a/car-usb-handler/src/android/car/usb/handler/UsbUtil.java b/car-usb-handler/src/android/car/usb/handler/UsbUtil.java
index 823c660..b251715 100644
--- a/car-usb-handler/src/android/car/usb/handler/UsbUtil.java
+++ b/car-usb-handler/src/android/car/usb/handler/UsbUtil.java
@@ -16,6 +16,7 @@
package android.car.usb.handler;
import android.annotation.Nullable;
+import android.content.Context;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
@@ -30,12 +31,13 @@
* Util methods to work with USB devices.
*/
class UsbUtil {
- public static List<UsbDevice> findAllPossibleAndroidDevices(UsbManager usbManager) {
+ public static List<UsbDevice> findAllPossibleAndroidDevices(Context context,
+ UsbManager usbManager) {
HashMap<String, UsbDevice> devices = usbManager.getDeviceList();
ArrayList<UsbDevice> androidDevices = new ArrayList<>(devices.size());
for (UsbDevice device : devices.values()) {
UsbDeviceConnection connection = openConnection(usbManager, device);
- if (AoapInterface.isSupported(connection)) {
+ if (AoapInterface.isSupported(context, device, connection)) {
androidDevices.add(device);
}
connection.close();
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-en-rXC/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..da28702
--- /dev/null
+++ b/car_product/overlay/frameworks/base/core/res/res/values-en-rXC/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="owner_name" msgid="3416113395996003764">"Driver"</string>
+</resources>
diff --git a/service/res/values-en-rXC/config.xml b/service/res/values-en-rXC/config.xml
new file mode 100644
index 0000000..8188d25
--- /dev/null
+++ b/service/res/values-en-rXC/config.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<!-- Resources to configure car service based on each OEM's preference. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="inputService" msgid="3911088558664251138">"android.car.input.service/.DefaultInputService"</string>
+ <string name="instrumentClusterRendererService" msgid="2610429499504752025">"android.car.cluster.loggingrenderer/.LoggingClusterRenderingService"</string>
+ <string name="activityBlockingActivity" msgid="1307583481022873450">"com.android.car/com.android.car.pm.ActivityBlockingActivity"</string>
+ <string name="activityWhitelist" msgid="3812149730686980242">"com.android.systemui,com.google.android.packageinstaller/com.android.packageinstaller.permission.ui.GrantPermissionsActivity"</string>
+ <string name="activityBlacklist" msgid="4824386090073724380"></string>
+ <string-array name="allowedAppInstallSources">
+ </string-array>
+ <string name="defaultHomeActivity" msgid="5991064545193106309"></string>
+ <string name="activityHandlerForFlashWearChanges" msgid="8628535766919400479">"com.google.android.car.defaultstoragemonitoringcompanionapp/.MainActivity"</string>
+ <string name="intentReceiverForUnacceptableIoMetrics" msgid="4017502061746918341">"com.google.android.car.defaultstoragemonitoringcompanionapp/.ExcessiveIoIntentReceiver"</string>
+</resources>
diff --git a/service/res/values-en-rXC/strings.xml b/service/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..9c48d03
--- /dev/null
+++ b/service/res/values-en-rXC/strings.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_title" msgid="2818894849672603016">"Car service"</string>
+ <string name="car_permission_label" msgid="2215078736675564541">"Car information"</string>
+ <string name="car_permission_desc" msgid="37967366937946700">"Access your car\'s information."</string>
+ <string name="car_permission_label_cabin" msgid="7737204489497269651">"Car Cabin"</string>
+ <string name="car_permission_desc_cabin" msgid="5658746726474282714">"Access your car\'s accessories, including doors, mirrors, seats, and windows."</string>
+ <string name="car_permission_label_camera" msgid="608969838109034886">"Car Camera"</string>
+ <string name="car_permission_desc_camera" msgid="7177565584644606387">"Access your car\'s camera(s)."</string>
+ <string name="car_permission_label_energy" msgid="3398092932402178393">"Car energy"</string>
+ <string name="car_permission_desc_energy" msgid="2925098075119509004">"Access your car\'s energy information."</string>
+ <string name="car_permission_label_hvac" msgid="8047274427463154164">"Car Hvac"</string>
+ <string name="car_permission_desc_hvac" msgid="7837686458309247154">"Access your car\'s hvac."</string>
+ <string name="car_permission_label_mileage" msgid="811821331694754443">"Car mileage"</string>
+ <string name="car_permission_desc_mileage" msgid="261946195057016914">"Access your car\'s mileage information."</string>
+ <string name="car_permission_label_speed" msgid="7315924371063443241">"Car speed"</string>
+ <string name="car_permission_desc_speed" msgid="4394638712070011650">"Access your car\'s speed."</string>
+ <string name="car_permission_label_vehicle_dynamics_state" msgid="6475840407257670137">"Vehicle dynamics state"</string>
+ <string name="car_permission_desc_vehicle_dynamics_state" msgid="2458601597024393569">"Access your car\'s dynamics state"</string>
+ <string name="car_permission_label_vendor_extension" msgid="9173884051360575867">"Car vendor channel"</string>
+ <string name="car_permission_desc_vendor_extension" msgid="7223384502421767491">"Access your car\'s vendor channel to exchange car-specific information."</string>
+ <string name="car_permission_label_radio" msgid="4768692394049267617">"Car Radio"</string>
+ <string name="car_permission_desc_radio" msgid="3544198603152937942">"Access your car\'s radio."</string>
+ <string name="car_permission_label_projection" msgid="7830068427803303154">"Car Projection"</string>
+ <string name="car_permission_label_audio_volume" msgid="4802249016680066596">"Car Audio Volume"</string>
+ <string name="car_permission_label_audio_settings" msgid="7788327093945466775">"Car Audio Settings"</string>
+ <string name="car_permission_desc_projection" msgid="2680001094361534439">"Project phone interface on car display."</string>
+ <string name="car_permission_label_mock_vehicle_hal" msgid="7429043278386896118">"Emulate vehicle HAL"</string>
+ <string name="car_permission_desc_mock_vehicle_hal" msgid="3549687008625373417">"Emulate your car\'s vehicle HAL for internal testing purpose."</string>
+ <string name="car_permission_desc_audio_volume" msgid="7484628324723179580">"Control your car\'s audio volume."</string>
+ <string name="car_permission_desc_audio_settings" msgid="2871870084988702516">"Control your car\'s audio settings."</string>
+ <string name="car_permission_label_control_app_blocking" msgid="9112678596919993386">"Application blocking"</string>
+ <string name="car_permission_desc_control_app_blocking" msgid="7539378161760696190">"Control application blocking while driving."</string>
+ <string name="car_permission_car_navigation_manager" msgid="5895461364007854077">"Navigation Manager"</string>
+ <string name="car_permission_desc_car_navigation_manager" msgid="6188751054665471537">"Report navigation data to instrument cluster"</string>
+ <string name="car_permission_car_display_in_cluster" msgid="4005987646292458684">"Direct rendering to instrument cluster"</string>
+ <string name="car_permission_desc_car_display_in_cluster" msgid="2668300546822672927">"Allow an application to declare activities to be displayed in the instrument cluster"</string>
+ <string name="car_permission_car_cluster_control" msgid="1382247204230165674">"Instrument cluster control"</string>
+ <string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Launch apps in the instrument cluster"</string>
+ <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrument Cluster Rendering"</string>
+ <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Receive instrument cluster data"</string>
+ <string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX Restrictions Configuration"</string>
+ <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configure UX Restrictions"</string>
+ <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Car Input Service"</string>
+ <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Handle input events"</string>
+ <string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus failed"</string>
+ <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus does not respond. Unplug and plug back headunit box and restart the car"</string>
+ <string name="activity_blocked_text" msgid="7117775117422916032">"For your safety, this activity isn’t available while you’re driving"</string>
+ <string name="debug_button_text" msgid="6395881820644544676">"Debug Info"</string>
+ <string name="exit_button" msgid="626660628135437972">"Restart App"</string>
+ <string name="car_permission_label_diag_read" msgid="2539365760945541902">"Diagnostic Data"</string>
+ <string name="car_permission_desc_diag_read" msgid="6300061847723430001">"Read diagnostic data from the car"</string>
+ <string name="car_permission_label_diag_clear" msgid="5276954546130303905">"Diagnostic Data"</string>
+ <string name="car_permission_desc_diag_clear" msgid="6890216593617069473">"Clear diagnostic data from the car"</string>
+ <string name="car_permission_label_vms_publisher" msgid="5738544816086673968">"VMS publisher"</string>
+ <string name="car_permission_desc_vms_publisher" msgid="154858011053838907">"Publish vms messages"</string>
+ <string name="car_permission_label_vms_subscriber" msgid="2776578987390414930">"VMS subscriber"</string>
+ <string name="car_permission_desc_vms_subscriber" msgid="6846187370448294450">"Subscribe to vms messages"</string>
+ <string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Flash storage monitoring"</string>
+ <string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Monitor flash storage usage"</string>
+ <string name="car_permission_label_driving_state" msgid="6069696010591163256">"Driving State"</string>
+ <string name="car_permission_desc_driving_state" msgid="4082684279226021396">"Listen to Driving state changes"</string>
+ <string name="car_permission_label_car_engine_detailed" msgid="9002892724697007617">"Engine Detailed"</string>
+ <string name="car_permission_desc_car_engine_detailed" msgid="7360817472577625295">"Access your car\'s detailed engine information"</string>
+ <string name="car_permission_label_car_energy_ports" msgid="4263949434683308884">"Energy Ports"</string>
+ <string name="car_permission_desc_car_energy_ports" msgid="557965577468080620">"Access energy ports"</string>
+ <string name="car_permission_label_car_identification" msgid="1729154715508060432">"Car identification"</string>
+ <string name="car_permission_desc_car_identification" msgid="3446202891279037295">"Access car\'s identification"</string>
+ <string name="car_permission_label_control_car_doors" msgid="982176169678332325">"Car Doors"</string>
+ <string name="car_permission_desc_control_car_doors" msgid="438796526924485694">"Control car\'s doors"</string>
+ <string name="car_permission_label_control_car_windows" msgid="8495424050848179521">"Car Windows"</string>
+ <string name="car_permission_desc_control_car_windows" msgid="7191531366203590752">"Control car\'s windows"</string>
+ <string name="car_permission_label_control_car_mirrors" msgid="5695032398073590372">"Car Mirrors"</string>
+ <string name="car_permission_desc_control_car_mirrors" msgid="1329068133900689986">"Control car\'s mirrors"</string>
+ <string name="car_permission_label_control_car_seats" msgid="4068728236135716379">"Car Seats"</string>
+ <string name="car_permission_desc_control_car_seats" msgid="5319108612196099191">"Control car\'s seats"</string>
+ <string name="car_permission_label_car_info" msgid="5638680944359440535">"Car basic information"</string>
+ <string name="car_permission_desc_car_info" msgid="1697298888275875496">"Access car basic information"</string>
+ <string name="car_permission_label_car_exterior_lights" msgid="6756996909877627936">"Car exterior lights"</string>
+ <string name="car_permission_desc_car_exterior_lights" msgid="5404593475424542202">"Access car exterior lights state"</string>
+ <string name="car_permission_label_control_car_exterior_lights" msgid="822902629489856498">"Car exterior lights"</string>
+ <string name="car_permission_desc_control_car_exterior_lights" msgid="1131149440610151914">"Control car exterior lights"</string>
+ <string name="car_permission_label_car_exterior_environment" msgid="7617025356417480155">"Car exterior temperature"</string>
+ <string name="car_permission_desc_car_exterior_environment" msgid="7665860792016287191">"Access car exterior temperature"</string>
+ <string name="car_permission_label_car_tires" msgid="7261327603773636683">"Car tires"</string>
+ <string name="car_permission_desc_car_tires" msgid="4398458490319322940">"Access car tire information"</string>
+ <string name="car_permission_label_car_powertrain" msgid="246182551556313624">"Car Powertrain"</string>
+ <string name="car_permission_desc_car_powertrain" msgid="3838172429633520832">"Access car powertrain information"</string>
+ <string name="car_permission_label_car_power" msgid="3671174734416372201">"Car Power"</string>
+ <string name="car_permission_desc_car_power" msgid="8955018800799758403">"Access car power state"</string>
+</resources>
diff --git a/service/src/com/android/car/CarUxRestrictionsManagerService.java b/service/src/com/android/car/CarUxRestrictionsManagerService.java
index 868b825..d4d34be 100644
--- a/service/src/com/android/car/CarUxRestrictionsManagerService.java
+++ b/service/src/com/android/car/CarUxRestrictionsManagerService.java
@@ -194,9 +194,8 @@
mContext.registerReceiver(mBroadcastReceiver, filter);
}
- @VisibleForTesting
- @Nullable
- /* package */ CarUxRestrictionsConfiguration getConfig() {
+ @Override
+ public CarUxRestrictionsConfiguration getConfig() {
return mCarUxRestrictionsConfiguration;
}
@@ -398,6 +397,18 @@
return persistConfig(config, CONFIG_FILENAME_STAGED);
}
+ @Override
+ @Nullable
+ public CarUxRestrictionsConfiguration getStagedConfig() {
+ File stagedConfig = mContext.getFileStreamPath(CONFIG_FILENAME_STAGED);
+ if (stagedConfig.exists()) {
+ logd("Attempting to read staged config");
+ return readPersistedConfig(stagedConfig);
+ } else {
+ return null;
+ }
+ }
+
/**
* Writes configuration into the specified file.
*
@@ -668,13 +679,13 @@
CarUxRestrictionsConfiguration createDefaultConfig() {
return new CarUxRestrictionsConfiguration.Builder()
.setUxRestrictions(CarDrivingStateEvent.DRIVING_STATE_PARKED,
- false, CarUxRestrictions.UX_RESTRICTIONS_BASELINE)
+ false, CarUxRestrictions.UX_RESTRICTIONS_BASELINE)
.setUxRestrictions(CarDrivingStateEvent.DRIVING_STATE_IDLING,
- false, CarUxRestrictions.UX_RESTRICTIONS_BASELINE)
+ false, CarUxRestrictions.UX_RESTRICTIONS_BASELINE)
.setUxRestrictions(CarDrivingStateEvent.DRIVING_STATE_MOVING,
- true, CarUxRestrictions.UX_RESTRICTIONS_FULLY_RESTRICTED)
+ true, CarUxRestrictions.UX_RESTRICTIONS_FULLY_RESTRICTED)
.setUxRestrictions(CarDrivingStateEvent.DRIVING_STATE_UNKNOWN,
- true, CarUxRestrictions.UX_RESTRICTIONS_FULLY_RESTRICTED)
+ true, CarUxRestrictions.UX_RESTRICTIONS_FULLY_RESTRICTED)
.build();
}
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index e3381a3..adcedf3 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -42,6 +42,7 @@
import com.android.car.internal.FeatureConfiguration;
import com.android.car.pm.CarPackageManagerService;
import com.android.car.systeminterface.SystemInterface;
+import com.android.car.trust.CarTrustAgentEnrollmentService;
import com.android.car.user.CarUserService;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.car.ICarServiceHelper;
@@ -83,6 +84,7 @@
private final CarDiagnosticService mCarDiagnosticService;
private final CarStorageMonitoringService mCarStorageMonitoringService;
private final CarConfigurationService mCarConfigurationService;
+ private final CarTrustAgentEnrollmentService mCarTrustAgentEnrollmentService;
private final CarUserManagerHelper mUserManagerHelper;
private CarUserService mCarUserService;
@@ -144,6 +146,7 @@
new CarConfigurationService(serviceContext, new JsonReaderImpl());
mCarLocationService = new CarLocationService(
mContext, mCarPropertyService, mUserManagerHelper);
+ mCarTrustAgentEnrollmentService = new CarTrustAgentEnrollmentService(serviceContext);
// Be careful with order. Service depending on other service should be inited later.
List<CarServiceBase> allServices = new ArrayList<>();
@@ -168,6 +171,7 @@
allServices.add(mCarConfigurationService);
allServices.add(mVmsSubscriberService);
allServices.add(mVmsPublisherService);
+ allServices.add(mCarTrustAgentEnrollmentService);
if (mUserManagerHelper.isHeadlessSystemUser()) {
allServices.add(new CarUserService(serviceContext, mUserManagerHelper));
}
@@ -272,6 +276,9 @@
return mCarUXRestrictionsService;
case Car.CAR_CONFIGURATION_SERVICE:
return mCarConfigurationService;
+ case Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE:
+ assertTrustAgentEnrollmentPermission(mContext);
+ return mCarTrustAgentEnrollmentService;
default:
Log.w(CarLog.TAG_SERVICE, "getCarService for unknown service:" + serviceName);
return null;
@@ -334,6 +341,14 @@
assertPermission(context, Car.PERMISSION_VMS_SUBSCRIBER);
}
+ /**
+ * Ensures the caller has the permission to enroll a Trust Agent.
+ * @param context
+ */
+ public static void assertTrustAgentEnrollmentPermission(Context context) {
+ assertPermission(context, Car.PERMISSION_CAR_ENROLL_TRUST);
+ }
+
public static void assertPermission(Context context, String permission) {
if (context.checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("requires " + permission);
diff --git a/service/src/com/android/car/hal/VmsHalService.java b/service/src/com/android/car/hal/VmsHalService.java
index ef33b31..71e1efc 100644
--- a/service/src/com/android/car/hal/VmsHalService.java
+++ b/service/src/com/android/car/hal/VmsHalService.java
@@ -88,7 +88,7 @@
private final Object mLock = new Object();
private final VmsRouting mRouting = new VmsRouting();
@GuardedBy("mLock")
- private final Map<IBinder, VmsLayersOffering> mOfferings = new HashMap<>();
+ private final Map<IBinder, Map<Integer, VmsLayersOffering>> mOfferings = new HashMap<>();
@GuardedBy("mLock")
private final VmsLayersAvailability mAvailableLayers = new VmsLayersAvailability();
private final VmsPublishersInfo mPublishersInfo = new VmsPublishersInfo();
@@ -761,10 +761,22 @@
private void updateOffering(IBinder publisherToken, VmsLayersOffering offering) {
synchronized (mLock) {
- mOfferings.put(publisherToken, offering);
+ Map<Integer, VmsLayersOffering> publisherOfferings = mOfferings.get(publisherToken);
+ if (publisherOfferings == null) {
+ publisherOfferings = new HashMap<>();
+ mOfferings.put(publisherToken, publisherOfferings);
+ }
+ publisherOfferings.put(offering.getPublisherId(), offering);
// Update layers availability.
- mAvailableLayers.setPublishersOffering(mOfferings.values());
+ Set<VmsLayersOffering> allPublisherOfferings = new HashSet<>();
+ for (Map<Integer, VmsLayersOffering> offerings : mOfferings.values()) {
+ allPublisherOfferings.addAll(offerings.values());
+ }
+ if (DBG) {
+ Log.d(TAG, "New layer availability: " + allPublisherOfferings);
+ }
+ mAvailableLayers.setPublishersOffering(allPublisherOfferings);
}
notifyOfAvailabilityChange();
}
diff --git a/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java b/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java
new file mode 100644
index 0000000..e6aeeac
--- /dev/null
+++ b/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java
@@ -0,0 +1,309 @@
+/*
+ * 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.car.trust;
+
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothDevice;
+import android.car.trust.ICarTrustAgentBleCallback;
+import android.car.trust.ICarTrustAgentEnrollment;
+import android.car.trust.ICarTrustAgentEnrollmentCallback;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.car.CarServiceBase;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A service that enables enrolling a phone as a trusted device for authenticating a user on the
+ * IHU. This implements the APIs that an enrollment app can call to conduct an enrollment.
+ */
+public class CarTrustAgentEnrollmentService extends ICarTrustAgentEnrollment.Stub implements
+ CarServiceBase {
+ private static final String TAG = "CarTrustAgentEnroll";
+ private final Context mContext;
+ // List of clients listening to Enrollment state change events.
+ private final List<EnrollmentStateClient> mEnrollmentStateClients = new ArrayList<>();
+ // List of clients listening to BLE state change events.
+ private final List<BleStateChangeClient> mBleStateChangeClients = new ArrayList<>();
+
+ public CarTrustAgentEnrollmentService(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public synchronized void init() {
+ }
+
+ @Override
+ public synchronized void release() {
+ for (EnrollmentStateClient client : mEnrollmentStateClients) {
+ client.mListenerBinder.unlinkToDeath(client, 0);
+ }
+ mEnrollmentStateClients.clear();
+ }
+
+
+ // Binder methods
+ // TODO(b/120911995) The methods don't do anything yet. The implementation will be checked in
+ // a follow up CL.
+ @Override
+ public void startEnrollmentAdvertising() {
+ }
+
+ @Override
+ public void stopEnrollmentAdvertising() {
+ }
+
+ @Override
+ public void initiateEnrollmentHandshake(BluetoothDevice device) {
+ }
+
+ @Override
+ public void enrollmentHandshakeAccepted() {
+ }
+
+ @Override
+ public void terminateEnrollmentHandshake() {
+ }
+
+ @Override
+ public void activateToken(long handle) {
+ }
+
+ @Override
+ public void revokeTrust(long handle) {
+ }
+
+ @Override
+ public int[] getEnrollmentHandlesForUser(int uid) {
+ int[] handles = {};
+ return handles;
+ }
+
+ /**
+ * Registers a {@link ICarTrustAgentEnrollmentCallback} to be notified for changes to the
+ * enrollment state.
+ *
+ * @param listener {@link ICarTrustAgentEnrollmentCallback}
+ */
+ @Override
+ public synchronized void registerEnrollmentCallback(ICarTrustAgentEnrollmentCallback listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("Listener is null");
+ }
+ // If a new client is registering, create a new EnrollmentStateClient and add it to the list
+ // of listening clients.
+ EnrollmentStateClient client = findEnrollmentStateClientLocked(listener);
+ if (client == null) {
+ client = new EnrollmentStateClient(listener);
+ try {
+ listener.asBinder().linkToDeath(client, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Cannot link death recipient to binder ", e);
+ return;
+ }
+ mEnrollmentStateClients.add(client);
+ }
+ }
+
+ /**
+ * Iterates through the list of registered Enrollment State Change clients -
+ * {@link EnrollmentStateClient} and finds if the given client is already registered.
+ *
+ * @param listener Listener to look for.
+ * @return the {@link EnrollmentStateClient} if found, null if not
+ */
+ @Nullable
+ private EnrollmentStateClient findEnrollmentStateClientLocked(
+ ICarTrustAgentEnrollmentCallback listener) {
+ IBinder binder = listener.asBinder();
+ // Find the listener by comparing the binder object they host.
+ for (EnrollmentStateClient client : mEnrollmentStateClients) {
+ if (client.isHoldingBinder(binder)) {
+ return client;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Unregister the given Enrollment State Change listener
+ *
+ * @param listener client to unregister
+ */
+ @Override
+ public synchronized void unregisterEnrollmentCallback(
+ ICarTrustAgentEnrollmentCallback listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("Listener is null");
+ }
+
+ EnrollmentStateClient client = findEnrollmentStateClientLocked(listener);
+ if (client == null) {
+ Log.e(TAG, "unregisterEnrollmentCallback(): listener was not previously "
+ + "registered");
+ return;
+ }
+ listener.asBinder().unlinkToDeath(client, 0);
+ mEnrollmentStateClients.remove(client);
+ }
+
+ /**
+ * Registers a {@link ICarTrustAgentBleCallback} to be notified for changes to the BLE state
+ * changes.
+ *
+ * @param listener {@link ICarTrustAgentBleCallback}
+ */
+ @Override
+ public synchronized void registerBleCallback(ICarTrustAgentBleCallback listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("Listener is null");
+ }
+ // If a new client is registering, create a new EnrollmentStateClient and add it to the list
+ // of listening clients.
+ BleStateChangeClient client = findBleStateClientLocked(listener);
+ if (client == null) {
+ client = new BleStateChangeClient(listener);
+ try {
+ listener.asBinder().linkToDeath(client, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Cannot link death recipient to binder " + e);
+ return;
+ }
+ mBleStateChangeClients.add(client);
+ }
+ }
+
+ /**
+ * Iterates through the list of registered BLE State Change clients -
+ * {@link BleStateChangeClient} and finds if the given client is already registered.
+ *
+ * @param listener Listener to look for.
+ * @return the {@link BleStateChangeClient} if found, null if not
+ */
+ @Nullable
+ private BleStateChangeClient findBleStateClientLocked(
+ ICarTrustAgentBleCallback listener) {
+ IBinder binder = listener.asBinder();
+ // Find the listener by comparing the binder object they host.
+ for (BleStateChangeClient client : mBleStateChangeClients) {
+ if (client.isHoldingBinder(binder)) {
+ return client;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Unregister the given BLE State Change listener
+ *
+ * @param listener client to unregister
+ */
+ @Override
+ public synchronized void unregisterBleCallback(ICarTrustAgentBleCallback listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("Listener is null");
+ }
+
+ BleStateChangeClient client = findBleStateClientLocked(listener);
+ if (client == null) {
+ Log.e(TAG, "unregisterBleCallback(): listener was not previously "
+ + "registered");
+ return;
+ }
+ listener.asBinder().unlinkToDeath(client, 0);
+ mBleStateChangeClients.remove(client);
+ }
+
+ /**
+ * Class that holds onto client related information - listener interface, process that hosts the
+ * binder object etc.
+ * <p>
+ * It also registers for death notifications of the host.
+ */
+ private class EnrollmentStateClient implements IBinder.DeathRecipient {
+ private final IBinder mListenerBinder;
+ private final ICarTrustAgentEnrollmentCallback mListener;
+
+ EnrollmentStateClient(ICarTrustAgentEnrollmentCallback listener) {
+ mListener = listener;
+ mListenerBinder = listener.asBinder();
+ }
+
+ @Override
+ public void binderDied() {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Binder died " + mListenerBinder);
+ }
+ mListenerBinder.unlinkToDeath(this, 0);
+ synchronized (CarTrustAgentEnrollmentService.this) {
+ mEnrollmentStateClients.remove(this);
+ }
+ }
+
+ /**
+ * Returns if the given binder object matches to what this client info holds.
+ * Used to check if the listener asking to be registered is already registered.
+ *
+ * @return true if matches, false if not
+ */
+ public boolean isHoldingBinder(IBinder binder) {
+ return mListenerBinder == binder;
+ }
+ }
+
+ private class BleStateChangeClient implements IBinder.DeathRecipient {
+ private final IBinder mListenerBinder;
+ private final ICarTrustAgentBleCallback mListener;
+
+ BleStateChangeClient(ICarTrustAgentBleCallback listener) {
+ mListener = listener;
+ mListenerBinder = listener.asBinder();
+ }
+
+ @Override
+ public void binderDied() {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Binder died " + mListenerBinder);
+ }
+ mListenerBinder.unlinkToDeath(this, 0);
+ synchronized (CarTrustAgentEnrollmentService.this) {
+ mBleStateChangeClients.remove(this);
+ }
+ }
+
+ /**
+ * Returns if the given binder object matches to what this client info holds.
+ * Used to check if the listener asking to be registered is already registered.
+ *
+ * @return true if matches, false if not
+ */
+ public boolean isHoldingBinder(IBinder binder) {
+ return mListenerBinder == binder;
+ }
+
+ }
+
+ @Override
+ public void dump(PrintWriter writer) {
+ }
+}
diff --git a/tests/UxRestrictionsSample/res/layout/main_activity.xml b/tests/UxRestrictionsSample/res/layout/main_activity.xml
index 851497a..0b097fb 100644
--- a/tests/UxRestrictionsSample/res/layout/main_activity.xml
+++ b/tests/UxRestrictionsSample/res/layout/main_activity.xml
@@ -26,41 +26,50 @@
android:orientation="vertical">
<TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
android:text="@string/status_header"
android:layout_gravity="center"
android:padding="@dimen/section_padding"
android:textSize="@dimen/header_text_size"
- android:layout_width="match_parent"
- android:textAppearance="?android:textAppearanceLarge"
- android:layout_height="wrap_content"/>
+ android:textAppearance="?android:textAppearanceLarge"/>
<TextView
android:id="@+id/driving_state"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
android:text="@string/driving_state"
android:textSize="@dimen/info_text_size"
android:layout_gravity="center"
android:padding="@dimen/section_padding"
- android:layout_width="match_parent"
- android:textAppearance="?android:textAppearanceLarge"
- android:layout_height="wrap_content"/>
+ android:textAppearance="?android:textAppearanceLarge"/>
<TextView
android:id="@+id/do_status"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
android:text="@string/is_do_reqd"
android:textSize="@dimen/info_text_size"
android:padding="@dimen/section_padding"
- android:layout_width="match_parent"
- android:textAppearance="?android:textAppearanceLarge"
- android:layout_height="wrap_content"/>
+ android:textAppearance="?android:textAppearanceLarge"/>
<TextView
android:id="@+id/uxr_status"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
android:text="@string/active_restrictions"
android:padding="@dimen/section_padding"
android:textSize="@dimen/info_text_size"
+ android:textAppearance="?android:textAppearanceLarge"/>
+
+ <TextView
+ android:id="@+id/show_uxr_config"
android:layout_width="match_parent"
- android:textAppearance="?android:textAppearanceLarge"
- android:layout_height="wrap_content"/>
+ android:layout_height="wrap_content"
+ android:text="@string/uxr_config_header"
+ android:padding="@dimen/section_padding"
+ android:textSize="@dimen/info_text_size"
+ android:textAppearance="?android:textAppearanceLarge"/>
<View
android:layout_width="match_parent"
@@ -70,12 +79,12 @@
android:background="@android:color/darker_gray"/>
<TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
android:text="@string/action_header"
android:padding="@dimen/section_padding"
android:textSize="@dimen/header_text_size"
- android:layout_width="match_parent"
- android:textAppearance="?android:textAppearanceLarge"
- android:layout_height="wrap_content"/>
+ android:textAppearance="?android:textAppearanceLarge"/>
<LinearLayout
android:layout_width="match_parent"
@@ -84,10 +93,29 @@
android:id="@+id/toggle_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/section_padding"
android:padding="@dimen/section_padding"
android:text="@string/disable_uxr"
android:textAllCaps="false"
android:textSize="@dimen/info_text_size"/>
+ <Button
+ android:id="@+id/show_staged_config"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/section_padding"
+ android:padding="@dimen/section_padding"
+ android:text="@string/show_staged_config"
+ android:textAllCaps="false"
+ android:textSize="@dimen/info_text_size"/>
+ <Button
+ android:id="@+id/show_prod_config"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/section_padding"
+ android:padding="@dimen/section_padding"
+ android:text="@string/show_prod_config"
+ android:textAllCaps="false"
+ android:textSize="@dimen/info_text_size"/>
</LinearLayout>
<View
@@ -98,12 +126,12 @@
android:background="@android:color/darker_gray"/>
<TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
android:text="@string/sample_header"
android:padding="@dimen/section_padding"
android:textSize="@dimen/header_text_size"
- android:layout_width="match_parent"
- android:textAppearance="?android:textAppearanceLarge"
- android:layout_height="wrap_content"/>
+ android:textAppearance="?android:textAppearanceLarge"/>
<LinearLayout
android:layout_width="match_parent"
@@ -112,6 +140,7 @@
android:id="@+id/launch_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:padding="@dimen/section_padding"
android:text="@string/sample_msg_activity"
android:textAllCaps="false"
android:textSize="@dimen/info_text_size"/>
@@ -125,12 +154,12 @@
android:background="@android:color/darker_gray"/>
<TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
android:text="@string/save_uxr_config_header"
android:padding="@dimen/section_padding"
android:textSize="@dimen/header_text_size"
- android:layout_width="match_parent"
- android:textAppearance="?android:textAppearanceLarge"
- android:layout_height="wrap_content"/>
+ android:textAppearance="?android:textAppearanceLarge"/>
<LinearLayout
android:layout_width="match_parent"
@@ -139,6 +168,7 @@
android:id="@+id/save_uxr_config"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:padding="@dimen/section_padding"
android:text="@string/save_uxr_config"
android:textSize="@dimen/info_text_size"/>
</LinearLayout>
diff --git a/tests/UxRestrictionsSample/res/values/strings.xml b/tests/UxRestrictionsSample/res/values/strings.xml
index aa32ff4..b36d7f9 100644
--- a/tests/UxRestrictionsSample/res/values/strings.xml
+++ b/tests/UxRestrictionsSample/res/values/strings.xml
@@ -20,8 +20,11 @@
<string name="driving_state" translatable="false">Driving State: </string>
<string name="is_do_reqd" translatable="false">Distraction Optimization Required? </string>
<string name="active_restrictions" translatable="false">Active UX Restrictions: </string>
+ <string name="uxr_config_header" translatable="false">UxR Configuration: </string>
<string name="action_header" translatable="false"><u>Available Actions</u></string>
<string name="disable_uxr" translatable="false">Disable Ux Restriction Engine</string>
+ <string name="show_staged_config" translatable="false">Show Staged Config</string>
+ <string name="show_prod_config" translatable="false">Show Production Config</string>
<string name="sample_header" translatable="false"><u>Sample Activities</u></string>
<string name="sample_msg_activity" translatable="false">Sample Message Activity</string>
<string name="return_home" translatable="false"><u>Return Home</u></string>
@@ -30,4 +33,8 @@
<string name="set_uxr_config_dialog_title" translatable="false">Select restrictions for IDLING/MOVING</string>
<string name="set_uxr_config_dialog_negative_button" translatable="false">Cancel</string>
<string name="set_uxr_config_dialog_positive_button" translatable="false">Save UXR Config</string>
+ <string name="no_staged_config" translatable="false">There is no staged configuration found</string>
+ <string name="no_prod_config" translatable="false">There is no production configuration found</string>
+ <string name="staged_config_title" translatable="false">Staged Config</string>
+ <string name="prod_config_title" translatable="false">Production Config</string>
</resources>
diff --git a/tests/UxRestrictionsSample/src/com/google/android/car/uxr/sample/MainActivity.java b/tests/UxRestrictionsSample/src/com/google/android/car/uxr/sample/MainActivity.java
index cd9c015..27738bc 100644
--- a/tests/UxRestrictionsSample/src/com/google/android/car/uxr/sample/MainActivity.java
+++ b/tests/UxRestrictionsSample/src/com/google/android/car/uxr/sample/MainActivity.java
@@ -34,11 +34,14 @@
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
+import android.util.JsonWriter;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
+import java.io.CharArrayWriter;
+
/**
* Sample app that uses components in car support library to demonstrate Car drivingstate UXR
* status.
@@ -47,7 +50,7 @@
public static final String TAG = "drivingstate";
// Order of elements is based on number of bits shifted in value of the constants.
- private static final CharSequence[] UX_RESTRICTION_NAMES = new CharSequence[] {
+ private static final CharSequence[] UX_RESTRICTION_NAMES = new CharSequence[]{
"BASELINE",
"NO_DIALPAD",
"NO_FILTERING",
@@ -70,6 +73,8 @@
private Button mToggleButton;
private Button mSampleMsgButton;
private Button mSaveUxrConfigButton;
+ private Button mShowStagedConfig;
+ private Button mShowProdConfig;
private boolean mEnableUxR;
@@ -86,7 +91,6 @@
Car.CAR_UX_RESTRICTION_SERVICE);
mCarPackageManager = (CarPackageManager) mCar.getCarManager(
Car.PACKAGE_SERVICE);
-
if (mCarDrivingStateManager != null) {
mCarDrivingStateManager.registerListener(mDrvStateChangeListener);
updateDrivingStateText(
@@ -183,6 +187,10 @@
mSaveUxrConfigButton = findViewById(R.id.save_uxr_config);
mSaveUxrConfigButton.setOnClickListener(v -> saveUxrConfig());
+ mShowStagedConfig = findViewById(R.id.show_staged_config);
+ mShowStagedConfig.setOnClickListener(v -> showStagedUxRestrictionsConfig());
+ mShowProdConfig = findViewById(R.id.show_prod_config);
+ mShowProdConfig.setOnClickListener(v -> showProdUxRestrictionsConfig());
mToggleButton.setOnClickListener(v -> updateToggleUxREnable());
mSampleMsgButton = findViewById(R.id.launch_message);
@@ -228,6 +236,56 @@
}
}
+ private void showStagedUxRestrictionsConfig() {
+ try {
+ CarUxRestrictionsConfiguration stagedConfig =
+ mCarUxRestrictionsManager.getStagedConfig();
+ if (stagedConfig == null) {
+ new AlertDialog.Builder(this)
+ .setMessage(R.string.no_staged_config)
+ .show();
+ return;
+ }
+ CharArrayWriter charWriter = new CharArrayWriter();
+ JsonWriter writer = new JsonWriter(charWriter);
+ writer.setIndent("\t");
+ stagedConfig.writeJson(writer);
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.staged_config_title)
+ .setMessage(charWriter.toString())
+ .show();
+ } catch (CarNotConnectedException e) {
+ Log.e(TAG, "Car not connected", e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void showProdUxRestrictionsConfig() {
+ try {
+ CarUxRestrictionsConfiguration prodConfig =
+ mCarUxRestrictionsManager.getConfig();
+ if (prodConfig == null) {
+ new AlertDialog.Builder(this)
+ .setMessage(R.string.no_prod_config)
+ .show();
+ return;
+ }
+ CharArrayWriter charWriter = new CharArrayWriter();
+ JsonWriter writer = new JsonWriter(charWriter);
+ writer.setIndent("\t");
+ prodConfig.writeJson(writer);
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.prod_config_title)
+ .setMessage(charWriter.toString())
+ .show();
+ } catch (CarNotConnectedException e) {
+ Log.e(TAG, "Car not connected", e);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
private void launchSampleMsgActivity(View view) {
Intent msgIntent = new Intent(this, SampleMessageActivity.class);
startActivity(msgIntent);
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/VmsHalServiceTest.java b/tests/carservice_unit_test/src/com/android/car/hal/VmsHalServiceTest.java
new file mode 100644
index 0000000..3e9eb56
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/hal/VmsHalServiceTest.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.hal;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.car.vms.VmsAssociatedLayer;
+import android.car.vms.VmsAvailableLayers;
+import android.car.vms.VmsLayer;
+import android.car.vms.VmsLayerDependency;
+import android.car.vms.VmsLayersOffering;
+import android.os.Binder;
+import android.os.IBinder;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.android.collect.Sets;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(AndroidJUnit4.class)
+public class VmsHalServiceTest {
+ @Rule public MockitoRule mockito = MockitoJUnit.rule();
+ @Mock private VehicleHal mMockVehicleHal;
+ @Mock private VmsHalService.VmsHalSubscriberListener mMockHalSusbcriber;
+ private IBinder mToken;
+ private VmsHalService mHalService;
+
+ @Before
+ public void setUp() throws Exception {
+ mToken = new Binder();
+ mHalService = new VmsHalService(mMockVehicleHal);
+ mHalService.addSubscriberListener(mMockHalSusbcriber);
+ }
+
+ @Test
+ public void testSetPublisherLayersOffering() {
+ VmsLayer layer = new VmsLayer(1, 2, 3);
+ VmsLayersOffering offering = new VmsLayersOffering(
+ Sets.newHashSet(new VmsLayerDependency(layer)), 12345);
+ mHalService.setPublisherLayersOffering(mToken, offering);
+
+ VmsAssociatedLayer associatedLayer = new VmsAssociatedLayer(layer, Sets.newHashSet(12345));
+ verify(mMockHalSusbcriber).onLayersAvaiabilityChange(eq(new VmsAvailableLayers(
+ Sets.newHashSet(associatedLayer),
+ 1)));
+ }
+
+ @Test
+ public void testSetPublisherLayersOffering_Repeated() {
+ VmsLayer layer = new VmsLayer(1, 2, 3);
+ VmsLayersOffering offering = new VmsLayersOffering(
+ Sets.newHashSet(new VmsLayerDependency(layer)), 12345);
+ mHalService.setPublisherLayersOffering(mToken, offering);
+ mHalService.setPublisherLayersOffering(mToken, offering);
+
+ VmsAssociatedLayer associatedLayer = new VmsAssociatedLayer(layer, Sets.newHashSet(12345));
+ verify(mMockHalSusbcriber).onLayersAvaiabilityChange(eq(new VmsAvailableLayers(
+ Sets.newHashSet(associatedLayer),
+ 1)));
+ verify(mMockHalSusbcriber).onLayersAvaiabilityChange(eq(new VmsAvailableLayers(
+ Sets.newHashSet(associatedLayer),
+ 2)));
+
+ }
+
+ @Test
+ public void testSetPublisherLayersOffering_MultiplePublishers() {
+ VmsLayer layer = new VmsLayer(1, 2, 3);
+ VmsLayersOffering offering = new VmsLayersOffering(
+ Sets.newHashSet(new VmsLayerDependency(layer)), 12345);
+ VmsLayersOffering offering2 = new VmsLayersOffering(
+ Sets.newHashSet(new VmsLayerDependency(layer)), 54321);
+ mHalService.setPublisherLayersOffering(mToken, offering);
+ mHalService.setPublisherLayersOffering(new Binder(), offering2);
+
+ verify(mMockHalSusbcriber).onLayersAvaiabilityChange(eq(new VmsAvailableLayers(
+ Sets.newHashSet(new VmsAssociatedLayer(layer, Sets.newHashSet(12345))),
+ 1)));
+ verify(mMockHalSusbcriber).onLayersAvaiabilityChange(eq(new VmsAvailableLayers(
+ Sets.newHashSet(new VmsAssociatedLayer(layer, Sets.newHashSet(12345, 54321))),
+ 2)));
+
+ }
+
+ @Test
+ public void testSetPublisherLayersOffering_MultiplePublishers_SharedToken() {
+ VmsLayer layer = new VmsLayer(1, 2, 3);
+ VmsLayersOffering offering = new VmsLayersOffering(
+ Sets.newHashSet(new VmsLayerDependency(layer)), 12345);
+ VmsLayersOffering offering2 = new VmsLayersOffering(
+ Sets.newHashSet(new VmsLayerDependency(layer)), 54321);
+ mHalService.setPublisherLayersOffering(mToken, offering);
+ mHalService.setPublisherLayersOffering(mToken, offering2);
+
+ verify(mMockHalSusbcriber).onLayersAvaiabilityChange(eq(new VmsAvailableLayers(
+ Sets.newHashSet(new VmsAssociatedLayer(layer, Sets.newHashSet(12345))),
+ 1)));
+ verify(mMockHalSusbcriber).onLayersAvaiabilityChange(eq(new VmsAvailableLayers(
+ Sets.newHashSet(new VmsAssociatedLayer(layer, Sets.newHashSet(12345, 54321))),
+ 2)));
+ }
+
+ @Test
+ public void testSetPublisherLayersOffering_MultiplePublishers_MultipleLayers() {
+ VmsLayer layer = new VmsLayer(1, 2, 3);
+ VmsLayer layer2 = new VmsLayer(2, 2, 3);
+ VmsLayersOffering offering = new VmsLayersOffering(
+ Sets.newHashSet(new VmsLayerDependency(layer)), 12345);
+ VmsLayersOffering offering2 = new VmsLayersOffering(
+ Sets.newHashSet(new VmsLayerDependency(layer2)), 54321);
+ mHalService.setPublisherLayersOffering(mToken, offering);
+ mHalService.setPublisherLayersOffering(new Binder(), offering2);
+
+ verify(mMockHalSusbcriber).onLayersAvaiabilityChange(eq(new VmsAvailableLayers(
+ Sets.newHashSet(new VmsAssociatedLayer(layer, Sets.newHashSet(12345))),
+ 1)));
+ verify(mMockHalSusbcriber).onLayersAvaiabilityChange(eq(new VmsAvailableLayers(
+ Sets.newHashSet(
+ new VmsAssociatedLayer(layer, Sets.newHashSet(12345)),
+ new VmsAssociatedLayer(layer2, Sets.newHashSet(54321))),
+ 2)));
+
+ }
+
+ @Test
+ public void testSetPublisherLayersOffering_MultiplePublishers_MultipleLayers_SharedToken() {
+ VmsLayer layer = new VmsLayer(1, 2, 3);
+ VmsLayer layer2 = new VmsLayer(2, 2, 3);
+ VmsLayersOffering offering = new VmsLayersOffering(
+ Sets.newHashSet(new VmsLayerDependency(layer)), 12345);
+ VmsLayersOffering offering2 = new VmsLayersOffering(
+ Sets.newHashSet(new VmsLayerDependency(layer2)), 54321);
+ mHalService.setPublisherLayersOffering(mToken, offering);
+ mHalService.setPublisherLayersOffering(mToken, offering2);
+
+ verify(mMockHalSusbcriber).onLayersAvaiabilityChange(eq(new VmsAvailableLayers(
+ Sets.newHashSet(new VmsAssociatedLayer(layer, Sets.newHashSet(12345))),
+ 1)));
+ verify(mMockHalSusbcriber).onLayersAvaiabilityChange(eq(new VmsAvailableLayers(
+ Sets.newHashSet(
+ new VmsAssociatedLayer(layer, Sets.newHashSet(12345)),
+ new VmsAssociatedLayer(layer2, Sets.newHashSet(54321))),
+ 2)));
+
+ }
+}
diff --git a/tests/obd2_app/res/values-en-rXC/arrays.xml b/tests/obd2_app/res/values-en-rXC/arrays.xml
new file mode 100644
index 0000000..0e5cd26
--- /dev/null
+++ b/tests/obd2_app/res/values-en-rXC/arrays.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2017 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:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="scan_delay_entries">
+ <item msgid="6824939704660193492">"2 seconds"</item>
+ <item msgid="4283574244056233745">"5 seconds"</item>
+ <item msgid="8984629990034652828">"10 seconds"</item>
+ </string-array>
+ <string-array name="scan_delay_entryValues">
+ <item msgid="9084818712104183355">"2"</item>
+ <item msgid="7912051093881958943">"5"</item>
+ <item msgid="8452837398897797309">"10"</item>
+ </string-array>
+</resources>
diff --git a/user/car-user-lib/src/android/car/userlib/CarUserManagerHelper.java b/user/car-user-lib/src/android/car/userlib/CarUserManagerHelper.java
index 4e7e02c..fe39d51 100644
--- a/user/car-user-lib/src/android/car/userlib/CarUserManagerHelper.java
+++ b/user/car-user-lib/src/android/car/userlib/CarUserManagerHelper.java
@@ -63,7 +63,8 @@
* Default set of restrictions for Non-Admin users.
*/
private static final Set<String> DEFAULT_NON_ADMIN_RESTRICTIONS = Sets.newArraySet(
- UserManager.DISALLOW_FACTORY_RESET
+ UserManager.DISALLOW_FACTORY_RESET,
+ UserManager.DISALLOW_RUN_IN_BACKGROUND
);
/**